From 3fe070987a2616c411d64fa380718123bb1f9036 Mon Sep 17 00:00:00 2001 From: Denny Sheirer Date: Sat, 23 Nov 2019 12:55:12 -0500 Subject: [PATCH] Resolves issue with clunky process for adding recording tuners. (#605) --- .../channelizer/PolyphaseChannelManager.java | 31 ++- .../dsheirer/source/tuner/TunerViewPanel.java | 17 +- .../recording/AddRecordingTunerDialog.java | 259 ++++++++++++++++++ .../tuner/recording/RecordingTuner.java | 2 - 4 files changed, 291 insertions(+), 18 deletions(-) create mode 100644 src/main/java/io/github/dsheirer/source/tuner/recording/AddRecordingTunerDialog.java diff --git a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java index dd57205a..33ee5d3f 100644 --- a/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java +++ b/src/main/java/io/github/dsheirer/dsp/filter/channelizer/PolyphaseChannelManager.java @@ -1,18 +1,24 @@ -/******************************************************************************* - * sdr-trunk - * Copyright (C) 2014-2018 Dennis Sheirer +/* * - * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any - * later version. + * * ****************************************************************************** + * * Copyright (C) 2014-2019 Dennis Sheirer + * * + * * This program is free software: you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation, either version 3 of the License, or + * * (at your option) any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program. If not, see + * * ***************************************************************************** * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see - * - ******************************************************************************/ + */ package io.github.dsheirer.dsp.filter.channelizer; import io.github.dsheirer.dsp.filter.FilterFactory; @@ -299,6 +305,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED: case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED: case NOTIFICATION_FREQUENCY_CORRECTION_CHANGE: + case NOTIFICATION_RECORDING_FILE_LOADED: //no-op break; default: diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java index f4b14208..746e2ab3 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerViewPanel.java @@ -28,7 +28,7 @@ import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor; import io.github.dsheirer.record.RecorderManager; import io.github.dsheirer.sample.Listener; import io.github.dsheirer.source.tuner.TunerEvent.Event; -import io.github.dsheirer.source.tuner.recording.RecordingTuner; +import io.github.dsheirer.source.tuner.recording.AddRecordingTunerDialog; import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,6 +49,7 @@ import javax.swing.table.TableRowSorter; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; @@ -180,9 +181,17 @@ public class TunerViewPanel extends JPanel @Override public void actionPerformed(ActionEvent e) { - RecordingTuner recordingTuner = new RecordingTuner(mUserPreferences); - mTunerModel.addTuner(recordingTuner); - addRecordingTunerButton.setEnabled(mTunerModel.canAddRecordingTuner()); + AddRecordingTunerDialog dialog = new AddRecordingTunerDialog(mUserPreferences, mTunerModel); + dialog.setLocationRelativeTo(TunerViewPanel.this); + + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + dialog.setVisible(true); + } + }); } }); tunerTablePanel.add(addRecordingTunerButton); diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/AddRecordingTunerDialog.java b/src/main/java/io/github/dsheirer/source/tuner/recording/AddRecordingTunerDialog.java new file mode 100644 index 00000000..f2da0707 --- /dev/null +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/AddRecordingTunerDialog.java @@ -0,0 +1,259 @@ +/* + * + * * ****************************************************************************** + * * Copyright (C) 2014-2019 Dennis Sheirer + * * + * * This program is free software: you can redistribute it and/or modify + * * it under the terms of the GNU General Public License as published by + * * the Free Software Foundation, either version 3 of the License, or + * * (at your option) any later version. + * * + * * This program is distributed in the hope that it will be useful, + * * but WITHOUT ANY WARRANTY; without even the implied warranty of + * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * * GNU General Public License for more details. + * * + * * You should have received a copy of the GNU General Public License + * * along with this program. If not, see + * * ***************************************************************************** + * + * + */ + +package io.github.dsheirer.source.tuner.recording; + +import io.github.dsheirer.preference.UserPreferences; +import io.github.dsheirer.properties.SystemProperties; +import io.github.dsheirer.source.tuner.TunerModel; +import net.miginfocom.swing.MigLayout; +import org.apache.commons.lang3.Validate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.filechooser.FileFilter; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Dialog to select a recording and specify a center frequency for use in adding a Recording Tuner + */ +public class AddRecordingTunerDialog extends JFrame +{ + private final static Logger mLog = LoggerFactory.getLogger(AddRecordingTunerDialog.class); + private static final String SELECT_A_FILE = "Please select a recording file"; + private static final String LAST_FILE_BROWSE_LOCATION_KEY = "AddRecordingTunerDialog.lastBrowseLocation"; + private UserPreferences mUserPreferences; + private TunerModel mTunerModel; + private JButton mSelectFileButton; + private File mSelectedRecording; + private JLabel mRecordingFileLabel; + private JLabel mFrequencyLabel; + private JTextField mFrequencyTextField; + private JButton mAddButton; + private JButton mCancelButton; + private static final Pattern TUNER_RECORDING_PATTERN = Pattern.compile("TUNER_(\\d*)_baseband_\\d{8}_\\d{6}\\.wav"); + + public AddRecordingTunerDialog(UserPreferences userPreferences, TunerModel tunerModel) + { + Validate.notNull(userPreferences, "UserPreferences cannot be null"); + Validate.notNull(tunerModel, "TunerModel cannot be null"); + + if(!tunerModel.canAddRecordingTuner()) + { + JOptionPane.showMessageDialog(AddRecordingTunerDialog.this, + "Cannot add a recording tuner. Only one recording tuner can be loaded at any time", + "Cannot Add Recording Tuner", + JOptionPane.ERROR_MESSAGE); + return; + } + + mTunerModel = tunerModel; + mUserPreferences = userPreferences; + + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setTitle("Select Recording File"); + setSize(new Dimension(500, 250)); + + JPanel content = new JPanel(); + content.setLayout(new MigLayout("", "[align right][][]", + "[][][grow][]")); + + mSelectFileButton = new JButton("Select ..."); + mSelectFileButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + JFileChooser fileChooser = new JFileChooser(); + String lastBrowsedDirectory = SystemProperties.getInstance().get(LAST_FILE_BROWSE_LOCATION_KEY, ""); + + File browseDirectory; + + if(lastBrowsedDirectory != null && !lastBrowsedDirectory.isEmpty()) + { + browseDirectory = new File(lastBrowsedDirectory); + } + else + { + browseDirectory = mUserPreferences.getDirectoryPreference().getDefaultRecordingDirectory().toFile(); + } + + fileChooser.setCurrentDirectory(browseDirectory); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setFileFilter(new FileFilter() + { + @Override + public boolean accept(File f) + { + return f.getAbsolutePath().endsWith(".wav") || f.isDirectory(); + } + + @Override + public String getDescription() + { + return "Recordings (*.wav)"; + } + }); + + int returnVal = fileChooser.showOpenDialog(AddRecordingTunerDialog.this); + + File lastDirectory = fileChooser.getCurrentDirectory(); + + if(lastDirectory != null) + { + SystemProperties.getInstance().set(LAST_FILE_BROWSE_LOCATION_KEY, lastDirectory.getAbsolutePath()); + } + + if(returnVal == JFileChooser.APPROVE_OPTION) + { + mSelectedRecording = fileChooser.getSelectedFile(); + + if(mSelectedRecording != null && + (mFrequencyTextField.getText() == null || mFrequencyTextField.getText().isEmpty())) + { + Matcher m = TUNER_RECORDING_PATTERN.matcher(mSelectedRecording.getName()); + + if(m.matches()) + { + mFrequencyTextField.setText(m.group(1)); + } + } + } + else + { + mSelectedRecording = null; + } + + mRecordingFileLabel.setText(mSelectedRecording != null ? mSelectedRecording.getName() : SELECT_A_FILE); + } + }); + content.add(mSelectFileButton); + + mRecordingFileLabel = new JLabel(SELECT_A_FILE); + content.add(mRecordingFileLabel, "span 2,wrap"); + + mFrequencyLabel = new JLabel("Frequency (Hz):"); + content.add(mFrequencyLabel); + + mFrequencyTextField = new JTextField(""); + mFrequencyTextField.setToolTipText("Center frequency for the recording in Hertz (Hz)"); + content.add(mFrequencyTextField, "span 2,grow,wrap"); + + content.add(new JLabel(""), "wrap"); + + content.add(new JLabel("")); + + mAddButton = new JButton("Add"); + mAddButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if(mSelectedRecording == null) + { + JOptionPane.showMessageDialog(AddRecordingTunerDialog.this, + "Please select a recording file", + "Select a Recording File", + JOptionPane.ERROR_MESSAGE); + return; + } + + long frequency = getFrequency(); + + if(frequency <= 0 || frequency > Integer.MAX_VALUE) + { + JOptionPane.showMessageDialog(AddRecordingTunerDialog.this, + "Please provide a recording center frequency (1 Hz to 2.14 GHz)", + "Center Frequency Required", + JOptionPane.ERROR_MESSAGE); + return; + } + + mLog.info("Adding recording tuner = frequency [" + frequency + + "] recording [" + mSelectedRecording.getAbsolutePath() + "]"); + + + try + { + RecordingTuner tuner = new RecordingTuner(mUserPreferences); + mTunerModel.addTuner(tuner); + RecordingTunerController controller = tuner.getTunerController(); + RecordingTunerConfiguration config = new RecordingTunerConfiguration(); + config.setFrequency(frequency); + config.setPath(mSelectedRecording.getAbsolutePath()); + controller.apply(config); + } + catch(Exception ex) + { + mLog.error("Error adding recording tuner", ex); + } + + AddRecordingTunerDialog.this.setVisible(false); + } + }); + content.add(mAddButton, "grow,push"); + + mCancelButton = new JButton("Cancel"); + mCancelButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + AddRecordingTunerDialog.this.setVisible(false); + } + }); + content.add(mCancelButton, "grow,push"); + + setContentPane(content); + } + + private long getFrequency() + { + String text = mFrequencyTextField.getText(); + + if(text != null && !text.isEmpty()) + { + try + { + return Long.parseLong(text); + } + catch(Exception e) + { + //Do nothing, we couldn't parse the frequency value + } + } + + return 0l; + } +} diff --git a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java index 62e8061c..ba7d5e6e 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/recording/RecordingTuner.java @@ -60,8 +60,6 @@ public class RecordingTuner extends Tuner { ChannelizerType channelizerType = userPreferences.getTunerPreference().getChannelizerType(); - mLog.debug("Using Channelizer Type: " + channelizerType); - if(channelizerType == ChannelizerType.POLYPHASE) { setChannelSourceManager(new PolyphaseChannelSourceManager(getTunerController()));