mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
Merge pull request #368 from DSheirer/96-disable-spectral-display-option
#96 Disable Spectral Display Option
This commit is contained in:
@@ -40,10 +40,13 @@ import io.github.dsheirer.record.RecorderManager;
|
|||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.SourceManager;
|
import io.github.dsheirer.source.SourceManager;
|
||||||
|
import io.github.dsheirer.source.tuner.Tuner;
|
||||||
import io.github.dsheirer.source.tuner.TunerEvent;
|
import io.github.dsheirer.source.tuner.TunerEvent;
|
||||||
import io.github.dsheirer.source.tuner.TunerModel;
|
import io.github.dsheirer.source.tuner.TunerModel;
|
||||||
import io.github.dsheirer.source.tuner.TunerSpectralDisplayManager;
|
import io.github.dsheirer.source.tuner.TunerSpectralDisplayManager;
|
||||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||||
|
import io.github.dsheirer.spectrum.ClearTunerMenuItem;
|
||||||
|
import io.github.dsheirer.spectrum.ShowTunerMenuItem;
|
||||||
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
|
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
import io.github.dsheirer.util.TimeStamp;
|
import io.github.dsheirer.util.TimeStamp;
|
||||||
@@ -174,10 +177,10 @@ public class SDRTrunk implements Listener<TunerEvent>
|
|||||||
mapService, mSettingsManager, mSourceManager, tunerModel);
|
mapService, mSettingsManager, mSourceManager, tunerModel);
|
||||||
|
|
||||||
mSpectralPanel = new SpectralDisplayPanel(mChannelModel,
|
mSpectralPanel = new SpectralDisplayPanel(mChannelModel,
|
||||||
mChannelProcessingManager, mSettingsManager);
|
mChannelProcessingManager, mSettingsManager, tunerModel);
|
||||||
|
|
||||||
TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel,
|
TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel,
|
||||||
mChannelModel, mChannelProcessingManager, mSettingsManager);
|
mChannelModel, mChannelProcessingManager, mSettingsManager, tunerModel);
|
||||||
tunerModel.addListener(tunerSpectralDisplayManager);
|
tunerModel.addListener(tunerSpectralDisplayManager);
|
||||||
tunerModel.addListener(this);
|
tunerModel.addListener(this);
|
||||||
|
|
||||||
@@ -325,6 +328,15 @@ public class SDRTrunk implements Listener<TunerEvent>
|
|||||||
JMenu viewMenu = new JMenu("View");
|
JMenu viewMenu = new JMenu("View");
|
||||||
|
|
||||||
viewMenu.add(new BroadcastStatusVisibleMenuItem(mControllerPanel));
|
viewMenu.add(new BroadcastStatusVisibleMenuItem(mControllerPanel));
|
||||||
|
viewMenu.add(new JSeparator());
|
||||||
|
|
||||||
|
for(Tuner tuner: mSourceManager.getTunerModel().getTuners())
|
||||||
|
{
|
||||||
|
viewMenu.add(new ShowTunerMenuItem(mSpectralPanel, tuner));
|
||||||
|
}
|
||||||
|
|
||||||
|
viewMenu.add(new JSeparator());
|
||||||
|
viewMenu.add(new ClearTunerMenuItem(mSpectralPanel));
|
||||||
|
|
||||||
menuBar.add(viewMenu);
|
menuBar.add(viewMenu);
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class TunerEvent
|
|||||||
CHANNEL_COUNT,
|
CHANNEL_COUNT,
|
||||||
FREQUENCY,
|
FREQUENCY,
|
||||||
SAMPLE_RATE,
|
SAMPLE_RATE,
|
||||||
|
CLEAR_MAIN_SPECTRAL_DISPLAY,
|
||||||
REQUEST_MAIN_SPECTRAL_DISPLAY,
|
REQUEST_MAIN_SPECTRAL_DISPLAY,
|
||||||
REQUEST_NEW_SPECTRAL_DISPLAY;
|
REQUEST_NEW_SPECTRAL_DISPLAY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.github.dsheirer.source.tuner;
|
package io.github.dsheirer.source.tuner;
|
||||||
|
|
||||||
|
import io.github.dsheirer.properties.SystemProperties;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.source.Source;
|
import io.github.dsheirer.source.Source;
|
||||||
import io.github.dsheirer.source.SourceException;
|
import io.github.dsheirer.source.SourceException;
|
||||||
@@ -9,6 +10,7 @@ import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
|||||||
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
|
||||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||||
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
|
||||||
|
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -177,10 +179,16 @@ public class TunerModel extends AbstractTableModel implements Listener<TunerEven
|
|||||||
*/
|
*/
|
||||||
public void requestFirstTunerDisplay()
|
public void requestFirstTunerDisplay()
|
||||||
{
|
{
|
||||||
if(mTuners.size() > 0)
|
SystemProperties properties = SystemProperties.getInstance();
|
||||||
|
boolean enabled = properties.get(SpectralDisplayPanel.SPECTRAL_DISPLAY_ENABLED, true);
|
||||||
|
|
||||||
|
if(enabled && mTuners.size() > 0)
|
||||||
{
|
{
|
||||||
broadcast(new TunerEvent(mTuners.get(0),
|
broadcast(new TunerEvent(mTuners.get(0), Event.REQUEST_MAIN_SPECTRAL_DISPLAY));
|
||||||
Event.REQUEST_MAIN_SPECTRAL_DISPLAY));
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
broadcast(new TunerEvent(null, Event.CLEAR_MAIN_SPECTRAL_DISPLAY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
package io.github.dsheirer.source.tuner;
|
package io.github.dsheirer.source.tuner;
|
||||||
|
|
||||||
import io.github.dsheirer.controller.channel.ChannelModel;
|
import io.github.dsheirer.controller.channel.ChannelModel;
|
||||||
@@ -7,49 +22,55 @@ import io.github.dsheirer.settings.SettingsManager;
|
|||||||
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
|
import io.github.dsheirer.spectrum.SpectralDisplayPanel;
|
||||||
import io.github.dsheirer.spectrum.SpectrumFrame;
|
import io.github.dsheirer.spectrum.SpectrumFrame;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
public class TunerSpectralDisplayManager implements Listener<TunerEvent>
|
public class TunerSpectralDisplayManager implements Listener<TunerEvent>
|
||||||
{
|
{
|
||||||
private SpectralDisplayPanel mSpectralDisplayPanel;
|
private SpectralDisplayPanel mSpectralDisplayPanel;
|
||||||
private ChannelModel mChannelModel;
|
private ChannelModel mChannelModel;
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
private ChannelProcessingManager mChannelProcessingManager;
|
||||||
private SettingsManager mSettingsManager;
|
private SettingsManager mSettingsManager;
|
||||||
|
private TunerModel mTunerModel;
|
||||||
|
|
||||||
public TunerSpectralDisplayManager( SpectralDisplayPanel panel,
|
public TunerSpectralDisplayManager(SpectralDisplayPanel panel,
|
||||||
ChannelModel channelModel,
|
ChannelModel channelModel,
|
||||||
ChannelProcessingManager channelProcessingManager,
|
ChannelProcessingManager channelProcessingManager,
|
||||||
SettingsManager settingsManager )
|
SettingsManager settingsManager,
|
||||||
{
|
TunerModel tunerModel)
|
||||||
mSpectralDisplayPanel = panel;
|
{
|
||||||
mChannelModel = channelModel;
|
mSpectralDisplayPanel = panel;
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
mChannelModel = channelModel;
|
||||||
mSettingsManager = settingsManager;
|
mChannelProcessingManager = channelProcessingManager;
|
||||||
}
|
mSettingsManager = settingsManager;
|
||||||
|
mTunerModel = tunerModel;
|
||||||
@Override
|
}
|
||||||
public void receive( TunerEvent event )
|
|
||||||
{
|
@Override
|
||||||
switch( event.getEvent() )
|
public void receive(TunerEvent event)
|
||||||
{
|
{
|
||||||
case REQUEST_MAIN_SPECTRAL_DISPLAY:
|
switch(event.getEvent())
|
||||||
mSpectralDisplayPanel.showTuner( event.getTuner() );
|
{
|
||||||
break;
|
case CLEAR_MAIN_SPECTRAL_DISPLAY:
|
||||||
case REQUEST_NEW_SPECTRAL_DISPLAY:
|
mSpectralDisplayPanel.clearTuner();
|
||||||
final SpectrumFrame frame = new SpectrumFrame( mChannelModel,
|
break;
|
||||||
mChannelProcessingManager, mSettingsManager, event.getTuner() );
|
case REQUEST_MAIN_SPECTRAL_DISPLAY:
|
||||||
|
mSpectralDisplayPanel.showTuner(event.getTuner());
|
||||||
EventQueue.invokeLater( new Runnable()
|
break;
|
||||||
{
|
case REQUEST_NEW_SPECTRAL_DISPLAY:
|
||||||
@Override
|
final SpectrumFrame frame = new SpectrumFrame(mChannelModel,
|
||||||
public void run()
|
mChannelProcessingManager, mSettingsManager, mTunerModel, event.getTuner());
|
||||||
{
|
|
||||||
frame.setVisible( true );
|
EventQueue.invokeLater(new Runnable()
|
||||||
}
|
{
|
||||||
} );
|
@Override
|
||||||
break;
|
public void run()
|
||||||
default:
|
{
|
||||||
break;
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
package io.github.dsheirer.spectrum;
|
||||||
|
|
||||||
|
import io.github.dsheirer.properties.SystemProperties;
|
||||||
|
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
public class ClearTunerMenuItem extends JMenuItem
|
||||||
|
{
|
||||||
|
private SpectralDisplayPanel mSpectralDisplayPanel;
|
||||||
|
|
||||||
|
public ClearTunerMenuItem(SpectralDisplayPanel spectralDisplayPanel)
|
||||||
|
{
|
||||||
|
super("Disable Spectrum & Waterfall");
|
||||||
|
|
||||||
|
mSpectralDisplayPanel = spectralDisplayPanel;
|
||||||
|
|
||||||
|
addActionListener(new ActionListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e)
|
||||||
|
{
|
||||||
|
mSpectralDisplayPanel.clearTuner();
|
||||||
|
SystemProperties properties = SystemProperties.getInstance();
|
||||||
|
properties.set(SpectralDisplayPanel.SPECTRAL_DISPLAY_ENABLED, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -165,12 +165,15 @@ public class DFTProcessor implements Listener<ReusableComplexBuffer>, ISourceEve
|
|||||||
|
|
||||||
public void start()
|
public void start()
|
||||||
{
|
{
|
||||||
//Schedule the DFT to run calculations at a fixed rate
|
if(mProcessorTaskHandle == null)
|
||||||
int initialDelay = 0;
|
{
|
||||||
int period = (int) (1000 / mFrameRate);
|
//Schedule the DFT to run calculations at a fixed rate
|
||||||
|
int initialDelay = 0;
|
||||||
|
int period = (int) (1000 / mFrameRate);
|
||||||
|
|
||||||
mProcessorTaskHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate(new DFTCalculationTask(), initialDelay, period,
|
mProcessorTaskHandle = ThreadPool.SCHEDULED.scheduleAtFixedRate(new DFTCalculationTask(), initialDelay, period,
|
||||||
TimeUnit.MILLISECONDS);
|
TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop()
|
public void stop()
|
||||||
@@ -179,9 +182,15 @@ public class DFTProcessor implements Listener<ReusableComplexBuffer>, ISourceEve
|
|||||||
if(mProcessorTaskHandle != null)
|
if(mProcessorTaskHandle != null)
|
||||||
{
|
{
|
||||||
mProcessorTaskHandle.cancel(true);
|
mProcessorTaskHandle.cancel(true);
|
||||||
|
mProcessorTaskHandle = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRunning()
|
||||||
|
{
|
||||||
|
return mProcessorTaskHandle != null;
|
||||||
|
}
|
||||||
|
|
||||||
public void restart()
|
public void restart()
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
|
|||||||
@@ -342,6 +342,10 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, ISourc
|
|||||||
{
|
{
|
||||||
minor = 1;
|
minor = 1;
|
||||||
}
|
}
|
||||||
|
if(label == 0)
|
||||||
|
{
|
||||||
|
label = 1;
|
||||||
|
}
|
||||||
|
|
||||||
//Adjust the start frequency to a multiple of the minor tick spacing
|
//Adjust the start frequency to a multiple of the minor tick spacing
|
||||||
long frequency = minFrequency - (minFrequency % minor);
|
long frequency = minFrequency - (minFrequency % minor);
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
package io.github.dsheirer.spectrum;
|
||||||
|
|
||||||
|
import io.github.dsheirer.source.tuner.Tuner;
|
||||||
|
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
public class ShowTunerMenuItem extends JMenuItem
|
||||||
|
{
|
||||||
|
private SpectralDisplayPanel mSpectralDisplayPanel;
|
||||||
|
private Tuner mTuner;
|
||||||
|
|
||||||
|
public ShowTunerMenuItem(SpectralDisplayPanel spectralDisplayPanel, Tuner tuner)
|
||||||
|
{
|
||||||
|
super(tuner != null ? "Show: " + tuner.getName() : "(empty)");
|
||||||
|
mSpectralDisplayPanel = spectralDisplayPanel;
|
||||||
|
mTuner = tuner;
|
||||||
|
|
||||||
|
addActionListener(new ActionListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e)
|
||||||
|
{
|
||||||
|
EventQueue.invokeLater(new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mSpectralDisplayPanel.showTuner(mTuner);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,6 @@ import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
|||||||
import io.github.dsheirer.controller.channel.ChannelUtils;
|
import io.github.dsheirer.controller.channel.ChannelUtils;
|
||||||
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||||
import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
||||||
import io.github.dsheirer.module.decode.DecoderType;
|
|
||||||
import io.github.dsheirer.properties.SystemProperties;
|
import io.github.dsheirer.properties.SystemProperties;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.sample.SampleType;
|
import io.github.dsheirer.sample.SampleType;
|
||||||
@@ -33,6 +32,7 @@ import io.github.dsheirer.settings.SettingsManager;
|
|||||||
import io.github.dsheirer.source.ISourceEventProcessor;
|
import io.github.dsheirer.source.ISourceEventProcessor;
|
||||||
import io.github.dsheirer.source.SourceEvent;
|
import io.github.dsheirer.source.SourceEvent;
|
||||||
import io.github.dsheirer.source.tuner.Tuner;
|
import io.github.dsheirer.source.tuner.Tuner;
|
||||||
|
import io.github.dsheirer.source.tuner.TunerModel;
|
||||||
import io.github.dsheirer.spectrum.OverlayPanel.ChannelDisplay;
|
import io.github.dsheirer.spectrum.OverlayPanel.ChannelDisplay;
|
||||||
import io.github.dsheirer.spectrum.converter.ComplexDecibelConverter;
|
import io.github.dsheirer.spectrum.converter.ComplexDecibelConverter;
|
||||||
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
|
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
|
||||||
@@ -71,7 +71,6 @@ import java.awt.event.ComponentEvent;
|
|||||||
import java.awt.event.ComponentListener;
|
import java.awt.event.ComponentListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseWheelEvent;
|
import java.awt.event.MouseWheelEvent;
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
@@ -82,9 +81,8 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(SpectralDisplayPanel.class);
|
private final static Logger mLog = LoggerFactory.getLogger(SpectralDisplayPanel.class);
|
||||||
|
|
||||||
private static DecimalFormat sCURSOR_FORMAT = new DecimalFormat("000.00000");
|
|
||||||
|
|
||||||
public static final String FFT_SIZE_PROPERTY = "spectral.display.dft.size";
|
public static final String FFT_SIZE_PROPERTY = "spectral.display.dft.size";
|
||||||
|
public static final String SPECTRAL_DISPLAY_ENABLED = "spectral.display.enabled";
|
||||||
public static final int NO_ZOOM = 0;
|
public static final int NO_ZOOM = 0;
|
||||||
public static final int MAX_ZOOM = 6;
|
public static final int MAX_ZOOM = 6;
|
||||||
|
|
||||||
@@ -102,6 +100,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
private ChannelModel mChannelModel;
|
private ChannelModel mChannelModel;
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
private ChannelProcessingManager mChannelProcessingManager;
|
||||||
private SettingsManager mSettingsManager;
|
private SettingsManager mSettingsManager;
|
||||||
|
private TunerModel mTunerModel;
|
||||||
private Tuner mTuner;
|
private Tuner mTuner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,11 +117,13 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
*/
|
*/
|
||||||
public SpectralDisplayPanel(ChannelModel channelModel,
|
public SpectralDisplayPanel(ChannelModel channelModel,
|
||||||
ChannelProcessingManager channelProcessingManager,
|
ChannelProcessingManager channelProcessingManager,
|
||||||
SettingsManager settingsManager)
|
SettingsManager settingsManager,
|
||||||
|
TunerModel tunerModel)
|
||||||
{
|
{
|
||||||
mChannelModel = channelModel;
|
mChannelModel = channelModel;
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
mChannelProcessingManager = channelProcessingManager;
|
||||||
mSettingsManager = settingsManager;
|
mSettingsManager = settingsManager;
|
||||||
|
mTunerModel = tunerModel;
|
||||||
|
|
||||||
mSpectrumPanel = new SpectrumPanel(mSettingsManager);
|
mSpectrumPanel = new SpectrumPanel(mSettingsManager);
|
||||||
mOverlayPanel = new OverlayPanel(mSettingsManager, mChannelModel);
|
mOverlayPanel = new OverlayPanel(mSettingsManager, mChannelModel);
|
||||||
@@ -428,6 +429,8 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
|
|
||||||
mDFTProcessor.clearBuffer();
|
mDFTProcessor.clearBuffer();
|
||||||
|
|
||||||
|
mDFTProcessor.start();
|
||||||
|
|
||||||
mTuner = tuner;
|
mTuner = tuner;
|
||||||
|
|
||||||
if(mTuner != null)
|
if(mTuner != null)
|
||||||
@@ -462,6 +465,11 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
mTuner.getTunerController().removeBufferListener(mDFTProcessor);
|
mTuner.getTunerController().removeBufferListener(mDFTProcessor);
|
||||||
mTuner = null;
|
mTuner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDFTProcessor.stop();
|
||||||
|
mDFTProcessor.clearBuffer();
|
||||||
|
mSpectrumPanel.clearSpectrum();
|
||||||
|
mWaterfallPanel.clearWaterfall();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -614,6 +622,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
if(event.getComponent() == mWaterfallPanel)
|
if(event.getComponent() == mWaterfallPanel)
|
||||||
{
|
{
|
||||||
contextMenu.add(new PauseItem(mWaterfallPanel, "Pause"));
|
contextMenu.add(new PauseItem(mWaterfallPanel, "Pause"));
|
||||||
|
contextMenu.add(new JSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
long frequency =
|
long frequency =
|
||||||
@@ -643,22 +652,6 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JMenu frequencyMenu = new JMenu(
|
|
||||||
// sCURSOR_FORMAT.format((float) frequency / 1000000.0f));
|
|
||||||
//
|
|
||||||
// JMenu decoderMenu = new JMenu("Add Decoder");
|
|
||||||
//
|
|
||||||
// for(DecoderType type : DecoderType.getPrimaryDecoders())
|
|
||||||
// {
|
|
||||||
// decoderMenu.add(new DecoderItem(type, frequency));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// frequencyMenu.add(decoderMenu);
|
|
||||||
//
|
|
||||||
// contextMenu.add(frequencyMenu);
|
|
||||||
//
|
|
||||||
// contextMenu.add(new JSeparator());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color Menus
|
* Color Menus
|
||||||
*/
|
*/
|
||||||
@@ -791,6 +784,27 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
|
|
||||||
contextMenu.add(zoomMenu);
|
contextMenu.add(zoomMenu);
|
||||||
|
|
||||||
|
if(mTuner != null)
|
||||||
|
{
|
||||||
|
contextMenu.add(new JSeparator());
|
||||||
|
contextMenu.add(new ClearTunerMenuItem(SpectralDisplayPanel.this));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean separatorAdded = false;
|
||||||
|
|
||||||
|
for(Tuner tuner: mTunerModel.getTuners())
|
||||||
|
{
|
||||||
|
if(mTuner == null || mTuner != tuner)
|
||||||
|
{
|
||||||
|
if(!separatorAdded)
|
||||||
|
{
|
||||||
|
contextMenu.add(new JSeparator());
|
||||||
|
separatorAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
contextMenu.add(new ShowTunerMenuItem(SpectralDisplayPanel.this, tuner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(contextMenu != null)
|
if(contextMenu != null)
|
||||||
{
|
{
|
||||||
@@ -920,34 +934,4 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Context menu item to provide one-click access to starting a channel
|
|
||||||
* processing with the selected decoder
|
|
||||||
*/
|
|
||||||
public class DecoderItem extends JMenuItem
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private ChannelModel mChannelModel;
|
|
||||||
private long mFrequency;
|
|
||||||
private DecoderType mDecoder;
|
|
||||||
|
|
||||||
public DecoderItem(DecoderType type, long frequency)
|
|
||||||
{
|
|
||||||
super(type.getDisplayString());
|
|
||||||
|
|
||||||
mFrequency = frequency;
|
|
||||||
mDecoder = type;
|
|
||||||
|
|
||||||
addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
mChannelModel.createChannel(mDecoder, mFrequency);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* SDR Trunk
|
* sdr-trunk
|
||||||
* Copyright (C) 2014 Dennis Sheirer
|
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||||
* it under the terms of the GNU General Public License as published by
|
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* later version.
|
||||||
* (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
|
||||||
* This program is distributed in the hope that it will be useful,
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
*
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* You should have received a copy of the GNU General Public License along with this program.
|
||||||
* GNU General Public License for more details.
|
* If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package io.github.dsheirer.spectrum;
|
package io.github.dsheirer.spectrum;
|
||||||
|
|
||||||
@@ -21,10 +19,11 @@ import io.github.dsheirer.controller.channel.ChannelModel;
|
|||||||
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.tuner.Tuner;
|
import io.github.dsheirer.source.tuner.Tuner;
|
||||||
|
import io.github.dsheirer.source.tuner.TunerModel;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.JFrame;
|
||||||
import java.awt.*;
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.awt.event.WindowListener;
|
import java.awt.event.WindowListener;
|
||||||
|
|
||||||
@@ -33,52 +32,70 @@ public class SpectrumFrame extends JFrame implements WindowListener
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private SpectralDisplayPanel mSpectralDisplayPanel;
|
private SpectralDisplayPanel mSpectralDisplayPanel;
|
||||||
|
|
||||||
public SpectrumFrame( ChannelModel channelModel,
|
|
||||||
ChannelProcessingManager channelProcessingManager,
|
|
||||||
SettingsManager settingsManager,
|
|
||||||
Tuner tuner )
|
|
||||||
{
|
|
||||||
setTitle( "SDRTRunk [" + tuner.getName() + "]" );
|
|
||||||
setBounds( 100, 100, 1280, 600 );
|
|
||||||
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
|
||||||
|
|
||||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow]", "[grow]") );
|
public SpectrumFrame(ChannelModel channelModel,
|
||||||
|
ChannelProcessingManager channelProcessingManager,
|
||||||
mSpectralDisplayPanel = new SpectralDisplayPanel( channelModel,
|
SettingsManager settingsManager,
|
||||||
channelProcessingManager, settingsManager );
|
TunerModel tunerModel,
|
||||||
|
Tuner tuner)
|
||||||
|
{
|
||||||
|
setTitle("SDRTRunk [" + tuner.getName() + "]");
|
||||||
|
setBounds(100, 100, 1280, 600);
|
||||||
|
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
|
||||||
mSpectralDisplayPanel.showTuner( tuner );
|
setLayout(new MigLayout("insets 0 0 0 0", "[grow]", "[grow]"));
|
||||||
add( mSpectralDisplayPanel, "grow" );
|
|
||||||
|
|
||||||
/* Register a shutdown listener */
|
mSpectralDisplayPanel = new SpectralDisplayPanel(channelModel,
|
||||||
this.addWindowListener( this );
|
channelProcessingManager, settingsManager, tunerModel);
|
||||||
|
|
||||||
EventQueue.invokeLater( new Runnable()
|
mSpectralDisplayPanel.showTuner(tuner);
|
||||||
|
add(mSpectralDisplayPanel, "grow");
|
||||||
|
|
||||||
|
/* Register a shutdown listener */
|
||||||
|
this.addWindowListener(this);
|
||||||
|
|
||||||
|
EventQueue.invokeLater(new Runnable()
|
||||||
{
|
{
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
setVisible( true );
|
setVisible(true);
|
||||||
}
|
}
|
||||||
} );
|
});
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void windowClosed( WindowEvent arg0 )
|
|
||||||
{
|
|
||||||
mSpectralDisplayPanel.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void windowActivated( WindowEvent arg0 ) {}
|
public void windowClosed(WindowEvent arg0)
|
||||||
@Override
|
{
|
||||||
public void windowClosing( WindowEvent arg0 ) {}
|
mSpectralDisplayPanel.dispose();
|
||||||
@Override
|
}
|
||||||
public void windowDeactivated( WindowEvent arg0 ) {}
|
|
||||||
@Override
|
@Override
|
||||||
public void windowDeiconified( WindowEvent arg0 ) {}
|
public void windowActivated(WindowEvent arg0)
|
||||||
@Override
|
{
|
||||||
public void windowIconified( WindowEvent arg0 ) {}
|
}
|
||||||
@Override
|
|
||||||
public void windowOpened( WindowEvent arg0 ) {}
|
@Override
|
||||||
|
public void windowClosing(WindowEvent arg0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowDeactivated(WindowEvent arg0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowDeiconified(WindowEvent arg0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowIconified(WindowEvent arg0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void windowOpened(WindowEvent arg0)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,8 +327,7 @@ public class SpectrumPanel extends JPanel implements DFTResultsListener, Setting
|
|||||||
*/
|
*/
|
||||||
public void clearSpectrum()
|
public void clearSpectrum()
|
||||||
{
|
{
|
||||||
mDisplayFFTBins = null;
|
Arrays.fill(mDisplayFFTBins, 0.0f);
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* SDR Trunk
|
* SDR Trunk
|
||||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -25,126 +25,143 @@ import io.github.dsheirer.settings.SettingsManager;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.JPanel;
|
||||||
import java.awt.*;
|
import java.awt.Color;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.Point;
|
||||||
import java.awt.geom.Line2D;
|
import java.awt.geom.Line2D;
|
||||||
import java.awt.image.ColorModel;
|
import java.awt.image.ColorModel;
|
||||||
import java.awt.image.MemoryImageSource;
|
import java.awt.image.MemoryImageSource;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
||||||
Pausable,
|
Pausable,
|
||||||
SettingChangeListener
|
SettingChangeListener
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final static Logger mLog =
|
private final static Logger mLog =
|
||||||
LoggerFactory.getLogger( WaterfallPanel.class );
|
LoggerFactory.getLogger(WaterfallPanel.class);
|
||||||
|
|
||||||
private static DecimalFormat CURSOR_FORMAT = new DecimalFormat( "0.00000" );
|
private static DecimalFormat CURSOR_FORMAT = new DecimalFormat("0.00000");
|
||||||
private static final String PAUSED = "PAUSED";
|
private static final String PAUSED = "PAUSED - Right Click to Unpause";
|
||||||
|
private static final String DISABLED = "DISABLED - Right Click to Select a Tuner";
|
||||||
|
|
||||||
private byte[] mPixels;
|
private byte[] mPixels;
|
||||||
private byte[] mPausedPixels;
|
private byte[] mPausedPixels;
|
||||||
private int mDFTSize = 4096;
|
private int mDFTSize = 4096;
|
||||||
private int mImageHeight = 700;
|
private int mImageHeight = 700;
|
||||||
private MemoryImageSource mMemoryImageSource;
|
private MemoryImageSource mMemoryImageSource;
|
||||||
private ColorModel mColorModel = WaterfallColorModel.getDefaultColorModel();
|
private ColorModel mColorModel = WaterfallColorModel.getDefaultColorModel();
|
||||||
private Color mColorSpectrumCursor;
|
private Color mColorSpectrumCursor;
|
||||||
private Image mWaterfallImage;
|
private Image mWaterfallImage;
|
||||||
|
|
||||||
private Point mCursorLocation = new Point( 0, 0 );
|
private Point mCursorLocation = new Point(0, 0);
|
||||||
private boolean mCursorVisible = false;
|
private boolean mCursorVisible = false;
|
||||||
private long mCursorFrequency = 0;
|
private long mCursorFrequency = 0;
|
||||||
private boolean mPaused = false;
|
private boolean mPaused = false;
|
||||||
private int mZoom = 0;
|
private boolean mDisabled = true;
|
||||||
private int mDFTZoomWindowOffset = 0;
|
private int mZoom = 0;
|
||||||
|
private int mDFTZoomWindowOffset = 0;
|
||||||
private SettingsManager mSettingsManager;
|
|
||||||
|
|
||||||
/**
|
private SettingsManager mSettingsManager;
|
||||||
* Displays a scrolling window of multiple DFT frequency bin outputs over
|
|
||||||
* time. Maps DFT frequency bin decibel values into a 256 bucket color map
|
|
||||||
* for display.
|
|
||||||
*
|
|
||||||
* @param settingsManager
|
|
||||||
*/
|
|
||||||
public WaterfallPanel( SettingsManager settingsManager )
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
|
|
||||||
mSettingsManager = settingsManager;
|
/**
|
||||||
|
* Displays a scrolling window of multiple DFT frequency bin outputs over
|
||||||
mSettingsManager.addListener( this );
|
* time. Maps DFT frequency bin decibel values into a 256 bucket color map
|
||||||
|
* for display.
|
||||||
mColorSpectrumCursor = getColor( ColorSettingName.SPECTRUM_CURSOR );
|
*
|
||||||
|
* @param settingsManager
|
||||||
|
*/
|
||||||
|
public WaterfallPanel(SettingsManager settingsManager)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
reset();
|
mSettingsManager = settingsManager;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
mSettingsManager.addListener(this);
|
||||||
* Prepares this instance for disposal
|
|
||||||
*/
|
|
||||||
public void dispose()
|
|
||||||
{
|
|
||||||
if( mSettingsManager != null )
|
|
||||||
{
|
|
||||||
mSettingsManager.removeListener( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
mSettingsManager = null;
|
|
||||||
mMemoryImageSource = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
mColorSpectrumCursor = getColor(ColorSettingName.SPECTRUM_CURSOR);
|
||||||
* Resets the memory image source and byte backing array when the DFT point
|
|
||||||
* size has changed
|
|
||||||
*/
|
|
||||||
private void reset()
|
|
||||||
{
|
|
||||||
mPixels = new byte[ mDFTSize * mImageHeight ];
|
|
||||||
|
|
||||||
mMemoryImageSource = new MemoryImageSource( mDFTSize,
|
reset();
|
||||||
mImageHeight,
|
}
|
||||||
mColorModel,
|
|
||||||
mPixels,
|
/**
|
||||||
0,
|
* Prepares this instance for disposal
|
||||||
mDFTSize );
|
*/
|
||||||
|
public void dispose()
|
||||||
mMemoryImageSource.setAnimated( true );
|
{
|
||||||
|
if(mSettingsManager != null)
|
||||||
|
{
|
||||||
|
mSettingsManager.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSettingsManager = null;
|
||||||
|
mMemoryImageSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the memory image source and byte backing array when the DFT point
|
||||||
|
* size has changed
|
||||||
|
*/
|
||||||
|
private void reset()
|
||||||
|
{
|
||||||
|
mPixels = new byte[mDFTSize * mImageHeight];
|
||||||
|
|
||||||
|
mMemoryImageSource = new MemoryImageSource(mDFTSize,
|
||||||
|
mImageHeight,
|
||||||
|
mColorModel,
|
||||||
|
mPixels,
|
||||||
|
0,
|
||||||
|
mDFTSize);
|
||||||
|
|
||||||
|
mMemoryImageSource.setAnimated(true);
|
||||||
|
|
||||||
|
mWaterfallImage = createImage(mMemoryImageSource);
|
||||||
|
|
||||||
mWaterfallImage = createImage( mMemoryImageSource );
|
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pausable interface - pauses updates to the waterfall
|
* Pausable interface - pauses updates to the waterfall
|
||||||
*/
|
*/
|
||||||
public void setPaused( boolean paused )
|
public void setPaused(boolean paused)
|
||||||
{
|
{
|
||||||
if( paused )
|
if(paused)
|
||||||
{
|
{
|
||||||
mPausedPixels = mPixels.clone();
|
mPausedPixels = mPixels.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPaused = paused;
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current pause state
|
||||||
|
*
|
||||||
|
* @return true if paused, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isPaused()
|
||||||
|
{
|
||||||
|
return mPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the waterfall is currently disabled.
|
||||||
|
*/
|
||||||
|
public boolean isDisabled()
|
||||||
|
{
|
||||||
|
return mDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
mPaused = paused;
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns current pause state
|
|
||||||
* @return true if paused, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean isPaused()
|
|
||||||
{
|
|
||||||
return mPaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current zoom level (2^zoom)
|
* Sets the current zoom level (2^zoom)
|
||||||
*
|
*
|
||||||
* 0 No Zoom
|
* 0 No Zoom
|
||||||
* 1 2x Zoom
|
* 1 2x Zoom
|
||||||
* 2 4x Zoom
|
* 2 4x Zoom
|
||||||
@@ -152,280 +169,294 @@ public class WaterfallPanel extends JPanel implements DFTResultsListener,
|
|||||||
* 4 16x Zoom
|
* 4 16x Zoom
|
||||||
* 5 32x Zoom
|
* 5 32x Zoom
|
||||||
* 6 64x Zoom
|
* 6 64x Zoom
|
||||||
*
|
*
|
||||||
* @param zoom level, 0 - 6.
|
* @param zoom level, 0 - 6.
|
||||||
* @param offset into the DFT bins for display
|
* @param offset into the DFT bins for display
|
||||||
*/
|
*/
|
||||||
public void setZoom( int zoom )
|
public void setZoom(int zoom)
|
||||||
{
|
|
||||||
mZoom = zoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiplier for the current zoom level
|
|
||||||
*/
|
|
||||||
private int getZoomMultiplier()
|
|
||||||
{
|
|
||||||
return (int)Math.pow( 2.0, mZoom );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the zoom window offset from zero
|
|
||||||
* @param offset in DFT bins
|
|
||||||
*/
|
|
||||||
public void setZoomWindowOffset( int offset )
|
|
||||||
{
|
|
||||||
mDFTZoomWindowOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches a named color setting from the settings manager. If the setting
|
|
||||||
* doesn't exist, creates the setting using the defaultColor
|
|
||||||
*/
|
|
||||||
private Color getColor( ColorSettingName name )
|
|
||||||
{
|
|
||||||
ColorSetting setting = mSettingsManager.getColorSetting( name );
|
|
||||||
|
|
||||||
return setting.getColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitors for setting changes. Colors can be changed by external actions
|
|
||||||
* and will automatically update in this class
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void settingChanged( Setting setting )
|
|
||||||
{
|
{
|
||||||
if( setting instanceof ColorSetting )
|
mZoom = zoom;
|
||||||
{
|
|
||||||
ColorSetting colorSetting = (ColorSetting)setting;
|
|
||||||
|
|
||||||
if( ( (ColorSetting) setting ).getColorSettingName() ==
|
|
||||||
ColorSettingName.SPECTRUM_CURSOR )
|
|
||||||
{
|
|
||||||
mColorSpectrumCursor = colorSetting.getColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void settingDeleted( Setting setting ) { /* Not implemented */ }
|
* Multiplier for the current zoom level
|
||||||
|
*/
|
||||||
/**
|
private int getZoomMultiplier()
|
||||||
* Sets the display location of the cursor. Cursor location monitoring is
|
|
||||||
* handled external to this class.
|
|
||||||
*
|
|
||||||
* @param point
|
|
||||||
*/
|
|
||||||
public void setCursorLocation( Point point )
|
|
||||||
{
|
|
||||||
mCursorLocation = point;
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the current cursor display frequency. Cursor location frequency
|
|
||||||
* monitoring is handled external to this class.
|
|
||||||
*
|
|
||||||
* @param frequency
|
|
||||||
*/
|
|
||||||
public void setCursorFrequency( long frequency )
|
|
||||||
{
|
|
||||||
mCursorFrequency = frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the visibility of the cursor
|
|
||||||
* @param visible
|
|
||||||
*/
|
|
||||||
public void setCursorVisible( boolean visible )
|
|
||||||
{
|
|
||||||
mCursorVisible = visible;
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the x-axis pixel offset from zero where to start rendering the
|
|
||||||
* waterfall image
|
|
||||||
*
|
|
||||||
* @param multiplier - current zoom multiplier
|
|
||||||
* @return x-axis pixel offset
|
|
||||||
*/
|
|
||||||
private double getPixelOffset( int multiplier )
|
|
||||||
{
|
|
||||||
double offset = 0;
|
|
||||||
|
|
||||||
if( mZoom != 0 )
|
|
||||||
{
|
|
||||||
double binPixelWidth = getBinPixelWidth( multiplier );
|
|
||||||
|
|
||||||
offset = -binPixelWidth * (double)( mDFTZoomWindowOffset );
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getBinPixelWidth( int multiplier )
|
|
||||||
{
|
|
||||||
return ( (double)getWidth() * (double)multiplier ) / (double)mDFTSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the screen at each refresh
|
|
||||||
*/
|
|
||||||
public void paintComponent( Graphics g )
|
|
||||||
{
|
|
||||||
super.paintComponent( g );
|
|
||||||
|
|
||||||
int multiplier = getZoomMultiplier();
|
|
||||||
|
|
||||||
double binPixelWidth = getBinPixelWidth( multiplier );
|
|
||||||
|
|
||||||
int offset = (int)( getPixelOffset( multiplier ) - binPixelWidth );
|
|
||||||
|
|
||||||
g.drawImage( mWaterfallImage,
|
|
||||||
offset,
|
|
||||||
0,
|
|
||||||
( getWidth() * multiplier ) + (int)binPixelWidth,
|
|
||||||
mImageHeight,
|
|
||||||
this );
|
|
||||||
|
|
||||||
Graphics2D graphics = (Graphics2D) g;
|
|
||||||
|
|
||||||
graphics.setColor( mColorSpectrumCursor );
|
|
||||||
|
|
||||||
if( mCursorVisible )
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
graphics.draw( new Line2D.Float( mCursorLocation.x,
|
|
||||||
0,
|
|
||||||
mCursorLocation.x,
|
|
||||||
(float)(getSize().getHeight() ) ) );
|
|
||||||
|
|
||||||
String frequency = CURSOR_FORMAT.format( mCursorFrequency / 1000000.0D );
|
|
||||||
|
|
||||||
graphics.drawString( frequency ,
|
|
||||||
mCursorLocation.x + 5,
|
|
||||||
mCursorLocation.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( mPaused )
|
|
||||||
{
|
|
||||||
graphics.drawString( PAUSED, 20, 20 );
|
|
||||||
}
|
|
||||||
|
|
||||||
paintZoomIndicator( graphics );
|
|
||||||
|
|
||||||
graphics.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When zoom level is greater than zero, paints a small indicator at the
|
|
||||||
* bottom center of the screen showing the location of the zoom window
|
|
||||||
* within the overall DFT results window
|
|
||||||
*/
|
|
||||||
private void paintZoomIndicator( Graphics2D graphics )
|
|
||||||
{
|
|
||||||
if( mZoom != 0 )
|
|
||||||
{
|
|
||||||
int width = getWidth() / 4;
|
|
||||||
|
|
||||||
int x = ( getWidth() / 2 ) - ( width / 2 );
|
|
||||||
|
|
||||||
//Draw the outer window
|
|
||||||
graphics.drawRect( x, getHeight() - 12, width, 10 );
|
|
||||||
|
|
||||||
int zoomWidth = width / getZoomMultiplier();
|
|
||||||
|
|
||||||
int windowOffset = 0;
|
|
||||||
|
|
||||||
if( mDFTZoomWindowOffset != 0 )
|
|
||||||
{
|
|
||||||
windowOffset = (int)( ( (double)mDFTZoomWindowOffset /
|
|
||||||
(double)mDFTSize ) * width );
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draw the zoom window
|
|
||||||
graphics.fillRect( x + windowOffset, getHeight() - 12, zoomWidth, 10 );
|
|
||||||
|
|
||||||
//Draw the zoom text
|
|
||||||
graphics.drawString( "Zoom: " + getZoomMultiplier() + "x",
|
|
||||||
x + width + 3, getHeight() - 2 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the DFT results listener interface method. This is the
|
|
||||||
* primary method for receiving new frequency bin results.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void receive( float[] update )
|
|
||||||
{
|
{
|
||||||
//If our FFT size changes, reset our pixel map and image source
|
return (int)Math.pow(2.0, mZoom);
|
||||||
if( mDFTSize != update.length )
|
}
|
||||||
{
|
|
||||||
mDFTSize = update.length;
|
|
||||||
|
|
||||||
reset();
|
/**
|
||||||
}
|
* Sets the zoom window offset from zero
|
||||||
|
*
|
||||||
|
* @param offset in DFT bins
|
||||||
|
*/
|
||||||
|
public void setZoomWindowOffset(int offset)
|
||||||
|
{
|
||||||
|
mDFTZoomWindowOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
//Move the pixels down a row to make room for the new results
|
/**
|
||||||
System.arraycopy( mPixels, 0,
|
* Fetches a named color setting from the settings manager. If the setting
|
||||||
mPixels, mDFTSize, mPixels.length - mDFTSize );
|
* doesn't exist, creates the setting using the defaultColor
|
||||||
|
*/
|
||||||
/**
|
private Color getColor(ColorSettingName name)
|
||||||
* Find the average value and scale the display to it
|
{
|
||||||
*/
|
ColorSetting setting = mSettingsManager.getColorSetting(name);
|
||||||
double sum = 0.0d;
|
|
||||||
|
|
||||||
for( int x = 0; x < update.length - 1; x++ )
|
|
||||||
{
|
|
||||||
sum += update[ x ];
|
|
||||||
}
|
|
||||||
|
|
||||||
float average = (float)( sum / (double)update.length - 1 );
|
|
||||||
|
|
||||||
float scale = 256.0f / average;
|
return setting.getColor();
|
||||||
|
}
|
||||||
for( int x = 0; x < update.length - 1; x++ )
|
|
||||||
{
|
|
||||||
float value = ( average - update[ x ] ) * scale;
|
|
||||||
|
|
||||||
if( value < 0 )
|
/**
|
||||||
{
|
* Monitors for setting changes. Colors can be changed by external actions
|
||||||
mPixels[ x ] = 0;
|
* and will automatically update in this class
|
||||||
}
|
*/
|
||||||
else if( value > 255 )
|
@Override
|
||||||
{
|
public void settingChanged(Setting setting)
|
||||||
mPixels[ x ] = (byte)255;
|
{
|
||||||
}
|
if(setting instanceof ColorSetting)
|
||||||
else
|
{
|
||||||
{
|
ColorSetting colorSetting = (ColorSetting)setting;
|
||||||
mPixels[ x ] = (byte)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Task the swing event thread to update the display
|
if(((ColorSetting)setting).getColorSettingName() ==
|
||||||
EventQueue.invokeLater( new Runnable()
|
ColorSettingName.SPECTRUM_CURSOR)
|
||||||
{
|
{
|
||||||
@Override
|
mColorSpectrumCursor = colorSetting.getColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void settingDeleted(Setting setting)
|
||||||
|
{ /* Not implemented */ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the display location of the cursor. Cursor location monitoring is
|
||||||
|
* handled external to this class.
|
||||||
|
*
|
||||||
|
* @param point
|
||||||
|
*/
|
||||||
|
public void setCursorLocation(Point point)
|
||||||
|
{
|
||||||
|
mCursorLocation = point;
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current cursor display frequency. Cursor location frequency
|
||||||
|
* monitoring is handled external to this class.
|
||||||
|
*
|
||||||
|
* @param frequency
|
||||||
|
*/
|
||||||
|
public void setCursorFrequency(long frequency)
|
||||||
|
{
|
||||||
|
mCursorFrequency = frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the cursor
|
||||||
|
*
|
||||||
|
* @param visible
|
||||||
|
*/
|
||||||
|
public void setCursorVisible(boolean visible)
|
||||||
|
{
|
||||||
|
mCursorVisible = visible;
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the x-axis pixel offset from zero where to start rendering the
|
||||||
|
* waterfall image
|
||||||
|
*
|
||||||
|
* @param multiplier - current zoom multiplier
|
||||||
|
* @return x-axis pixel offset
|
||||||
|
*/
|
||||||
|
private double getPixelOffset(int multiplier)
|
||||||
|
{
|
||||||
|
double offset = 0;
|
||||||
|
|
||||||
|
if(mZoom != 0)
|
||||||
|
{
|
||||||
|
double binPixelWidth = getBinPixelWidth(multiplier);
|
||||||
|
|
||||||
|
offset = -binPixelWidth * (double)(mDFTZoomWindowOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getBinPixelWidth(int multiplier)
|
||||||
|
{
|
||||||
|
return ((double)getWidth() * (double)multiplier) / (double)mDFTSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the screen at each refresh
|
||||||
|
*/
|
||||||
|
public void paintComponent(Graphics g)
|
||||||
|
{
|
||||||
|
super.paintComponent(g);
|
||||||
|
|
||||||
|
int multiplier = getZoomMultiplier();
|
||||||
|
|
||||||
|
double binPixelWidth = getBinPixelWidth(multiplier);
|
||||||
|
|
||||||
|
int offset = (int)(getPixelOffset(multiplier) - binPixelWidth);
|
||||||
|
|
||||||
|
g.drawImage(mWaterfallImage,
|
||||||
|
offset,
|
||||||
|
0,
|
||||||
|
(getWidth() * multiplier) + (int)binPixelWidth,
|
||||||
|
mImageHeight,
|
||||||
|
this);
|
||||||
|
|
||||||
|
Graphics2D graphics = (Graphics2D)g;
|
||||||
|
|
||||||
|
graphics.setColor(mColorSpectrumCursor);
|
||||||
|
|
||||||
|
if(mCursorVisible)
|
||||||
|
{
|
||||||
|
graphics.draw(new Line2D.Float(mCursorLocation.x, 0, mCursorLocation.x, (float)(getSize().getHeight())));
|
||||||
|
String frequency = CURSOR_FORMAT.format(mCursorFrequency / 1000000.0D);
|
||||||
|
graphics.drawString(frequency, mCursorLocation.x + 5, mCursorLocation.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mDisabled)
|
||||||
|
{
|
||||||
|
graphics.drawString(DISABLED, 20, 20);
|
||||||
|
}
|
||||||
|
else if(mPaused)
|
||||||
|
{
|
||||||
|
graphics.drawString(PAUSED, 20, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
paintZoomIndicator(graphics);
|
||||||
|
|
||||||
|
graphics.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When zoom level is greater than zero, paints a small indicator at the
|
||||||
|
* bottom center of the screen showing the location of the zoom window
|
||||||
|
* within the overall DFT results window
|
||||||
|
*/
|
||||||
|
private void paintZoomIndicator(Graphics2D graphics)
|
||||||
|
{
|
||||||
|
if(mZoom != 0)
|
||||||
|
{
|
||||||
|
int width = getWidth() / 4;
|
||||||
|
|
||||||
|
int x = (getWidth() / 2) - (width / 2);
|
||||||
|
|
||||||
|
//Draw the outer window
|
||||||
|
graphics.drawRect(x, getHeight() - 12, width, 10);
|
||||||
|
|
||||||
|
int zoomWidth = width / getZoomMultiplier();
|
||||||
|
|
||||||
|
int windowOffset = 0;
|
||||||
|
|
||||||
|
if(mDFTZoomWindowOffset != 0)
|
||||||
|
{
|
||||||
|
windowOffset = (int)(((double)mDFTZoomWindowOffset /
|
||||||
|
(double)mDFTSize) * width);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Draw the zoom window
|
||||||
|
graphics.fillRect(x + windowOffset, getHeight() - 12, zoomWidth, 10);
|
||||||
|
|
||||||
|
//Draw the zoom text
|
||||||
|
graphics.drawString("Zoom: " + getZoomMultiplier() + "x",
|
||||||
|
x + width + 3, getHeight() - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the DFT results listener interface method. This is the
|
||||||
|
* primary method for receiving new frequency bin results.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void receive(float[] update)
|
||||||
|
{
|
||||||
|
mDisabled = false;
|
||||||
|
|
||||||
|
//If our FFT size changes, reset our pixel map and image source
|
||||||
|
if(mDFTSize != update.length)
|
||||||
|
{
|
||||||
|
mDFTSize = update.length;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Move the pixels down a row to make room for the new results
|
||||||
|
System.arraycopy(mPixels, 0, mPixels, mDFTSize, mPixels.length - mDFTSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the average value and scale the display to it
|
||||||
|
*/
|
||||||
|
double sum = 0.0d;
|
||||||
|
|
||||||
|
for(int x = 0; x < update.length - 1; x++)
|
||||||
|
{
|
||||||
|
sum += update[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
float average = (float)(sum / (double)update.length - 1);
|
||||||
|
|
||||||
|
float scale = 256.0f / average;
|
||||||
|
|
||||||
|
for(int x = 0; x < update.length - 1; x++)
|
||||||
|
{
|
||||||
|
float value = (average - update[x]) * scale;
|
||||||
|
|
||||||
|
if(value < 0)
|
||||||
|
{
|
||||||
|
mPixels[x] = 0;
|
||||||
|
}
|
||||||
|
else if(value > 255)
|
||||||
|
{
|
||||||
|
mPixels[x] = (byte)255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPixels[x] = (byte)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Task the swing event thread to update the display
|
||||||
|
EventQueue.invokeLater(new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
if( mMemoryImageSource != null )
|
if(mMemoryImageSource != null)
|
||||||
{
|
{
|
||||||
if( mPaused )
|
if(mPaused)
|
||||||
{
|
{
|
||||||
mMemoryImageSource.newPixels( mPausedPixels, mColorModel, 0, mDFTSize );
|
mMemoryImageSource.newPixels(mPausedPixels, mColorModel, 0, mDFTSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mMemoryImageSource.newPixels( mPixels, mColorModel, 0, mDFTSize );
|
mMemoryImageSource.newPixels(mPixels, mColorModel, 0, mDFTSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} );
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearWaterfall()
|
||||||
|
{
|
||||||
|
Arrays.fill(mPixels, (byte)0);
|
||||||
|
mDisabled = true;
|
||||||
|
|
||||||
|
EventQueue.invokeLater(new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
mMemoryImageSource.newPixels(mPixels, mColorModel, 0, mDFTSize);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user