Merges from master branch.

This commit is contained in:
Denny
2017-12-27 10:10:51 -05:00
parent 667c50174d
commit 236df8f3f4
262 changed files with 7701 additions and 49122 deletions

View File

@@ -1,3 +1,18 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2017 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.controller.channel.Channel;
@@ -18,8 +33,7 @@ import io.github.dsheirer.settings.ColorSettingMenuItem;
import io.github.dsheirer.settings.Setting;
import io.github.dsheirer.settings.SettingChangeListener;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
import io.github.dsheirer.spectrum.converter.RealDecibelConverter;
import io.github.dsheirer.spectrum.menu.AveragingItem;
@@ -30,8 +44,13 @@ import io.github.dsheirer.spectrum.menu.SmoothingItem;
import io.github.dsheirer.spectrum.menu.SmoothingTypeItem;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
@@ -39,446 +58,456 @@ import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.concurrent.atomic.AtomicBoolean;
public class ChannelSpectrumPanel extends JPanel
implements ChannelEventListener,
Listener<RealBuffer>,
SettingChangeListener,
SpectralDisplayAdjuster
public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener,
Listener<RealBuffer>, SettingChangeListener, SpectralDisplayAdjuster
{
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private DFTProcessor mDFTProcessor = new DFTProcessor( SampleType.REAL );
private DFTProcessor mDFTProcessor = new DFTProcessor(SampleType.REAL);
private DFTResultsConverter mDFTConverter = new RealDecibelConverter();
private JLayeredPane mLayeredPane;
private SpectrumPanel mSpectrumPanel;
private ChannelOverlayPanel mOverlayPanel;
private Channel mCurrentChannel;
private int mSampleBufferSize = 2400;
private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true );
private HalfBandFilter_RB_RB mDecimatingFilter = new HalfBandFilter_RB_RB(
Filters.FIR_HALF_BAND_31T_ONE_EIGHTH_FCO.getCoefficients(), 1.0f, true);
private AtomicBoolean mEnabled = new AtomicBoolean();
private SettingsManager mSettingsManager;
private ChannelProcessingManager mChannelProcessingManager;
public ChannelSpectrumPanel( SettingsManager settingsManager,
ChannelProcessingManager channelProcessingManager )
public ChannelSpectrumPanel(SettingsManager settingsManager,
ChannelProcessingManager channelProcessingManager)
{
mSettingsManager = settingsManager;
mChannelProcessingManager = channelProcessingManager;
if( mSettingsManager != null )
{
mSettingsManager.addListener( this );
}
mSpectrumPanel = new SpectrumPanel( mSettingsManager );
mSpectrumPanel.setAveraging( 1 );
mSettingsManager = settingsManager;
mChannelProcessingManager = channelProcessingManager;
mOverlayPanel = new ChannelOverlayPanel( mSettingsManager );
mDFTProcessor.addConverter( mDFTConverter );
mDFTConverter.addListener( mSpectrumPanel );
if(mSettingsManager != null)
{
mSettingsManager.addListener(this);
}
/* Set the DFTProcessor to the decimated 24kHz sample rate */
mDFTProcessor.frequencyChanged(
new FrequencyChangeEvent( Event.NOTIFICATION_SAMPLE_RATE_CHANGE, 24000 ) );
initGui();
mSpectrumPanel = new SpectrumPanel(mSettingsManager);
mSpectrumPanel.setAveraging(1);
mOverlayPanel = new ChannelOverlayPanel(mSettingsManager);
mDFTProcessor.addConverter(mDFTConverter);
mDFTConverter.addListener(mSpectrumPanel);
/* Set the DFTProcessor to the decimated 24kHz sample rate */
mDFTProcessor.process(SourceEvent.sampleRateChange(24000.0));
initGui();
}
public void dispose()
{
setEnabled( false );
mDFTProcessor.dispose();
setEnabled(false);
if( mSettingsManager != null )
{
mSettingsManager.removeListener( this );
}
mSettingsManager = null;
mCurrentChannel = null;
mDFTProcessor = null;
mSpectrumPanel = null;
mDFTProcessor.dispose();
if(mSettingsManager != null)
{
mSettingsManager.removeListener(this);
}
mSettingsManager = null;
mCurrentChannel = null;
mDFTProcessor = null;
mSpectrumPanel = null;
}
public void setFrameRate( int framesPerSecond )
public void setFrameRate(int framesPerSecond)
{
mSampleBufferSize = (int)( 48000 / framesPerSecond );
mDFTProcessor.setFrameRate( framesPerSecond );
mSampleBufferSize = (int)(48000 / framesPerSecond);
mDFTProcessor.setFrameRate(framesPerSecond);
}
private void initGui()
{
setLayout( new MigLayout( "insets 0 0 0 0 ",
"[grow,fill]",
"[grow,fill]") );
mLayeredPane = new JLayeredPane();
mLayeredPane.addComponentListener( new ResizeListener() );
MouseEventProcessor mouser = new MouseEventProcessor();
mOverlayPanel.addMouseListener( mouser );
mOverlayPanel.addMouseMotionListener( mouser );
mLayeredPane.add( mSpectrumPanel, new Integer( 0 ), 0 );
mLayeredPane.add( mOverlayPanel, new Integer( 1 ), 0 );
setLayout(new MigLayout("insets 0 0 0 0 ",
"[grow,fill]",
"[grow,fill]"));
add( mLayeredPane );
mLayeredPane = new JLayeredPane();
mLayeredPane.addComponentListener(new ResizeListener());
MouseEventProcessor mouser = new MouseEventProcessor();
mOverlayPanel.addMouseListener(mouser);
mOverlayPanel.addMouseMotionListener(mouser);
mLayeredPane.add(mSpectrumPanel, new Integer(0), 0);
mLayeredPane.add(mOverlayPanel, new Integer(1), 0);
add(mLayeredPane);
}
public void setEnabled( boolean enabled )
public void setEnabled(boolean enabled)
{
if( enabled && mEnabled.compareAndSet( false, true ) )
{
start();
}
else if( !enabled && mEnabled.compareAndSet( true, false ) )
{
stop();
}
if(enabled && mEnabled.compareAndSet(false, true))
{
start();
}
else if(!enabled && mEnabled.compareAndSet(true, false))
{
stop();
}
}
@Override
@SuppressWarnings( "incomplete-switch" )
public void channelChanged( ChannelEvent event )
@SuppressWarnings("incomplete-switch")
public void channelChanged(ChannelEvent event)
{
switch( event.getEvent() )
{
case NOTIFICATION_SELECTION_CHANGE:
//ChannelSelectionManager ensures that only 1 channel can be
//selected and any previously selected channel will be first
//deselected before we get a new selection event
if( event.getChannel().isSelected() )
{
if( mCurrentChannel != null )
{
stop();
mCurrentChannel = null;
}
mCurrentChannel = event.getChannel();
if( mEnabled.get() )
{
start();
}
}
else
{
stop();
mCurrentChannel = null;
}
break;
case NOTIFICATION_PROCESSING_STOP:
if( event.getChannel() == mCurrentChannel )
{
if( mEnabled.get() )
{
stop();
}
mCurrentChannel = null;
}
break;
}
}
private void start()
{
if( mEnabled.get() && mCurrentChannel != null && mCurrentChannel.getEnabled() )
{
ProcessingChain processingChain = mChannelProcessingManager
.getProcessingChain( mCurrentChannel );
if( processingChain != null )
{
processingChain.addRealBufferListener( this );
mDFTProcessor.start();
}
}
}
private void stop()
{
if( mCurrentChannel != null && mCurrentChannel.getEnabled() )
{
ProcessingChain processingChain = mChannelProcessingManager
.getProcessingChain( mCurrentChannel );
if( processingChain != null )
{
processingChain.removeRealBufferListener( this );
}
}
mDFTProcessor.stop();
mSpectrumPanel.clearSpectrum();
}
@Override
public void settingChanged( Setting setting )
{
if( mSpectrumPanel != null )
{
mSpectrumPanel.settingChanged( setting );
}
if( mOverlayPanel != null )
{
mOverlayPanel.settingChanged( setting );
}
}
@Override
public void settingDeleted( Setting setting )
{
if( mSpectrumPanel != null )
{
mSpectrumPanel.settingDeleted( setting );
}
if( mOverlayPanel != null )
{
mOverlayPanel.settingDeleted( setting );
}
}
@Override
public void receive( RealBuffer buffer )
{
RealBuffer decimated = mDecimatingFilter.filter( buffer );
//Hack: we're placing real samples in a complex buffer that the DFT
//processor is expecting.
mDFTProcessor.receive( new ComplexBuffer( decimated.getSamples() ) );
}
/**
* Monitors the sizing of the layered pane and resizes the spectrum and
* channel panels whenever the layered pane is resized
*/
public class ResizeListener implements ComponentListener
{
@Override
public void componentResized( ComponentEvent e )
switch(event.getEvent())
{
Component c = e.getComponent();
mSpectrumPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() );
mOverlayPanel.setBounds( 0, 0, c.getWidth(), c.getHeight() );
case NOTIFICATION_SELECTION_CHANGE:
//ChannelSelectionManager ensures that only 1 channel can be
//selected and any previously selected channel will be first
//deselected before we get a new selection event
if(event.getChannel().isSelected())
{
if(mCurrentChannel != null)
{
stop();
mCurrentChannel = null;
}
mCurrentChannel = event.getChannel();
if(mEnabled.get())
{
start();
}
}
else
{
stop();
mCurrentChannel = null;
}
break;
case NOTIFICATION_PROCESSING_STOP:
if(event.getChannel() == mCurrentChannel)
{
if(mEnabled.get())
{
stop();
}
mCurrentChannel = null;
}
break;
}
}
private void start()
{
if(mEnabled.get() && mCurrentChannel != null && mCurrentChannel.getEnabled())
{
ProcessingChain processingChain = mChannelProcessingManager
.getProcessingChain(mCurrentChannel);
if(processingChain != null)
{
processingChain.addRealBufferListener(this);
mDFTProcessor.start();
}
}
}
private void stop()
{
if(mCurrentChannel != null && mCurrentChannel.getEnabled())
{
ProcessingChain processingChain = mChannelProcessingManager
.getProcessingChain(mCurrentChannel);
if(processingChain != null)
{
processingChain.removeRealBufferListener(this);
}
}
@Override
public void componentHidden( ComponentEvent arg0 ) {}
@Override
public void componentMoved( ComponentEvent arg0 ) {}
@Override
public void componentShown( ComponentEvent arg0 ) {}
}
/**
* Mouse event handler for the channel panel.
*/
public class MouseEventProcessor implements MouseMotionListener, MouseListener
{
@Override
public void mouseMoved( MouseEvent event )
mDFTProcessor.stop();
mSpectrumPanel.clearSpectrum();
}
@Override
public void settingChanged(Setting setting)
{
if(mSpectrumPanel != null)
{
update( event );
mSpectrumPanel.settingChanged(setting);
}
@Override
public void mouseDragged( MouseEvent event )
{
update( event );
}
private void update( MouseEvent event )
{
if( event.getComponent() == mOverlayPanel )
{
mOverlayPanel.setCursorLocation( event.getPoint() );
}
}
@Override
public void mouseEntered( MouseEvent e )
{
if( e.getComponent() == mOverlayPanel )
{
mOverlayPanel.setCursorVisible( true );
}
}
@Override
public void mouseExited( MouseEvent e )
{
mOverlayPanel.setCursorVisible( false );
}
/**
* Displays the context menu.
*/
@Override
public void mouseClicked( MouseEvent event )
if(mOverlayPanel != null)
{
if( SwingUtilities.isRightMouseButton( event ) )
{
JPopupMenu contextMenu = new JPopupMenu();
/**
* Color Menus
*/
JMenu colorMenu = new JMenu( "Color" );
mOverlayPanel.settingChanged(setting);
}
}
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.SPECTRUM_CURSOR ) );
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.SPECTRUM_LINE ) );
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.SPECTRUM_BACKGROUND ) );
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.SPECTRUM_GRADIENT_BOTTOM ) );
colorMenu.add( new ColorSettingMenuItem( mSettingsManager,
ColorSettingName.SPECTRUM_GRADIENT_TOP ) );
contextMenu.add( colorMenu );
/**
* Display items: fft and frame rate
*/
JMenu displayMenu = new JMenu( "Display" );
contextMenu.add( displayMenu );
/**
* Averaging menu
*/
JMenu averagingMenu = new JMenu( "Averaging" );
averagingMenu.add(
new AveragingItem( ChannelSpectrumPanel.this, 2 ) );
displayMenu.add( averagingMenu );
/**
* FFT width
*/
JMenu fftWidthMenu = new JMenu( "FFT Width" );
displayMenu.add( fftWidthMenu );
for( DFTSize width: DFTSize.values() )
{
fftWidthMenu.add( new DFTSizeItem( mDFTProcessor, width ) );
}
/**
* DFT Processor Frame Rate
*/
JMenu frameRateMenu = new JMenu( "Frame Rate" );
displayMenu.add( frameRateMenu );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 14 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 16 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 18 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 20 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 25 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 30 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 40 ) );
frameRateMenu.add( new FrameRateItem( mDFTProcessor, 50 ) );
/**
* FFT Window Type
*/
JMenu fftWindowType = new JMenu( "Window Type" );
displayMenu.add( fftWindowType );
for( WindowType type: WindowType.values() )
{
fftWindowType.add(
new FFTWindowTypeItem( mDFTProcessor, type ) );
}
/**
* Smoothing menu
*/
JMenu smoothingMenu = new JMenu( "Smoothing" );
if( mSpectrumPanel.getSmoothingType() != SmoothingType.NONE )
{
smoothingMenu.add( new SmoothingItem( ChannelSpectrumPanel.this, 5 ) );
smoothingMenu.add( new JSeparator() );
}
smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.GAUSSIAN ) );
smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.TRIANGLE ) );
smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.RECTANGLE ) );
smoothingMenu.add( new SmoothingTypeItem( ChannelSpectrumPanel.this, SmoothingType.NONE ) );
displayMenu.add( smoothingMenu );
if( contextMenu != null )
{
contextMenu.show( mOverlayPanel,
event.getX(),
event.getY() );
}
}
@Override
public void settingDeleted(Setting setting)
{
if(mSpectrumPanel != null)
{
mSpectrumPanel.settingDeleted(setting);
}
@Override
public void mousePressed( MouseEvent e ) {}
@Override
public void mouseReleased( MouseEvent e ) {}
}
if(mOverlayPanel != null)
{
mOverlayPanel.settingDeleted(setting);
}
}
@Override
@Override
public void receive(RealBuffer buffer)
{
RealBuffer decimated = mDecimatingFilter.filter(buffer);
//Hack: we're placing real samples in a complex buffer that the DFT
//processor is expecting.
mDFTProcessor.receive(new ComplexBuffer(decimated.getSamples()));
}
/**
* Monitors the sizing of the layered pane and resizes the spectrum and
* channel panels whenever the layered pane is resized
*/
public class ResizeListener implements ComponentListener
{
@Override
public void componentResized(ComponentEvent e)
{
Component c = e.getComponent();
mSpectrumPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
mOverlayPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
}
@Override
public void componentHidden(ComponentEvent arg0)
{
}
@Override
public void componentMoved(ComponentEvent arg0)
{
}
@Override
public void componentShown(ComponentEvent arg0)
{
}
}
/**
* Mouse event handler for the channel panel.
*/
public class MouseEventProcessor implements MouseMotionListener, MouseListener
{
@Override
public void mouseMoved(MouseEvent event)
{
update(event);
}
@Override
public void mouseDragged(MouseEvent event)
{
update(event);
}
private void update(MouseEvent event)
{
if(event.getComponent() == mOverlayPanel)
{
mOverlayPanel.setCursorLocation(event.getPoint());
}
}
@Override
public void mouseEntered(MouseEvent e)
{
if(e.getComponent() == mOverlayPanel)
{
mOverlayPanel.setCursorVisible(true);
}
}
@Override
public void mouseExited(MouseEvent e)
{
mOverlayPanel.setCursorVisible(false);
}
/**
* Displays the context menu.
*/
@Override
public void mouseClicked(MouseEvent event)
{
if(SwingUtilities.isRightMouseButton(event))
{
JPopupMenu contextMenu = new JPopupMenu();
/**
* Color Menus
*/
JMenu colorMenu = new JMenu("Color");
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
ColorSettingName.SPECTRUM_CURSOR));
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
ColorSettingName.SPECTRUM_LINE));
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
ColorSettingName.SPECTRUM_BACKGROUND));
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
ColorSettingName.SPECTRUM_GRADIENT_BOTTOM));
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
ColorSettingName.SPECTRUM_GRADIENT_TOP));
contextMenu.add(colorMenu);
/**
* Display items: fft and frame rate
*/
JMenu displayMenu = new JMenu("Display");
contextMenu.add(displayMenu);
/**
* Averaging menu
*/
JMenu averagingMenu = new JMenu("Averaging");
averagingMenu.add(
new AveragingItem(ChannelSpectrumPanel.this, 2));
displayMenu.add(averagingMenu);
/**
* FFT width
*/
JMenu fftWidthMenu = new JMenu("FFT Width");
displayMenu.add(fftWidthMenu);
for(DFTSize width : DFTSize.values())
{
fftWidthMenu.add(new DFTSizeItem(mDFTProcessor, width));
}
/**
* DFT Processor Frame Rate
*/
JMenu frameRateMenu = new JMenu("Frame Rate");
displayMenu.add(frameRateMenu);
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 14));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 16));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 18));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 20));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 25));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 30));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 40));
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 50));
/**
* FFT Window Type
*/
JMenu fftWindowType = new JMenu("Window Type");
displayMenu.add(fftWindowType);
for(WindowType type : WindowType.values())
{
fftWindowType.add(
new FFTWindowTypeItem(mDFTProcessor, type));
}
/**
* Smoothing menu
*/
JMenu smoothingMenu = new JMenu("Smoothing");
if(mSpectrumPanel.getSmoothingType() != SmoothingType.NONE)
{
smoothingMenu.add(new SmoothingItem(ChannelSpectrumPanel.this, 5));
smoothingMenu.add(new JSeparator());
}
smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.GAUSSIAN));
smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.TRIANGLE));
smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.RECTANGLE));
smoothingMenu.add(new SmoothingTypeItem(ChannelSpectrumPanel.this, SmoothingType.NONE));
displayMenu.add(smoothingMenu);
if(contextMenu != null)
{
contextMenu.show(mOverlayPanel,
event.getX(),
event.getY());
}
}
}
@Override
public void mousePressed(MouseEvent e)
{
}
@Override
public void mouseReleased(MouseEvent e)
{
}
}
@Override
public int getAveraging()
{
return mSpectrumPanel.getAveraging();
return mSpectrumPanel.getAveraging();
}
@Override
public void setAveraging( int averaging )
@Override
public void setAveraging(int averaging)
{
mSpectrumPanel.setAveraging( averaging );
mSpectrumPanel.setAveraging(averaging);
}
public void setSampleSize( double sampleSize )
{
mSpectrumPanel.setSampleSize( sampleSize );
}
public void setSampleSize(double sampleSize)
{
mSpectrumPanel.setSampleSize(sampleSize);
}
@Override
public int getSmoothing()
{
return mSpectrumPanel.getSmoothing();
}
@Override
public int getSmoothing()
{
return mSpectrumPanel.getSmoothing();
}
@Override
public void setSmoothing( int smoothing )
{
mSpectrumPanel.setSmoothing( smoothing );
}
@Override
public void setSmoothing(int smoothing)
{
mSpectrumPanel.setSmoothing(smoothing);
}
@Override
public SmoothingType getSmoothingType()
{
return mSpectrumPanel.getSmoothingType();
}
@Override
public SmoothingType getSmoothingType()
{
return mSpectrumPanel.getSmoothingType();
}
@Override
public void setSmoothingType( SmoothingType type )
{
mSpectrumPanel.setSmoothingType( type );
}
@Override
public void setSmoothingType(SmoothingType type)
{
mSpectrumPanel.setSmoothingType(type);
}
}

View File

@@ -1,19 +1,16 @@
/*******************************************************************************
* sdrtrunk
* sdr-trunk
* Copyright (C) 2014-2017 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 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.
* 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/>
* 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;
@@ -25,8 +22,8 @@ import io.github.dsheirer.sample.Buffer;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.SampleType;
import io.github.dsheirer.sample.complex.ComplexBuffer;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
import io.github.dsheirer.util.ThreadPool;
import org.jtransforms.fft.FloatFFT_1D;
@@ -46,7 +43,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Processes both complex samples or float samples and dispatches a float array
* of DFT results, using configurable fft size and output dispatch timelines.
*/
public class DFTProcessor implements Listener<ComplexBuffer>, IFrequencyChangeProcessor, IDFTWidthChangeProcessor
public class DFTProcessor implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
{
private final static Logger mLog = LoggerFactory.getLogger(DFTProcessor.class);
@@ -70,7 +67,7 @@ public class DFTProcessor implements Listener<ComplexBuffer>, IFrequencyChangePr
/* The Cosine and Hanning windows seem to offer the best spectral display
* with minimal bin leakage/smearing */
private WindowType mWindowType = Window.WindowType.HANNING;
private WindowType mWindowType = WindowType.BLACKMAN_HARRIS_7;
private FloatFFT_1D mFFT = new FloatFFT_1D(mDFTSize.getSize());
@@ -452,7 +449,7 @@ public class DFTProcessor implements Listener<ComplexBuffer>, IFrequencyChangePr
}
@Override
public void frequencyChanged(FrequencyChangeEvent event)
public void process(SourceEvent event)
{
switch(event.getEvent())
{

View File

@@ -28,14 +28,22 @@ import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
import io.github.dsheirer.settings.Setting;
import io.github.dsheirer.settings.SettingChangeListener;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.tuner.TunerChannel;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import java.awt.*;
import javax.swing.JPanel;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Line2D;
@@ -44,7 +52,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequencyChangeProcessor,
public class OverlayPanel extends JPanel implements ChannelEventListener, ISourceEventProcessor,
SettingChangeListener
{
private static final long serialVersionUID = 1L;
@@ -635,7 +643,7 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ
* Frequency change event handler
*/
@Override
public void frequencyChanged(FrequencyChangeEvent event)
public void process(SourceEvent event)
{
switch(event.getEvent())
{

View File

@@ -1,19 +1,16 @@
/*******************************************************************************
* sdrtrunk
* sdr-trunk
* Copyright (C) 2014-2017 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 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.
* 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/>
* 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;
@@ -33,10 +30,9 @@ import io.github.dsheirer.sample.complex.ComplexBuffer;
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
import io.github.dsheirer.settings.ColorSettingMenuItem;
import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
import io.github.dsheirer.spectrum.OverlayPanel.ChannelDisplay;
import io.github.dsheirer.spectrum.converter.ComplexDecibelConverter;
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
@@ -50,11 +46,25 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
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.ComponentEvent;
@@ -65,7 +75,7 @@ import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Hashtable;
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, IFrequencyChangeProcessor, IDFTWidthChangeProcessor
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, ISourceEventProcessor, IDFTWidthChangeProcessor
{
private static final long serialVersionUID = 1L;
@@ -223,7 +233,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
*
* @param zoom level, 0 - 6.
* @param frequency under the mouse to maintain while zooming
* @param xAxisOffset where to maintain the frequency under the mouse
* @param windowOffset where to maintain the frequency under the mouse
*/
public void setZoom(int zoom, long frequency, double windowOffset)
{
@@ -247,7 +257,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
//Calculate the bin offset into the newly sized zoom window that
//would place the frequency in the same proportional window location
//that it was in the previous zoom size
double windowBinOffset = (double) getZoomWindowSizeInBins() * windowOffset;
double windowBinOffset = (double)getZoomWindowSizeInBins() * windowOffset;
//Set the overall offset to place the reference frequency in the
//same location in the newly zoomed window
@@ -276,7 +286,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
offset = mDFTSize.getSize() - getZoomWindowSizeInBins();
}
mDFTZoomWindowOffset = (int) offset;
mDFTZoomWindowOffset = (int)offset;
mSpectrumPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
mOverlayPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
@@ -294,7 +304,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
public int getZoomMultiplier()
{
return (int) Math.pow(2.0, mZoom);
return (int)Math.pow(2.0, mZoom);
}
/**
@@ -310,9 +320,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
if(mOverlayPanel.containsFrequency(frequency))
{
offset = (double) mDFTSize.getSize() *
((double) (frequency - mOverlayPanel.getMinFrequency()) /
(double) mOverlayPanel.getBandwidth());
offset = (double)mDFTSize.getSize() *
((double)(frequency - mOverlayPanel.getMinFrequency()) /
(double)mOverlayPanel.getBandwidth());
}
return offset;
@@ -357,15 +367,15 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
mWaterfallPanel.addMouseMotionListener(mouser);
mWaterfallPanel.addMouseWheelListener(mouser);
/* Attempt to set a 50/50 split preferred size for the split pane */
/* Attempt to set a 50/50 split preferred size for the split pane */
double totalHeight = mLayeredPanel.getPreferredSize().getHeight() +
mWaterfallPanel.getPreferredSize().getHeight();
mLayeredPanel.setPreferredSize(new Dimension((int) mLayeredPanel
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
mLayeredPanel.setPreferredSize(new Dimension((int)mLayeredPanel
.getPreferredSize().getWidth(), (int)(totalHeight / 2.0d)));
mWaterfallPanel.setPreferredSize(new Dimension((int) mWaterfallPanel
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
mWaterfallPanel.setPreferredSize(new Dimension((int)mWaterfallPanel
.getPreferredSize().getWidth(), (int)(totalHeight / 2.0d)));
//Create the split pane to hold the layered pane and the waterfall
JideSplitPane splitPane = new JideSplitPane(JSplitPane.VERTICAL_SPLIT);
@@ -385,17 +395,17 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
mDFTConverter = new ComplexDecibelConverter();
mDFTProcessor.addConverter(mDFTConverter);
mDFTConverter.addListener((DFTResultsListener) mSpectrumPanel);
mDFTConverter.addListener((DFTResultsListener) mWaterfallPanel);
mDFTConverter.addListener((DFTResultsListener)mSpectrumPanel);
mDFTConverter.addListener((DFTResultsListener)mWaterfallPanel);
}
/**
* Receives frequency change events -- primarily from tuner components.
*/
public void frequencyChanged(FrequencyChangeEvent event)
public void process(SourceEvent event)
{
mOverlayPanel.frequencyChanged(event);
mDFTProcessor.frequencyChanged(event);
mOverlayPanel.process(event);
mDFTProcessor.process(event);
}
/**
@@ -425,19 +435,15 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
mTuner.getTunerController().addListener(this);
//Register the dft processor to receive samples from the tuner
mTuner.addListener((Listener<ComplexBuffer>) mDFTProcessor);
mTuner.getSourceManager().addComplexBufferListener(mDFTProcessor);
mSpectrumPanel.setSampleSize(mTuner.getSampleSize());
//Fire frequency and sample rate change events so that the spectrum
//and overlay panels can synchronize
frequencyChanged(new FrequencyChangeEvent(
Event.NOTIFICATION_FREQUENCY_CHANGE,
mTuner.getTunerController().getFrequency()));
process(SourceEvent.frequencyChange(mTuner.getTunerController().getFrequency()));
frequencyChanged(new FrequencyChangeEvent(
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
mTuner.getTunerController().getSampleRate()));
process(SourceEvent.sampleRateChange(mTuner.getTunerController().getSampleRate()));
}
}
@@ -452,7 +458,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
mTuner.getTunerController().removeListener(this);
//Deregister the dft processor from receiving samples
mTuner.removeListener((Listener<ComplexBuffer>) mDFTProcessor);
mTuner.getTunerController().removeComplexBufferListener(mDFTProcessor);
mTuner = null;
}
}
@@ -508,7 +514,7 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
long frequency = mOverlayPanel.getFrequencyFromAxis(e.getX());
double windowOffset = (double) e.getX() / (double) getWidth();
double windowOffset = (double)e.getX() / (double)getWidth();
setZoom(zoom, frequency, windowOffset);
}
@@ -526,9 +532,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
int dragDistance = mDragStartX - event.getX();
double binDistance = (double) dragDistance / mPixelsPerBin;
double binDistance = (double)dragDistance / mPixelsPerBin;
int offset = (int) (mDFTZoomWindowOffsetAtDragStart + binDistance);
int offset = (int)(mDFTZoomWindowOffsetAtDragStart + binDistance);
if(offset < 0)
{
@@ -552,9 +558,9 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
mDFTZoomWindowOffsetAtDragStart = mDFTZoomWindowOffset;
mPixelsPerBin = (double) getWidth() /
((double) (mDFTSize.getSize()) /
(double) getZoomMultiplier());
mPixelsPerBin = (double)getWidth() /
((double)(mDFTSize.getSize()) /
(double)getZoomMultiplier());
}
/**
@@ -773,12 +779,12 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
displayMenu.add(smoothingMenu);
}
/*
* Zoom menu
*/
/*
* Zoom menu
*/
JMenuItem zoomMenu = new JMenu("Zoom");
double windowOffset = (double) event.getX() / (double) getWidth();
double windowOffset = (double)event.getX() / (double)getWidth();
zoomMenu.add(new ZoomItem(frequency, windowOffset));
@@ -943,4 +949,4 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuff
});
}
}
}
}