Mixer: Implement plugin spectrum view.
This commit is contained in:
parent
cf46b447d0
commit
6673dcd28e
|
@ -672,6 +672,41 @@ Module::draw_box ( int tx, int ty, int tw, int th )
|
||||||
fl_pop_clip();
|
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
|
void
|
||||||
Module::draw_label ( int tx, int ty, int tw, int th )
|
Module::draw_label ( int tx, int ty, int tw, int th )
|
||||||
{
|
{
|
||||||
|
@ -888,6 +923,10 @@ Module::menu_cb ( const Fl_Menu_ *m )
|
||||||
{
|
{
|
||||||
paste_before();
|
paste_before();
|
||||||
}
|
}
|
||||||
|
else if ( ! strcmp( picked, "Show Analysis" ) )
|
||||||
|
{
|
||||||
|
show_analysis_window();
|
||||||
|
}
|
||||||
else if ( ! strcmp( picked, "Remove" ) )
|
else if ( ! strcmp( picked, "Remove" ) )
|
||||||
command_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, (void*)this, 0);
|
||||||
m.add( "Insert", 0, &Module::menu_cb, const_cast< Fl_Menu_Item *>( insert_menu->menu() ), FL_SUBMENU_POINTER );
|
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( "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( "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( "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( "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( "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 );
|
m.add( "Remove", FL_Delete, &Module::menu_cb, (void*)this );
|
||||||
|
|
||||||
// menu_set_callback( menu, &Module::menu_cb, (void*)this );
|
// menu_set_callback( menu, &Module::menu_cb, (void*)this );
|
||||||
|
|
|
@ -440,7 +440,9 @@ public:
|
||||||
|
|
||||||
char *get_parameters ( void ) const;
|
char *get_parameters ( void ) const;
|
||||||
void set_parameters ( const char * );
|
void set_parameters ( const char * );
|
||||||
|
|
||||||
|
bool show_analysis_window ( void );
|
||||||
|
|
||||||
void send_feedback ( void );
|
void send_feedback ( void );
|
||||||
virtual bool initialize ( void ) { return true; }
|
virtual bool initialize ( void ) { return true; }
|
||||||
|
|
||||||
|
@ -468,6 +470,13 @@ public:
|
||||||
|
|
||||||
virtual void handle_port_connection_change () {}
|
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) \
|
#define MODULE_CLONE_FUNC(class) \
|
||||||
virtual Module *clone_empty ( void ) const \
|
virtual Module *clone_empty ( void ) const \
|
||||||
{ \
|
{ \
|
||||||
|
@ -480,8 +489,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
nframes_t sample_rate ( void ) const { return Module::_sample_rate; }
|
|
||||||
|
|
||||||
void draw_connections ( void );
|
void draw_connections ( void );
|
||||||
void draw_label ( int X, int Y, int W, int H );
|
void draw_label ( int X, int Y, int W, int H );
|
||||||
void draw_box ( 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 );
|
bool add_aux_port ( bool input, const char *prefix, int n );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
nframes_t sample_rate ( void ) const { return Module::_sample_rate; }
|
||||||
|
|
||||||
|
|
||||||
void auto_connect_outputs();
|
void auto_connect_outputs();
|
||||||
void auto_disconnect_outputs();
|
void auto_disconnect_outputs();
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
#include "FL/menu_popup.H"
|
#include "FL/menu_popup.H"
|
||||||
|
|
||||||
|
|
||||||
|
#include "SpectrumView.H"
|
||||||
|
|
||||||
Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_Window( 900,240)
|
Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_Window( 900,240)
|
||||||
{
|
{
|
||||||
_module = module;
|
_module = module;
|
||||||
|
@ -97,6 +99,7 @@ Module_Parameter_Editor::Module_Parameter_Editor ( Module *module ) : Fl_Double_
|
||||||
o->flow( true );
|
o->flow( true );
|
||||||
o->vspacing( 5 );
|
o->vspacing( 5 );
|
||||||
o->hspacing( 5 );
|
o->hspacing( 5 );
|
||||||
|
|
||||||
o->end();
|
o->end();
|
||||||
}
|
}
|
||||||
o->resizable( 0 );
|
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
|
void
|
||||||
Module_Parameter_Editor::make_controls ( void )
|
Module_Parameter_Editor::make_controls ( void )
|
||||||
{
|
{
|
||||||
|
@ -124,6 +150,17 @@ Module_Parameter_Editor::make_controls ( void )
|
||||||
|
|
||||||
control_pack->clear();
|
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();
|
controls_by_port.clear();
|
||||||
|
|
||||||
/* these are for detecting related parameter groups which can be
|
/* 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->flow(true);
|
||||||
control_pack->flowdown(false);
|
control_pack->flowdown(false);
|
||||||
control_pack->type( FL_HORIZONTAL );
|
control_pack->type( FL_HORIZONTAL );
|
||||||
control_pack->size( 900, 350 );
|
control_pack->size( 900, 250 );
|
||||||
}
|
}
|
||||||
else if ( mode_choice->value() == 0 )
|
else if ( mode_choice->value() == 0 )
|
||||||
{
|
{
|
||||||
control_pack->vspacing( 10 );
|
control_pack->vspacing( 10 );
|
||||||
control_pack->hspacing( 10 );
|
control_pack->hspacing( 10 );
|
||||||
control_pack->flow(true);
|
control_pack->flow(true);
|
||||||
control_pack->flowdown(false);
|
control_pack->flowdown(true);
|
||||||
control_pack->type( FL_HORIZONTAL );
|
control_pack->type( FL_HORIZONTAL );
|
||||||
control_pack->size( 700, 50 );
|
control_pack->size( 700, 50 );
|
||||||
|
|
||||||
|
@ -381,6 +418,8 @@ Module_Parameter_Editor::make_controls ( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
update_control_visibility();
|
update_control_visibility();
|
||||||
|
|
||||||
|
update_spectrum();
|
||||||
|
|
||||||
control_pack->dolayout();
|
control_pack->dolayout();
|
||||||
|
|
||||||
|
@ -504,6 +543,8 @@ Module_Parameter_Editor::handle_control_changed ( Module::Port *p )
|
||||||
|
|
||||||
v->value( p->control_value() );
|
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() )
|
if ( _module->control_input[i].connected() )
|
||||||
_module->control_input[i].connected_port()->module()->handle_control_changed( _module->control_input[i].connected_port() );
|
_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] );
|
// _module->handle_control_changed( &_module->control_input[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ class Module;
|
||||||
class Fl_Menu_Button;
|
class Fl_Menu_Button;
|
||||||
class Panner;
|
class Panner;
|
||||||
class Fl_Scroll;
|
class Fl_Scroll;
|
||||||
|
class SpectrumView;
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
@ -76,10 +77,12 @@ class Module_Parameter_Editor : public Fl_Double_Window
|
||||||
void set_value (int i, float value );
|
void set_value (int i, float value );
|
||||||
void bind_control ( int i );
|
void bind_control ( int i );
|
||||||
void make_controls ( void );
|
void make_controls ( void );
|
||||||
|
void update_spectrum ( void );
|
||||||
|
|
||||||
static void menu_cb ( Fl_Widget *w, void *v );
|
static void menu_cb ( Fl_Widget *w, void *v );
|
||||||
void menu_cb ( Fl_Menu_ *m );
|
void menu_cb ( Fl_Menu_ *m );
|
||||||
|
|
||||||
|
SpectrumView *spectrum_view;
|
||||||
Fl_Scroll *control_scroll;
|
Fl_Scroll *control_scroll;
|
||||||
Fl_Flowpack *control_pack;
|
Fl_Flowpack *control_pack;
|
||||||
Fl_Menu_Button *mode_choice;
|
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 */
|
/* Client */
|
||||||
/**********/
|
/**********/
|
||||||
|
|
|
@ -99,6 +99,8 @@ private:
|
||||||
void set_control_buffer ( int n, void *buf );
|
void set_control_buffer ( int n, void *buf );
|
||||||
void activate ( void );
|
void activate ( void );
|
||||||
void deactivate ( void );
|
void deactivate ( void );
|
||||||
|
|
||||||
|
bool apply ( sample_t *buf, nframes_t nframes );
|
||||||
void process ( unsigned long nframes );
|
void process ( unsigned long nframes );
|
||||||
|
|
||||||
bool plugin_instances ( unsigned int );
|
bool plugin_instances ( unsigned int );
|
||||||
|
@ -109,6 +111,8 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual bool get_impulse_response ( sample_t *buf, nframes_t nframes );
|
||||||
|
|
||||||
virtual nframes_t get_module_latency ( void ) const;
|
virtual nframes_t get_module_latency ( void ) const;
|
||||||
|
|
||||||
virtual void update ( void );
|
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/Project.C
|
||||||
src/Group.C
|
src/Group.C
|
||||||
src/main.C
|
src/main.C
|
||||||
|
src/SpectrumView.C
|
||||||
src/Spatialization_Console.C
|
src/Spatialization_Console.C
|
||||||
''',
|
''',
|
||||||
target = 'non-mixer',
|
target = 'non-mixer',
|
||||||
|
|
|
@ -181,7 +181,7 @@ buffer_fill_with_silence ( sample_t *buf, nframes_t nframes )
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
buffer_is_digital_black ( sample_t *buf, nframes_t nframes )
|
buffer_is_digital_black ( const sample_t *buf, nframes_t nframes )
|
||||||
{
|
{
|
||||||
while ( nframes-- )
|
while ( nframes-- )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue