2014-11-15 23:41:41 -05:00
# include "WaterfallCanvas.h"
# include "wx/wxprec.h"
# ifndef WX_PRECOMP
# include "wx/wx.h"
# endif
# if !wxUSE_GLCANVAS
# error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
# endif
# include "CubicSDR.h"
# include "CubicSDRDefs.h"
# include "AppFrame.h"
# include <algorithm>
2014-11-25 22:51:14 -05:00
# include <wx/numformatter.h>
2015-01-01 18:08:54 -05:00
# define MIN_BANDWIDTH 1500
2014-12-29 00:24:10 -05:00
2014-11-15 23:41:41 -05:00
wxBEGIN_EVENT_TABLE ( WaterfallCanvas , wxGLCanvas ) EVT_PAINT ( WaterfallCanvas : : OnPaint )
EVT_KEY_DOWN ( WaterfallCanvas : : OnKeyDown )
2014-12-10 00:34:27 -05:00
EVT_KEY_UP ( WaterfallCanvas : : OnKeyUp )
2014-11-15 23:41:41 -05:00
EVT_IDLE ( WaterfallCanvas : : OnIdle )
2014-11-25 22:51:14 -05:00
EVT_MOTION ( WaterfallCanvas : : mouseMoved )
EVT_LEFT_DOWN ( WaterfallCanvas : : mouseDown )
EVT_LEFT_UP ( WaterfallCanvas : : mouseReleased )
EVT_LEAVE_WINDOW ( WaterfallCanvas : : mouseLeftWindow )
EVT_ENTER_WINDOW ( WaterfallCanvas : : mouseEnterWindow )
2014-11-15 23:41:41 -05:00
wxEND_EVENT_TABLE ( )
WaterfallCanvas : : WaterfallCanvas ( wxWindow * parent , int * attribList ) :
2015-01-02 21:32:24 -05:00
InteractiveCanvas ( parent , attribList ) , spectrumCanvas ( NULL ) , activeDemodulatorBandwidth ( 0 ) , activeDemodulatorFrequency ( 0 ) , dragState (
WF_DRAG_NONE ) , nextDragState ( WF_DRAG_NONE ) , fft_size ( 0 ) , waterfall_lines ( 0 ) , plan (
NULL ) , in ( NULL ) , out ( NULL ) , resampler ( NULL ) , resample_ratio ( 0 ) , last_input_bandwidth ( 0 ) , zoom ( 0 ) {
2014-11-15 23:41:41 -05:00
glContext = new WaterfallContext ( this , & wxGetApp ( ) . GetContext ( this ) ) ;
2014-12-28 05:13:46 -05:00
nco_shift = nco_crcf_create ( LIQUID_NCO ) ;
shift_freq = 0 ;
2014-11-25 00:35:06 -05:00
2014-12-31 19:45:01 -05:00
fft_ceil_ma = fft_ceil_maa = 100.0 ;
fft_floor_ma = fft_floor_maa = 0.0 ;
2014-11-25 00:35:06 -05:00
SetCursor ( wxCURSOR_CROSS ) ;
2014-11-15 23:41:41 -05:00
}
WaterfallCanvas : : ~ WaterfallCanvas ( ) {
2014-12-28 05:13:46 -05:00
nco_crcf_destroy ( nco_shift ) ;
}
2014-11-15 23:41:41 -05:00
2014-12-28 05:13:46 -05:00
void WaterfallCanvas : : Setup ( int fft_size_in , int waterfall_lines_in ) {
if ( fft_size = = fft_size_in & & waterfall_lines_in = = waterfall_lines ) {
return ;
}
fft_size = fft_size_in ;
waterfall_lines = waterfall_lines_in ;
2014-11-30 18:54:13 -05:00
2014-12-28 05:13:46 -05:00
if ( in ) {
free ( in ) ;
}
in = ( fftw_complex * ) fftw_malloc ( sizeof ( fftw_complex ) * fft_size ) ;
if ( out ) {
free ( out ) ;
}
out = ( fftw_complex * ) fftw_malloc ( sizeof ( fftw_complex ) * fft_size ) ;
if ( plan ) {
fftw_destroy_plan ( plan ) ;
}
2015-01-01 18:08:54 -05:00
plan = fftw_plan_dft_1d ( fft_size , in , out , FFTW_FORWARD , FFTW_ESTIMATE ) ;
2014-12-28 05:13:46 -05:00
glContext - > Setup ( fft_size , waterfall_lines ) ;
}
2014-12-28 20:55:05 -05:00
WaterfallCanvas : : DragState WaterfallCanvas : : getDragState ( ) {
return dragState ;
}
WaterfallCanvas : : DragState WaterfallCanvas : : getNextDragState ( ) {
return nextDragState ;
}
2014-12-29 00:24:10 -05:00
void WaterfallCanvas : : attachSpectrumCanvas ( SpectrumCanvas * canvas_in ) {
spectrumCanvas = canvas_in ;
}
2014-11-15 23:41:41 -05:00
void WaterfallCanvas : : OnPaint ( wxPaintEvent & WXUNUSED ( event ) ) {
wxPaintDC dc ( this ) ;
const wxSize ClientSize = GetClientSize ( ) ;
glContext - > SetCurrent ( * this ) ;
glViewport ( 0 , 0 , ClientSize . x , ClientSize . y ) ;
2014-11-25 22:51:14 -05:00
glContext - > BeginDraw ( ) ;
2014-11-15 23:41:41 -05:00
glContext - > Draw ( spectrum_points ) ;
2014-11-30 18:54:13 -05:00
std : : vector < DemodulatorInstance * > & demods = wxGetApp ( ) . getDemodMgr ( ) . getDemodulators ( ) ;
2014-12-10 00:34:27 -05:00
DemodulatorInstance * activeDemodulator = wxGetApp ( ) . getDemodMgr ( ) . getActiveDemodulator ( ) ;
DemodulatorInstance * lastActiveDemodulator = wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) ;
2014-12-24 01:28:33 -05:00
bool isNew = shiftDown
| | ( wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) & & ! wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) - > isActive ( ) ) ;
2014-12-18 21:39:32 -05:00
2014-12-28 05:13:46 -05:00
int currentBandwidth = GetBandwidth ( ) ;
int currentCenterFreq = GetCenterFrequency ( ) ;
2014-11-30 18:54:13 -05:00
if ( mTracker . mouseInView ( ) ) {
2014-12-11 20:50:58 -05:00
if ( nextDragState = = WF_DRAG_RANGE ) {
if ( mTracker . mouseDown ( ) ) {
float width = mTracker . getOriginDeltaMouseX ( ) ;
2014-12-11 21:37:01 -05:00
float centerPos = mTracker . getOriginMouseX ( ) + width / 2.0 ;
2014-11-26 21:05:19 -05:00
2014-12-18 21:39:32 -05:00
if ( isNew ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( centerPos , 0 , 1 , 0 , width ? width : ( 1.0 / ( float ) ClientSize . x ) , currentCenterFreq ,
currentBandwidth ) ;
2014-12-10 00:34:27 -05:00
} else {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( centerPos , 1 , 1 , 0 , width ? width : ( 1.0 / ( float ) ClientSize . x ) , currentCenterFreq ,
currentBandwidth ) ;
2014-12-10 00:34:27 -05:00
}
2014-12-10 21:22:13 -05:00
} else {
2014-12-18 21:39:32 -05:00
if ( isNew ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( mTracker . getMouseX ( ) , 0 , 1 , 0 , 1.0 / ( float ) ClientSize . x , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
} else {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( mTracker . getMouseX ( ) , 1 , 1 , 0 , 1.0 / ( float ) ClientSize . x , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
}
2014-12-10 00:34:27 -05:00
}
2014-11-30 18:54:13 -05:00
} else {
2014-12-11 20:50:58 -05:00
if ( activeDemodulator = = NULL ) {
if ( lastActiveDemodulator ) {
2014-12-18 21:39:32 -05:00
if ( isNew ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( mTracker . getMouseX ( ) , 0 , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
} else {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
glContext - > DrawFreqSelector ( mTracker . getMouseX ( ) , 1 , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
}
} else {
2014-12-28 05:13:46 -05:00
glContext - > DrawFreqSelector ( mTracker . getMouseX ( ) , 1 , 1 , 0 , 0 , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
}
} else {
if ( lastActiveDemodulator ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
2014-12-11 20:50:58 -05:00
}
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( activeDemodulator , 1 , 1 , 0 , currentCenterFreq , currentBandwidth ) ;
2014-12-10 00:34:27 -05:00
}
2014-11-30 18:54:13 -05:00
}
2014-12-10 00:34:27 -05:00
} else {
if ( activeDemodulator ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( activeDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
2014-12-10 00:34:27 -05:00
}
if ( lastActiveDemodulator ) {
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( lastActiveDemodulator , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
2014-12-10 00:34:27 -05:00
}
2014-11-26 21:05:19 -05:00
}
2014-11-30 18:54:13 -05:00
for ( int i = 0 , iMax = demods . size ( ) ; i < iMax ; i + + ) {
2014-12-10 00:34:27 -05:00
if ( activeDemodulator = = demods [ i ] | | lastActiveDemodulator = = demods [ i ] ) {
2014-11-30 18:54:13 -05:00
continue ;
}
2014-12-28 05:13:46 -05:00
glContext - > DrawDemod ( demods [ i ] , 1 , 1 , 1 , currentCenterFreq , currentBandwidth ) ;
2014-11-25 22:51:14 -05:00
}
2014-11-30 18:54:13 -05:00
2014-11-25 22:51:14 -05:00
glContext - > EndDraw ( ) ;
2014-11-15 23:41:41 -05:00
SwapBuffers ( ) ;
}
2014-12-10 00:34:27 -05:00
void WaterfallCanvas : : OnKeyUp ( wxKeyEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : OnKeyUp ( event ) ;
2014-12-10 21:22:13 -05:00
shiftDown = event . ShiftDown ( ) ;
2014-12-11 20:50:58 -05:00
altDown = event . AltDown ( ) ;
ctrlDown = event . ControlDown ( ) ;
2015-01-01 21:10:54 -05:00
switch ( event . GetKeyCode ( ) ) {
case ' A ' :
zoom = 0 ;
break ;
case ' Z ' :
zoom = 0 ;
break ;
}
2014-12-10 00:34:27 -05:00
}
2014-11-15 23:41:41 -05:00
void WaterfallCanvas : : OnKeyDown ( wxKeyEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : OnKeyDown ( event ) ;
2014-11-15 23:41:41 -05:00
float angle = 5.0 ;
2014-12-10 21:22:13 -05:00
DemodulatorInstance * activeDemod = wxGetApp ( ) . getDemodMgr ( ) . getActiveDemodulator ( ) ;
2014-11-15 23:41:41 -05:00
unsigned int freq ;
2015-01-01 21:10:54 -05:00
unsigned int bw ;
switch ( event . GetKeyCode ( ) ) {
case ' A ' :
zoom = 1 ;
break ;
case ' Z ' :
zoom = - 1 ;
break ;
case WXK_RIGHT :
freq = wxGetApp ( ) . getFrequency ( ) ;
if ( shiftDown ) {
freq + = SRATE * 10 ;
2015-01-02 21:32:24 -05:00
if ( isView ) {
SetView ( center_freq + SRATE * 10 , GetBandwidth ( ) ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( GetCenterFrequency ( ) , GetBandwidth ( ) ) ;
}
}
2015-01-01 21:10:54 -05:00
} else {
freq + = SRATE / 2 ;
2015-01-02 21:32:24 -05:00
if ( isView ) {
SetView ( center_freq + SRATE / 2 , GetBandwidth ( ) ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( GetCenterFrequency ( ) , GetBandwidth ( ) ) ;
}
}
2015-01-01 21:10:54 -05:00
}
wxGetApp ( ) . setFrequency ( freq ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Set center frequency: %s " , freq ) ;
2015-01-01 21:10:54 -05:00
break ;
case WXK_LEFT :
freq = wxGetApp ( ) . getFrequency ( ) ;
if ( shiftDown ) {
freq - = SRATE * 10 ;
2015-01-02 21:32:24 -05:00
if ( isView ) {
SetView ( center_freq - SRATE * 10 , GetBandwidth ( ) ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( GetCenterFrequency ( ) , GetBandwidth ( ) ) ;
}
}
2015-01-01 21:10:54 -05:00
} else {
freq - = SRATE / 2 ;
2015-01-02 21:32:24 -05:00
if ( isView ) {
SetView ( center_freq - SRATE / 2 , GetBandwidth ( ) ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( GetCenterFrequency ( ) , GetBandwidth ( ) ) ;
}
}
2015-01-01 21:10:54 -05:00
}
wxGetApp ( ) . setFrequency ( freq ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Set center frequency: %s " , freq ) ;
2015-01-01 21:10:54 -05:00
break ;
case ' D ' :
case WXK_DELETE :
if ( ! activeDemod ) {
2014-12-28 05:13:46 -05:00
break ;
2015-01-01 21:10:54 -05:00
}
wxGetApp ( ) . removeDemodulator ( activeDemod ) ;
wxGetApp ( ) . getDemodMgr ( ) . deleteThread ( activeDemod ) ;
break ;
case ' S ' :
if ( ! activeDemod ) {
2014-12-28 05:13:46 -05:00
break ;
2015-01-01 21:10:54 -05:00
}
if ( activeDemod - > isSquelchEnabled ( ) ) {
activeDemod - > setSquelchEnabled ( false ) ;
} else {
activeDemod - > squelchAuto ( ) ;
}
break ;
case WXK_SPACE :
if ( ! activeDemod ) {
2014-12-28 05:13:46 -05:00
break ;
2014-12-21 16:08:32 -05:00
}
2015-01-01 21:10:54 -05:00
if ( activeDemod - > isStereo ( ) ) {
activeDemod - > setStereo ( false ) ;
} else {
activeDemod - > setStereo ( true ) ;
}
break ;
default :
event . Skip ( ) ;
return ;
2014-11-15 23:41:41 -05:00
}
}
2014-12-28 05:13:46 -05:00
void WaterfallCanvas : : setData ( DemodulatorThreadIQData * input ) {
if ( ! input ) {
return ;
}
2015-01-01 21:10:54 -05:00
unsigned int bw ;
if ( zoom ) {
2015-01-02 19:35:34 -05:00
int freq = wxGetApp ( ) . getFrequency ( ) ;
2015-01-01 21:10:54 -05:00
if ( zoom > 0 ) {
center_freq = GetCenterFrequency ( ) ;
bw = GetBandwidth ( ) ;
bw = ( unsigned int ) ceil ( ( float ) bw * 0.95 ) ;
if ( bw < 80000 ) {
bw = 80000 ;
}
2015-01-02 19:35:34 -05:00
if ( mTracker . mouseInView ( ) ) {
int mfreqA = GetFrequencyAt ( mTracker . getMouseX ( ) ) ;
SetBandwidth ( bw ) ;
int mfreqB = GetFrequencyAt ( mTracker . getMouseX ( ) ) ;
center_freq + = mfreqA - mfreqB ;
}
2015-01-01 21:10:54 -05:00
SetView ( center_freq , bw ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( center_freq , bw ) ;
}
} else {
if ( isView ) {
bw = GetBandwidth ( ) ;
bw = ( unsigned int ) ceil ( ( float ) bw * 1.05 ) ;
if ( ( int ) bw > = SRATE ) {
bw = ( unsigned int ) SRATE ;
DisableView ( ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > DisableView ( ) ;
}
} else {
2015-01-02 19:35:34 -05:00
if ( mTracker . mouseInView ( ) ) {
int freq = wxGetApp ( ) . getFrequency ( ) ;
int mfreqA = GetFrequencyAt ( mTracker . getMouseX ( ) ) ;
SetBandwidth ( bw ) ;
int mfreqB = GetFrequencyAt ( mTracker . getMouseX ( ) ) ;
center_freq + = mfreqA - mfreqB ;
}
2015-01-01 21:10:54 -05:00
SetView ( GetCenterFrequency ( ) , bw ) ;
if ( spectrumCanvas ) {
spectrumCanvas - > SetView ( center_freq , bw ) ;
}
}
}
}
2015-01-02 19:35:34 -05:00
if ( center_freq < freq & & ( center_freq - bandwidth / 2 ) < ( freq - SRATE / 2 ) ) {
center_freq = ( freq - SRATE / 2 ) + bandwidth / 2 ;
}
if ( center_freq > freq & & ( center_freq + bandwidth / 2 ) > ( freq + SRATE / 2 ) ) {
center_freq = ( freq + SRATE / 2 ) - bandwidth / 2 ;
}
2015-01-01 21:10:54 -05:00
}
2014-12-28 05:13:46 -05:00
std : : vector < liquid_float_complex > * data = & input - > data ;
2014-11-15 23:41:41 -05:00
if ( data & & data - > size ( ) ) {
2015-01-01 21:10:54 -05:00
// if (fft_size != data->size() && !isView) {
// Setup(data->size(), waterfall_lines);
// }
2014-11-15 23:41:41 -05:00
2015-01-01 21:10:54 -05:00
// if (last_bandwidth != bandwidth && !isView) {
// Setup(bandwidth, waterfall_lines);
// }
2014-12-28 05:13:46 -05:00
if ( spectrum_points . size ( ) < fft_size * 2 ) {
spectrum_points . resize ( fft_size * 2 ) ;
}
if ( isView ) {
if ( ! input - > frequency | | ! input - > bandwidth ) {
return ;
}
if ( center_freq ! = input - > frequency ) {
2014-12-28 20:55:05 -05:00
if ( ( ( int ) center_freq - ( int ) input - > frequency ) ! = shift_freq | | last_input_bandwidth ! = input - > bandwidth ) {
if ( ( int ) input - > frequency - abs ( ( int ) center_freq ) < ( int ) ( ( float ) ( ( float ) SRATE / 2.0 ) ) ) {
shift_freq = ( int ) center_freq - ( int ) input - > frequency ;
2014-12-28 05:13:46 -05:00
nco_crcf_reset ( nco_shift ) ;
nco_crcf_set_frequency ( nco_shift , ( 2.0 * M_PI ) * ( ( ( float ) abs ( shift_freq ) ) / ( ( float ) input - > bandwidth ) ) ) ;
}
}
if ( shift_buffer . size ( ) ! = input - > data . size ( ) ) {
if ( shift_buffer . capacity ( ) < input - > data . size ( ) ) {
shift_buffer . reserve ( input - > data . size ( ) ) ;
}
shift_buffer . resize ( input - > data . size ( ) ) ;
}
if ( shift_freq < 0 ) {
nco_crcf_mix_block_up ( nco_shift , & input - > data [ 0 ] , & shift_buffer [ 0 ] , input - > data . size ( ) ) ;
} else {
nco_crcf_mix_block_down ( nco_shift , & input - > data [ 0 ] , & shift_buffer [ 0 ] , input - > data . size ( ) ) ;
}
} else {
shift_buffer . assign ( input - > data . begin ( ) , input - > data . end ( ) ) ;
}
if ( ! resampler | | bandwidth ! = last_bandwidth | | last_input_bandwidth ! = input - > bandwidth ) {
2015-01-01 18:08:54 -05:00
resample_ratio = ( double ) ( bandwidth ) / ( double ) input - > bandwidth ;
2014-12-28 05:13:46 -05:00
float As = 60.0f ;
if ( resampler ) {
msresamp_crcf_destroy ( resampler ) ;
}
resampler = msresamp_crcf_create ( resample_ratio , As ) ;
last_bandwidth = bandwidth ;
last_input_bandwidth = input - > bandwidth ;
}
2015-01-01 21:10:54 -05:00
int out_size = ceil ( ( double ) ( input - > data . size ( ) ) * resample_ratio ) + 512 ;
2014-12-28 05:13:46 -05:00
if ( resampler_buffer . size ( ) ! = out_size ) {
if ( resampler_buffer . capacity ( ) < out_size ) {
resampler_buffer . reserve ( out_size ) ;
}
resampler_buffer . resize ( out_size ) ;
}
unsigned int num_written ;
msresamp_crcf_execute ( resampler , & shift_buffer [ 0 ] , input - > data . size ( ) , & resampler_buffer [ 0 ] , & num_written ) ;
resampler_buffer . resize ( fft_size ) ;
2015-01-01 18:08:54 -05:00
if ( num_written < fft_size ) {
for ( int i = 0 ; i < num_written ; i + + ) {
in [ i ] [ 0 ] = resampler_buffer [ i ] . real ;
in [ i ] [ 1 ] = resampler_buffer [ i ] . imag ;
}
for ( int i = num_written ; i < fft_size ; i + + ) {
in [ i ] [ 0 ] = 0 ;
in [ i ] [ 1 ] = 0 ;
}
} else {
for ( int i = 0 ; i < fft_size ; i + + ) {
in [ i ] [ 0 ] = resampler_buffer [ i ] . real ;
in [ i ] [ 1 ] = resampler_buffer [ i ] . imag ;
}
2014-12-28 05:13:46 -05:00
}
} else {
2015-01-01 18:08:54 -05:00
if ( data - > size ( ) < fft_size ) {
for ( int i = 0 , iMax = data - > size ( ) ; i < iMax ; i + + ) {
in [ i ] [ 0 ] = ( * data ) [ i ] . real ;
in [ i ] [ 1 ] = ( * data ) [ i ] . imag ;
}
for ( int i = data - > size ( ) ; i < fft_size ; i + + ) {
in [ i ] [ 0 ] = 0 ;
in [ i ] [ 1 ] = 0 ;
}
} else {
for ( int i = 0 ; i < fft_size ; i + + ) {
in [ i ] [ 0 ] = ( * data ) [ i ] . real ;
in [ i ] [ 1 ] = ( * data ) [ i ] . imag ;
}
2014-12-28 05:13:46 -05:00
}
2014-11-15 23:41:41 -05:00
}
fftw_execute ( plan ) ;
double fft_ceil = 0 , fft_floor = 1 ;
2014-12-28 05:13:46 -05:00
if ( fft_result . size ( ) < fft_size ) {
fft_result . resize ( fft_size ) ;
fft_result_ma . resize ( fft_size ) ;
fft_result_maa . resize ( fft_size ) ;
2014-11-15 23:41:41 -05:00
}
2014-11-29 13:58:20 -05:00
int n ;
2014-12-28 05:13:46 -05:00
for ( int i = 0 , iMax = fft_size / 2 ; i < iMax ; i + + ) {
2014-11-29 13:58:20 -05:00
n = ( i = = 0 ) ? 1 : i ;
double a = out [ n ] [ 0 ] ;
double b = out [ n ] [ 1 ] ;
double c = sqrt ( a * a + b * b ) ;
2014-11-15 23:41:41 -05:00
2014-12-28 05:13:46 -05:00
double x = out [ fft_size / 2 + n ] [ 0 ] ;
double y = out [ fft_size / 2 + n ] [ 1 ] ;
2014-11-29 13:58:20 -05:00
double z = sqrt ( x * x + y * y ) ;
2014-11-15 23:41:41 -05:00
2014-11-29 13:58:20 -05:00
fft_result [ i ] = ( z ) ;
2014-12-28 05:13:46 -05:00
fft_result [ fft_size / 2 + i ] = ( c ) ;
2014-11-15 23:41:41 -05:00
}
2014-12-28 05:13:46 -05:00
for ( int i = 0 , iMax = fft_size ; i < iMax ; i + + ) {
2014-12-31 19:45:01 -05:00
if ( isView ) {
fft_result_maa [ i ] + = ( fft_result_ma [ i ] - fft_result_maa [ i ] ) * 0.85 ;
fft_result_ma [ i ] + = ( fft_result [ i ] - fft_result_ma [ i ] ) * 0.55 ;
} else {
fft_result_maa [ i ] + = ( fft_result_ma [ i ] - fft_result_maa [ i ] ) * 0.65 ;
fft_result_ma [ i ] + = ( fft_result [ i ] - fft_result_ma [ i ] ) * 0.65 ;
}
2014-11-15 23:41:41 -05:00
if ( fft_result_maa [ i ] > fft_ceil ) {
fft_ceil = fft_result_maa [ i ] ;
}
if ( fft_result_maa [ i ] < fft_floor ) {
fft_floor = fft_result_maa [ i ] ;
}
}
fft_ceil + = 1 ;
fft_floor - = 1 ;
2014-12-31 19:45:01 -05:00
fft_ceil_ma = fft_ceil_ma + ( fft_ceil - fft_ceil_ma ) * 0.05 ;
2015-01-01 18:08:54 -05:00
fft_ceil_maa = fft_ceil_maa + ( fft_ceil_ma - fft_ceil_maa ) * 0.05 ;
2014-11-15 23:41:41 -05:00
2015-01-01 18:08:54 -05:00
fft_floor_ma = fft_floor_ma + ( fft_floor - fft_floor_ma ) * 0.05 ;
fft_floor_maa = fft_floor_maa + ( fft_floor_ma - fft_floor_maa ) * 0.05 ;
2014-11-15 23:41:41 -05:00
2014-12-28 05:13:46 -05:00
for ( int i = 0 , iMax = fft_size ; i < iMax ; i + + ) {
2015-01-01 18:08:54 -05:00
double v = ( log10 ( fft_result_maa [ i ] - fft_floor_maa ) / log10 ( fft_ceil_maa - fft_floor_maa ) ) ;
2014-11-15 23:41:41 -05:00
spectrum_points [ i * 2 ] = ( ( float ) i / ( float ) iMax ) ;
spectrum_points [ i * 2 + 1 ] = v ;
}
2014-12-29 00:24:10 -05:00
if ( spectrumCanvas ) {
2015-01-01 18:08:54 -05:00
spectrumCanvas - > spectrum_points . assign ( spectrum_points . begin ( ) , spectrum_points . end ( ) ) ;
2014-12-29 00:24:10 -05:00
}
2014-11-15 23:41:41 -05:00
}
}
void WaterfallCanvas : : OnIdle ( wxIdleEvent & event ) {
2014-11-25 22:51:14 -05:00
Refresh ( false ) ;
2014-11-15 23:41:41 -05:00
}
2014-11-25 22:51:14 -05:00
void WaterfallCanvas : : mouseMoved ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseMoved ( event ) ;
2014-12-10 00:34:27 -05:00
DemodulatorInstance * demod = wxGetApp ( ) . getDemodMgr ( ) . getActiveDemodulator ( ) ;
2014-11-26 21:05:19 -05:00
2014-11-25 22:51:14 -05:00
if ( mTracker . mouseDown ( ) ) {
2014-12-06 21:10:29 -05:00
if ( demod = = NULL ) {
return ;
}
2014-11-30 21:14:17 -05:00
if ( dragState = = WF_DRAG_BANDWIDTH_LEFT | | dragState = = WF_DRAG_BANDWIDTH_RIGHT ) {
2014-12-28 05:13:46 -05:00
int bwDiff = ( int ) ( mTracker . getDeltaMouseX ( ) * ( float ) GetBandwidth ( ) ) * 2 ;
2014-11-25 22:51:14 -05:00
2014-11-30 21:14:17 -05:00
if ( dragState = = WF_DRAG_BANDWIDTH_LEFT ) {
bwDiff = - bwDiff ;
}
if ( ! activeDemodulatorBandwidth ) {
activeDemodulatorBandwidth = demod - > getParams ( ) . bandwidth ;
2014-11-26 21:05:19 -05:00
}
2014-11-25 22:51:14 -05:00
2014-11-26 21:05:19 -05:00
DemodulatorThreadCommand command ;
2014-11-30 23:33:55 -05:00
command . cmd = DemodulatorThreadCommand : : DEMOD_THREAD_CMD_SET_BANDWIDTH ;
2014-11-30 21:14:17 -05:00
activeDemodulatorBandwidth = activeDemodulatorBandwidth + bwDiff ;
2014-12-29 00:24:10 -05:00
if ( activeDemodulatorBandwidth > SRATE ) {
activeDemodulatorBandwidth = SRATE ;
2014-11-26 21:05:19 -05:00
}
2015-01-01 18:08:54 -05:00
if ( activeDemodulatorBandwidth < MIN_BANDWIDTH ) {
activeDemodulatorBandwidth = MIN_BANDWIDTH ;
2014-11-26 21:05:19 -05:00
}
2014-11-30 21:14:17 -05:00
command . int_value = activeDemodulatorBandwidth ;
2014-11-26 21:05:19 -05:00
demod - > getCommandQueue ( ) - > push ( command ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Set demodulator bandwidth: %s " , activeDemodulatorBandwidth ) ;
2014-11-25 22:51:14 -05:00
}
2014-11-26 21:05:19 -05:00
2014-11-30 21:14:17 -05:00
if ( dragState = = WF_DRAG_FREQUENCY ) {
2014-12-28 05:13:46 -05:00
int bwDiff = ( int ) ( mTracker . getDeltaMouseX ( ) * ( float ) GetBandwidth ( ) ) ;
2014-11-30 18:54:13 -05:00
2014-11-30 21:14:17 -05:00
if ( ! activeDemodulatorFrequency ) {
activeDemodulatorFrequency = demod - > getParams ( ) . frequency ;
}
2014-11-30 18:54:13 -05:00
2014-11-30 21:14:17 -05:00
DemodulatorThreadCommand command ;
2014-11-30 23:33:55 -05:00
command . cmd = DemodulatorThreadCommand : : DEMOD_THREAD_CMD_SET_FREQUENCY ;
2014-11-30 21:14:17 -05:00
activeDemodulatorFrequency = activeDemodulatorFrequency + bwDiff ;
command . int_value = activeDemodulatorFrequency ;
demod - > getCommandQueue ( ) - > push ( command ) ;
2014-12-11 20:50:58 -05:00
demod - > updateLabel ( activeDemodulatorFrequency ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Set demodulator frequency: %s " , activeDemodulatorFrequency ) ;
2014-11-30 21:14:17 -05:00
}
} else {
2014-11-30 18:54:13 -05:00
int freqPos = GetFrequencyAt ( mTracker . getMouseX ( ) ) ;
std : : vector < DemodulatorInstance * > * demodsHover = wxGetApp ( ) . getDemodMgr ( ) . getDemodulatorsAt ( freqPos , 15000 ) ;
2014-12-10 00:34:27 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( NULL ) ;
2014-12-11 20:50:58 -05:00
if ( altDown ) {
nextDragState = WF_DRAG_RANGE ;
mTracker . setVertDragLock ( true ) ;
mTracker . setHorizDragLock ( false ) ;
2015-01-02 22:44:09 -05:00
if ( shiftDown ) {
setStatusText ( " Click and drag to create a new demodulator by range. " ) ;
} else {
setStatusText ( " Click and drag to set the current demodulator range. " ) ;
}
2014-12-11 20:50:58 -05:00
} else if ( demodsHover - > size ( ) ) {
2014-11-30 21:14:17 -05:00
int hovered = - 1 ;
2014-12-28 05:13:46 -05:00
int near_dist = GetBandwidth ( ) ;
2014-11-30 21:14:17 -05:00
2014-12-10 00:34:27 -05:00
DemodulatorInstance * activeDemodulator = NULL ;
2014-11-30 18:54:13 -05:00
for ( int i = 0 , iMax = demodsHover - > size ( ) ; i < iMax ; i + + ) {
2014-11-30 21:14:17 -05:00
DemodulatorInstance * demod = ( * demodsHover ) [ i ] ;
2014-12-06 21:47:18 -05:00
int freqDiff = ( int ) demod - > getParams ( ) . frequency - freqPos ;
2014-12-10 00:34:27 -05:00
int halfBw = ( demod - > getParams ( ) . bandwidth / 2 ) ;
2014-11-30 18:54:13 -05:00
2014-12-06 21:47:18 -05:00
int dist = abs ( freqDiff ) ;
2014-11-30 18:54:13 -05:00
if ( dist < near_dist ) {
2014-11-30 21:14:17 -05:00
activeDemodulator = demod ;
near_dist = dist ;
2014-11-30 18:54:13 -05:00
}
2014-12-06 21:47:18 -05:00
2014-12-10 00:34:27 -05:00
if ( dist < = halfBw & & dist > = ( int ) ( ( float ) halfBw / ( float ) 1.5 ) ) {
2014-12-06 21:47:18 -05:00
int edge_dist = abs ( halfBw - dist ) ;
if ( edge_dist < near_dist ) {
activeDemodulator = demod ;
near_dist = edge_dist ;
}
}
2014-11-30 18:54:13 -05:00
}
2014-12-10 00:34:27 -05:00
if ( activeDemodulator = = NULL ) {
return ;
}
2014-12-10 18:52:24 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( activeDemodulator ) ;
2014-12-10 00:34:27 -05:00
2014-12-06 21:47:18 -05:00
int freqDiff = ( ( int ) activeDemodulator - > getParams ( ) . frequency - freqPos ) ;
2014-11-30 21:14:17 -05:00
2014-12-06 21:47:18 -05:00
if ( abs ( freqDiff ) > ( activeDemodulator - > getParams ( ) . bandwidth / 3 ) ) {
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_SIZEWE ) ;
2014-11-30 21:14:17 -05:00
if ( freqDiff > 0 ) {
nextDragState = WF_DRAG_BANDWIDTH_LEFT ;
} else {
nextDragState = WF_DRAG_BANDWIDTH_RIGHT ;
}
2014-11-30 18:54:13 -05:00
2014-11-30 21:14:17 -05:00
mTracker . setVertDragLock ( true ) ;
mTracker . setHorizDragLock ( false ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Click and drag to change demodulator bandwidth. D to delete, SPACE for stereo. " ) ;
2014-11-30 21:14:17 -05:00
} else {
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_SIZING ) ;
2014-11-30 21:14:17 -05:00
nextDragState = WF_DRAG_FREQUENCY ;
mTracker . setVertDragLock ( true ) ;
mTracker . setHorizDragLock ( false ) ;
2015-01-02 22:44:09 -05:00
setStatusText ( " Click and drag to change demodulator frequency. D to delete, SPACE for stereo. " ) ;
2014-11-30 21:14:17 -05:00
}
} else {
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_CROSS ) ;
2014-11-30 21:14:17 -05:00
nextDragState = WF_DRAG_NONE ;
2015-01-02 22:44:09 -05:00
if ( shiftDown ) {
setStatusText ( " Click to create a new demodulator or hold ALT to drag range. " ) ;
} else {
setStatusText ( " Click to move active demodulator frequency or hold ALT to drag range; hold SHIFT to create new. A / Z to Zoom. Arrow keys (+SHIFT) to move center frequency. " ) ;
}
2014-11-30 21:14:17 -05:00
}
2014-11-30 18:54:13 -05:00
delete demodsHover ;
2014-11-25 22:51:14 -05:00
}
}
void WaterfallCanvas : : mouseDown ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseDown ( event ) ;
2014-12-10 00:34:27 -05:00
2015-01-02 21:32:24 -05:00
dragState = nextDragState ;
2014-12-10 21:22:13 -05:00
2014-12-11 20:50:58 -05:00
if ( dragState & & dragState ! = WF_DRAG_RANGE ) {
2014-12-10 00:34:27 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( wxGetApp ( ) . getDemodMgr ( ) . getActiveDemodulator ( ) , false ) ;
}
2014-11-30 21:14:17 -05:00
activeDemodulatorBandwidth = 0 ;
activeDemodulatorFrequency = 0 ;
2014-11-25 22:51:14 -05:00
}
void WaterfallCanvas : : mouseWheelMoved ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseWheelMoved ( event ) ;
2014-11-25 22:51:14 -05:00
}
void WaterfallCanvas : : mouseReleased ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseReleased ( event ) ;
2014-12-10 21:22:13 -05:00
2014-12-24 01:28:33 -05:00
bool isNew = shiftDown
| | ( wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) & & ! wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) - > isActive ( ) ) ;
2014-12-18 21:39:32 -05:00
2014-12-11 20:50:58 -05:00
mTracker . setVertDragLock ( false ) ;
mTracker . setHorizDragLock ( false ) ;
2014-12-10 00:34:27 -05:00
2014-12-11 21:37:01 -05:00
DemodulatorInstance * demod ;
2014-12-10 00:34:27 -05:00
2014-12-11 21:37:01 -05:00
if ( mTracker . getOriginDeltaMouseX ( ) = = 0 & & mTracker . getOriginDeltaMouseY ( ) = = 0 ) {
2014-12-10 18:52:24 -05:00
float pos = mTracker . getMouseX ( ) ;
2014-12-28 05:13:46 -05:00
int input_center_freq = GetCenterFrequency ( ) ;
int freq = input_center_freq - ( int ) ( 0.5 * ( float ) GetBandwidth ( ) ) + ( int ) ( ( float ) pos * ( float ) GetBandwidth ( ) ) ;
2014-12-10 18:52:24 -05:00
2014-12-11 20:50:58 -05:00
if ( dragState = = WF_DRAG_NONE ) {
2014-12-18 21:39:32 -05:00
if ( ! isNew & & wxGetApp ( ) . getDemodMgr ( ) . getDemodulators ( ) . size ( ) ) {
2014-12-11 20:50:58 -05:00
demod = wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) ;
} else {
demod = wxGetApp ( ) . getDemodMgr ( ) . newThread ( ) ;
demod - > getParams ( ) . frequency = freq ;
2014-12-06 21:10:29 -05:00
2014-12-11 20:50:58 -05:00
if ( DemodulatorInstance * last = wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) ) {
demod - > getParams ( ) . bandwidth = last - > getParams ( ) . bandwidth ;
2015-01-02 19:35:34 -05:00
demod - > setDemodulatorType ( last - > getDemodulatorType ( ) ) ;
demod - > setSquelchLevel ( last - > getSquelchLevel ( ) ) ;
demod - > setSquelchEnabled ( last - > isSquelchEnabled ( ) ) ;
demod - > setStereo ( last - > isStereo ( ) ) ;
2014-12-11 20:50:58 -05:00
}
2014-12-10 18:52:24 -05:00
2014-12-11 20:50:58 -05:00
demod - > run ( ) ;
2014-12-10 21:22:13 -05:00
2014-12-11 20:50:58 -05:00
wxGetApp ( ) . bindDemodulator ( demod ) ;
2014-12-16 21:30:03 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( demod , false ) ;
2014-12-11 20:50:58 -05:00
}
2014-11-25 22:51:14 -05:00
2014-12-10 18:52:24 -05:00
if ( demod = = NULL ) {
2014-12-11 21:37:01 -05:00
dragState = WF_DRAG_NONE ;
2014-12-10 18:52:24 -05:00
return ;
}
2014-11-25 22:51:14 -05:00
2014-12-11 20:50:58 -05:00
demod - > updateLabel ( freq ) ;
2014-12-10 00:34:27 -05:00
DemodulatorThreadCommand command ;
command . cmd = DemodulatorThreadCommand : : DEMOD_THREAD_CMD_SET_FREQUENCY ;
command . int_value = freq ;
demod - > getCommandQueue ( ) - > push ( command ) ;
2014-11-27 22:13:21 -05:00
2015-01-02 22:44:09 -05:00
setStatusText ( " New demodulator at frequency: %s " , freq ) ;
2014-11-25 22:51:14 -05:00
2014-12-10 00:34:27 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) , false ) ;
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_SIZING ) ;
2014-12-10 00:34:27 -05:00
nextDragState = WF_DRAG_FREQUENCY ;
mTracker . setVertDragLock ( true ) ;
mTracker . setHorizDragLock ( false ) ;
} else {
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( wxGetApp ( ) . getDemodMgr ( ) . getActiveDemodulator ( ) , false ) ;
2014-12-16 21:03:45 -05:00
nextDragState = WF_DRAG_FREQUENCY ;
2014-12-10 00:34:27 -05:00
}
2014-12-11 21:37:01 -05:00
} else if ( dragState = = WF_DRAG_RANGE ) {
float width = mTracker . getOriginDeltaMouseX ( ) ;
float pos = mTracker . getOriginMouseX ( ) + width / 2.0 ;
2014-12-28 05:13:46 -05:00
int input_center_freq = GetCenterFrequency ( ) ;
unsigned int freq = input_center_freq - ( int ) ( 0.5 * ( float ) GetBandwidth ( ) ) + ( int ) ( ( float ) pos * ( float ) GetBandwidth ( ) ) ;
unsigned int bw = ( unsigned int ) ( fabs ( width ) * ( float ) GetBandwidth ( ) ) ;
2014-12-11 21:37:01 -05:00
2015-01-01 18:08:54 -05:00
if ( bw < MIN_BANDWIDTH ) {
bw = MIN_BANDWIDTH ;
2014-12-11 21:37:01 -05:00
}
2014-12-28 05:13:46 -05:00
if ( ! bw ) {
2014-12-11 21:37:01 -05:00
dragState = WF_DRAG_NONE ;
return ;
}
2014-12-18 21:39:32 -05:00
if ( ! isNew & & wxGetApp ( ) . getDemodMgr ( ) . getDemodulators ( ) . size ( ) ) {
2014-12-11 21:37:01 -05:00
demod = wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) ;
} else {
demod = wxGetApp ( ) . getDemodMgr ( ) . newThread ( ) ;
demod - > getParams ( ) . frequency = freq ;
2014-12-28 05:13:46 -05:00
demod - > getParams ( ) . bandwidth = bw ;
2015-01-02 19:35:34 -05:00
if ( DemodulatorInstance * last = wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) ) {
demod - > setDemodulatorType ( last - > getDemodulatorType ( ) ) ;
demod - > setSquelchLevel ( last - > getSquelchLevel ( ) ) ;
demod - > setSquelchEnabled ( last - > isSquelchEnabled ( ) ) ;
demod - > setStereo ( last - > isStereo ( ) ) ;
}
2014-12-11 21:37:01 -05:00
demod - > run ( ) ;
wxGetApp ( ) . bindDemodulator ( demod ) ;
2014-12-16 21:30:03 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( demod , false ) ;
2014-12-11 21:37:01 -05:00
}
if ( demod = = NULL ) {
dragState = WF_DRAG_NONE ;
return ;
}
2015-01-02 22:44:09 -05:00
setStatusText ( " New demodulator at frequency: %s " , freq ) ;
2014-12-11 21:37:01 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( wxGetApp ( ) . getDemodMgr ( ) . getLastActiveDemodulator ( ) , false ) ;
demod - > updateLabel ( freq ) ;
DemodulatorThreadCommand command ;
command . cmd = DemodulatorThreadCommand : : DEMOD_THREAD_CMD_SET_FREQUENCY ;
command . int_value = freq ;
demod - > getCommandQueue ( ) - > push ( command ) ;
command . cmd = DemodulatorThreadCommand : : DEMOD_THREAD_CMD_SET_BANDWIDTH ;
2014-12-28 05:13:46 -05:00
command . int_value = bw ;
2014-12-11 21:37:01 -05:00
demod - > getCommandQueue ( ) - > push ( command ) ;
2014-11-25 22:51:14 -05:00
}
2014-11-30 21:14:17 -05:00
dragState = WF_DRAG_NONE ;
2014-11-25 22:51:14 -05:00
}
void WaterfallCanvas : : mouseLeftWindow ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseLeftWindow ( event ) ;
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_CROSS ) ;
2014-12-10 00:34:27 -05:00
wxGetApp ( ) . getDemodMgr ( ) . setActiveDemodulator ( NULL ) ;
2014-11-25 22:51:14 -05:00
}
void WaterfallCanvas : : mouseEnterWindow ( wxMouseEvent & event ) {
2015-01-02 21:32:24 -05:00
InteractiveCanvas : : mouseEnterWindow ( event ) ;
2014-12-28 20:55:05 -05:00
SetCursor ( wxCURSOR_CROSS ) ;
2014-11-25 22:51:14 -05:00
}
2014-12-28 05:13:46 -05:00