| @@ -672,6 +672,41 @@ Module::draw_box ( int tx, int ty, int tw, int th ) | |||
| fl_pop_clip(); | |||
| } | |||
| #include "SpectrumView.H" | |||
| #include <FL/Fl_Double_Window.H> | |||
| bool | |||
| Module::show_analysis_window ( void ) | |||
| { | |||
| nframes_t nframes = 4096; | |||
| float *buf = new float[nframes]; | |||
| if ( ! get_impulse_response( buf, nframes ) ) | |||
| return false; | |||
| Fl_Double_Window *w = new Fl_Double_Window( 1000, 500 ); | |||
| { | |||
| SpectrumView * o = new SpectrumView( 25,25, 1000 - 50, 500 - 50, label() ); | |||
| o->labelsize(10); | |||
| o->align(FL_ALIGN_RIGHT|FL_ALIGN_TOP); | |||
| o->sample_rate( sample_rate() ); | |||
| /* o->minimum_frequency( 10 ); */ | |||
| /* o->maximum_frequency( 50000 ); */ | |||
| o->data( buf, nframes ); | |||
| } | |||
| w->end(); | |||
| w->show(); | |||
| while ( w->shown() ) | |||
| Fl::wait(); | |||
| return true; | |||
| } | |||
| void | |||
| Module::draw_label ( int tx, int ty, int tw, int th ) | |||
| { | |||
| @@ -888,6 +923,10 @@ Module::menu_cb ( const Fl_Menu_ *m ) | |||
| { | |||
| paste_before(); | |||
| } | |||
| else if ( ! strcmp( picked, "Show Analysis" ) ) | |||
| { | |||
| show_analysis_window(); | |||
| } | |||
| else if ( ! strcmp( picked, "Remove" ) ) | |||
| command_remove(); | |||
| } | |||
| @@ -924,10 +963,12 @@ Module::menu ( void ) const | |||
| m.add( "Insert", 0, &Module::menu_cb, (void*)this, 0); | |||
| m.add( "Insert", 0, &Module::menu_cb, const_cast< Fl_Menu_Item *>( insert_menu->menu() ), FL_SUBMENU_POINTER ); | |||
| m.add( "Edit Parameters", ' ', &Module::menu_cb, (void*)this, 0 ); | |||
| m.add( "Show Analysis", 's', &Module::menu_cb, (void*)this, 0); | |||
| m.add( "Bypass", 'b', &Module::menu_cb, (void*)this, FL_MENU_TOGGLE | ( bypass() ? FL_MENU_VALUE : 0 ) ); | |||
| m.add( "Cut", FL_CTRL + 'x', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 ); | |||
| m.add( "Copy", FL_CTRL + 'c', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 ); | |||
| m.add( "Paste", FL_CTRL + 'v', &Module::menu_cb, (void*)this, _copied_module_empty ? 0 : FL_MENU_INACTIVE ); | |||
| m.add( "Remove", FL_Delete, &Module::menu_cb, (void*)this ); | |||
| // menu_set_callback( menu, &Module::menu_cb, (void*)this ); | |||
| @@ -440,7 +440,9 @@ public: | |||
| char *get_parameters ( void ) const; | |||
| void set_parameters ( const char * ); | |||
| bool show_analysis_window ( void ); | |||
| void send_feedback ( void ); | |||
| virtual bool initialize ( void ) { return true; } | |||
| @@ -468,6 +470,13 @@ public: | |||
| virtual void handle_port_connection_change () {} | |||
| /* module should create a new context, run against this impulse, | |||
| * and return true if there's anything worth reporting */ | |||
| virtual bool get_impulse_response ( sample_t *buf, nframes_t nframes ) | |||
| { | |||
| return false; | |||
| } | |||
| #define MODULE_CLONE_FUNC(class) \ | |||
| virtual Module *clone_empty ( void ) const \ | |||
| { \ | |||
| @@ -480,8 +489,6 @@ public: | |||
| protected: | |||
| nframes_t sample_rate ( void ) const { return Module::_sample_rate; } | |||
| void draw_connections ( void ); | |||
| void draw_label ( int X, int Y, int W, int H ); | |||
| void draw_box ( int X, int Y, int W, int H ); | |||
| @@ -495,6 +502,8 @@ protected: | |||
| bool add_aux_port ( bool input, const char *prefix, int n ); | |||
| public: | |||
| nframes_t sample_rate ( void ) const { return Module::_sample_rate; } | |||
| void auto_connect_outputs(); | |||
| void auto_disconnect_outputs(); | |||
| @@ -47,6 +47,8 @@ | |||
| #include "FL/menu_popup.H" | |||
| #include "SpectrumView.H" | |||
| Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_Window( 900,240) | |||
| { | |||
| _module = module; | |||
| @@ -97,6 +99,7 @@ Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_ | |||
| o->flow( true ); | |||
| o->vspacing( 5 ); | |||
| o->hspacing( 5 ); | |||
| o->end(); | |||
| } | |||
| o->resizable( 0 ); | |||
| @@ -117,6 +120,29 @@ Module_Parameter_Editor::~Module_Parameter_Editor ( ) | |||
| void | |||
| Module_Parameter_Editor::update_spectrum ( void ) | |||
| { | |||
| nframes_t nframes = 4096; | |||
| float *buf = new float[nframes]; | |||
| SpectrumView *o = spectrum_view; | |||
| o->sample_rate( _module->sample_rate() ); | |||
| if ( ! _module->get_impulse_response( buf, nframes ) ) | |||
| { | |||
| o->data( buf, 1 ); | |||
| /* o->hide(); */ | |||
| } | |||
| else | |||
| { | |||
| o->data( buf, nframes ); | |||
| o->parent()->show(); | |||
| } | |||
| o->redraw(); | |||
| } | |||
| void | |||
| Module_Parameter_Editor::make_controls ( void ) | |||
| { | |||
| @@ -124,6 +150,17 @@ Module_Parameter_Editor::make_controls ( void ) | |||
| control_pack->clear(); | |||
| { SpectrumView *o = spectrum_view = new SpectrumView( 25, 40, 300, 240, "Spectrum" ); | |||
| o->labelsize(9); | |||
| o->align(FL_ALIGN_TOP); | |||
| Fl_Labelpad_Group *flg = new Fl_Labelpad_Group( (Fl_Widget*)o ); | |||
| flg->hide(); | |||
| control_pack->add( flg ); | |||
| } | |||
| controls_by_port.clear(); | |||
| /* these are for detecting related parameter groups which can be | |||
| @@ -156,14 +193,14 @@ Module_Parameter_Editor::make_controls ( void ) | |||
| control_pack->flow(true); | |||
| control_pack->flowdown(false); | |||
| control_pack->type( FL_HORIZONTAL ); | |||
| control_pack->size( 900, 350 ); | |||
| control_pack->size( 900, 250 ); | |||
| } | |||
| else if ( mode_choice->value() == 0 ) | |||
| { | |||
| control_pack->vspacing( 10 ); | |||
| control_pack->hspacing( 10 ); | |||
| control_pack->flow(true); | |||
| control_pack->flowdown(false); | |||
| control_pack->flowdown(true); | |||
| control_pack->type( FL_HORIZONTAL ); | |||
| control_pack->size( 700, 50 ); | |||
| @@ -381,6 +418,8 @@ Module_Parameter_Editor::make_controls ( void ) | |||
| } | |||
| update_control_visibility(); | |||
| update_spectrum(); | |||
| control_pack->dolayout(); | |||
| @@ -504,6 +543,8 @@ Module_Parameter_Editor::handle_control_changed ( Module::Port *p ) | |||
| v->value( p->control_value() ); | |||
| } | |||
| update_spectrum(); | |||
| } | |||
| @@ -524,6 +565,8 @@ Module_Parameter_Editor::set_value (int i, float value ) | |||
| if ( _module->control_input[i].connected() ) | |||
| _module->control_input[i].connected_port()->module()->handle_control_changed( _module->control_input[i].connected_port() ); | |||
| } | |||
| update_spectrum(); | |||
| // _module->handle_control_changed( &_module->control_input[i] ); | |||
| } | |||
| @@ -27,6 +27,7 @@ class Module; | |||
| class Fl_Menu_Button; | |||
| class Panner; | |||
| class Fl_Scroll; | |||
| class SpectrumView; | |||
| #include <vector> | |||
| #include <list> | |||
| @@ -76,10 +77,12 @@ class Module_Parameter_Editor : public Fl_Double_Window | |||
| void set_value (int i, float value ); | |||
| void bind_control ( int i ); | |||
| void make_controls ( void ); | |||
| void update_spectrum ( void ); | |||
| static void menu_cb ( Fl_Widget *w, void *v ); | |||
| void menu_cb ( Fl_Menu_ *m ); | |||
| SpectrumView *spectrum_view; | |||
| Fl_Scroll *control_scroll; | |||
| Fl_Flowpack *control_pack; | |||
| Fl_Menu_Button *mode_choice; | |||
| @@ -778,6 +778,80 @@ Plugin_Module::handle_port_connection_change ( void ) | |||
| bool | |||
| Plugin_Module::get_impulse_response ( sample_t *buf, nframes_t nframes ) | |||
| { | |||
| memset( buf, 0, sizeof( float ) * nframes ); | |||
| buf[0] = 1; | |||
| apply( buf, nframes ); | |||
| if ( buffer_is_digital_black( buf + 1, nframes - 1 )) | |||
| /* no impulse response... */ | |||
| return false; | |||
| return true; | |||
| } | |||
| /** Instantiate a temporary version of the plugin, and run it (in place) against the provided buffer */ | |||
| bool | |||
| Plugin_Module::apply ( sample_t *buf, nframes_t nframes ) | |||
| { | |||
| // actually osc or UI THREAD_ASSERT( UI ); | |||
| LADSPA_Handle h; | |||
| if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, sample_rate() ) ) ) | |||
| { | |||
| WARNING( "Failed to instantiate plugin" ); | |||
| return false; | |||
| } | |||
| int ij = 0; | |||
| int oj = 0; | |||
| for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) | |||
| { | |||
| if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) ) | |||
| { | |||
| if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) ) | |||
| _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() ); | |||
| else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) ) | |||
| _idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() ); | |||
| } | |||
| } | |||
| if ( _idata->descriptor->activate ) | |||
| _idata->descriptor->activate( h ); | |||
| int tframes = 512; | |||
| float tmp[tframes]; | |||
| memset( tmp, 0, sizeof( float ) * tframes ); | |||
| for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) | |||
| if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) | |||
| _idata->descriptor->connect_port( h, k, tmp ); | |||
| /* flush any parameter interpolation */ | |||
| _idata->descriptor->run( h, tframes ); | |||
| for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k ) | |||
| if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) ) | |||
| _idata->descriptor->connect_port( h, k, buf ); | |||
| /* run for real */ | |||
| _idata->descriptor->run( h, nframes ); | |||
| if ( _idata->descriptor->deactivate ) | |||
| _idata->descriptor->deactivate( h ); | |||
| if ( _idata->descriptor->cleanup ) | |||
| _idata->descriptor->cleanup( h ); | |||
| return true; | |||
| } | |||
| /**********/ | |||
| /* Client */ | |||
| /**********/ | |||
| @@ -99,6 +99,8 @@ private: | |||
| void set_control_buffer ( int n, void *buf ); | |||
| void activate ( void ); | |||
| void deactivate ( void ); | |||
| bool apply ( sample_t *buf, nframes_t nframes ); | |||
| void process ( unsigned long nframes ); | |||
| bool plugin_instances ( unsigned int ); | |||
| @@ -109,6 +111,8 @@ private: | |||
| public: | |||
| virtual bool get_impulse_response ( sample_t *buf, nframes_t nframes ); | |||
| virtual nframes_t get_module_latency ( void ) const; | |||
| virtual void update ( void ); | |||
| @@ -0,0 +1,342 @@ | |||
| /*******************************************************************************/ | |||
| /* Copyright (C) 2013 Mark McCurry */ | |||
| /* Copyright (C) 2013 Jonathan Moore Liles */ | |||
| /* */ | |||
| /* 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 2 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; see the file COPYING. If not,write to the Free Software */ | |||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
| /*******************************************************************************/ | |||
| #include "SpectrumView.H" | |||
| #include <FL/Fl.H> | |||
| #include <FL/fl_draw.H> | |||
| #include <math.h> | |||
| #include <cstdlib> | |||
| #include <cstring> | |||
| #include <map> | |||
| #include <assert.h> | |||
| static std::map<int,float*> _cached_plan; | |||
| float SpectrumView::_fmin = 10; | |||
| float SpectrumView::_fmax = 24000; | |||
| unsigned int SpectrumView::_sample_rate = 48000; | |||
| void | |||
| SpectrumView::clear_bands ( void ) | |||
| { | |||
| if ( _bands ) | |||
| delete[] _bands; | |||
| _bands = NULL; | |||
| } | |||
| void | |||
| SpectrumView::data ( float *data, unsigned int nframes ) | |||
| { | |||
| if ( _data ) | |||
| delete[] _data; | |||
| _data = data; | |||
| _nframes = nframes; | |||
| clear_bands(); | |||
| redraw(); | |||
| } | |||
| void | |||
| SpectrumView::sample_rate ( unsigned int sample_rate ) | |||
| { | |||
| if ( _sample_rate != sample_rate ) | |||
| { | |||
| _sample_rate = sample_rate; | |||
| _fmin = 10; | |||
| _fmax = _sample_rate * 0.5f; | |||
| /* invalidate all plans */ | |||
| for ( std::map<int,float*>::iterator i = _cached_plan.begin(); | |||
| i != _cached_plan.end(); | |||
| i++ ) | |||
| { | |||
| delete[] i->second; | |||
| } | |||
| _cached_plan.clear(); | |||
| } | |||
| } | |||
| #define min(a,b) (a<b?a:b) | |||
| #define max(a,b) (a<b?b:a) | |||
| static float* | |||
| qft_plan ( unsigned frames, unsigned samples, float Fs, float Fmin, float Fmax ) | |||
| { | |||
| float *op = new float[ frames * samples * 2 ]; | |||
| //Our scaling function must be some f(0) = Fmin and f(1) = Fmax | |||
| // Thus, | |||
| // f(x)=10^(a*x+b) -> b=log(Fmin)/log(10) | |||
| // log10(Fmax)=a+b -> a=log(Fmax)/log(10)-b | |||
| const float b = logf(Fmin)/logf(10); | |||
| const float a = logf(Fmax)/logf(10)-b; | |||
| //Evaluate at set frequencies | |||
| const float one_over_samples = 1.0f / samples; | |||
| const float one_over_samplerate = 1.0f / Fs; | |||
| for(unsigned i=0; i<samples; ++i) | |||
| { | |||
| const float F = powf(10.0,a*i*one_over_samples+b)*one_over_samplerate; | |||
| const float Fp = -2*M_PI*F; | |||
| float Fpj = 0; | |||
| for(unsigned j = 0; j < frames; ++j, Fpj += Fp ) | |||
| { | |||
| const unsigned ji = i*frames*2+2*j; | |||
| op[ji+0] = sinf(Fpj); | |||
| op[ji+1] = cosf(Fpj); | |||
| } | |||
| } | |||
| return op; | |||
| } | |||
| /** Input should be an impulse response of an EQ. Output will be a | |||
| * buffer of /bands/ floats of dB values for each frequency band */ | |||
| void | |||
| SpectrumView::analyze_data ( unsigned int _plan_size ) | |||
| { | |||
| float res[_plan_size * 2]; | |||
| memset(res,0,sizeof(float) * _plan_size * 2); | |||
| if ( _cached_plan.find( _plan_size ) == _cached_plan.end() ) | |||
| _cached_plan[_plan_size ] = qft_plan( _nframes, _plan_size, _sample_rate, _fmin, _fmax); | |||
| const float *plan = _cached_plan[_plan_size]; | |||
| //Evaluate at set frequencies | |||
| for(unsigned i=0; i<_plan_size; ++i) { | |||
| unsigned ti = i*2; | |||
| unsigned tif = ti*_nframes; | |||
| for(unsigned int j=0; j < _nframes ; ++j) { | |||
| unsigned ji = tif+j*2; | |||
| res[ti+0] += plan[ji+0]*_data[j]; | |||
| res[ti+1] += plan[ji+1]*_data[j]; | |||
| } | |||
| } | |||
| float *result = new float[_plan_size]; | |||
| for(unsigned i=0; i<_plan_size; ++i) { | |||
| const float abs_ = sqrtf(res[2*i]*res[2*i]+res[2*i+1]*res[2*i+1]); | |||
| result[i] = 20*logf(abs_)/logf(10); | |||
| } | |||
| { | |||
| if ( _auto_level ) | |||
| { | |||
| /* find range and normalize */ | |||
| float _min=1000, _max=-1000; | |||
| for(unsigned int i=0; i< _plan_size; ++i) | |||
| { | |||
| _min = min(_min, result[i]); | |||
| _max = max(_max, result[i]); | |||
| } | |||
| _dbmin = _min; | |||
| _dbmax = _max; | |||
| } | |||
| double minS = 1.0 / (_dbmax-_dbmin); | |||
| for( unsigned int i=0; i<_plan_size; ++i) | |||
| result[i] = (result[i]-_dbmin)*minS; | |||
| } | |||
| clear_bands(); | |||
| _bands = result; | |||
| } | |||
| SpectrumView::~SpectrumView ( void ) | |||
| { | |||
| clear_bands(); | |||
| if ( _data ) | |||
| delete[] _data; | |||
| } | |||
| SpectrumView::SpectrumView ( int X, int Y, int W, int H, const char *L ) | |||
| : Fl_Box(X,Y,W,H,L) | |||
| { | |||
| _auto_level = 0; | |||
| _data = 0; | |||
| _nframes = 0; | |||
| _bands = 0; | |||
| _dbmin = -70; | |||
| _dbmax = 30; | |||
| box(FL_FLAT_BOX); | |||
| color(fl_rgb_color(20,20,20)); | |||
| selection_color( fl_rgb_color( 210, 80, 80 ) ); | |||
| // end(); | |||
| } | |||
| static int padding_right = 0; | |||
| static int padding_bottom = 0; | |||
| void | |||
| SpectrumView::draw_semilog ( void ) | |||
| { | |||
| int W = w() - padding_right; | |||
| int H = h() - padding_bottom; | |||
| /* char dash[] = {5,5 }; */ | |||
| /* fl_line_style(0, 1, dash); */ | |||
| fl_line_style(FL_SOLID,0); | |||
| //Db grid is easy, it is just a linear spacing | |||
| for(int i=0; i<8; ++i) { | |||
| int level = y()+H*i/8.0; | |||
| fl_line(x(), level, x()+W, level); | |||
| } | |||
| //The frequency grid is defined with points at | |||
| //10,11,12,...,18,19,20,30,40,50,60,70,80,90,100,200,400,... | |||
| //Thus we find each scale that we cover and draw the nine lines unique to | |||
| //that scale | |||
| const int min_base = logf(_fmin)/logf(10); | |||
| const int max_base = logf(_fmax)/logf(10); | |||
| const float b = logf(_fmin)/logf(10); | |||
| const float a = logf(_fmax)/logf(10)-b; | |||
| for(int i=min_base; i<=max_base; ++i) { | |||
| for(int j=1; j<10; ++j) { | |||
| const float freq = pow(10.0, i)*j; | |||
| const float xloc = (logf(freq)/logf(10)-b)/a; | |||
| if(xloc<1.0 && xloc > -0.001) | |||
| fl_line(xloc*W+x(), y(), xloc*W+x(), y()+H); | |||
| } | |||
| } | |||
| fl_end_line(); | |||
| fl_font( FL_HELVETICA_ITALIC, 7 ); | |||
| //Place the text labels | |||
| char label[256]; | |||
| for(int i=0; i<8; ++i) { | |||
| int level = (y()+H*i/8.0) + 3; | |||
| float value = (1-i/8.0)*(_dbmax-_dbmin) + _dbmin; | |||
| sprintf(label, "%.1f dB", value); | |||
| // fl_draw(label, x()+w() + 3, level); | |||
| fl_draw(label, x(), level, w(), 7, FL_ALIGN_RIGHT ); | |||
| } | |||
| for(int i=min_base; i<=max_base; ++i) { | |||
| { | |||
| const float freq = pow(10.0, i)*1; | |||
| const float xloc = (logf(freq)/logf(10)-b)/a; | |||
| sprintf(label, "%0.f %s", freq < 1000.0 ? freq : freq / 1000.0, freq < 1000.0 ? "Hz" : "KHz" ); | |||
| if(xloc<1.0) | |||
| fl_draw(label, xloc*W+x()+1, y()+h()); | |||
| } | |||
| } | |||
| } | |||
| void | |||
| SpectrumView::draw_curve ( void ) | |||
| { | |||
| int W = w() - padding_right; | |||
| //Build lines | |||
| float inc = 1.0 / (float)W; | |||
| float fx = 0; | |||
| for( int i = 0; i < W; i++, fx += inc ) | |||
| fl_vertex(fx, 1.0 - _bands[i]); | |||
| } | |||
| void | |||
| SpectrumView::draw ( void ) | |||
| { | |||
| //Clear Widget | |||
| Fl_Box::draw(); | |||
| int W = w() - padding_right; | |||
| int H = h() - padding_bottom; | |||
| if ( !_bands ) { | |||
| analyze_data( W ); | |||
| } | |||
| //Draw grid | |||
| fl_color(fl_color_add_alpha(fl_rgb_color( 100,100,100), 50 )); | |||
| draw_semilog(); | |||
| fl_push_clip( x(),y(),W,H); | |||
| fl_color(fl_color_add_alpha( selection_color(), 20 )); | |||
| fl_push_matrix(); | |||
| fl_translate( x(), y() + 2 ); | |||
| fl_scale( W,H- 2 ); | |||
| fl_begin_polygon(); | |||
| fl_vertex(0.0,1.0); | |||
| draw_curve(); | |||
| fl_vertex(1.0,1.0); | |||
| fl_end_polygon(); | |||
| fl_color(fl_color_add_alpha( selection_color(), 100 )); | |||
| fl_begin_line(); | |||
| fl_line_style(FL_SOLID,2); | |||
| /* fl_vertex(0.0,1.0); */ | |||
| draw_curve(); | |||
| /* fl_vertex(1.0,1.0); */ | |||
| fl_end_line(); | |||
| fl_pop_matrix(); | |||
| fl_line_style(FL_SOLID,0); | |||
| fl_pop_clip(); | |||
| } | |||
| void | |||
| SpectrumView::resize ( int X, int Y, int W, int H ) | |||
| { | |||
| if ( W != w() ) | |||
| clear_bands(); | |||
| Fl_Box::resize(X,Y,W,H); | |||
| } | |||
| @@ -0,0 +1,62 @@ | |||
| /*******************************************************************************/ | |||
| /* Copyright (C) 2013 Mark McCurry */ | |||
| /* Copyright (C) 2013 Jonathan Moore Liles */ | |||
| /* */ | |||
| /* 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 2 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; see the file COPYING. If not,write to the Free Software */ | |||
| /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
| /*******************************************************************************/ | |||
| #include <FL/Fl_Box.H> | |||
| class SpectrumView : public Fl_Box | |||
| { | |||
| static unsigned int _sample_rate; | |||
| static float _fmin; | |||
| static float _fmax; | |||
| float * _data; | |||
| unsigned int _nframes; | |||
| float * _bands; | |||
| float _dbmin; | |||
| float _dbmax; | |||
| bool _auto_level; | |||
| void draw_curve ( void ); | |||
| void draw_semilog ( void ); | |||
| void analyze_data ( unsigned int plan_size ); | |||
| void clear_bands ( void ); | |||
| public: | |||
| static void sample_rate ( unsigned int sample_rate ); | |||
| /* set dB range. If min == max, then auto leveling will be enabled */ | |||
| void db_range ( float min, float max ) | |||
| { | |||
| _dbmin = min; | |||
| _dbmax = max; | |||
| _auto_level = min == max; | |||
| } | |||
| /** /data/ must point to allocated memory. It will be freed when new data is set or when the control is destroyed */ | |||
| void data ( float *data, unsigned int nframes ); | |||
| SpectrumView ( int X, int Y, int W, int H, const char *L=0 ); | |||
| virtual ~SpectrumView ( ); | |||
| virtual void resize ( int X, int Y, int W, int H ); | |||
| virtual void draw ( void ); | |||
| }; | |||
| @@ -66,6 +66,7 @@ src/Plugin_Module.C | |||
| src/Project.C | |||
| src/Group.C | |||
| src/main.C | |||
| src/SpectrumView.C | |||
| src/Spatialization_Console.C | |||
| ''', | |||
| target = 'non-mixer', | |||
| @@ -181,7 +181,7 @@ buffer_fill_with_silence ( sample_t *buf, nframes_t nframes ) | |||
| } | |||
| bool | |||
| buffer_is_digital_black ( sample_t *buf, nframes_t nframes ) | |||
| buffer_is_digital_black ( const sample_t *buf, nframes_t nframes ) | |||
| { | |||
| while ( nframes-- ) | |||
| { | |||