From 9fdd30556bf391428e1d3f2f9e91dbbdf771fa84 Mon Sep 17 00:00:00 2001 From: Douglas Gillespie <50671166+douggillespie@users.noreply.github.com> Date: Tue, 12 Jul 2022 15:53:07 +0100 Subject: [PATCH] Variable sound output level (#39) Mods to SoundPlayback module to allow additional parameters. Implemented system for NI cards to allow changes to selected output voltage range meaning output can be boosted to level higher than current default. --- src/asiojni/ASIOFilePlaybackSystem.java | 7 ++ src/nidaqdev/NIFilePlayback.java | 69 ++++++++++++++- src/nidaqdev/NIFilePlaybackParams.java | 21 +++++ src/nidaqdev/NIPlaybackSettingsPanel.java | 83 +++++++++++++++++++ src/nidaqdev/Nidaq.java | 14 +++- src/soundPlayback/FilePlaybackDevice.java | 7 ++ src/soundPlayback/SoundCardFilePlayback.java | 7 ++ .../swing/FilePlaybackDialogComponent.java | 36 +++++++- 8 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 src/nidaqdev/NIFilePlaybackParams.java create mode 100644 src/nidaqdev/NIPlaybackSettingsPanel.java diff --git a/src/asiojni/ASIOFilePlaybackSystem.java b/src/asiojni/ASIOFilePlaybackSystem.java index 39e49fad..f0c270d7 100644 --- a/src/asiojni/ASIOFilePlaybackSystem.java +++ b/src/asiojni/ASIOFilePlaybackSystem.java @@ -16,6 +16,7 @@ import com.synthbot.jasiohost.AsioSampleType; import PamController.PamController; import PamDetection.RawDataUnit; import PamUtils.PamUtils; +import PamView.dialog.PamDialogPanel; import PamguardMVC.PamConstants; import soundPlayback.FilePlayback; import soundPlayback.FilePlaybackDevice; @@ -334,4 +335,10 @@ public class ASIOFilePlaybackSystem implements FilePlaybackDevice { return null; } + @Override + public PamDialogPanel getSettingsPanel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/src/nidaqdev/NIFilePlayback.java b/src/nidaqdev/NIFilePlayback.java index ddd8ddc2..f87a35ef 100644 --- a/src/nidaqdev/NIFilePlayback.java +++ b/src/nidaqdev/NIFilePlayback.java @@ -1,10 +1,15 @@ package nidaqdev; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; +import PamController.PamControlledUnitSettings; +import PamController.PamSettingManager; +import PamController.PamSettings; import PamDetection.RawDataUnit; import PamUtils.PamUtils; +import PamView.dialog.PamDialogPanel; import soundPlayback.FilePlayback; import soundPlayback.FilePlaybackDevice; import soundPlayback.PlayDeviceState; @@ -17,7 +22,7 @@ import soundPlayback.PlaybackParameters; * @author Doug Gillespie * */ -public class NIFilePlayback implements FilePlaybackDevice { +public class NIFilePlayback implements FilePlaybackDevice, PamSettings { private volatile boolean prepared; @@ -39,9 +44,14 @@ public class NIFilePlayback implements FilePlaybackDevice { private NIDeviceInfo currentDeviceInfo; + private NIPlaybackSettingsPanel playSettingsPanel; + + private NIFilePlaybackParams niFilePlaybackParams = new NIFilePlaybackParams(); + public NIFilePlayback(FilePlayback filePlayback) { super(); this.filePlayback = filePlayback; + PamSettingManager.getInstance().registerSettings(this); niDaq = new Nidaq(); getNIDevices(); } @@ -131,7 +141,7 @@ public class NIFilePlayback implements FilePlaybackDevice { } int playRate = (int) playbackParameters.getPlaybackRate(); - int ans = niDaq.javaPreparePlayback(bn, playRate, playRate, outchans); + int ans = niDaq.javaPreparePlayback(bn, playRate, playRate, outchans, (float) niFilePlaybackParams.outputRange); // System.out.println("NI Answer = " + ans); prepared = (ans == 0); return prepared; @@ -163,4 +173,59 @@ public class NIFilePlayback implements FilePlaybackDevice { } } + @Override + public PamDialogPanel getSettingsPanel() { + if (playSettingsPanel == null) { + playSettingsPanel = new NIPlaybackSettingsPanel(this); + } + return playSettingsPanel; + } + + /** + * @return the niFilePlaybackParams + */ + public NIFilePlaybackParams getNiFilePlaybackParams() { + return niFilePlaybackParams; + } + + /** + * @param niFilePlaybackParams the niFilePlaybackParams to set + */ + public void setNiFilePlaybackParams(NIFilePlaybackParams niFilePlaybackParams) { + this.niFilePlaybackParams = niFilePlaybackParams; + } + + @Override + public String getUnitName() { + return "NIFilePalybackSettings"; + } + + @Override + public String getUnitType() { + return "NIFilePalybackSettings"; + } + + @Override + public Serializable getSettingsReference() { + return niFilePlaybackParams; + } + + @Override + public long getSettingsVersion() { + return NIFilePlaybackParams.serialVersionUID; + } + + @Override + public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) { + niFilePlaybackParams = (NIFilePlaybackParams) pamControlledUnitSettings.getSettings(); + return true; + } + + /** + * @return the currentDeviceInfo + */ + public NIDeviceInfo getCurrentDeviceInfo() { + return currentDeviceInfo; + } + } diff --git a/src/nidaqdev/NIFilePlaybackParams.java b/src/nidaqdev/NIFilePlaybackParams.java new file mode 100644 index 00000000..fc6c01bb --- /dev/null +++ b/src/nidaqdev/NIFilePlaybackParams.java @@ -0,0 +1,21 @@ +package nidaqdev; + +import java.io.Serializable; + +public class NIFilePlaybackParams implements Serializable, Cloneable{ + + public static final long serialVersionUID = 1L; + + public double outputRange = 2.0; + + @Override + protected NIFilePlaybackParams clone() { + try { + return (NIFilePlaybackParams) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/src/nidaqdev/NIPlaybackSettingsPanel.java b/src/nidaqdev/NIPlaybackSettingsPanel.java new file mode 100644 index 00000000..65af6c88 --- /dev/null +++ b/src/nidaqdev/NIPlaybackSettingsPanel.java @@ -0,0 +1,83 @@ +package nidaqdev; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + +import PamView.dialog.PamDialog; +import PamView.dialog.PamDialogPanel; +import PamView.dialog.PamGridBagContraints; + +public class NIPlaybackSettingsPanel implements PamDialogPanel { + + private NIFilePlayback niFilePlayback; + + private JPanel mainPanel; + + private JComboBox outputLevel; + + public NIPlaybackSettingsPanel(NIFilePlayback niFilePlayback) { + this.niFilePlayback = niFilePlayback; + mainPanel = new JPanel(new GridBagLayout()); + mainPanel.setBorder(new TitledBorder("NI Play options")); + GridBagConstraints c = new PamGridBagContraints(); + + mainPanel.add(new JLabel("Output level ", JLabel.RIGHT), c); + c.gridx++; + mainPanel.add(outputLevel = new JComboBox<>(), c); + c.gridx++; + mainPanel.add(new JLabel(" V(0-p)"), c); + + outputLevel.addItem("1.0"); + outputLevel.addItem("10.0"); + } + + @Override + public JComponent getDialogComponent() { + return mainPanel; + } + + @Override + public void setParams() { + NIDeviceInfo deviceInfo = niFilePlayback.getCurrentDeviceInfo(); + NIFilePlaybackParams params = niFilePlayback.getNiFilePlaybackParams(); + if (deviceInfo == null) { + return; + } + int nRange = deviceInfo.getNumAOVoltageRanges(); + outputLevel.removeAllItems(); + int selInd = -1; + for (int i = 0; i < nRange; i++) { + double aRange = deviceInfo.getAOVoltageRangeEnd(i); + outputLevel.addItem(String.format("%3.1f", aRange)); + if (aRange == params.outputRange) { + selInd = i; + } + } + if (selInd >= 0) { + outputLevel.setSelectedIndex(selInd); + } + } + + @Override + public boolean getParams() { + NIDeviceInfo deviceInfo = niFilePlayback.getCurrentDeviceInfo(); + NIFilePlaybackParams params = niFilePlayback.getNiFilePlaybackParams(); + if (deviceInfo == null) { + return false; + } + int nRange = deviceInfo.getNumAOVoltageRanges(); + int selInd = outputLevel.getSelectedIndex(); + if (selInd < 0 || selInd >= nRange) { + return PamDialog.showWarning(null, "Invalid parameter", "Invalid output range"); + } + params.outputRange = deviceInfo.getAOVoltageRangeEnd(selInd); + return true; + } + +} diff --git a/src/nidaqdev/Nidaq.java b/src/nidaqdev/Nidaq.java index 800b5f48..a3609da6 100644 --- a/src/nidaqdev/Nidaq.java +++ b/src/nidaqdev/Nidaq.java @@ -253,8 +253,20 @@ public class Nidaq { public int javaPreparePlayback(int boardNumber, int sampleRate, int bufferSamples, int[] outputChannelList) { +// if (loadLibraryOK) { +// return jniPreparePlayback(boardNumber, sampleRate, playVoltageRange, bufferSamples, outputChannelList); +// } +// else { +// return 0; +// } + return javaPreparePlayback(boardNumber, sampleRate, bufferSamples, outputChannelList, playVoltageRange); + } + + public int javaPreparePlayback(int boardNumber, int sampleRate, + int bufferSamples, int[] outputChannelList, float outputLevel) { if (loadLibraryOK) { - return jniPreparePlayback(boardNumber, sampleRate, playVoltageRange, bufferSamples, outputChannelList); + outputLevel = Math.abs(outputLevel); + return jniPreparePlayback(boardNumber, sampleRate, outputLevel, bufferSamples, outputChannelList); } else { return 0; diff --git a/src/soundPlayback/FilePlaybackDevice.java b/src/soundPlayback/FilePlaybackDevice.java index 1c5d73df..58a1aa12 100644 --- a/src/soundPlayback/FilePlaybackDevice.java +++ b/src/soundPlayback/FilePlaybackDevice.java @@ -1,6 +1,7 @@ package soundPlayback; import PamDetection.RawDataUnit; +import PamView.dialog.PamDialogPanel; /** * Interface to device types that can be used to play @@ -67,4 +68,10 @@ public interface FilePlaybackDevice { public String getDeviceName(); + /** + * Get a settings panel for additional options. Can be null. + * @return settings panel or null for additional options. + */ + public PamDialogPanel getSettingsPanel(); + } diff --git a/src/soundPlayback/SoundCardFilePlayback.java b/src/soundPlayback/SoundCardFilePlayback.java index 34775b90..86ed3372 100644 --- a/src/soundPlayback/SoundCardFilePlayback.java +++ b/src/soundPlayback/SoundCardFilePlayback.java @@ -15,6 +15,7 @@ import Acquisition.SoundCardSystem; import PamDetection.RawDataUnit; import PamUtils.PamCalendar; import PamUtils.PamUtils; +import PamView.dialog.PamDialogPanel; import warnings.PamWarning; import warnings.WarningSystem; @@ -89,4 +90,10 @@ public class SoundCardFilePlayback implements FilePlaybackDevice { return soundCardPlaybackBase.getDeviceState(); } + @Override + public PamDialogPanel getSettingsPanel() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/src/soundPlayback/swing/FilePlaybackDialogComponent.java b/src/soundPlayback/swing/FilePlaybackDialogComponent.java index 670a95a3..8d8abc72 100644 --- a/src/soundPlayback/swing/FilePlaybackDialogComponent.java +++ b/src/soundPlayback/swing/FilePlaybackDialogComponent.java @@ -20,8 +20,11 @@ import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import PamView.dialog.GenericSwingDialog; import PamView.dialog.PamDialog; +import PamView.dialog.PamDialogPanel; import PamView.dialog.PamGridBagContraints; +import PamView.dialog.SettingsButton; import PamguardMVC.PamDataBlock; import PamguardMVC.PamRawDataBlock; import soundPlayback.FilePlayback; @@ -48,6 +51,8 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { private FilePlayback filePlayback; private PlaybackParameters playbackParameters; + + private SettingsButton deviceSettingsButton; private JButton defButton; @@ -57,6 +62,8 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { private PamDataBlock dataSource; + private FilePlaybackDevice selectedDeviceType; + /** * Dialog component for sound playback when input is from a file. *

@@ -91,10 +98,23 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { c.gridy++; PamDialog.addComponent(panel, deviceTypes, c); c.gridy++; + c.gridwidth = 3; PamDialog.addComponent(panel, new JLabel("Output device name ..."), c); + c.gridx += c.gridwidth; + c.gridwidth = 1; + PamDialog.addComponent(panel, deviceSettingsButton = new SettingsButton(), c); + c.gridx = 0; + c.gridwidth = 4; c.gridy++; PamDialog.addComponent(panel, soundCards, c); + deviceSettingsButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + deviceSettings(); + } + }); + c.gridy++; c.gridx = 0; c.gridwidth = 1; @@ -153,6 +173,17 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { } + protected void deviceSettings() { + if (selectedDeviceType == null) { + return; + } + PamDialogPanel devicePanel = selectedDeviceType.getSettingsPanel(); + if (devicePanel == null) { + return; + } + GenericSwingDialog.showDialog(getParentDialog(), "More Settings", devicePanel); + } + private void playSpeedChange() { playbackSpeed.setText(playSpeedSlider.getRatioString()); sayDecimateInfo(); @@ -280,6 +311,9 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { if (parentDialog != null) { parentDialog.pack(); } + if (selectedDeviceType != null) { + deviceSettingsButton.setEnabled(selectedDeviceType.getSettingsPanel() != null); + } } } @@ -297,7 +331,7 @@ public class FilePlaybackDialogComponent extends PlaybackDialogComponent { public void fillDeviceSpecificList() { int deviceType = deviceTypes.getSelectedIndex(); deviceType = Math.max(0, deviceType); - FilePlaybackDevice selectedDeviceType = filePlayback.getFilePBDevices().get(deviceType); + selectedDeviceType = filePlayback.getFilePBDevices().get(deviceType); soundCards.removeAllItems(); String[] devList = selectedDeviceType.getDeviceNames(); for (int i = 0; i < devList.length; i++) {