Compare commits

...

100 Commits

Author SHA1 Message Date
Jonathan Moore Liles cdad26211b Bump versions. 2021-01-27 17:50:26 -08:00
Jonathan Moore Liles ba30c91dad Update NTK 2021-01-27 17:46:38 -08:00
Jonathan Moore Liles 3aa5fc3c21 Mixer: Avoid some unnecessary reallocations when changing channel count. 2021-01-27 17:43:35 -08:00
Jonathan Moore Liles ce633212bb Timeline: Tweak style of loop point indicator. 2021-01-27 17:42:28 -08:00
Jonathan Moore Liles 0f8017a1ef Mixer: Cope with some plugins having insane numbers of parameters. 2021-01-27 17:41:19 -08:00
Jonathan Moore Liles e909d9594b Revert "Add 128x128 hicolor as possible icon path"
This PR was submitted in bad faith by a bad actor, didn't do anything useful, and was only accepted out of diplomacy. That was a mistake. Reverting.
This reverts commit 55de086026.
2021-01-26 17:05:13 -08:00
Jonathan Moore Liles f76de32c44 Update NTK. 2021-01-20 18:31:25 -08:00
Jonathan Moore Liles 181dd64689 Mixer: Fix export strip function. 2021-01-20 17:22:51 -08:00
Jonathan Moore Liles c83aa8ebd8 Update NTK. 2021-01-10 14:47:02 -08:00
Jonathan Moore Liles 0b23c871ee Mixer: Re-transmit the minimum amount of OSC/MIDI feedback messages when strips are rearranged. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles e7c85f1a37 Timeline: Fix region DND onto last track that was a connection DND source. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 826bea3c30 Timeline: Fix rare issue where moving the mouse over a region while recording at just the right moment could cause a spurious SET action to be written to the history. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 393684f376 Mixer: Enforce stability of module OSC path over close/open cycles.
Also, allow CV input of for multiple instances of the same plugin/parameter on the same strip.
2021-01-10 14:46:27 -08:00
Jonathan Moore Liles ab469f8a23 Mixer: Fix crash on save after group removal. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles cf03ea1562 Mixer: fix size of SM blinker. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles cda92589e9 Mixer: Fix meter falloff in chain view. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles f2aeb8a1f8 Mixer/DPM: Fix bug where peaks are sometimes not drawn. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 9f3181b9c7 Mixer: Because disconnecting/connecting JACK ports is slow, when handling a change of strip auto input setting, avoid disconnecting a port and then reconnecting it later. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 20dce6c6e6 Timeline: Don't assert if peakfile contains no blocks---it's probably just because it was just opened and hasn't been written into yet. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 793a9c1d4b Mixer: Make port autoconnection during startup and shutdown more efficient. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles f6e3ca8831 Mixer: Automatically run in "noui" mode if DISPLAY environment variable unset (i.e. X11 not available). 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 286dec338c Mixer: Fix JACK port disconnection when Auto Input/Output mode is changed. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 00c02c7d74 Mixer: Fix settings menu layout issue. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles e46fac4470 Partially revert "Mixer: Avoid some unnecessary redraws when opening project."
This reverts commit e303cf093f32472ed582ec0cad1ff758278f71f6.
2021-01-10 14:46:27 -08:00
Jonathan Moore Liles e0402a3b99 Mixer: Fix glitch in redrawing of meter scales when scrolling. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 7c071c7422 wscript: Use -mtune=native by default for performance boost benefiting those who build from source, packagers can disable. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 9e82b28f07 dsp: code style tweak. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles a0fd557baf Timeline: fix crash when removing a track. 2021-01-10 14:46:27 -08:00
Jonathan Moore Liles 82f9610ca8 Mixer: Try to better cope with parameter feedback feedback cycles. 2021-01-10 14:46:20 -08:00
Jonathan Moore Liles 1f0f01c0ad Timeline: Don't send the same OSC control sequence value twice and so avoid messing with OSC learning in non-mixer when transport is stopped. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles e290c6ea60 Mixer: Fix crash if user messes with the window while project is loading. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 9aa275e0af Mixer: Fix crash when disabling strip auto output. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles f5b215066a Mixer: Implement slow fall off for meters. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles c808c53d6c Timeline: Acquire sequence lock for region split. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles ae773fbf62 Mixer: Tweak appearance. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 6bde5017f5 Mixer,Timeline: Fix port connection drag and drop between applications. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles da78618e5b Mixer: Make meters more efficient. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 368492f1c0 Sequencer: Use a 3 break gradient for velocity colors. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 5ea0c24468 Sequencer: Fix crash in event editor. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles d84416c196 Mixer/Module_Parameter_Editor: Tweak layout so that 4-Band Parametric Filter plugin is more legible. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles a59823e4c5 Mixer: Tweak strip highlighting. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 6673606262 Mixer: Tweak meter appearance. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 54e8737a90 Timeline: Don't forget to log changing takes after the fact. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 0157734a30 Timeline: Add "Disabled" fade type to disable both fade and declicking for cases where regions need to be abutted perfectly. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 655ccf94c3 Mixer: Avoid some unnecessary redraws when opening project. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles a9846d1fc3 Mixer: Tweak meter appearance. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles ad6dbba07c Timeline: Split OSC send and receive functionality into different threads. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 362a153412 nonlib/OSC/Endpoint: Work around for liblo/UDP layer dropping packets on bulk signal listing. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 830823a226 Mixer/DPM: Quick hack to add smoothing to meter values. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles dd274db49b Mixer/Module_Parameter_Editor: Tweak slider appearance. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 13c107ebcc Mixer: Tweak meter appearance to look better with light color schemes. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles b1d59fc68a Timeline,Mixer: Tweak colors for light themes. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles e42b50814a FL/Fl_Sometimes_Input: Allow user to abort edit with Escape key. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 628fef30e9 Mixer/Module_Parameter_Editor: Increase font sizes, tweak boxtypes. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 53ff9621ff Sequencer: Fix bug in fitting scale to viewport. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles ee872467fb Mixer: Make panner points more opaque. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 9987f78a72 Mixer: Dezipper spatializer azimuth and elevation automation. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 7895b5ec7e Mixer: Allow Mono Pan module to be added a stereo chain. This converts the signal to mono and then pans the result. Useful for auditioning a mix in mono. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 83f7aa87f0 Timeline: Tweak styling of selected regions. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 8d6885387b Mixer: Show strip number at top of each strip (eases mentally mapping onto hardware control surface). 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 4c14cdd350 Timeline: Redraw right hand child region on split. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles b13d2da674 Timeline: Fix rare segfault which occurred when region loop point is just beyond the end of a region and at the beginning of a buffer. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 5378bbbb27 Timeline: Improve error message for sf_open create. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles b0d850ff76 nonlib/MIDI: Cleanup some type signatures. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles e5c08b3b58 MIDI-Mapper: Require controls to be actuated/moved twice before mapping signal in order to detect whether value has 14, 7 or 1 significant bits.
Also, support non-motirzed faders/endless encoders by not transmitting control change until value of controller comes within 5% of value of signal.
Also, change file format (backwards compatible).
Also, fix some issues with NRPN decoding.
2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 572f94ad44 MIDI-Mapper: Preserve mapping creation order when loading/saving. This makes it possible to fiddle controls in a defined order and then edit the file to give them useful names. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles e36a053b84 Sequencer: Don't crash when user picks the branch instead of the leaf in scale chooser. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 10bcd0c2d7 Midi-Mapper: Don't get confused if user neglects to operate all controls on the first run. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles cd4896b762 Sequencer: Just use theme UP_BOX for note shape... 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 19b7927f08 Sequencer: Tweak appearance to look better with different color schemes. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles a2089421b1 Mixer: Give better visual feedback in control OSC/MIDI learning mode. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 5affbe4cef Mixer: Fix osc/midi by-number mode control for strips with names containing punctuation and spaces. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 9b87c089d0 Mixer: Improve contrast with light color scheme. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles cb3d4f9254 Mixer: Remove superfluous semicolon. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 9330b07d99 Mixer: Fix off by one bug in strip autoconnect affecting Auxes. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles a578cbb8e1 Sequencer: Add some missing items to GM Drum note map. 2021-01-09 15:00:35 -08:00
Jonathan Moore Liles 820298f4dd Timeline: Make clocks look more contrasty with light color scheme. 2021-01-09 15:00:23 -08:00
Jonathan Moore Liles 992e55bf0d Sequencer: Fix configuration bug causing error message "Couldn't open instrument directory". 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles 81e24f4239 Sequencer: Fix off-by-one bug preventing notes from being inserted ahead of other notes. 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles 6bee859f6f Timeline: Tweak style of measure lines. 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles 455cc0f3ad Timeline: Tweak style of audio regions. 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles 8109ff7bc0 Sequencer: Fix casting/sign related bug which could cause a hang during SMF writing. 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles 1a07dda5d9 Sequencer: Save file to tmp file before overwriting original. 2021-01-05 18:20:24 -08:00
Jonathan Moore Liles b3ffef17b5 Mixer: Show strip number at top of each strip (eases mentally mapping onto hardware control surface). 2021-01-05 18:20:23 -08:00
Jonathan Moore Liles a7a7b967c8 Mixer: Tweak module colors. Show LADSPA plugins in a different color. 2021-01-05 18:20:23 -08:00
falkTX 55de086026 Add 128x128 hicolor as possible icon path
128 / 32 = 4, so it scales cleanly

Fixes showing icon for zynaddsubfx and carla
2021-01-05 18:12:32 -08:00
Jonathan Moore Liles 7565be85fb Session-manager: Work around for clients with stupidly large icons. 2021-01-03 18:35:37 -08:00
Jonathan Moore Liles 0106604073 Mixer: Fix crash when closing project containing certain configurations of modules. 2021-01-02 13:28:13 -08:00
Jonathan Moore Liles 97d12322f5 Revert "Merge remote-tracking branch 'diovudau/master'"
This reverts commit bbe8386499, reversing
changes made to d958df0486.

Change was poorly thought out, unnecessary, ill advised, and poorly implemented, but was accepted in the name of diplomacy. That was a mistake. Reverting.
2021-01-02 13:25:53 -08:00
Jonathan Moore Liles bbe8386499 Merge remote-tracking branch 'diovudau/master' 2020-03-06 21:48:57 -08:00
Nils aa940df662 Add message /nsm/gui/session/root to ask for the absolute path of the NSM directory 2020-03-02 18:29:27 +01:00
Jonathan Moore Liles d958df0486 Upgrade waf to 2.0.18
Closes #253
2019-09-25 00:03:13 -07:00
Olivier Humbert c15bfa85fd Update non-timeline.desktop.in 2018-09-16 11:14:52 -07:00
Olivier Humbert 7f0cc1d733 Update non-session-manager.desktop.in 2018-09-16 11:14:52 -07:00
Olivier Humbert 911a9bded4 Update non-sequencer.desktop.in 2018-09-16 11:14:52 -07:00
Olivier Humbert d280f9391f Update non-mixer.desktop.in 2018-09-16 11:14:52 -07:00
Jonathan Moore Liles ea6ff30cea wscript: Fix install error caused by upgrade to waf 2.0.9.
Closes #244
2018-08-25 13:16:36 -07:00
Jonathan Moore Liles d0432caa0b Update NTK submodule. 2018-08-21 18:10:14 -07:00
Jonathan Moore Liles 9e9f90f2f0 Upgrade waf to 2.0.9
Closes #244
2018-08-20 21:21:38 -07:00
Jonathan Moore Liles 5ae43bb27c nonlib/OSC: Don't try to send feedback to non-existent path.
Closes #227.
2018-02-14 17:28:39 -08:00
83 changed files with 2321 additions and 936 deletions

View File

@ -30,6 +30,7 @@
class Fl_Sometimes_Input : public Fl_Input
{
Fl_Boxtype _up_box;
char *_text;
public:
@ -53,7 +54,7 @@ public:
{
fl_draw_box( up_box(), x(), y(), w(), h(), color() );
Fl_Color c = fl_contrast( textcolor(), color() );
Fl_Color c = textcolor();// fl_contrast( textcolor(), color() );
fl_color( active_r() ? c : fl_inactive( c ) );
@ -80,19 +81,30 @@ public:
case FL_KEYDOWN:
{
if ( ( Fl::event_key() == FL_Enter ||
Fl::event_key() == FL_Tab ) )
Fl::event_key() == FL_Tab ) )
{
do_callback();
free( _text );
Fl::focus( NULL );
r = 1;
}
else if ( Fl::event_key() == FL_Escape )
{
value( _text );
Fl::focus( NULL );
r = 1;
}
break;
}
case FL_FOCUS:
_text = strdup( value() );
redraw();
r = 1;
break;
case FL_UNFOCUS:
do_callback();
_text = NULL;
redraw();
r = 1;
break;
case FL_PUSH:

@ -1 +1 @@
Subproject commit 92365eca0f9a6f054abc70489c009aba0fcde0ff
Subproject commit 720d8d33200ebd030df700c6c7a5a9cdf4581c03

View File

@ -1,6 +1,7 @@
[Desktop Entry]
Name=Non Mixer
Comment=Modular Digital Audio Workstation - Mixer
Comment[fr]=Station de travail audio-numérique modulaire - Mixeur
Exec=@BIN_PATH@/non-mixer
Terminal=false
Type=Application

View File

@ -29,8 +29,6 @@ AUX_Module::AUX_Module ( ) : JACK_Module ( false )
{
is_default( false );
_number = 0;
{
Port p( this, Port::INPUT, Port::CONTROL, "Gain (dB)" );
p.hints.type = Port::Hints::LINEAR;
@ -49,8 +47,6 @@ AUX_Module::AUX_Module ( ) : JACK_Module ( false )
color( FL_DARK1 );
copy_label( "Aux" );
smoothing.sample_rate( sample_rate() );
}
@ -62,35 +58,10 @@ AUX_Module::~AUX_Module ( )
void
AUX_Module::get ( Log_Entry &e ) const
{
e.add( ":number", number() );
JACK_Module::get(e);
}
void
AUX_Module::set ( Log_Entry &e )
{
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
e.get( i, &s, &v );
if ( ! ( strcmp( s, ":number" ) ) )
{
number( atoi(v) );
}
}
JACK_Module::set(e);
}
void
AUX_Module::number ( int n )
{
_number = n;
JACK_Module::number(n);
char s[10];
snprintf( s, sizeof(s), "aux-%c", 'A' + n );

View File

@ -24,17 +24,12 @@
class AUX_Module : public JACK_Module
{
int _number;
Value_Smoothing_Filter smoothing;
protected:
virtual void get ( Log_Entry &e ) const;
virtual void set ( Log_Entry &e );
public:
virtual void number ( int v );
virtual const char *name ( void ) const { return "AUX"; }
int can_support_inputs ( int n ) { return n > 0 ? n : -1; }
@ -42,9 +37,6 @@ public:
virtual bool configure_outputs ( int n );
virtual bool configure_inputs ( int n );
void number ( int n );
int number ( void ) const { return _number; }
AUX_Module ( );
virtual ~AUX_Module ( );

View File

@ -174,17 +174,23 @@ Chain::~Chain ( )
_deleting = true;
client()->lock();
/* FIXME: client may already be dead during teardown if group is destroyed first. */
if ( client() )
client()->lock();
for ( unsigned int i = scratch_port.size(); i--; )
free( (sample_t*)scratch_port[i].buffer() );
scratch_port.clear();
/* if we leave this up to FLTK, it will happen after we've
already destroyed the client */
modules_pack->clear();
modules_pack = NULL;
controls_pack->clear();
modules_pack = NULL;
client()->unlock();
if ( client() )
client()->unlock();
}
Group *
@ -322,10 +328,17 @@ Chain::remove ( Controller_Module *m )
}
void
Chain::send_feedback ( void )
Chain::send_feedback ( bool force )
{
for ( int i = 0; i < modules(); i++ )
module(i)->send_feedback();
module(i)->send_feedback( force );
}
void
Chain::schedule_feedback ( void )
{
for ( int i = 0; i < modules(); i++ )
module(i)->schedule_feedback();
}
/* remove a module from the chain. this isn't guaranteed to succeed,
@ -365,7 +378,7 @@ Chain::configure_ports ( void )
client()->lock();
for ( int i = 0; i < modules(); ++i )
{
{
module( i )->configure_inputs( nouts );
nouts = module( i )->noutputs();
}
@ -376,17 +389,21 @@ Chain::configure_ports ( void )
if ( scratch_port.size() < req_buffers )
{
for ( unsigned int i = scratch_port.size(); i--; )
free(scratch_port[i].buffer());
scratch_port.clear();
for ( unsigned int i = 0; i < req_buffers; ++i )
{
Module::Port p( NULL, Module::Port::OUTPUT, Module::Port::AUDIO );
for ( unsigned int i = req_buffers - scratch_port.size(); i--; )
{
Module::Port p( NULL, Module::Port::OUTPUT, Module::Port::AUDIO );
p.set_buffer( buffer_alloc( client()->nframes() ) );
buffer_fill_with_silence( (sample_t*)p.buffer(), client()->nframes() );
scratch_port.push_back( p );
}
}
}
else if ( scratch_port.size() > req_buffers )
{
for ( unsigned int i = scratch_port.size() - req_buffers; i--; )
{
free(scratch_port.back().buffer());
scratch_port.pop_back();
}
}
build_process_queue();
@ -445,8 +462,8 @@ Chain::get_module_instance_number ( Module *m )
{
int n = 0;
for ( int i = 0; i < modules() && module(i) != m; ++i )
if ( ! strcmp( module(i)->label(), m->label() ) )
for ( int i = 0; i < modules(); ++i )
if ( ! strcmp( module(i)->base_label(), m->base_label() ) )
n++;
return n;
@ -534,6 +551,8 @@ Chain::name ( const char *name )
if ( strip()->group() )
{
if ( strip()->group()->single() )
/* we are the owner of this group and its only member, so
* rename it */
strip()->group()->name(name);
}
@ -566,6 +585,13 @@ Chain::insert ( Module *m, Module *n )
{
client()->lock();
Module::sample_rate( client()->sample_rate() );
n->resize_buffers( client()->nframes() );
/* inserting a new instance */
if ( -1 == n->number() )
n->number( get_module_instance_number( n ) );
if ( !m )
{
if ( modules() == 0 && n->can_support_inputs( 0 ) >= 0 )
@ -713,6 +739,8 @@ Chain::add_to_process_queue ( Module *m )
void
Chain::build_process_queue ( void )
{
client()->lock();
process_queue.clear();
for ( int i = 0; i < modules(); ++i )
@ -780,6 +808,8 @@ Chain::build_process_queue ( void )
/* delete[] s; */
/* } */
/* } */
client()->unlock();
}
void
@ -901,9 +931,9 @@ Chain::process ( nframes_t nframes )
{
for ( std::list<Module*>::const_iterator i = process_queue.begin(); i != process_queue.end(); ++i )
{
Module *m = *i;
m->process( nframes );
Module *m = *i;
m->process( nframes );
}
}
@ -927,7 +957,7 @@ Chain::buffer_size ( nframes_t nframes )
int
Chain::sample_rate_change ( nframes_t nframes )
{
Module::set_sample_rate ( nframes );
Module::sample_rate ( nframes );
for ( int i = 0; i < modules(); ++i )
{
Module *m = module(i);

View File

@ -100,8 +100,9 @@ public:
const char *name ( void ) const { return _name; }
void name ( const char *name );
void send_feedback ( void );
void send_feedback ( bool force );
void schedule_feedback ( void );
int get_module_instance_number ( Module *m );
void configure_ports ( void );
@ -109,7 +110,7 @@ public:
bool can_support_input_channels ( int n );
int modules ( void ) const { return modules_pack->children(); }
int modules ( void ) const { return modules_pack ? modules_pack->children() : 0; }
Module *module ( int n ) const { return (Module*)modules_pack->child( n ); }
void remove ( Controller_Module *m );
void remove ( Module *m );

View File

@ -50,6 +50,9 @@
bool Controller_Module::learn_by_number = false;
bool Controller_Module::_learn_mode = false;
Controller_Module* Controller_Module::_learning_control = NULL;
void
@ -96,8 +99,6 @@ Controller_Module::~Controller_Module ( )
/* shutdown JACK port, if we have one */
mode( GUI );
// disconnect();
}
void
@ -188,7 +189,6 @@ Controller_Module::set ( Log_Entry &e )
{
connect_to( &module->control_input[port] );
module->chain()->add_control( this );
label( module->control_input[port].name() );
}
for ( int i = 0; i < e.size(); ++i )
@ -219,8 +219,15 @@ Controller_Module::mode ( Mode m )
Port *p = control_output[0].connected_port();
char prefix[512];
snprintf( prefix, sizeof(prefix), "CV-%s", p->name() );
const Module *m = p->module();
if ( m->number() >= 0 )
/* we do it this way now to ensure uniqueness */
snprintf( prefix, sizeof(prefix), "CV-%s/%s", m->label(), p->name() );
else
snprintf( prefix, sizeof(prefix), "CV-%s", p->name() );
add_aux_cv_input( prefix, 0 );
chain()->client()->unlock();
@ -403,6 +410,19 @@ Controller_Module::connect_spatializer_to ( Module *m )
return true;
}
void
Controller_Module::apply_label ( Port *p, Fl_Widget *o )
{
char path[256];
if ( is_default() )
snprintf( path, sizeof(path) - 1, "%s", p->name() );
else
snprintf( path, sizeof(path) - 1, "%s/%s", p->module()->label(), p->name() );
o->copy_label(path);
}
void
Controller_Module::connect_to ( Port *p )
{
@ -414,7 +434,7 @@ Controller_Module::connect_to ( Port *p )
if ( p->hints.type == Module::Port::Hints::BOOLEAN )
{
Fl_Button *o = new Fl_Button( 0, 0, 40, 40, p->name() );
Fl_Button *o = new Fl_Button( 0, 0, 40, 40 );
w = o;
o->type( FL_TOGGLE_BUTTON );
o->value( p->control_value() );
@ -428,7 +448,8 @@ Controller_Module::connect_to ( Port *p )
else if ( p->hints.type == Module::Port::Hints::INTEGER )
{
Fl_Counter *o = new Fl_Counter(0, 0, 58, 24, p->name() );
Fl_Counter *o = new Fl_Counter(0, 0, 58, 24 );
control = o;
w = o;
@ -448,7 +469,8 @@ Controller_Module::connect_to ( Port *p )
// else if ( p->hints.type == Module::Port::Hints::LOGARITHMIC )
else
{
Fl_Value_SliderX *o = new Fl_Value_SliderX(0, 0, 30, 250, p->name() );
Fl_Value_SliderX *o = new Fl_Value_SliderX(0, 0, 30, 250 );
control = o;
w = o;
@ -512,6 +534,8 @@ Controller_Module::connect_to ( Port *p )
/* _type = KNOB; */
/* } */
apply_label(p,control);
control_value = p->control_value();
w->clear_visible_focus();
@ -838,10 +862,27 @@ Controller_Module::draw ( void )
if ( learn_mode() )
{
fl_rectf( x(),y(),w(),h(), fl_color_add_alpha( FL_MAGENTA, 50 ) );
fl_rectf( x(),y(),w(),h(),
fl_color_add_alpha(
this == _learning_control
? FL_RED
: FL_GREEN,
60 ) );
}
}
void Controller_Module::learning_callback ( void *userdata )
{
((Controller_Module*)userdata)->learning_callback();
}
void Controller_Module::learning_callback ( void )
{
_learning_control = NULL;
this->redraw();
}
int
Controller_Module::handle ( int m )
{
@ -854,6 +895,10 @@ Controller_Module::handle ( int m )
{
tooltip( "Now learning control. Move the desired control on your controller" );
_learning_control = this;
this->redraw();
//connect_to( &module->control_input[port] );
Port *p = control_output[0].connected_port();
@ -863,7 +908,7 @@ Controller_Module::handle ( int m )
DMESSAGE( "Will learn %s", path );
mixer->osc_endpoint->learn( path );
mixer->osc_endpoint->learn( path, Controller_Module::learning_callback, this );
}
return 1;

View File

@ -47,9 +47,13 @@ class Controller_Module : public Module
void add_osc_peers_to_menu ( Fl_Menu_Button *m, const char *prefix );
void add_osc_connections_to_menu ( Fl_Menu_Button *m, const char *prefix );
static void learning_callback ( void *userdata );
void learning_callback ( void );
public:
static bool _learn_mode;
static Controller_Module *_learning_control;
static bool learn_by_number;
static bool learn_mode ( void ) { return _learn_mode; }
@ -115,6 +119,7 @@ protected:
private:
void apply_label ( Port *p, Fl_Widget *o );
void maybe_create_panner ( void );
char *generate_osc_path ( void );
void change_osc_path ( char *path );

View File

@ -43,33 +43,44 @@ DPM::DPM ( int X, int Y, int W, int H, const char *L ) :
_last_drawn_hi_segment = 0;
pixels_per_segment( 4 );
pixels_per_segment( 5 );
type( FL_VERTICAL );
// resize( X, Y, W, H );
dim( 0.85f );
dim( 0.95f );
box( FL_FLAT_BOX );
color(FL_BLACK);
/* color( fl_color_average( FL_BLACK, FL_BACKGROUND_COLOR, 0.25f ) ); */
/* initialize gradients */
if ( DPM::_gradient[ 0 ] == 0 )
{
int breaks[] = {0,60,70,80,90,127};
int breaks[] = {0,80,90,110,127};
Fl_Color cols[] = {
fl_rgb_color( 45,58,64),
fl_rgb_color( 84,181,195 ),
fl_rgb_color( 122,200,211 ),
fl_rgb_color( 178,213,212 ),
fl_rgb_color( 209,213,179 ),
fl_rgb_color( 250, 40, 30 )
Fl_Color cols[] = {
fl_darker( FL_CYAN ),
FL_CYAN,
fl_lighter( FL_CYAN ),
fl_color_average( FL_YELLOW, FL_RED, 0.50f ),
FL_RED
};
DPM::blend( 6, breaks, cols );
}
for ( int i = 0; i < 4; ++i )
{
cols[i] = fl_color_average( cols[i], FL_BACKGROUND_COLOR, 0.60f );
}
box( FL_FLAT_BOX );
color( FL_BACKGROUND_COLOR );
DPM::blend( 5,
breaks,
cols,
color() );
}
resize( X,Y,W,H);
}
@ -78,40 +89,40 @@ DPM::DPM ( int X, int Y, int W, int H, const char *L ) :
const int marks [] = { -70, -50, -40, -30, -20, -10, -3, 0, 4 };
void
DPM::draw_label ( void )
DPM::public_draw_label ( int X, int Y, int W, int H )
{
/* dirty hack */
if ( parent()->child( 0 ) == this )
fl_push_clip(X,Y,W,H);
fl_rectf( X,Y,W,H, FL_BACKGROUND_COLOR);
fl_font( FL_TIMES, 8 );
fl_color( active_r() ? FL_FOREGROUND_COLOR : fl_inactive( FL_FOREGROUND_COLOR ) );
/* draw marks */
char pat[5];
if ( type() == FL_HORIZONTAL )
{
fl_font( FL_TIMES, 8 );
fl_color( FL_WHITE );
/* draw marks */
char pat[5];
if ( type() == FL_HORIZONTAL )
{
for ( int i = sizeof( marks ) / sizeof( marks[0] ); i-- ; )
{
sprintf( pat, "%d", marks[ i ] );
for ( int i = sizeof( marks ) / sizeof( marks[0] ); i-- ; )
{
sprintf( pat, "%d", marks[ i ] );
int v = w() * deflection( (float)marks[ i ] );
int v = w() * deflection( (float)marks[ i ] );
fl_draw( pat, x() + v, (y() + h() + 8), 19, 8, (Fl_Align) (FL_ALIGN_RIGHT | FL_ALIGN_TOP) );
}
fl_draw( pat, X + v, (Y + H + 8), W, 8, (Fl_Align) (FL_ALIGN_RIGHT | FL_ALIGN_TOP) );
}
}
else
{
for ( int i = sizeof( marks ) / sizeof( marks[0] ); i-- ; )
{
sprintf( pat, "%d", marks[ i ] );
int v = h() * deflection( (float)marks[ i ] );
fl_draw( pat, x() - 20, (y() + h() - 4) - v, 19, 8, (Fl_Align) (FL_ALIGN_RIGHT | FL_ALIGN_TOP) );
}
}
}
else
{
for ( int i = sizeof( marks ) / sizeof( marks[0] ); i-- ; )
{
sprintf( pat, "%d", marks[ i ] );
int v = h() * deflection( (float)marks[ i ] );
fl_draw( pat, X, (Y + H - 4) - v, W, 8, (Fl_Align) (FL_ALIGN_RIGHT | FL_ALIGN_TOP) );
}
}
fl_pop_clip();
}
void
@ -135,12 +146,17 @@ DPM::resize ( int X, int Y, int W, int H )
void DPM::bbox ( int &X, int &Y, int &W, int &H )
{
X = x() + 2;
Y = y() + 2;
W = w() - 4;
H = h() - 4;
/* X = x() + 2; */
/* Y = y() + 2; */
/* W = w() - 4; */
/* H = h() - 4; */
X = x();
Y = y();
W = w();
H = h();
}
void
DPM::draw ( void )
{
@ -149,7 +165,7 @@ DPM::draw ( void )
int X,Y,W,H;
bbox(X,Y,W,H);
int v = pos( value() );
int pv = pos( peak() );
@ -159,15 +175,17 @@ DPM::draw ( void )
/* int bh = _pixels_per_segment; */
/* int bw = _pixels_per_segment; */
int bw = W / _segments;
if ( 0 == fl_not_clipped(X,Y,W,H ) )
return;
if ( damage() & FL_DAMAGE_ALL )
{
draw_label();
/* draw_label(); */
draw_box( FL_FLAT_BOX, x(), y(), w(), h(), FL_DARK1 );
draw_box( box(), X, Y, W, H, color() );
}
fl_push_clip( X, Y, W, H );
const int active = active_r();
@ -176,12 +194,16 @@ DPM::draw ( void )
/* only draw as many segments as necessary */
if ( damage() == FL_DAMAGE_USER1 )
{
if ( v > _last_drawn_hi_segment )
if ( v == _last_drawn_hi_segment )
{
return;
}
else if ( v > _last_drawn_hi_segment )
{
hi = v;
lo = _last_drawn_hi_segment;
}
else
else if ( v < _last_drawn_hi_segment )
{
hi = _last_drawn_hi_segment;
lo = v;
@ -195,62 +217,50 @@ DPM::draw ( void )
_last_drawn_hi_segment = v;
for ( int p = lo; p <= hi; p++ )
fl_push_clip( X, Y, W, H );
for ( int p = lo; p <= hi + 1; ++p )
{
Fl_Color c;
if ( p <= v )
{
if ( p == clipv )
c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 );
else
c = div_color( p );
}
else if ( p == pv )
c = div_color( p );
else
c = dim_div_color( p );
if ( ! active )
c = fl_inactive( c );
int yy = 0;
int xx = 0;
if ( type() == FL_HORIZONTAL )
{
xx = X + p * bw;
fl_rectf( X + (p * bw), Y, bw, H, c );
}
else
{
yy = Y + H - ((p+1) * bh);
fl_rectf( X, yy, W, bh, c );
}
if ( _pixels_per_segment >= 3 )
{
fl_color( FL_DARK1 );
if ( type() == FL_HORIZONTAL )
{
fl_line( xx, Y, xx, Y + H - 1 );
}
else
{
fl_line( X, yy, X + W - 1, yy );
}
}
/* } */
/* else */
/* { */
/* if ( type() == FL_HORIZONTAL ) */
/* fl_draw_box( box(), X + (p * bw), Y, bw, H, c ); */
/* else */
/* fl_draw_box( box(), X, Y + H - ((p + 1) * bh), W, bh, c ); */
/* } */
Fl_Color c;
if ( p <= v || p == pv )
{
if ( p == clipv )
c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 );
else
c = div_color( p );
}
else
c = fl_darker( FL_BACKGROUND_COLOR );//FL_DARK1; // fl_color_average( FL_BACKGROUND_COLOR, FL_BLACK, 0.50f );// FL_BACKGROUND_COLOR; //dim_div_color( p );
if ( ! active )
c = fl_inactive( c );
int yy = 0;
int xx = 0;
if ( type() == FL_HORIZONTAL )
{
xx = X + p * bw;
fl_rectf( xx + 1, Y, bw - 1, H, c );
}
else
{
yy = Y + H - ((p+1) * bh);
fl_rectf( X, yy + 1, W, bh - 1, c );
}
}
fl_pop_clip();
}
void
DPM::update ( void )
{
/* do falloff */
float f = value() - 0.33f;
if ( f < -80.0f )
f = -80.0f;
value(f);
}

View File

@ -30,9 +30,7 @@ class DPM : public Meter
int _segments;
int _pixels_per_segment;
int _last_drawn_hi_segment;
float _value;
int pos ( float v )
{
float pv = deflection( v ) * ( _segments - 1 );
@ -55,44 +53,43 @@ class DPM : public Meter
{
return _dim_gradient[ i * 127 / _segments ];
}
protected:
virtual void draw_label ( void );
virtual void draw ( void );
virtual void resize ( int, int, int, int );
/* virtual void draw_label ( void ); */
void bbox ( int &X, int &Y, int &W, int &H );
public:
void public_draw_label ( int X, int Y, int W, int H );
DPM ( int X, int Y, int W, int H, const char *L = 0 );
void value ( float v )
{
if ( _value != v )
{
if ( pos( v ) != pos( _value ) )
Meter::value( v );
}
_value = v;
}
float value ( void ) const
{
return _value;
}
void pixels_per_segment ( int v ) { _pixels_per_segment = v; }
float dim ( void ) const { return _dim; }
void dim ( float v ) { _dim = v; if ( visible_r() ) redraw(); }
virtual void value ( float v )
{
/* only trigger redraw for changes at or above our resolution*/
if ( pos( value() ) != pos( v ) && visible_r() )
damage( FL_DAMAGE_USER1 );
Meter::value( v );
}
virtual float value ( void ) { return Meter::value(); }
void update ( void );
static
void
blend ( int nbreaks, int* b, Fl_Color *c )
blend ( int nbreaks, int* b, Fl_Color *c, Fl_Color bc )
{
for ( int i = 0; i < nbreaks - 1; i++ )
{

View File

@ -56,9 +56,20 @@ Group::~Group ( )
{
DMESSAGE( "Destroying group" );
mixer->remove_group(this);
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
i != strips.end();
i++ )
{
/* avoid a use after free during project close when the group
* may be destroyed before its member strips are */
(*i)->clear_group();
}
if ( _name )
free( _name );
deactivate();
}
@ -101,12 +112,16 @@ Group::set ( Log_Entry &e )
void
Group::latency ( jack_latency_callback_mode_t mode )
{
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
i != strips.end();
i++ )
if ( trylock() )
{
if ( (*i)->chain() )
(*i)->chain()->set_latency(mode == JackCaptureLatency ? JACK::Port::Input : JACK::Port::Output );
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
i != strips.end();
i++ )
{
if ( (*i)->chain() )
(*i)->chain()->set_latency(mode == JackCaptureLatency ? JACK::Port::Input : JACK::Port::Output );
}
unlock();
}
}
@ -208,8 +223,9 @@ Group::process ( nframes_t nframes )
void
Group::recal_load_coef ( void )
{
_load_coef = 1.0f / ( nframes() / (float)sample_rate() * 1000000.0 );
_load_coef = 1.0f / ( nframes() / (float)sample_rate() * 1000000.0f );
}
int
Group::sample_rate_changed ( nframes_t srate )
{
@ -261,7 +277,7 @@ Group::name ( const char *n )
if ( !active() )
{
Client::init( ename );
Module::set_sample_rate( sample_rate() );
Module::sample_rate( sample_rate() );
}
else
{
@ -273,6 +289,7 @@ void
Group::add ( Mixer_Strip *o )
{
lock();
if ( ! active() )
{
/* to call init */
@ -280,10 +297,12 @@ Group::add ( Mixer_Strip *o )
name(n);
free(n);
}
if ( o->chain() )
o->chain()->thaw_ports();
strips.push_back(o);
unlock();
}
@ -291,13 +310,15 @@ void
Group::remove ( Mixer_Strip *o )
{
lock();
strips.remove(o);
if ( o->chain() )
o->chain()->freeze_ports();
if ( strips.size() == 0 && active() )
{
Client::close();
}
unlock();
}

View File

@ -97,6 +97,8 @@ public:
void add (Mixer_Strip*);
void remove (Mixer_Strip*);
int children ( void ) const { return strips.size(); }
/* Engine *engine ( void ) { return _engine; } */
};

View File

@ -25,6 +25,7 @@
#include <FL/Fl_Box.H>
#include <FL/Fl_Pack.H>
#include <FL/Fl_Scalepack.H>
#include <FL/Enumerations.H>
#include "dsp.h"
@ -48,6 +49,8 @@ extern char *instance_name;
#include "Mixer.H"
#include "Group.H"
#include "Project.H"
static JACK_Module *receptive_to_drop = NULL;
@ -164,7 +167,7 @@ JACK_Module::JACK_Module ( bool log )
Fl_Browser *o = connection_display = new Fl_Browser( 0, 0, w(), h() );
o->has_scrollbar(Fl_Browser_::VERTICAL);
o->textsize( 10 );
o->textcolor( FL_LIGHT3 );
o->textcolor( fl_contrast( FL_LIGHT3, FL_BACKGROUND_COLOR ) );
o->textfont( FL_COURIER );
o->box( FL_FLAT_BOX );
o->color( FL_DARK1 );
@ -298,12 +301,23 @@ JACK_Module::update_connection_status ( void )
return;
}
/* /\* causes a lot of unnecessary redraws to do this when loading *\/ */
/* if ( Project::is_opening_closing() ) */
/* return; */
/* FIXME: only do something if port list actually changed! */
std::list<std::string> output_names = get_connections_for_ports( aux_audio_output );
std::list<std::string> input_names = get_connections_for_ports( aux_audio_input );
if ( (unsigned int)connection_display->size() == input_names.size() + output_names.size() )
/* looks like nothing was added or removed, bail.
FIXME: this would be better if it actually compared the lists item by item. */
return;
connection_display->clear();
int n = 0;
for ( std::list<std::string>::const_iterator j = input_names.begin();
j != input_names.end();
j++ )
@ -599,13 +613,12 @@ JACK_Module::handle ( int m )
if ( Fl::event_inside( output_connection_handle ) ||
Fl::event_inside( output_connection2_handle ) ||
Fl::event_inside( input_connection_handle ) )
{
fl_cursor( FL_CURSOR_HAND );
}
else
fl_cursor( FL_CURSOR_DEFAULT );
Module::handle(m);
/* This calls Fl_Group::handle() which somehow prevent DND FL_PASTE event from being delivered later */
/* Module::handle(m); */
return 1;
case FL_ENTER:
case FL_DND_ENTER:

View File

@ -84,17 +84,14 @@ public:
virtual void value ( float v )
{
if ( visible_r() )
damage( FL_DAMAGE_USER1 );
_value = v;
if ( _value > _peak )
_peak = _value;
_value = v;
if ( _value > _peak )
_peak = _value;
}
virtual float value ( void ) const { return _value; }
float peak ( void ) const { return _peak; }
virtual float peak ( void ) const { return _peak; }
void reset ( void ) { _peak = -80.0f; redraw(); }

View File

@ -31,18 +31,22 @@
#include "FL/Fl_Dial.H"
#include "FL/Fl_Labelpad_Group.H"
#include "FL/Fl_Scalepack.H"
#include <FL/fl_draw.H>
#include "Chain.H"
#include "DPM.H"
#include "dsp.h"
#include "FL/test_press.H"
const int DX = 1;
Meter_Indicator_Module::Meter_Indicator_Module ( bool is_default )
: Module ( is_default, 50, 100, name() )
{
box( FL_FLAT_BOX );
/* color( fl_darker( fl_darker( FL_BACKGROUND_COLOR ))); */
color( FL_BLACK );
_disable_context_menu = false;
@ -53,15 +57,23 @@ Meter_Indicator_Module::Meter_Indicator_Module ( bool is_default )
control_input[0].hints.visible = false;
dpm_pack = new Fl_Scalepack( x(), y(), w(), h() );
dpm_pack->color( FL_BACKGROUND_COLOR );
dpm_pack->box( FL_FLAT_BOX );
/* dpm_pack = new Fl_Scalepack( x() + 2, y() + 2, w() - 4, h() - 4 ); */
/* /\* dpm_pack->color( FL_BACKGROUND_COLOR ); *\/ */
/* dpm_pack->box( FL_NO_BOX ); */
/* dpm_pack->type( FL_HORIZONTAL ); */
/* dpm_pack->spacing(1); */
dpm_pack = new Fl_Scalepack( x() + 20 + 2, y() + 2, w() - 20 - 4, h() - 4 );
/* dpm_pack->color( FL_BACKGROUND_COLOR ); */
dpm_pack->box( FL_NO_BOX );
dpm_pack->type( FL_HORIZONTAL );
dpm_pack->spacing(1);
end();
end();
control_value = new float[1];
*control_value = -70.0f;
control_value = new float[1*2];
control_value[0] =
control_value[1] = 0;
align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE ) );
@ -81,6 +93,32 @@ Meter_Indicator_Module::~Meter_Indicator_Module ( )
void Meter_Indicator_Module::resize ( int X, int Y, int W, int H )
{
Fl_Group::resize(X,Y,W,H);
dpm_pack->resize( x() + 20 + DX , y() + DX, w() - 20 - DX*2, h() - DX*2);
}
void
Meter_Indicator_Module::draw ( void )
{
/* if ( damage() & FL_DAMAGE_ALL ) */
/* draw_box(x(),y(),w(),h()); */
Fl_Group::draw();
if ( damage() & FL_DAMAGE_ALL )
{
/* need to trigger redraw of exterior label */
if ( dpm_pack->children() )
{
((DPM*)dpm_pack->child(0))->public_draw_label( x(), y(), 19, h() );
}
}
fl_rect( x(), y(), w(), h(), fl_darker(fl_darker(FL_BACKGROUND_COLOR)));
}
void
Meter_Indicator_Module::get ( Log_Entry &e ) const
{
@ -138,37 +176,29 @@ Meter_Indicator_Module::update ( void )
// A little hack to detect that the connected module's number
// of control outs has changed.
Port *p = control_input[0].connected_port();
for ( int i = 0; i < dpm_pack->children(); ++i )
{
DPM *o = (DPM*)dpm_pack->child(i);
if ( dpm_pack->children() != p->hints.dimensions )
{
/* engine->lock(); */
float dB = CO_DB( control_value[i] );
if ( dB > o->value() )
o->value( dB );
dpm_pack->clear();
o->update();
/* else */
/* { */
/* /\* do falloff *\/ */
/* float f = o->value() - 0.75f; */
/* if ( f < -70.0f ) */
/* f = -70.0f; */
/* o->value( f ); */
/* } */
control_value = new float[p->hints.dimensions];
for ( int i = p->hints.dimensions; i--; )
{
DPM *dpm = new DPM( x(), y(), w(), h() );
dpm->type( FL_VERTICAL );
dpm_pack->add( dpm );
control_value[i] = -70.0f;
dpm->value( -70.0f );
}
/* engine->unlock(); */
}
else
{
for ( int i = 0; i < dpm_pack->children(); ++i )
{
((DPM*)dpm_pack->child( i ))->value( control_value[i] );
control_value[i] = -70.0f;
}
}
control_value[i] = 0;
}
}
}
@ -228,7 +258,7 @@ Meter_Indicator_Module::handle_control_changed ( Port *p )
control_value = new float[p->hints.dimensions];
for ( int i = p->hints.dimensions; i--; )
for ( int i = 0; i < p->hints.dimensions; i++ )
{
DPM *dpm = new DPM( x(), y(), w(), h() );
dpm->type( FL_VERTICAL );
@ -237,8 +267,10 @@ Meter_Indicator_Module::handle_control_changed ( Port *p )
dpm_pack->add( dpm );
dpm_pack->redraw();
control_value[i] = -70.0f;
dpm->value( -70.0f );
control_value[i] = 0;
dpm->value( CO_DB( control_value[i] ));
}
redraw();
@ -256,12 +288,22 @@ Meter_Indicator_Module::process ( nframes_t )
if ( control_input[0].connected() )
{
Port *p = control_input[0].connected_port();
volatile float *cv = control_value;
float *pv = (float*)control_input[0].buffer();
for ( int i = 0; i < p->hints.dimensions; ++i )
{
float dB = ((float*)control_input[0].buffer())[i];
if ( dB > control_value[i])
control_value[i] = dB;
/* peak value since we last checked */
if ( *pv > *cv )
{
*cv = *pv;
/* reset now that we've got it */
*pv = 0;
}
cv++;
pv++;
}
}
}

View File

@ -70,12 +70,8 @@ protected:
void get ( Log_Entry &e ) const;
void set ( Log_Entry &e );
virtual void draw ( void )
{
// draw_box();
Fl_Group::draw();
}
virtual void draw ( void );
virtual void resize ( int X, int Y, int W, int H );
virtual int handle ( int m );
private:

View File

@ -22,6 +22,7 @@
#include <math.h>
#include <FL/Fl.H>
#include <FL/Fl_Single_Window.H>
#include <FL/fl_draw.H>
#include "FL/Fl_Scalepack.H"
#include "FL/test_press.H"
@ -30,30 +31,33 @@
#include "DPM.H"
#include "JACK/Port.H"
#include "dsp.h"
Meter_Module::Meter_Module ( )
: Module ( 50, 100, name() )
{
box( FL_NO_BOX );
dpm_pack = new Fl_Scalepack( x(), y(), w(), h() );
box( FL_FLAT_BOX );
dpm_pack = new Fl_Scalepack( x() + 2, y() + 2, w() - 4, h() - 4 );
dpm_pack->type( FL_HORIZONTAL );
dpm_pack->spacing( 1 );
control_value = 0;
color( FL_BLACK );
peaks = 0;
meter_sample_period_count = 0;
meter_sample_periods = 0;
color( fl_darker( fl_darker( FL_BACKGROUND_COLOR )));
end();
Port p( this, Port::OUTPUT, Port::CONTROL, "dB level" );
p.hints.type = Port::Hints::LOGARITHMIC;
Port p( this, Port::OUTPUT, Port::CONTROL, "peak level" );
p.hints.type = Port::Hints::LINEAR;
p.hints.ranged = true;
p.hints.maximum = 6.0f;
p.hints.minimum = -70.0f;
p.hints.maximum = 10.0f;
p.hints.minimum = 0.0f;
p.hints.dimensions = 1;
p.connect_to( new float[1] );
p.control_value_no_callback( -70.0f );
p.control_value_no_callback( 0 );
add_port( p );
@ -70,13 +74,40 @@ Meter_Module::~Meter_Module ( )
void Meter_Module::resize ( int X, int Y, int W, int H )
{
Fl_Group::resize(X,Y,W,H);
dpm_pack->resize( x() + 2, y() + 2, w() - 4, h() - 4 );
}
void
Meter_Module::draw ( void )
{
/* draw_box(x(),y(),w(),h()); */
Fl_Group::draw();
fl_rect( x(), y(), w(), h(), fl_darker(FL_BACKGROUND_COLOR));
fl_rect( x()+1, y()+1, w()-2, h()-2, fl_darker(fl_darker(FL_BACKGROUND_COLOR)));
}
void
Meter_Module::update ( void )
{
for ( int i = dpm_pack->children(); i--; )
{
((DPM*)dpm_pack->child( i ))->value( control_value[i] );
control_value[i] = -70.0f;
DPM* o = ((DPM*)dpm_pack->child( i ));
const float v = CO_DB( control_value[i] );
if ( v > o->value() )
o->value( v );
o->update();
control_value[i] = 0;
}
}
@ -99,7 +130,6 @@ Meter_Module::configure_inputs ( int n )
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
}
}
else
@ -114,16 +144,20 @@ Meter_Module::configure_inputs ( int n )
audio_input.pop_back();
audio_output.back().disconnect();
audio_output.pop_back();
smoothing.pop_back();
}
}
/* DMESSAGE( "sample rate: %lu, nframes: %lu", sample_rate(), this->nframes() ); */
control_output[0].hints.dimensions = n;
delete[] (float*)control_output[0].buffer();
{
float *f = new float[n];
for ( int i = n; i--; )
f[i] = -70.0f;
f[i] = 0;
control_output[0].connect_to( f );
}
@ -133,7 +167,7 @@ Meter_Module::configure_inputs ( int n )
control_value = new float[n];
for ( int i = n; i--; )
control_value[i] = -70.0f;
control_value[i] = 0;
if ( control_output[0].connected() )
control_output[0].connected_port()->module()->handle_control_changed( control_output[0].connected_port() );
@ -175,11 +209,19 @@ Meter_Module::process ( nframes_t nframes )
{
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
// float dB = 20 * log10( get_peak_sample( (float*)audio_input[i].buffer(), nframes ) / 2.0f );
float dB = 20 * log10( buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes ) );
const float peak = buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes );
/* const float RMS = sqrtf( peak / (float)nframes); */
((float*)control_output[0].buffer())[i] = dB;
if (dB > control_value[i])
control_value[i] = dB;
/* since the GUI only updates at 20 or 30hz, there's no point in doing this more often than necessary. */
/* need to store this separately from other peaks as it must be reset each time we do a round of smoothing output */
/* store peak value */
if ( peak > ((float*)control_output[0].buffer())[i] )
((float*)control_output[0].buffer())[i] = peak;
if ( peak > control_value[i] )
control_value[i] = peak;
}
}

View File

@ -20,6 +20,8 @@
#pragma once
#include "Module.H"
#include "dsp.h"
#include <vector>
class Fl_Scalepack;
@ -27,8 +29,19 @@ class Meter_Module : public Module
{
Fl_Scalepack *dpm_pack;
std::vector <Value_Smoothing_Filter> smoothing;
volatile float *control_value;
volatile float *peaks;
int meter_sample_periods; /* no need to do computations every
* buffer when the gui only updates at
* 30Hz. So only do it every n
* buffers */
int meter_sample_period_count;
void set_smoothing_sample_rate ( nframes_t nframes, nframes_t sample_rate );
public:
Meter_Module ( );
@ -47,5 +60,6 @@ protected:
virtual int handle ( int m );
virtual void process ( nframes_t nframes );
virtual void draw ( void ) { draw_box(x(),y(),w(),h()); }
virtual void draw ( void );
virtual void resize ( int X, int Y, int W, int H );
};

View File

@ -49,7 +49,8 @@
#include "Controller_Module.H"
const double FEEDBACK_UPDATE_FREQ = 1.0f;
/* const double FEEDBACK_UPDATE_FREQ = 1.0f; */
const double FEEDBACK_UPDATE_FREQ = 1.0f / 30.0f;
extern char *user_config_dir;
extern char *instance_name;
@ -308,7 +309,7 @@ void Mixer::cb_menu(Fl_Widget* o) {
}
else if ( !strcmp( picked, "&Remote Control/Send State" ) )
{
send_feedback();
send_feedback(true);
}
else if ( ! strcmp( picked, "&Remote Control/Clear All Mappings" ) )
{
@ -354,7 +355,7 @@ void Mixer::cb_menu(Fl_Widget* o) {
{
fl_theme_chooser();
}
else if ( ! strcmp( picked, "&Mixer/Swap &Fader//Signal View" ) )
else if ( ! strcmp( picked, "&Mixer/Toggle &Fader View" ) )
{
command_toggle_fader_view();
}
@ -416,7 +417,7 @@ Mixer::update_cb ( void )
{
Fl::repeat_timeout( _update_interval, &Mixer::update_cb, this );
if ( active_r() && visible_r() )
/* if ( active_r() && visible_r() ) */
{
for ( int i = 0; i < mixer_strips->children(); i++ )
{
@ -527,7 +528,7 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
o->add( "&Mixer/&Import Strip" );
o->add( "&Mixer/Paste", FL_CTRL + 'v', 0, 0 );
o->add( "&Mixer/&Spatialization Console", FL_F + 8, 0, 0, FL_MENU_TOGGLE );
o->add( "&Mixer/Swap &Fader//Signal View", FL_ALT + 'f', 0, 0, FL_MENU_TOGGLE );
o->add( "&Mixer/Toggle &Fader View", FL_ALT + 'f', 0, 0, FL_MENU_TOGGLE );
// o->add( "&Mixer/&Signal View", FL_ALT + 's', 0, 0, FL_MENU_TOGGLE );
o->add( "&Remote Control/Start Learning", FL_F + 9, 0, 0 );
o->add( "&Remote Control/Stop Learning", FL_F + 10, 0, 0 );
@ -571,6 +572,7 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE) );
o->flow( false );
o->box( FL_FLAT_BOX );
o->color( fl_darker(FL_BACKGROUND_COLOR ));
o->type( Fl_Pack::HORIZONTAL );
o->hspacing( 2 );
o->vspacing( 2 );
@ -590,9 +592,8 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
resize( X,Y,W,H );
update_frequency( 15 );
update_frequency( 24 );
Fl::add_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, this );
update_menu();
@ -621,8 +622,14 @@ Mixer::osc_strip_by_number ( const char *path, const char *types, lo_arg **argv,
}
char *new_path;
char *stripname = escape_url( o->name() );
asprintf( &new_path, "%s/strip/%s/%s", client_name, o->name(), rem );
asprintf( &new_path, "%s/strip/%s/%s", client_name, stripname, rem );
free( stripname );
/* DMESSAGE( "Forwarding by-number OSC path: %s === %s", path, new_path ); */
free( rem );
@ -743,6 +750,8 @@ void Mixer::resize ( int X, int Y, int W, int H )
{
Fl_Group::resize( X, Y, W, H );
sm_blinker->resize( X + W - 40, Y + 5, 35, 15 );
scroll->resize( X, Y + 24, W, H - 24 - 18 );
mixer_strips->resize( X, Y + 24, W, H - (18*2) - 24 );
@ -757,8 +766,10 @@ void Mixer::add ( Mixer_Strip *ms )
mixer_strips->add( ms );
ms->size( ms->w(), _strip_height );
ms->redraw();
ms->take_focus();
ms->redraw();
ms->take_focus();
renumber_strips();
}
int
@ -775,12 +786,25 @@ Mixer::quit ( void )
while ( Fl::first_window() ) Fl::first_window()->hide();
}
void
Mixer::renumber_strips ( void )
{
for ( int i = mixer_strips->children(); i--; )
{
Mixer_Strip *o = (Mixer_Strip*)mixer_strips->child(i);
o->number( find_strip( o ) );
}
}
void
Mixer::insert ( Mixer_Strip *ms, Mixer_Strip *before )
{
// mixer_strips->remove( ms );
mixer_strips->insert( *ms, before );
renumber_strips();
schedule_feedback();
// scroll->redraw();
}
void
@ -789,6 +813,7 @@ Mixer::insert ( Mixer_Strip *ms, int i )
Mixer_Strip *before = (Mixer_Strip*)mixer_strips->child( i );
insert( ms, before);
renumber_strips();
}
void
@ -799,6 +824,7 @@ Mixer::move_left ( Mixer_Strip *ms )
if ( i > 0 )
insert( ms, i - 1 );
renumber_strips();
/* FIXME: do better */
mixer_strips->redraw();
}
@ -811,6 +837,8 @@ Mixer::move_right ( Mixer_Strip *ms )
if ( i < mixer_strips->children() - 1 )
insert( ms, i + 2 );
renumber_strips();
/* FIXME: do better */
mixer_strips->redraw();
}
@ -821,10 +849,11 @@ void Mixer::remove ( Mixer_Strip *ms )
mixer_strips->remove( ms );
ms->group()->remove( ms );
if ( parent() )
parent()->redraw();
renumber_strips();
schedule_feedback();
}
@ -893,7 +922,7 @@ Mixer::rows ( int ideal_rows )
_rows = ideal_rows;
if ( _strip_height != sh );
if ( _strip_height != sh )
{
mixer_strips->redraw();
scroll->redraw();
@ -1051,20 +1080,24 @@ Mixer::send_feedback_cb ( void *v )
{
Mixer *m = (Mixer*)v;
m->send_feedback();
m->send_feedback(false);
/* just to it once at the start... */
Fl::repeat_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, v );
}
/** unconditionally send feedback to all mapped controls. This is
* useful for updating the state of an external controller. */
void
Mixer::send_feedback ( void )
Mixer::send_feedback ( bool force )
{
for ( int i = 0; i < mixer_strips->children(); i++ )
{
((Mixer_Strip*)mixer_strips->child(i))->send_feedback();
}
((Mixer_Strip*)mixer_strips->child(i))->send_feedback(force);
}
void
Mixer::schedule_feedback ( void )
{
for ( int i = 0; i < mixer_strips->children(); i++ )
((Mixer_Strip*)mixer_strips->child(i))->schedule_feedback();
}
@ -1072,6 +1105,9 @@ Mixer::send_feedback ( void )
int
Mixer::handle ( int m )
{
/* if user presses certain keys when project is loading it can cause a crash. Don't respond to input. */
if ( Project::is_opening_closing() )
return 0;
if ( Fl_Group::handle( m ) )
return 1;
@ -1082,7 +1118,9 @@ Mixer::handle ( int m )
{
if ( ! Fl::event_inside( this ) )
return 0;
DMESSAGE( "Got paste into mixer, expecting strip file..." );
const char *text = Fl::event_text();
char *file;
@ -1148,7 +1186,7 @@ Mixer::get_auto_connect_targets ( void )
void
Mixer::auto_connect ( void )
{
if ( Project::is_opening() )
if ( Project::is_opening_closing() )
/* it's more efficient to do this once at the end rather than as we go. */
return;
@ -1176,7 +1214,7 @@ Mixer::auto_connect ( void )
void
Mixer::maybe_auto_connect_output ( Module::Port *p )
{
if ( Project::is_opening() )
if ( Project::is_opening_closing() )
/* it's more efficient to do this once at the end rather than as we go. */
return;
@ -1192,7 +1230,7 @@ Mixer::maybe_auto_connect_output ( Module::Port *p )
return;
}
/* now do that catch-alls, first one wins! */
/* now do the catch-alls, first one wins! */
for ( int i = 0; i < mixer_strips->children(); i++ )
{
Mixer_Strip *s = ((Mixer_Strip*)mixer_strips->child(i));
@ -1267,6 +1305,9 @@ Mixer::command_load ( const char *path, const char *display_name )
mixer->activate();
/* Fl::remove_timeout( send_feedback_cb, this ); */
Fl::add_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, this );
return true;
}

View File

@ -78,7 +78,8 @@ private:
void load_translations ( void );
static void send_feedback_cb ( void *v );
void send_feedback ( void );
void send_feedback ( bool force );
void schedule_feedback ( void );
void redraw_windows ( void );
static void handle_dirty ( int, void *v );
@ -159,6 +160,8 @@ public:
void save_project_settings ( void );
void load_project_settings ( void );
void renumber_strips ( void );
public:
void command_toggle_fader_view ( void );

View File

@ -73,6 +73,7 @@ Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
init();
/* create single member group */
_group = new Group(strip_name, true);
_group->add( this );
@ -105,14 +106,30 @@ Mixer_Strip::~Mixer_Strip ( )
// _chain->engine()->lock();
log_destroy();
mixer->remove( this );
/* make sure this gets destroyed before the chain */
fader_tab->clear();
delete _chain;
_chain = NULL;
if ( _group )
{
_group->remove( this );
}
if ( _chain )
{
delete _chain;
_chain = NULL;
}
if ( _group )
{
if ( 0 == _group->children() )
delete _group;
_group = NULL;
}
}
@ -347,6 +364,7 @@ void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
void
Mixer_Strip::group ( Group *g )
{
/* FIXME: what is the intention here? */
if ( !g && _group && _group->single() )
return;
@ -544,16 +562,35 @@ Mixer_Strip::init ( )
o->box(FL_FLAT_BOX);
o->tooltip( "Drag and drop to move strip" );
}
{ Fl_Progress* o = dsp_load_progress = new Fl_Progress(61, 183, 45, 14, "group dsp");
o->box(FL_BORDER_BOX);
o->type(FL_HORIZONTAL);
/* o->labelsize( 9 ); */
o->minimum( 0 );
// o->maximum( 0.25f );
o->maximum( 1 );
/* o->color(fl_rgb_color( 10,10,10 ) ); */
o->color2(FL_CYAN);
o->color(fl_contrast(FL_DARK1,FL_FOREGROUND_COLOR));
o->labelcolor(FL_FOREGROUND_COLOR);
/* o->labeltype(FL_NORMAL_LABEL); */
o->labeltype(FL_NORMAL_LABEL);
o->labelfont( FL_COURIER_BOLD );
o->labelsize( 12 );
}
{ Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
o->type( Fl_Pack::VERTICAL );
o->spacing( 2 );
o->spacing(2);
{
Fl_Sometimes_Input *o = new Fl_Sometimes_Input( 2, 2, 144, 15 );
name_field = o;
o->up_box( FL_NO_BOX );
o->up_box( FL_FLAT_BOX );
o->box( FL_FLAT_BOX );
o->color( FL_BACKGROUND_COLOR );
o->selection_color( FL_BLACK );
o->labeltype( FL_NO_LABEL );
o->labelcolor( FL_GRAY0 );
@ -564,7 +601,7 @@ Mixer_Strip::init ( )
}
{ Fl_Scalepack *o = new Fl_Scalepack( 7, 143, 110, 18 );
o->type( Fl_Pack::HORIZONTAL );
o->spacing(2);
{ Fl_Flip_Button* o = width_button = new Fl_Flip_Button(61, 183, 45, 22, "[]/[-]");
o->type(1);
o->tooltip( "Switch between wide and narrow views" );
@ -586,16 +623,6 @@ Mixer_Strip::init ( )
o->end();
} // Fl_Group* o
{ Fl_Progress* o = dsp_load_progress = new Fl_Progress(61, 183, 45, 14, "group dsp");
o->box(FL_BORDER_BOX);
o->type(FL_HORIZONTAL);
o->labelsize( 9 );
o->minimum( 0 );
// o->maximum( 0.25f );
o->maximum( 1 );
o->color(fl_rgb_color( 10,10,10 ) );
o->color2(FL_CYAN);
}
{ Fl_Choice* o = group_choice = new Fl_Choice(61, 183, 45, 22);
o->tooltip( "Create or assign group" );
o->labeltype(FL_NO_LABEL);
@ -607,6 +634,7 @@ Mixer_Strip::init ( )
}
{ Fl_Scalepack *o = new Fl_Scalepack( 0,0, 45, 22 );
o->type( FL_HORIZONTAL );
o->spacing(2);
{ Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "Fadr/Signl");
o->tooltip( "Switch between fader and signal views" );
o->type(1);
@ -647,7 +675,7 @@ Mixer_Strip::init ( )
{ Fl_Scalepack* o = new Fl_Scalepack(2, 135, 105, 311 );
// o->box( FL_BORDER_BOX );
// o->color( FL_RED );
o->spacing( 20 );
o->spacing( 0 );
o->type( Fl_Scalepack::HORIZONTAL );
{ Controller_Module *o = gain_controller = new Controller_Module( true );
o->horizontal(false);
@ -790,9 +818,8 @@ Mixer_Strip::export_strip ( const char *filename )
{
MESSAGE( "Exporting chain state" );
Loggable::snapshot_callback( &Mixer_Strip::snapshot, this );
Loggable::snapshot( filename );
return true;
}
return Loggable::snapshot( filename );
}
bool
Mixer_Strip::import_strip ( const char *filename )
@ -865,9 +892,12 @@ Mixer_Strip::menu_cb ( const Fl_Menu_ *m )
free( suggested_name );
if ( s )
export_strip( s );
fl_message( "Strip exported." );
{
if ( export_strip( s ) )
fl_message( "Strip exported." );
else
fl_alert("Failed to export strip");
}
}
else if ( ! strcmp( picked, "/Remove" ) )
{
@ -912,6 +942,9 @@ Mixer_Strip::menu_cb ( Fl_Widget *w, void *v )
void
Mixer_Strip::auto_input ( const char *s )
{
/* break old connections */
disconnect_auto_inputs(s);
if ( _auto_input )
free( _auto_input );
@ -920,6 +953,7 @@ Mixer_Strip::auto_input ( const char *s )
if ( s )
_auto_input = strdup( s );
/* make new connections */
mixer->auto_connect();
}
@ -952,13 +986,13 @@ static bool matches_pattern ( const char *pattern, Module::Port *p )
return false;
}
/* DMESSAGE( "Auto-connect comparing pattern: %s, to port %s", pattern, */
/* p->jack_port()->name() ); */
/* group matches... try port group */
if ( ! strcmp( port_group, "mains" ) )
{
if ( index( p->jack_port()->name(), '/' ) )
return false;
else
return true;
{
return !index( p->jack_port()->name(), '/' );
}
else
{
@ -968,7 +1002,7 @@ static bool matches_pattern ( const char *pattern, Module::Port *p )
if ( n )
{
// *n = 0;
if ( ! strncmp( port_group, pn, ( n - 1 ) - pn ) )
if ( ! strncmp( port_group, pn, n - pn ) )
return true;
else
return false;
@ -996,6 +1030,42 @@ Mixer_Strip::has_group_affinity ( void ) const
return _auto_input && strncmp( _auto_input, "*/", 2 );
}
void
Mixer_Strip::disconnect_auto_inputs ( const char *exclude_pattern )
{
if ( chain() )
{
JACK_Module *m = (JACK_Module*)chain()->module(0);
if ( m )
{
for ( unsigned int i = 0; i < m->aux_audio_input.size(); ++i )
{
Module::Port *p1 = &m->aux_audio_input[i];
if ( _auto_input && exclude_pattern )
{
/* avoid disconnecting a port that we'll immediately be reconnecting */
for ( unsigned int j = 0; j < p1->nconnected(); ++j )
{
Module::Port *p2 = p1->connected_port( j );
if ( !matches_pattern( exclude_pattern, p2 ) )
{
p1->disconnect( p2 );
j--; /* keep our place in the iteration */
}
}
}
else
{
m->aux_audio_input[i].disconnect();
}
}
}
}
}
bool
Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
{
@ -1008,15 +1078,19 @@ Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
if ( ! _auto_input )
{
/* break any previous connection between this port and this module */
p->disconnect_from_strip(this);
/* not accepting auto inputs, so ensure all previous auto
input connection are broken and ignore this port. */
p->disconnect_from_strip(this);
return false;
}
if ( _auto_input && matches_pattern( _auto_input, p ) )
if ( _auto_input &&
matches_pattern( _auto_input, p ) )
{
/* break any prior auto-connection */
p->disconnect();
/* got a match, add this to list of accepted connections */
// FIXME: Find a better way to get the port index.
const char* jack_name = p->jack_port()->jack_name();
@ -1039,6 +1113,9 @@ Mixer_Strip::maybe_auto_connect_output ( Module::Port *p )
return false;
}
if ( ! m->aux_audio_input[n].connected_to( p ) )
m->aux_audio_input[n].connect_to( p );
m->aux_audio_input[n].connect_to( p );
if ( p->module()->is_default() )
@ -1121,6 +1198,9 @@ Mixer_Strip::handle ( int m )
{
static int _button = 0;
if (!_chain )
return 0;
Logger log( this );
static Fl_Widget *dragging = NULL;
@ -1201,16 +1281,40 @@ Mixer_Strip::handle ( int m )
}
void
Mixer_Strip::send_feedback ( void )
Mixer_Strip::send_feedback ( bool force )
{
if ( _chain )
_chain->send_feedback();
_chain->send_feedback(force);
}
void
Mixer_Strip::schedule_feedback ( void )
{
if ( _chain )
_chain->schedule_feedback();
}
/* called to inform the strip its number has changed. */
void
Mixer_Strip::number ( int n )
{
if ( _number != n )
{
_number = n;
char *s =NULL;
asprintf( &s,"%i", n+1 );
dsp_load_progress->label(s);
/* color code groups of eight */
dsp_load_progress->color( (n / 8) % 2 == 0 ? FL_BACKGROUND_COLOR : FL_BLACK );
/* dsp_load_progress->color( fl_color_average( (Fl_Color)n / 8, FL_BACKGROUND_COLOR, 0.66f )); */
dsp_load_progress->labelcolor(fl_contrast( FL_BACKGROUND_COLOR, dsp_load_progress->color() ));
}
}
int
Mixer_Strip::number ( void ) const
{
return mixer->find_strip( this );
return _number;
}
/************/

View File

@ -98,6 +98,7 @@ private:
int _gain_controller_mode;
int _mute_controller_mode;
bool _manual_connection;
int _number;
Fl_Menu_Button *output_connection_button;
Fl_Flip_Button *width_button;
@ -125,7 +126,7 @@ private:
Fl_Progress *dsp_load_progress;
Fl_Box *color_box;
nframes_t nframes;
Fl_Color _color;
@ -160,6 +161,7 @@ public:
void manual_connection ( bool b );
bool has_group_affinity ( void ) const;
void disconnect_auto_inputs ( const char *exclude_pattern );
void auto_connect_outputs ( void );
bool maybe_auto_connect_output ( Module::Port *p );
@ -169,12 +171,15 @@ public:
Controller_Module *spatializer ( void );
Group *group ( void ) { return _group;}
Group *group ( void ) { return _group; }
void clear_group ( void ) { _group = NULL; }
// int group ( void ) const;
void group ( Group * );
void send_feedback ( void );
void send_feedback ( bool force );
void schedule_feedback ( void );
int number ( void ) const;
void number ( int );
static bool import_strip ( const char *filename );
void command_toggle_fader_view ( void );

View File

@ -20,6 +20,7 @@
#include "Module.H"
#include <FL/fl_draw.H>
#include <FL/fl_ask.H>
#include <FL/Enumerations.H>
#include <stdlib.h>
#include <string.h>
@ -47,6 +48,9 @@
#include "string_util.h"
#include "time.h"
nframes_t Module::_sample_rate = 0;
@ -104,27 +108,36 @@ Module::~Module ( )
if ( control_input[i].connected() )
{
Module *o = (Module*)control_input[i].connected_port()->module();
if ( ! o->is_default() )
{
control_input[i].disconnect();
DMESSAGE( "Deleting connected module %s", o->label() );
delete o;
}
else
{
control_input[i].disconnect();
}
}
if ( !o )
{
DWARNING( "Programming error. Connected port has null module. %s %s",
label(),
control_input[i].connected_port()->name());
}
control_input[i].disconnect();
if ( o )
{
if ( ! o->is_default() )
{
DMESSAGE( "Deleting connected module %s", o->label() );
delete o;
}
}
}
control_input[i].destroy_osc_port();
}
for ( unsigned int i = 0; i < control_output.size(); ++i )
control_output[i].disconnect();
aux_audio_output.clear();
aux_audio_input.clear();
audio_input.clear();
audio_output.clear();
@ -156,7 +169,9 @@ Module::init ( void )
_chain = 0;
_instances = 1;
_bypass = 0;
_base_label = NULL;
_number = -2; /* magic number indicates old instance, before numbering */
box( FL_UP_BOX );
labeltype( FL_NO_LABEL );
align( FL_ALIGN_CENTER | FL_ALIGN_INSIDE );
@ -164,7 +179,9 @@ Module::init ( void )
selection_color( FL_YELLOW );
labelsize(12);
color( fl_rgb_color( 122,190,200 ) );
color( fl_color_average( fl_rgb_color( 0x3a, 0x99, 0x7c ), FL_BACKGROUND_COLOR, 1.0f ));
tooltip();
}
@ -192,6 +209,8 @@ Module::get ( Log_Entry &e ) const
e.add( ":is_default", is_default() );
e.add( ":chain", chain() );
e.add( ":active", ! bypass() );
if ( number() >= 0 )
e.add( ":number", number() );
}
bool
@ -222,7 +241,8 @@ Module::copy ( void ) const
/* we don't want this module to get added to the current
chain... */
if ( !( !strcmp( s, ":chain" ) ||
!strcmp( s, ":is_default" ) ) )
!strcmp( s, ":is_default" ) ||
!strcmp( s, ":number" ) ) )
{
DMESSAGE( "%s = %s", s, v );
ne->add_raw( s, v );
@ -235,6 +255,7 @@ Module::copy ( void ) const
return true;
}
void
Module::paste_before ( void )
{
@ -251,6 +272,8 @@ Module::paste_before ( void )
m->set( le );
m->number(-1);
if ( ! chain()->insert( this, m ) )
{
fl_alert( "Copied module cannot be inserted at this point in the chain" );
@ -264,22 +287,48 @@ Module::paste_before ( void )
m->copy();
}
void
Module::number ( int v )
{
_number = v;
char s[255];
if ( v > 0 && !is_default() )
snprintf( s, sizeof(s), "%s.%i", base_label(), v );
else
snprintf( s, sizeof(s), "%s", base_label() );
copy_label( s );
}
void
Module::base_label ( const char *s )
{
if ( _base_label )
free( _base_label );
_base_label = NULL;
if ( s )
_base_label = strdup(s);
}
void
Module::Port::disconnect_from_strip ( Mixer_Strip *o )
{
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); i++ )
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); )
{
Port *p = *i;
i++; /* iterator trick */
if ( p->module()->chain()->strip() == o )
{
/* iterator about to be invalidated... */
i = _connected.erase(i);
disconnect(p);
}
}
}
}
@ -319,8 +368,11 @@ Module::Port::osc_number_path ( void )
}
void
Module::Port::send_feedback ( void )
Module::Port::send_feedback ( bool force )
{
if ( !force && !_pending_feedback )
return;
float f = control_value();
if ( hints.ranged )
@ -333,26 +385,53 @@ Module::Port::send_feedback ( void )
f = ( f - offset ) / scale;
}
if ( f > 1.0 )
f = 1.0;
else if ( f < 0.0 )
f = 0.0;
if ( f > 1.0f )
f = 1.0f;
else if ( f < 0.0f )
f = 0.0f;
/* struct timespec t; */
/* clock_gettime( CLOCK_MONOTONIC, &t ); */
/* /\* don't send feedback more at more than 30Hz rate. *\/ */
/* unsigned long long ms = (t.tv_sec * 1000 + ( t.tv_nsec / 1000000 )); */
/* if ( ms - _feedback_milliseconds < 1000 / 30 ) */
/* return; */
/* _feedback_milliseconds = ms; */
if ( _scaled_signal )
{
/* send feedback for by_name signal */
mixer->osc_endpoint->send_feedback( _scaled_signal->path(), f );
/* send feedback for by number signal */
mixer->osc_endpoint->send_feedback( osc_number_path(), f );
/* if ( fabsf( _feedback_value - f ) > (1.0f / 128.0f) ) */
{
/* only send feedback if value has changed significantly since the last time we sent it. */
/* DMESSAGE( "signal value: %f, controL_value: %f", _scaled_signal->value(), f ); */
/* send feedback for by_name signal */
mixer->osc_endpoint->send_feedback( _scaled_signal->path(), f, force );
/* send feedback for by number signal */
mixer->osc_endpoint->send_feedback( osc_number_path(), f, force );
/* _feedback_value = f; */
_pending_feedback = false;
/* _scaled_signal->value( f ); */
}
}
}
void
Module::send_feedback ( void )
Module::schedule_feedback ( void )
{
for ( int i = 0; i < ncontrol_inputs(); i++ )
control_input[i].send_feedback();
control_input[i].schedule_feedback();
}
void
Module::send_feedback ( bool force )
{
for ( int i = 0; i < ncontrol_inputs(); i++ )
control_input[i].send_feedback(force);
}
void
@ -361,7 +440,11 @@ Module::handle_control_changed ( Port *p )
if ( _editor )
_editor->handle_control_changed ( p );
p->send_feedback();
p->schedule_feedback();
/* DMESSAGE("Control changed"); */
/* p->send_feedback(false); */
}
/* bool */
@ -387,12 +470,7 @@ Module::Port::generate_osc_path ()
return NULL;
}
int n = module()->chain()->get_module_instance_number( module() );
if ( n > 0 )
asprintf( &path, "/strip/%s/%s.%i/%s", module()->chain()->name(), p->module()->label(), n, p->name() );
else
asprintf( &path, "/strip/%s/%s/%s", module()->chain()->name(), p->module()->label(), p->name() );
asprintf( &path, "/strip/%s/%s/%s", module()->chain()->name(), p->module()->label(), p->name() );
char *s = escape_url( path );
@ -531,6 +609,24 @@ Module::Port::osc_control_change_cv ( float v, void *user_data )
void
Module::set ( Log_Entry &e )
{
/* have to do this before adding to chain... */
int n = -2;
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
e.get( i, &s, &v );
if ( ! strcmp(s, ":number" ) )
{
n = atoi(v);
}
}
number(n);
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
@ -614,18 +710,21 @@ Module::chain ( Chain *v )
char *
Module::get_parameters ( void ) const
{
char *s = new char[1024];
int len = control_input.size() * 50;
char *s = new char[ len ];
s[0] = 0;
char *sp = s;
if ( control_input.size() )
{
for ( unsigned int i = 0; i < control_input.size(); ++i )
sp += snprintf( sp, 1024 - (sp - s),"%f:", control_input[i].control_value() );
sp += snprintf( sp, len - (sp - s),"%f:", control_input[i].control_value() );
*(sp - 1) = '\0';
}
/* DMESSAGE("get_parameters: %s",s); */
return s;
}
@ -677,6 +776,9 @@ Module::draw_box ( int tx, int ty, int tw, int th )
Fl_Color c = color();
if ( bypass() )
c = fl_darker(fl_darker(c));
if ( ! active_r() )
c = fl_inactive( c );
@ -767,8 +869,14 @@ Module::draw_label ( int tx, int ty, int tw, int th )
Fl_Color c = fl_contrast( FL_FOREGROUND_COLOR, color() );
fl_color( active_r() && ! bypass() ? c : fl_inactive(c) );
if ( bypass() )
c = fl_darker(c);
/* fl_color( active_r() && ! bypass() ? c : fl_inactive(c) ); */
if ( !active_r() )
c = fl_inactive(c);
fl_font( FL_HELVETICA, labelsize() );
char *di = strstr( lab, " -" );
@ -817,15 +925,18 @@ Module::draw_label ( int tx, int ty, int tw, int th )
}
fl_color( c );
fl_draw( s ? s : lab, tx, ty, tw, th, align() | FL_ALIGN_CLIP );
if ( bypass() )
{
fl_color( fl_color_add_alpha( fl_color(), 127 ) );
fl_line_style( FL_SOLID, 2 );
fl_line( tx, ty + th * 0.5, tx + tw, ty + th * 0.5 );
fl_line_style( FL_SOLID, 0 );
}
/* if ( bypass() ) */
/* { */
/* fl_color( fl_color_add_alpha( fl_color(), 127 ) ); */
/* fl_line_style( FL_SOLID, 2 ); */
/* fl_line( tx, ty + th * 0.5, tx + tw, ty + th * 0.5 ); */
/* fl_line_style( FL_SOLID, 0 ); */
/* } */
free(lab);
@ -846,19 +957,7 @@ Module::insert_menu_cb ( const Fl_Menu_ *m )
if ( !strcmp( picked, "Aux" ) )
{
int n = 0;
for ( int i = 0; i < chain()->modules(); i++ )
{
if ( !strcmp( chain()->module(i)->name(), "AUX" ) )
n++;
}
AUX_Module *jm = new AUX_Module();
jm->chain( chain() );
jm->number( n );
jm->configure_inputs( ninputs() );
jm->configure_outputs( ninputs() );
jm->initialize();
mod = jm;
}
@ -876,9 +975,6 @@ Module::insert_menu_cb ( const Fl_Menu_ *m )
Spatializer_Module *jm = new Spatializer_Module();
jm->chain( chain() );
// jm->number( n );
// jm->configure_inputs( ninputs() );
// jm->configure_outputs( ninputs() );
jm->initialize();
mod = jm;
@ -886,8 +982,6 @@ Module::insert_menu_cb ( const Fl_Menu_ *m )
}
else if ( !strcmp( picked, "Gain" ) )
mod = new Gain_Module();
/* else if ( !strcmp( picked, "Spatializer" ) ) */
/* mod = new Spatializer_Module(); */
else if ( !strcmp( picked, "Meter" ) )
mod = new Meter_Module();
else if ( !strcmp( picked, "Mono Pan" ))
@ -908,6 +1002,8 @@ Module::insert_menu_cb ( const Fl_Menu_ *m )
if ( mod )
{
mod->number(-1);
if ( ! chain()->insert( this, mod ) )
{
fl_alert( "Cannot insert this module at this point in the chain" );
@ -1180,7 +1276,19 @@ Module::freeze_ports ( void )
for ( int i = 0; i < ncontrol_inputs(); ++i )
{
if ( control_input[i].connected() )
control_input[i].connected_port()->module()->freeze_ports();
{
if ( ! control_input[i].connected_port()->module() )
{
DWARNING( "Programming error. Connected port has null module. %s %s",
name(),
control_input[i].connected_port()->name());
}
else
{
control_input[i].connected_port()->module()->freeze_ports();
}
}
}
for ( unsigned int i = 0; i < aux_audio_input.size(); ++i )
@ -1247,10 +1355,10 @@ Module::auto_disconnect_outputs ( void )
{
Module::Port *p = &aux_audio_output[i];
if ( p->connected_port() )
while ( p->connected() )
{
p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
p->disconnect();
p->connected_port()->jack_port()->disconnect( p->jack_port()->jack_name() );
p->disconnect(p->connected_port());
}
}
}

View File

@ -46,14 +46,17 @@ class Module : public Fl_Group, public Loggable {
int _ins;
int _outs;
int _instances;
nframes_t _nframes;
Chain *_chain;
bool _is_default;
char *_base_label;
nframes_t _nframes;
static nframes_t _sample_rate;
static Module *_copied_module_empty;
static char *_copied_module_settings;
int _number;
void init ( void );
void insert_menu_cb ( const Fl_Menu_ *m );
@ -74,6 +77,13 @@ protected:
public:
virtual int number ( void ) const { return _number; }
virtual void number ( int v );
virtual const char * base_label ( void ) const { return _base_label ? _base_label : name(); }
virtual void base_label ( const char * );
virtual nframes_t get_module_latency ( void ) const { return 0; }
virtual void get_latency ( JACK::Port::direction_e dir, nframes_t *min, nframes_t *max ) const;
@ -103,6 +113,7 @@ public:
connected_port()->_buf = _buf;
}
public:
enum Direction { INPUT, OUTPUT };
@ -120,7 +131,7 @@ public:
float default_value;
int dimensions;
bool visible;
Hints ( )
{
type = LINEAR;
@ -153,6 +164,9 @@ public:
_by_number_path = 0;
_by_number_number = -1;
_jack_port = 0;
/* _feedback_value = -2; */
_pending_feedback = false;
_feedback_milliseconds = 0;
}
Port ( const Port& p )
@ -169,21 +183,27 @@ public:
_by_number_path = 0;
_by_number_number = -1;
_jack_port = p._jack_port;
/* _feedback_value = p._feedback_value; */
}
virtual ~Port ( )
{
/* FIXME: will this cause problems with cloning an instance? */
disconnect();
if ( _by_number_path )
free( _by_number_path );
_by_number_path = NULL;
}
nframes_t nframes ( void ) const { return _nframes; }
void nframes ( nframes_t n) { _nframes = n; }
const char *name ( void ) const { return _name; }
Type type ( void ) const { return _type; }
Direction direction ( void ) const { return _direction; }
Module * module ( void ) const { return _module; }
nframes_t nframes ( void ) const { return _nframes; }
void buffer ( void *buf, nframes_t nframes ) { _buf = buf; _nframes = nframes; };
void *buffer ( void ) const { return _buf; }
@ -253,14 +273,27 @@ public:
/* control and external audio ports belong to a graph */
return _connected.size() > 0;
}
unsigned int nconnected ( void ) const { return _connected.size(); }
bool connected_osc ( void ) const;
Port *connected_port ( void ) const
{
ASSERT( _type == Port::CONTROL, "Operation only available for control ports" );
return _connected.size() == 0 ? NULL : _connected.front();
}
Port *connected_port ( int n ) const
{
int j = 0;
for ( std::list<Module::Port*>::const_iterator i = _connected.begin();
i != _connected.end(); ++i, ++j )
if ( j == n )
return *i;
return NULL;
}
void connect_to ( Port *to )
{
if ( _type != Port::AUX_AUDIO )
@ -295,7 +328,7 @@ public:
_buf = buf;
}
void send_feedback ( void );
void send_feedback ( bool force );
bool connected_to ( Port *p )
{
@ -321,23 +354,15 @@ public:
/* disconnect from *all* connected ports */
void disconnect ( void )
{
if ( _connected.size() )
{
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); i++ )
{
Port *p = *i;
/* iterator about to be invalidated... */
i = _connected.erase(i);
disconnect(p);
}
}
}
while ( _connected.size() )
disconnect(_connected.front());
}
void jack_port ( JACK::Port *v ) { _jack_port = v; }
JACK::Port *jack_port ( void ) const { return _jack_port; }
void schedule_feedback ( void ) { _pending_feedback = true; }
private:
char *generate_osc_path ( void );
@ -356,6 +381,10 @@ public:
OSC::Signal *_scaled_signal;
OSC::Signal *_unscaled_signal;
/* float _feedback_value; */
bool _pending_feedback;
unsigned long long _feedback_milliseconds;
static void handle_signal_connection_state_changed ( OSC::Signal *, void *o );
};
@ -375,7 +404,6 @@ public:
LOG_NAME_FUNC( Module );
nframes_t nframes ( void ) const { return _nframes; }
virtual void resize_buffers ( nframes_t v ) { _nframes = v; }
@ -496,7 +524,8 @@ public:
bool show_analysis_window ( void );
void send_feedback ( void );
void send_feedback ( bool force );
void schedule_feedback ( void );
virtual bool initialize ( void ) { return true; }
/* for the given number of inputs, return how many outputs this
@ -555,7 +584,9 @@ protected:
bool add_aux_port ( bool input, const char *prefix, int n , JACK::Port::type_e type );
public:
nframes_t sample_rate ( void ) const { return Module::_sample_rate; }
static nframes_t sample_rate ( void ) { return Module::_sample_rate; }
nframes_t nframes ( void ) { return _nframes; }
void auto_connect_outputs();
@ -568,7 +599,7 @@ public:
bool add_aux_audio_input ( const char *prefix, int n );
bool add_aux_cv_input ( const char *prefix, int n );
static void set_sample_rate ( nframes_t srate ) { _sample_rate = srate; }
static void sample_rate ( nframes_t srate ) { _sample_rate = srate; }
void command_open_parameter_editor();
virtual void command_activate ( void );

View File

@ -174,8 +174,8 @@ Module_Parameter_Editor::make_controls ( void )
control_pack->clear();
{ SpectrumView *o = spectrum_view = new SpectrumView( 25, 40, 300, 240, "Spectrum" );
o->labelsize(9);
{ SpectrumView *o = spectrum_view = new SpectrumView( 25, 40, 360, 300, "Spectrum" );
o->labelsize(14);
o->align(FL_ALIGN_TOP);
@ -199,7 +199,7 @@ Module_Parameter_Editor::make_controls ( void )
float radius_value = 0.0f;
Fl_Color fc = fl_color_add_alpha( FL_CYAN, 200 );
Fl_Color bc = FL_BACKGROUND2_COLOR;
Fl_Color bc = FL_BACKGROUND_COLOR;
controls_by_port.resize( module->control_input.size() );
@ -210,7 +210,7 @@ Module_Parameter_Editor::make_controls ( void )
control_pack->flow(true);
control_pack->flowdown(true);
control_pack->type( FL_HORIZONTAL );
control_pack->size( 900, 240 );
control_pack->size( 900, 300 );
}
else if ( mode_choice->value() == 2 )
{
@ -306,11 +306,11 @@ Module_Parameter_Editor::make_controls ( void )
o->minimum( p->hints.minimum );
o->maximum( p->hints.maximum );
}
o->color( bc );
o->color( FL_BACKGROUND_COLOR );
o->selection_color( fc );
o->value( p->control_value() );
o->align(FL_ALIGN_TOP);
o->box( FL_DOWN_BOX );
o->box( FL_FLAT_BOX );
/* a couple of plugins have ridiculously small units */
float r = fabs( p->hints.maximum - p->hints.minimum );
@ -383,11 +383,12 @@ Module_Parameter_Editor::make_controls ( void )
o->color( bc );
o->selection_color( fc );
o->value( p->control_value() );
o->box( FL_BORDER_BOX );
}
}
// w->align(FL_ALIGN_TOP);
w->labelsize( 10 );
w->labelsize( 14 );
controls_by_port[i] = w;
@ -422,7 +423,7 @@ Module_Parameter_Editor::make_controls ( void )
o->align(FL_ALIGN_TOP);
o->when(FL_WHEN_CHANGED);
o->label( "Spatialization" );
o->labelsize( 10 );
o->labelsize( 14 );
_callback_data.push_back( callback_data( this, azimuth_port_number, elevation_port_number, radius_port_number ) );
o->callback( cb_panner_value_handle, &_callback_data.back() );

View File

@ -66,8 +66,22 @@ Mono_Pan_Module::handle_sample_rate_change ( nframes_t n )
}
bool
Mono_Pan_Module::configure_inputs ( int )
Mono_Pan_Module::configure_inputs ( int n )
{
THREAD_ASSERT( UI );
int on = audio_input.size();
if ( n > on )
{
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
}
else if ( n < on )
{
audio_input.back().disconnect();
audio_input.pop_back();
}
return true;
}
@ -82,7 +96,10 @@ Mono_Pan_Module::process ( nframes_t nframes )
{
if ( unlikely( bypass() ) )
{
buffer_copy( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes );
if ( audio_input.size() == 1 )
{
buffer_copy( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes );
}
}
else
{
@ -90,11 +107,18 @@ Mono_Pan_Module::process ( nframes_t nframes )
sample_t gainbuf[nframes];
bool use_gainbuf = smoothing.apply( gainbuf, nframes, gt );
if ( audio_input.size() == 2 )
{
/* convert stereo to mono */
buffer_mix( (sample_t*)audio_input[0].buffer(),
(sample_t*)audio_input[1].buffer(),
nframes );
}
if ( unlikely( use_gainbuf ) )
{
/* right channel */
/* right channel */
buffer_copy_and_apply_gain_buffer( (sample_t*)audio_output[1].buffer(),
(sample_t*)audio_input[0].buffer(),
gainbuf,

View File

@ -33,7 +33,7 @@ public:
const char *name ( void ) const { return "Mono Pan"; }
int can_support_inputs ( int n ) { return ( n == 1 ) ? 2 : -1; }
int can_support_inputs ( int n ) { return ( n == 1 || n == 2 ) ? 2 : -1; }
bool configure_inputs ( int n );
LOG_CREATE_FUNC( Mono_Pan_Module );

View File

@ -56,6 +56,7 @@ Panner::Panner ( int X, int Y, int W, int H, const char *L ) :
o->add("5 Meters",0,0,&ranges[2]);
o->add("10 Meters",0,0,&ranges[3]);
o->add("15 Meters",0,0,&ranges[4]);
o->textcolor( fl_contrast( FL_GRAY0, FL_FOREGROUND_COLOR ));
o->value(_range_mode);
o->callback( cb_mode, this );
}
@ -69,6 +70,7 @@ Panner::Panner ( int X, int Y, int W, int H, const char *L ) :
o->add("Spherical");
o->add("Planar");
o->value(_projection_mode);
o->textcolor( fl_contrast( FL_GRAY0, FL_FOREGROUND_COLOR ));
o->callback( cb_mode, this );
}
@ -378,7 +380,7 @@ Panner::draw ( void )
if ( ! p->visible )
continue;
Fl_Color c = fl_color_add_alpha( p->color, 100 );
Fl_Color c = fl_color_add_alpha( p->color, 150 );
fl_color(c);

View File

@ -66,6 +66,8 @@ Plugin_Module::Plugin_Module ( ) : Module( 50, 35, name() )
{
init();
color( fl_color_average( fl_rgb_color( 0x99, 0x7c, 0x3a ), FL_BACKGROUND_COLOR, 1.0f ));
end();
log_create();
@ -96,6 +98,24 @@ Plugin_Module::get ( Log_Entry &e ) const
void
Plugin_Module::set ( Log_Entry &e )
{
int n = 0;
/* we need to have number() defined before we create the control inputs in load() */
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
e.get( i, &s, &v );
if ( ! strcmp(s, ":number" ) )
{
n = atoi(v);
}
}
/* need to call this to set label even for version 0 modules */
number(n);
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
@ -441,11 +461,15 @@ Plugin_Module::load ( unsigned long id )
{
/* unknown plugin ID */
WARNING( "Unknown plugin ID: %lu", id );
label( "----" );
char s[25];
snprintf( s, 24, "! %lu", id );
base_label( s );
return false;
}
label( _idata->descriptor->Name );
base_label( _idata->descriptor->Name );
if ( _idata->descriptor )
{

View File

@ -58,7 +58,7 @@ char Project::_name[256];
char Project::_created_on[40];
char Project::_path[512];
bool Project::_is_open = false;
bool Project::_is_opening = false;
bool Project::_is_opening_closing = false;
int Project::_lockfd = 0;
@ -193,6 +193,8 @@ Project::close ( void )
if ( ! save() )
return false;
Project::_is_opening_closing = true;
Loggable::close();
/* // write_info(); */
@ -203,6 +205,8 @@ Project::close ( void )
release_lock( &_lockfd, ".lock" );
Project::_is_opening_closing = false;
return true;
}
@ -262,7 +266,7 @@ Project::open ( const char *name )
if ( version != PROJECT_VERSION )
return E_VERSION;
_is_opening = true;
_is_opening_closing = true;
if ( ! Loggable::replay( "snapshot" ) )
return E_INVALID;
@ -282,7 +286,7 @@ Project::open ( const char *name )
_is_open = true;
_is_opening = false;
_is_opening_closing = false;
// tle->load_timeline_settings();
// timeline->zoom_fit();

View File

@ -27,7 +27,7 @@ class Project
static int _lockfd;
static bool _is_open;
static bool _is_opening;
static bool _is_opening_closing;
static char _name[256];
static char _path[512];
static char _created_on[40];
@ -62,5 +62,5 @@ public:
static const char *path ( void ) { return _path; }
static const char *created_on ( void ) { return _created_on; }
static const bool is_opening ( void ) { return _is_opening; }
static const bool is_opening_closing ( void ) { return _is_opening_closing; }
};

View File

@ -536,6 +536,8 @@ Spatializer_Module::Spatializer_Module ( ) : JACK_Module ( false )
early_gain_smoothing.sample_rate( sample_rate() );
delay_smoothing.cutoff( 0.5f );
delay_smoothing.sample_rate( sample_rate() );
azimuth_smoothing.sample_rate( sample_rate() );
elevation_smoothing.sample_rate( sample_rate() );
}
Spatializer_Module::~Spatializer_Module ( )
@ -557,6 +559,8 @@ Spatializer_Module::handle_sample_rate_change ( nframes_t n )
delay_smoothing.sample_rate( n );
early_gain_smoothing.sample_rate( n );
late_gain_smoothing.sample_rate( n );
azimuth_smoothing.sample_rate( n );
elevation_smoothing.sample_rate( n );
for ( unsigned int i = 0; i < audio_input.size(); i++ )
{
@ -626,9 +630,13 @@ Spatializer_Module::process ( nframes_t nframes )
sample_t gainbuf[nframes];
sample_t delaybuf[nframes];
sample_t azimuthbuf[nframes];
sample_t elevationbuf[nframes];
bool use_gainbuf = false;
bool use_delaybuf = delay_smoothing.apply( delaybuf, nframes, delay_seconds );
bool use_azimuthbuf = azimuth_smoothing.apply( azimuthbuf, nframes, azimuth );
bool use_elevationbuf = elevation_smoothing.apply( elevationbuf, nframes, elevation );
for ( unsigned int i = 0; i < audio_input.size(); i++ )
{
@ -655,12 +663,30 @@ Spatializer_Module::process ( nframes_t nframes )
buffer_apply_gain( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), nframes, late_gain );
}
float early_angle = azimuth - angle;
if ( early_angle > 180.0f )
early_angle = -180 - ( early_angle - 180 );
else if ( early_angle < -180.0f )
early_angle = 180 - ( early_angle + 180 );
if ( !use_azimuthbuf )
{
/* for ( nframes_t i = 0; i < nframes; ++i ) */
azimuthbuf[0] = azimuth + angle;
}
else
{
/* for ( nframes_t i = 0; i < nframes; ++i ) */
azimuthbuf[0] += angle;
}
if ( !use_elevationbuf )
elevationbuf[0] = elevation;
azimuth = azimuthbuf[0];
elevation = elevationbuf[0];
/* send to early reverb */
if ( audio_input.size() == 1 )
{

View File

@ -32,6 +32,8 @@ class Spatializer_Module : public JACK_Module
Value_Smoothing_Filter delay_smoothing;
Value_Smoothing_Filter late_gain_smoothing;
Value_Smoothing_Filter early_gain_smoothing;
Value_Smoothing_Filter azimuth_smoothing;
Value_Smoothing_Filter elevation_smoothing;
std::vector<filter*> _lowpass;
std::vector<filter*> _highpass;

View File

@ -218,10 +218,19 @@ main ( int argc, char **argv )
char *name = strdup( argv[0] );
char *n = basename( name );
if ( ! strcmp( n, "non-mixer-noui" ) )
if ( ! strcmp( n, "non-mixer-noui" ) )
{
DMESSAGE("Not running UI: invoked as non-mixer-noui");
no_ui = true;
}
free( name );
if ( NULL == getenv("DISPLAY") )
{
DMESSAGE("Not running UI: $DISPLAY environment variable unset");
no_ui = true;
}
}
if ( ! no_ui )
@ -313,7 +322,6 @@ main ( int argc, char **argv )
}
else
{
DMESSAGE( "Not Running UI..." );
while ( ! got_sigterm )
{
Fl::wait(2147483.648); /* magic number means forever */

View File

@ -1,4 +1,3 @@
/*******************************************************************************/
/* Copyright (C) 2013 Jonathan Moore Liles */
/* */
@ -25,6 +24,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <math.h>
using namespace MIDI;
@ -48,11 +48,15 @@ const char *APP_NAME = "non-midi-mapper";
#undef APP_TITLE
const char *APP_TITLE = "Non-MIDI-Mapper";
#undef VERSION
const char *VERSION = "1.0";
const char *VERSION = "1.1";
const int FILE_VERSION = 1;
nsm_client_t *nsm;
char *instance_name;
static nframes_t buffers = 0;
OSC::Endpoint *osc = 0;
/* const double NSM_CHECK_INTERVAL = 0.25f; */
@ -121,9 +125,9 @@ public:
Engine ( )
{
input_ring_buf = jack_ringbuffer_create( 16 * 16 * sizeof( jack_midi_event_t ));
input_ring_buf = jack_ringbuffer_create( 32 * 32 * sizeof( jack_midi_event_t ));
jack_ringbuffer_reset( input_ring_buf );
output_ring_buf = jack_ringbuffer_create( 16 * 16 * sizeof( jack_midi_event_t ));
output_ring_buf = jack_ringbuffer_create( 32 * 32 * sizeof( jack_midi_event_t ));
jack_ringbuffer_reset( output_ring_buf );
midi_input_port = 0;
@ -134,20 +138,33 @@ public:
{
deactivate();
}
int process ( nframes_t nframes )
{
++buffers;
/* process input */
{
if ( !midi_input_port )
return 0;
/* jack_position_t pos; */
/* jack_transport_query( this->jack_client(), &pos ); */
void *buf = midi_input_port->buffer( nframes );
jack_midi_event_t ev;
jack_nframes_t count = jack_midi_get_event_count( buf );
/* if ( count > 0 ) */
/* { */
/* DMESSAGE( "Event count: %lu", count); */
/* } */
/* place MIDI events into ringbuffer for non-RT thread */
for ( uint i = 0; i < count; ++i )
@ -155,15 +172,26 @@ public:
// MESSAGE( "Got midi input!" );
jack_midi_event_get( &ev, buf, i );
midievent e;
/* e.timestamp( pos.frame + ev.time ); */
e.timestamp( ev.time );
e.status( ev.buffer[0] );
e.lsb( ev.buffer[1] );
if ( ev.size == 3 )
e.msb( ev.buffer[2] );
else
e.msb( 0 );
/* /\* time is frame within cycle, convert to absolute tick *\/ */
/* e.timestamp( ph + (ev.time / transport.frames_per_tick) ); */
/* e.status( ev.buffer[0] ); */
/* e.lsb( ev.buffer[1] ); */
/* if ( ev.size == 3 ) */
/* e.msb( ev.buffer[2] ); */
if ( jack_ringbuffer_write( input_ring_buf, (char*)&ev, sizeof( jack_midi_event_t ) ) != sizeof( jack_midi_event_t ) )
if ( jack_ringbuffer_write( input_ring_buf, (char*)&e, sizeof( midievent ) ) != sizeof( midievent ) )
WARNING( "input buffer overrun" );
}
}
@ -229,7 +257,8 @@ public:
Engine *engine;
const float MAX_NRPN = 16383.0f;
const unsigned int MAX_14BIT = 16383;
const unsigned int MAX_7BIT = 127;
static char
get_lsb( int i )
@ -243,29 +272,48 @@ get_msb( int i )
return ( i >> 7 ) & 0x7F;
}
static int
static unsigned int
get_14bit ( char msb, char lsb )
{
return msb * 128 + lsb;
}
{
return msb * (MAX_7BIT + 1) + lsb;
}
class signal_mapping
{
public:
bool is_nrpn;
// int nrpn;
bool is_nrpn14;
bool is_toggle;
midievent event;
std::string signal_name;
OSC::Signal *signal;
nframes_t last_midi_tick;
nframes_t last_feedback_tick;
int learning_value_msb;
int learning_value_lsb;
bool is_learning ( )
{
return NULL == signal;
}
signal_mapping ( )
{
is_nrpn = false;
is_nrpn14 = false;
is_toggle =- false;
signal = NULL;
last_midi_tick = 0;
last_feedback_tick = 0;
learning_value_lsb = 0;
learning_value_msb = 0;
}
~signal_mapping ( )
@ -275,37 +323,37 @@ public:
signal = NULL;
}
char *serialize ( void ) const
{
char *s;
const char *opcode = 0;
int v1 = 0;
/* char *serialize ( void ) const */
/* { */
/* char *s; */
/* const char *opcode = 0; */
/* int v1 = 0; */
if ( is_nrpn )
{
opcode = "NRPN";
v1 = get_14bit( event.msb(), event.lsb() );
}
else
switch ( event.opcode() )
{
case MIDI::midievent::CONTROL_CHANGE:
opcode = "CC";
v1 = event.lsb();
break;
case MIDI::midievent::NOTE_ON:
opcode = "NOTE_ON";
v1 = event.note();
break;
default:
// unsupported
break;
}
/* if ( is_nrpn ) */
/* { */
/* opcode = is_nrpn14 ? "NRPN14" : "NRPN"; */
/* v1 = get_14bit( event.msb(), event.lsb() ); */
/* } */
/* else */
/* switch ( event.opcode() ) */
/* { */
/* case MIDI::midievent::CONTROL_CHANGE: */
/* opcode = "CC"; */
/* v1 = event.lsb(); */
/* break; */
/* case MIDI::midievent::NOTE_ON: */
/* opcode = "NOTE_ON"; */
/* v1 = event.note(); */
/* break; */
/* default: */
/* // unsupported */
/* break; */
/* } */
asprintf( &s, "%s %d %d", opcode, event.channel(), v1 );
/* asprintf( &s, "%s %d %d%s", opcode, event.channel(), v1, is_toggle ? " T" : "" ); */
return s;
}
/* return s; */
/* } */
void deserialize ( const char *s )
{
@ -313,16 +361,16 @@ public:
char *opcode;
int control;
if ( 3 == sscanf( s, "%ms %d %d", &opcode, &channel, &control ) )
if ( 3 == sscanf( s, "%ms %d %d", &opcode, &channel, &control ) )
{
event.channel( channel );
event.opcode( MIDI::midievent::CONTROL_CHANGE );
is_nrpn = 0;
is_nrpn = false;
if ( !strcmp( opcode, "NRPN" ) )
{
is_nrpn = 1;
is_nrpn = true;
event.lsb( get_lsb( control ));
event.msb( get_msb( control ));
@ -334,6 +382,10 @@ public:
free(opcode);
}
else
{
DMESSAGE( "Failed to parse midi event descriptor: %s", s );
}
}
};
@ -341,7 +393,15 @@ public:
int signal_handler ( float value, void *user_data )
{
signal_mapping *m = (signal_mapping*)user_data;
/* DMESSAGE( "Received value: %f", value ); */
m->last_feedback_tick = buffers;
/* magic number to give a release time to prevent thrashing. */
/* if ( ! ( m->last_feedback_tick > m->last_midi_tick + 4 )) */
/* return 0; */
if ( m->is_nrpn )
{
jack_midi_event_t jev[4];
@ -373,7 +433,7 @@ int signal_handler ( float value, void *user_data )
e.opcode( MIDI::midievent::CONTROL_CHANGE );
e.channel( m->event.channel() );
e.lsb( 6 );
e.msb( int(value * MAX_NRPN ) >> 7 );
e.msb( (int)(value * (float)MAX_14BIT) >> 7 );
jev[2].size = e.size();
e.raw( (byte_t*)&jev[2], e.size() );
// e.pretty_print();
@ -384,7 +444,7 @@ int signal_handler ( float value, void *user_data )
e.opcode( MIDI::midievent::CONTROL_CHANGE );
e.channel( m->event.channel() );
e.lsb( 38 );
e.msb( int( value * MAX_NRPN ) & 0x7F );
e.msb( (int)(value * (float)MAX_14BIT) & 0x7F );
jev[3].size = e.size();
e.raw( (byte_t*)&jev[3], e.size() );
// e.pretty_print();
@ -401,7 +461,7 @@ int signal_handler ( float value, void *user_data )
{
jack_midi_event_t ev;
m->event.msb( value * 127.0f );
m->event.msb( value * (float)MAX_7BIT );
ev.size = m->event.size();
m->event.raw( (byte_t*)&ev, m->event.size() );
@ -416,6 +476,7 @@ int signal_handler ( float value, void *user_data )
std::map<std::string,signal_mapping> sig_map;
std::map<int,std::string> sig_map_ordered;
bool
save_settings ( void )
@ -424,19 +485,38 @@ save_settings ( void )
if ( !fp )
return false;
fprintf( fp, "# Non-MIDI-Mapper version %i\n", FILE_VERSION );
for ( std::map<std::string,signal_mapping>::const_iterator i = sig_map.begin();
i != sig_map.end();
for ( std::map<int,std::string>::const_iterator i = sig_map_ordered.begin();
i != sig_map_ordered.end();
i++ )
{
fprintf( fp, "[%s] %s\n", i->first.c_str(), i->second.signal_name.c_str() );
signal_mapping &m = sig_map[i->second.c_str()];
/* char *midi_event = m.serialize(); */
/* FIXME: instead of T and NRPN14, use 1 7 and 14 (value significant bits).
Also, use syntax like so: [NRPN 0 0] 1bit :: /foo/bar */
fprintf( fp, "%s\t%s\t%s\n",
i->second.c_str(),
// midi_event,
m.is_toggle ? "1-BIT" :
m.is_nrpn && m.is_nrpn14 ? "14-BIT" :
"7-BIT",
m.signal_name.c_str() );
/* free(midi_event); */
}
fclose(fp);
return true;
}
static int max_signal = 0;
bool
load_settings ( void )
@ -447,23 +527,55 @@ load_settings ( void )
return false;
sig_map.clear();
sig_map_ordered.clear();
char *signal_name;
char *midi_event;
char *flags = NULL;
max_signal = 0;
while ( 2 == fscanf( fp, "[%m[^]]] %m[^\n]\n", &midi_event, &signal_name ) )
int version = 0;
if ( 1 == fscanf( fp, "# Non-MIDI-Mapper version %i\n", &version ) )
{
DMESSAGE( "%s, %s", midi_event, signal_name );
}
else
{
version = 0;
rewind(fp);
}
DMESSAGE( "Detected file version %i", version);
while (
( 1 == version &&
3 == fscanf( fp, "%m[^\t]\t%m[^\t]\t%m[^\n]\n", &midi_event, &flags, &signal_name ) )
||
( 0 == version &&
2 == fscanf( fp, "[%m[^]]] %m[^\n]\n", &midi_event, &signal_name ) ) )
{
DMESSAGE( "Read mapping: %s, %s (%s)", midi_event, signal_name, flags );
if ( sig_map.find( midi_event ) == sig_map.end() )
{
++max_signal;
signal_mapping m;
m.deserialize( midi_event );
if ( flags )
{
m.is_toggle = !strcmp( "1-BIT", flags );
m.is_nrpn14 = !strcmp( "14-BIT", flags );
}
sig_map[midi_event] = m;
sig_map[midi_event].signal_name = signal_name;
sig_map[midi_event].signal = osc->add_signal( signal_name, OSC::Signal::Output, 0, 1, 0, signal_handler, &sig_map[midi_event] );
sig_map_ordered[max_signal] = midi_event;
}
free(signal_name);
@ -606,47 +718,79 @@ command_broadcast ( const char *path, lo_message msg, void *userdata )
}
enum nrpn_awaiting
{
CONTROL_MSB,
CONTROL_LSB,
VALUE_MSB,
VALUE_LSB,
COMPLETE
};
struct nrpn_state
{
char control_msb;
char control_lsb;
char value_msb;
char value_lsb;
bool decending;
byte_t control_msb;
byte_t control_lsb;
byte_t value_msb;
byte_t value_lsb;
bool value_lsb_exists;
bool complete;
nrpn_awaiting awaiting;
};
static
struct nrpn_state *
decode_nrpn ( nrpn_state *state, midievent e, int *take_action )
decode_nrpn ( nrpn_state *state, midievent e, bool *emit_one )
{
/* use a bit of state machine to allow people to misuse value LSB and value MSB CCs as regular CCs */
nrpn_state *n = &state[e.channel()];
*take_action = 0;
*emit_one = false;
switch ( e.lsb() )
{
case 6:
if ( e.msb() < n->value_msb )
n->value_lsb = 127;
else if ( e.msb() > n->value_msb )
n->value_lsb = 0;
n->value_msb = e.msb();
*take_action = 1;
return n;
if ( VALUE_MSB == n->awaiting )
{
n->value_msb = e.msb();
n->value_lsb = 0 == e.msb() ? 0 : MAX_7BIT;
n->complete = true;
n->awaiting = VALUE_LSB;
*emit_one = true;
return n;
}
break;
case 38:
n->value_lsb = e.msb();
*take_action = 1;
return n;
if ( VALUE_LSB == n->awaiting )
{
n->value_lsb_exists = true;
n->value_lsb = e.msb();
*emit_one = true;
n->complete = true;
n->awaiting = COMPLETE;
return n;
}
break;
case 99:
n->control_msb = e.msb();
n->control_lsb = 0;
return n;
case 98:
n->control_lsb = e.msb();
return n;
n->complete = false;
n->value_lsb_exists = false;
n->control_msb = e.msb();
n->control_lsb = 0;
n->awaiting = CONTROL_LSB;
n->value_msb = 0;
n->value_lsb = 0;
return n;
case 98:
n->awaiting = VALUE_MSB;
n->complete = false;
n->control_lsb = e.msb();
return n;
}
return NULL;
}
@ -659,11 +803,209 @@ sigterm_handler ( int )
got_sigterm = 1;
}
void emit_signal_for_event ( const char *midi_event, midievent &e, struct nrpn_state *st )
{
bool is_nrpn = st != NULL;
if ( sig_map.find( midi_event ) == sig_map.end() )
{
/* first time seeing this control. */
signal_mapping m;
m.event.lsb( e.lsb() );
m.event.msb( e.msb() );
m.event.opcode( e.opcode() );
m.event.channel( e.channel() );
m.is_nrpn = is_nrpn;
if ( is_nrpn )
{
m.event.lsb( st->control_lsb );
m.event.msb( st->control_msb );
if ( st->value_lsb_exists )
m.learning_value_lsb = st->value_lsb;
m.learning_value_msb = st->value_msb;
}
else
m.learning_value_msb = e.msb();
/* wait until we see it again to remember it */
DMESSAGE("First time seeing control %s, will map on next event instance.", midi_event );
sig_map[midi_event] = m;
return;
}
/* if we got this far, it means we are on the second event for a the event type being learned */
signal_mapping *m = &sig_map[midi_event];
if ( m->is_learning() )
{
/* FIXME: need to gather NRPN LSB value that (maybe) arrives between first and second event for this NRPN controller.
14-bit flag is set if there was an LSB, otherwise, 7 or 1 bit mode is applied.
In normal operation, 14-bit NRPN controls should await the LSB before sending signal, 7 and 1 bit can send on MSB.
*/
DMESSAGE( "Going to learn event %s now", midi_event );
char *s;
asprintf( &s, "/control/%i", ++max_signal );
DMESSAGE( "Creating signal %s for event %s.", s, midi_event );
bool is_toggle = false;
bool is_14bit_nrpn = false;
if ( !is_nrpn )
{
DMESSAGE( "Learning value msb: %u, msb: %u", m->learning_value_msb, e.msb() );
is_toggle = ( m->learning_value_msb == 0 && e.msb() == MAX_7BIT ) ||
( m->learning_value_msb == MAX_7BIT && e.msb() == 0 );
}
else
{
is_14bit_nrpn = m->learning_value_lsb != -1;
unsigned int val1 = get_14bit( m->learning_value_msb, m->learning_value_lsb );
unsigned int val2 = get_14bit( st->value_msb, st->value_lsb );
is_toggle = !is_14bit_nrpn
? ( m->learning_value_msb == 0 && st->value_msb == MAX_7BIT ) ||
( m->learning_value_msb == MAX_7BIT && st->value_msb == 0 )
: ( val1 == 0 && val2 == MAX_14BIT ) ||
( val1 == MAX_14BIT && val2 == 0);
}
DMESSAGE( "is toggle %i", is_toggle );
m->is_toggle = is_toggle;
m->is_nrpn14 = is_14bit_nrpn;
m->learning_value_msb = m->learning_value_lsb = 0;
m->signal_name = s;
m->signal =
osc->add_signal( s, OSC::Signal::Output, 0, 1, 0,
signal_handler,
m );
sig_map_ordered[max_signal] = midi_event;
nsm_send_is_dirty( nsm );
free(s);
}
float val = 0;
if ( is_nrpn )
{
unsigned int fbv = get_14bit( st->value_msb, st->value_lsb );
if ( m->is_nrpn14 )
val = fbv / (float)MAX_14BIT;
else /* also covers toggles */
val = st->value_msb / (float)MAX_7BIT;
}
else if ( e.opcode() == MIDI::midievent::CONTROL_CHANGE )
val = e.msb() / (float)MAX_7BIT;
else if ( e.opcode() == MIDI::midievent::PITCH_WHEEL )
val = e.pitch() / (float)MAX_14BIT;
/* DMESSAGE( "Val: %f, sigval %f", val, m->signal->value() ); */
/* wait for values to sync for continuous controls (faders and knobs) before emitting signal. For toggles, just send it immediately. */
if (
/* magic number to give a release time to prevent thrashing. */
m->last_feedback_tick > m->last_midi_tick + 100
&&
!m->is_toggle )
{
float percent_off = fabs( val - m->signal->value() ) * 100.0f;
if ( percent_off > 5 )
{
DMESSAGE( "Wating for controls to sync. %s: %f percent off target (must be < 5%) [ M:%f S:%f ] ",
m->signal_name.c_str(),
percent_off,
val,
m->signal->value()
);
return;
}
}
m->last_midi_tick = buffers;
/* DMESSAGE( "Sent value: %f", val ); */
m->signal->value( val );
}
void handle_control_change ( nrpn_state *nrpn_state, midievent &e )
{
bool emit_one = false;
char midi_event[51];
struct nrpn_state *st = decode_nrpn( nrpn_state, e, &emit_one );
if ( st != NULL &&
( VALUE_LSB == st->awaiting ||
COMPLETE == st->awaiting ) )
{
snprintf( midi_event, 50, "NRPN %d %d", e.channel(), get_14bit( st->control_msb, st->control_lsb ));
if ( VALUE_LSB == st->awaiting )
{
if ( sig_map.find(midi_event) != sig_map.end() )
{
signal_mapping &m = sig_map[midi_event];
if ( m.is_nrpn14 )
{
/* we know there's an LSB coming, so hold off on emitting until we get it */
return;
}
}
}
emit_signal_for_event(midi_event, e, st);
}
if ( st == NULL )
{
if ( e.opcode() == MIDI::midievent::CONTROL_CHANGE )
{
snprintf( midi_event, 50, "CC %d %d", e.channel(), e.lsb() );
emit_signal_for_event( midi_event, e, NULL);
}
}
}
/* else if ( e.opcode() == MIDI::midievent::PITCH_WHEEL ) */
/* asprintf( &s, "/midi/%i/PB", e.channel() ); */
int
main ( int argc, char **argv )
{
nrpn_state nrpn_state[16];
memset( &nrpn_state, 0, sizeof(struct nrpn_state) * 16 );
signal( SIGTERM, sigterm_handler );
signal( SIGHUP, sigterm_handler );
signal( SIGINT, sigterm_handler );
@ -700,10 +1042,8 @@ main ( int argc, char **argv )
DMESSAGE( "waiting for events" );
static int max_signal = 1;
jack_midi_event_t ev;
midievent e;
/* jack_midi_event_t ev; */
while ( ! got_sigterm )
{
osc->wait(20);
@ -712,92 +1052,28 @@ main ( int argc, char **argv )
if ( ! engine )
continue;
while ( jack_ringbuffer_read( engine->input_ring_buf, (char *)&ev, sizeof( jack_midi_event_t ) ) )
{
e.timestamp( ev.time );
e.status( ev.buffer[0] );
e.lsb( ev.buffer[1] );
if ( ev.size == 3 )
e.msb( ev.buffer[2] );
midievent e;
while ( jack_ringbuffer_read( engine->input_ring_buf, (char *)&e, sizeof( midievent ) ) )
{
/* midievent e; */
/* e.timestamp( ev.time ); */
/* e.status( ev.buffer[0] ); */
/* e.lsb( ev.buffer[1] ); */
/* if ( ev.size == 3 ) */
/* e.msb( ev.buffer[2] ); */
/* else */
/* e.msb( 0 ); */
/* DMESSAGE( "[%lu] %u %u %u", e.timestamp(), e.status(), e.lsb(), e.msb() ); */
switch ( e.opcode() )
{
case MIDI::midievent::CONTROL_CHANGE:
case MIDI::midievent::PITCH_WHEEL:
{
int is_nrpn = 0;
struct nrpn_state *st = decode_nrpn( nrpn_state, e, &is_nrpn );
if ( st != NULL && !is_nrpn )
continue;
char *midi_event;
if ( is_nrpn )
{
asprintf( &midi_event, "NRPN %d %d", e.channel(), get_14bit( st->control_msb, st->control_lsb ));
}
else if ( e.opcode() == MIDI::midievent::CONTROL_CHANGE )
asprintf( &midi_event, "CC %d %d", e.channel(), e.lsb() );
/* else if ( e.opcode() == MIDI::midievent::PITCH_WHEEL ) */
/* asprintf( &s, "/midi/%i/PB", e.channel() ); */
else
break;
if ( sig_map.find( midi_event ) == sig_map.end() )
{
char *s;
asprintf( &s, "/control/%i", max_signal++ );
signal_mapping m;
m.event.opcode( e.opcode() );
m.event.channel( e.channel() );
m.event.lsb( e.lsb() );
m.event.msb( e.msb() );
m.is_nrpn = is_nrpn;
if ( is_nrpn )
{
m.event.lsb( st->control_lsb );
m.event.msb( st->control_msb );
}
/* if ( is_nrpn ) */
/* m.nrpn = nrpnc_msb * 127 + nrpnc_lsb; */
MESSAGE( "creating signal %s", s );
sig_map[midi_event] = m;
sig_map[midi_event].signal_name = s;
sig_map[midi_event].signal = osc->add_signal( s, OSC::Signal::Output, 0, 1, 0, signal_handler, &sig_map[midi_event] );
nsm_send_is_dirty( nsm );
free(s);
}
float val = 0;
if ( is_nrpn )
{
val = get_14bit( st->value_msb, st->value_lsb ) / MAX_NRPN;
}
else if ( e.opcode() == MIDI::midievent::CONTROL_CHANGE )
val = e.msb() / 127.0f;
else if ( e.opcode() == MIDI::midievent::PITCH_WHEEL )
val = e.pitch() / MAX_NRPN;
// MESSAGE( "sending signal for %s = %f", s, val );
sig_map[midi_event].signal->value( val );
free( midi_event );
handle_control_change(nrpn_state,e);
break;
}
default:
@ -806,7 +1082,6 @@ main ( int argc, char **argv )
// e.pretty_print();
}
// usleep( 500 );
}

View File

@ -5,7 +5,7 @@ import string
import os
# Version of this package (even if built as a child)
PACKAGE_VERSION = '1.2.0'
PACKAGE_VERSION = '1.3.0'
# Variables for 'waf dist'
APPNAME = 'non-mixer'

View File

@ -94,7 +94,6 @@ unescape ( char *s )
char *
Log_Entry::print ( void ) const
{
/* FIXME: gross over-allocation */
char *r = (char*)malloc( 1024 );
r[0] = 0;
@ -105,20 +104,17 @@ Log_Entry::print ( void ) const
get( i, &s, &v );
/* FIXME: arbitrary limit */
char t[1024];
snprintf( t, sizeof( t ), "%s %s%s", s, v, size() == i + 1 ? "" : " " );
char *t;
asprintf( &t, "%s %s%s", s, v, size() == i + 1 ? "" : " " );
r = (char*)realloc( r, strlen(r) + strlen(t) + 1 );
strcat( r, t );
free(t);
}
char *r2 = (char*)malloc( strlen( r ) + 1 );
strcpy( r2, r );
free( r );
return r2;
return r;
}
/** sigh. parse a string of ":name value :name value" pairs into an

View File

@ -346,10 +346,18 @@ Loggable::update_id ( unsigned int id )
const char *
Loggable::escape ( const char *s )
{
static char r[512];
static size_t rl = 256;
static char *r = new char[rl + 1];
if ( strlen(s) * 2 > rl )
{
delete []r;
rl = strlen(s) * 2;
r = new char[ rl + 1 ];
}
size_t i = 0;
for ( ; *s && i < sizeof( r ); ++i, ++s )
for ( ; *s && i < rl; ++i, ++s )
{
if ( '\n' == *s )
{
@ -590,20 +598,30 @@ Loggable::snapshot ( const char *name )
{
FILE *fp;
char *tmpname;
char *tmp = NULL;
{
const char *filename = basename(name);
char *dir = (char*)malloc( (strlen(name) - strlen(filename)) + 1 );
strncpy( dir, name, strlen(name) - strlen(filename) );
asprintf( &tmp, "%s#%s", dir, filename );
free(dir);
}
asprintf( &tmpname, ".#%s", name );
if ( ! ( fp = fopen( tmpname, "w" ) ))
if ( ! ( fp = fopen( tmp, "w" ) ))
{
DWARNING( "Could not open file for writing: %s", tmp );
return false;
}
bool r = snapshot( fp );
fclose( fp );
rename( tmpname, name );
rename( tmp, name );
free(tmpname);
free(tmp);
return r;
}

View File

@ -87,19 +87,19 @@ namespace MIDI
memcpy( p, &_data, l );
}
int
byte_t
midievent::size ( void ) const
{
return midievent::event_size( opcode() );
}
void
midievent::note_velocity ( int vel )
midievent::note_velocity ( byte_t vel )
{
_data.msb = vel & 0x7F;
}
unsigned char
byte_t
midievent::note ( void ) const
{
return _data.lsb;
@ -111,7 +111,7 @@ namespace MIDI
_data.lsb = note & 0x7F;
}
unsigned char
byte_t
midievent::note_velocity ( void ) const
{
return _data.msb;

View File

@ -59,7 +59,7 @@ namespace MIDI
public:
static inline int
static inline byte_t
event_size ( byte_t op )
{
switch ( op )
@ -104,15 +104,15 @@ namespace MIDI
void opcode ( byte_t o );
void lsb ( byte_t n );
void msb ( byte_t n );
int lsb ( void ) const;
int msb ( void ) const;
byte_t lsb ( void ) const;
byte_t msb ( void ) const;
int pitch ( void ) const;
void pitch ( int n );
void data ( byte_t D1, byte_t D2 );
void data ( byte_t *D1, byte_t *D2 ) const;
void raw ( byte_t *p, int l) const;
int size ( void ) const;
void note_velocity ( int vel );
byte_t size ( void ) const;
void note_velocity ( byte_t vel );
bool is_note_on ( void ) const;
bool is_note_off ( void ) const;
virtual unsigned char note ( void ) const;
@ -198,13 +198,13 @@ namespace MIDI
_data.msb = n & 0x7F;
}
inline int
inline byte_t
midievent::lsb ( void ) const
{
return _data.lsb;
}
inline int
inline byte_t
midievent::msb ( void ) const
{
return _data.msb;

View File

@ -23,6 +23,8 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <math.h>
#include "Endpoint.H"
@ -30,6 +32,8 @@
#pragma GCC diagnostic ignored "-Wunused-parameter"
static int SCAN_BATCH_SIZE = 100;
namespace OSC
{
@ -187,6 +191,7 @@ namespace OSC
Endpoint::Endpoint ( )
{
_learning_path = NULL;
_learning_callback = NULL;
_peer_signal_notification_callback = 0;
_peer_signal_notification_userdata = 0;
_peer_scan_complete_callback = 0;
@ -685,8 +690,13 @@ namespace OSC
DMESSAGE( "Learned translation \"%s\" -> \"%s\"", path, ep->_learning_path );
free(ep->_learning_path);
ep->_learning_callback(ep->_learning_userdata);
ep->_learning_userdata = NULL;
ep->_learning_callback = NULL;
ep->_learning_path = NULL;
return 0;
}
@ -705,7 +715,9 @@ namespace OSC
i->second.current_value = argv[0]->f;
}
i->second.suppress_feedback = true;
/* FIXME: this was intended to break feedback cycles, but it actually
results in some feedback values not being sent at all */
/* i->second.suppress_feedback = true; */
lo_send_message(ep->_addr, dpath, msg );
return 0;
@ -738,34 +750,122 @@ namespace OSC
{
// OSC_DMSG();
DMESSAGE( "Listing signals." );
const char *prefix = NULL;
int skip = 0;
bool batch_mode = true;
int start;
if ( argc )
const int count = SCAN_BATCH_SIZE;
if ( 's' == types[0] )
{
prefix = &argv[0]->s;
DMESSAGE( "Listing signals for prefix \"%s\"", prefix );
skip++;
batch_mode = 2 == argc;
}
else
{
DMESSAGE( "Listing all signals." );
}
if ( 0 == argc || 's' == types[0] )
{
/* obsolete unbatched mode left for backwards compatibility... */
WARNING("Peer asked for unbatched signal list... will incur delays!");
batch_mode = false;
}
else
{
/* we have to list these in batches, otherwise they the UDP packets overrun and get dropped... Probably
wouldn't be an issue with TCP transport. */
batch_mode = true;
start = argv[0+skip]->i;
/* count = argv[1+skip]->i; */
}
Endpoint *ep = (Endpoint*)user_data;
int sent = 0;
int s = 0;
bool more = false;
lo_bundle b;
if ( batch_mode )
{
b = lo_bundle_new(LO_TT_IMMEDIATE);
}
for ( std::list<Signal*>::const_iterator i = ep->_signals.begin(); i != ep->_signals.end(); ++i )
{
Signal *o = *i;
if ( ! prefix || ! strncmp( o->path(), prefix, strlen(prefix) ) )
{
ep->send( lo_message_get_source( msg ),
"/reply",
path,
o->path(),
o->_direction == Signal::Input ? "in" : "out",
o->parameter_limits().min,
o->parameter_limits().max,
o->parameter_limits().default_value
if ( s++ < start )
continue;
/* DMESSAGE( "Listing signal %s", o->path() ); */
if ( batch_mode )
{
lo_message m = lo_message_new();
lo_message_add_string( m, path );
lo_message_add_string( m, o->path() );
lo_message_add_string( m, o->_direction == Signal::Input ? "in" : "out" );
lo_message_add_float( m, o->parameter_limits().min );
lo_message_add_float( m, o->parameter_limits().max );
lo_message_add_float( m, o->parameter_limits().default_value );
lo_bundle_add_message( b, "/reply", m );
}
else
{
ep->send( lo_message_get_source( msg ),
"/reply",
path,
o->path(),
o->_direction == Signal::Input ? "in" : "out",
o->parameter_limits().min,
o->parameter_limits().max,
o->parameter_limits().default_value
);
}
if ( batch_mode )
{
if ( ++sent == count )
{
more = true;
break;
}
}
else
{
usleep(1000);
}
}
}
ep->send( lo_message_get_source( msg ), "/reply", path );
if ( batch_mode )
{
lo_message m = lo_message_new();
lo_message_add_string(m, path);
lo_message_add_int32( m, sent );
lo_message_add_int32( m, more );
lo_bundle_add_message( b, "/reply", m );
lo_send_bundle_from( lo_message_get_source( msg ), ep->_server, b );
/* ep->send( lo_message_get_source( msg ), "/reply", path, sent, more ); */
}
else
ep->send( lo_message_get_source( msg ), "/reply", path );
return 0;
}
@ -900,13 +1000,38 @@ namespace OSC
return 0;
}
if ( argc == 1 )
if ( argc == 1 )
{
/* old handler for backwards compatibility */
p->_scanning = false;
DMESSAGE( "Done scanning %s", p->name );
if ( ep->_peer_scan_complete_callback )
ep->_peer_scan_complete_callback(ep->_peer_scan_complete_userdata);
}
else
if ( argc == 3 )
{
p->_scanning = false;
DMESSAGE( "Done scanning %s", p->name );
const int sent = argv[1]->i;
const int more = argv[2]->i;
if ( !more )
{
p->_scanning = false;
DMESSAGE( "Done scanning %s", p->name );
if ( ep->_peer_scan_complete_callback )
ep->_peer_scan_complete_callback(ep->_peer_scan_complete_userdata);
}
else
{
DMESSAGE( "Scanning next batch %s", p->name );
if ( ep->_peer_scan_complete_callback )
ep->_peer_scan_complete_callback(ep->_peer_scan_complete_userdata);
p->_scanning_current += sent;
ep->send( p->addr, "/signal/list", p->_scanning_current );
}
}
else if ( argc == 6 && p->_scanning )
{
@ -915,7 +1040,7 @@ namespace OSC
if ( s )
return 0;
DMESSAGE( "Peer %s has signal %s (%s)", p->name, &argv[1]->s, &argv[2]->s );
/* DMESSAGE( "Peer %s has signal %s (%s)", p->name, &argv[1]->s, &argv[2]->s ); */
int dir = 0;
@ -1066,29 +1191,32 @@ namespace OSC
/* prepare to learn a translation for /path/. The next unhandled message to come through will be mapped to /path/ */
void
Endpoint::learn ( const char *path )
Endpoint::learn ( const char *path, void (*callback)(void*), void *userdata )
{
if ( _learning_path )
free( _learning_path );
_learning_path = NULL;
_learning_callback = callback;
_learning_userdata = userdata;
if ( path )
_learning_path = strdup( path );
}
/** if there's a translation with a destination of 'path', then send feedback for it */
void
Endpoint::send_feedback ( const char *path, float v )
Endpoint::send_feedback ( const char *path, float v, bool force )
{
for ( std::map<std::string,TranslationDestination>::iterator i = _translations.begin();
i != _translations.end();
i++ )
{
if ( ! strcmp( i->second.path.c_str(), path ) )
if ( path && ! strcmp( i->second.path.c_str(), path ) )
{
/* found it */
if ( !i->second.suppress_feedback && i->second.current_value != v )
if ( !i->second.suppress_feedback && ( force || fabsf(i->second.current_value - v ) > 0.001f ))
{
const char *spath = i->first.c_str();
@ -1134,10 +1262,11 @@ namespace OSC
Peer *p = add_peer(name,url);
p->_scanning = true;
p->_scanning_current = 0;
DMESSAGE( "Scanning peer %s", name );
send( p->addr, "/signal/list" );
send( p->addr, "/signal/list", p->_scanning_current );
}
void *

View File

@ -120,6 +120,7 @@ namespace OSC
struct Peer
{
bool _scanning;
int _scanning_current;
char *name;
lo_address addr;
@ -241,6 +242,8 @@ namespace OSC
std::list<Method*> _methods;
char *_learning_path;
void (*_learning_callback)(void *);
void *_learning_userdata;
class TranslationDestination {
@ -304,8 +307,8 @@ namespace OSC
public:
void send_feedback ( const char *path, float v );
void learn ( const char *path );
void send_feedback ( const char *path, float v, bool force );
void learn ( const char *path, void (*callback)(void*), void *userdata );
lo_address address ( void )
{

View File

@ -48,9 +48,9 @@ buffer_apply_gain ( sample_t * __restrict__ buf, nframes_t nframes, float g )
if ( g == 1.0f )
return;
for ( nframes_t i = 0; i < nframes; i++ )
buf_[i] *= g;
while ( nframes-- )
*buf_++ *= g;
}
void
@ -58,9 +58,9 @@ buffer_apply_gain_unaligned ( sample_t * __restrict__ buf, nframes_t nframes, fl
{
if ( g == 1.0f )
return;
for ( nframes_t i = 0; i < nframes; i++ )
buf[i] *= g;
while ( nframes-- )
*buf++ *= g;
}
void
@ -69,8 +69,8 @@ buffer_apply_gain_buffer ( sample_t * __restrict__ buf, const sample_t * __restr
sample_t * buf_ = (sample_t*) assume_aligned(buf);
const sample_t * gainbuf_ = (const sample_t*) assume_aligned(gainbuf);
for ( nframes_t i = 0; i < nframes; i++ )
buf_[i] *= gainbuf_[i];
while ( nframes-- )
*buf_++ *= *gainbuf_++;
}
void
@ -79,9 +79,9 @@ buffer_copy_and_apply_gain_buffer ( sample_t * __restrict__ dst, const sample_t
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);
const sample_t * gainbuf_ = (const sample_t*) assume_aligned(gainbuf);
for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] = src_[i] * gainbuf_[i];
while ( nframes-- )
*dst_++ = *src_++ * *gainbuf_++;
}
void
@ -90,8 +90,8 @@ buffer_mix ( sample_t * __restrict__ dst, const sample_t * __restrict__ src, nfr
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);
for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] += src_[i];
while ( nframes-- )
*dst_++ += *src_++;
}
void
@ -100,8 +100,8 @@ buffer_mix_with_gain ( sample_t * __restrict__ dst, const sample_t * __restrict_
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const sample_t * src_ = (const sample_t*) assume_aligned(src);
for ( nframes_t i = 0; i < nframes; i++ )
dst_[i] += src_[i] * g;
while ( nframes-- )
*dst_++ = *src_++ * g;
}
void
@ -199,19 +199,17 @@ buffer_get_peak ( const sample_t * __restrict__ buf, nframes_t nframes )
{
const sample_t * buf_ = (const sample_t*) assume_aligned(buf);
float pmax = 0.0f;
float pmin = 0.0f;
for ( nframes_t i = 0; i < nframes; i++ )
float p = 0.0f;
while (nframes--)
{
pmax = buf_[i] > pmax ? buf_[i] : pmax;
pmin = buf_[i] < pmin ? buf_[i] : pmin;
const float v = fabsf( *buf_++ );
if ( v > p )
p = v;
}
pmax = fabsf(pmax);
pmin = fabsf(pmin);
return pmax > pmin ? pmax : pmin;
return p;
}
void
@ -237,9 +235,13 @@ Value_Smoothing_Filter::sample_rate ( nframes_t n )
w = _cutoff / (FS * T);
}
/* FIXME: need a method that just returns a single value, skipping the within-buffer interpolation */
bool
Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, float gt )
{
if ( target_reached(gt) )
return false;
sample_t * dst_ = (sample_t*) assume_aligned(dst);
const float a = 0.07f;
@ -250,9 +252,6 @@ Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, f
float g1 = this->g1;
float g2 = this->g2;
if ( target_reached(gt) )
return false;
for (nframes_t i = 0; i < nframes; i++)
{
g1 += w * (gm - g1 - a * g2);
@ -260,6 +259,8 @@ Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, f
dst_[i] = g2;
}
g2 += 1e-10f; /* denormal protection */
if ( fabsf( gt - g2 ) < 0.0001f )
g2 = gt;

View File

@ -57,6 +57,8 @@ public:
void cutoff ( float v ) { _cutoff = v; }
void reset ( float v ) { g2 = g1 = v; }
void sample_rate ( nframes_t v );
inline bool target_reached ( float gt ) const { return gt == g2; }

View File

@ -1,3 +1,4 @@
"Accoustic Bass Drum", 35, 100
"Bass Drum 1", 36, 100
"Side Stick", 37, 80
"Acoustic Snare", 38, 100
@ -20,6 +21,8 @@
"Splash Cymbal", 55, 64
"Cowbell", 56, 64
"Crash Cymbal 2", 57, 64
"Vibraslap", 58, 65
"Ride Cymbal 2", 59, 80
"Hi Bongo", 60, 100
"Low Bongo", 61, 100
"Mute Hi Conga", 62, 80

View File

@ -1,6 +1,7 @@
[Desktop Entry]
Name=Non Sequencer
Comment=Realtime MIDI sequencer for JACK MIDI
Comment[fr]=Séquenceur MIDI temps-réel pour JACK MIDI
Exec=@BIN_PATH@/non-sequencer
Terminal=false
Type=Application

View File

@ -167,7 +167,8 @@ Canvas::Canvas ( int X, int Y, int W, int H, const char *L ) : Fl_Group( X,Y,W,H
o->canvas = this;
o->box( FL_FLAT_BOX );
// o->color(fl_color_average( FL_BLACK, FL_WHITE, 0.90 ));
o->color( FL_BLACK );
/* o->color( FL_BLACK ); */
o->color(fl_darker(FL_BACKGROUND_COLOR));
// o->color(FL_BACKGROUND_COLOR);
// o->type( FL_HORIZONTAL );
o->callback( cb_scroll, this );
@ -291,7 +292,7 @@ Canvas::_update_row_mapping ( void )
else
m.maxh = 128;
m.vp->h = min( m.vp->h, m.maxh );
m.vp->h = max( m.vp->h, m.maxh );
resize_grid();
}
@ -488,10 +489,12 @@ gui_draw_string ( int x, int y, int w, int h, int color, const char *s, bool dra
{
// fl_rectf( x,y,w,h, FL_BACKGROUND_COLOR );
if ( color )
fl_color( velocity_colors[ color ] );
else
fl_color( FL_DARK_CYAN );
fl_color( FL_FOREGROUND_COLOR );
/* if ( color ) */
/* fl_color( velocity_colors[ color ] ); */
/* else */
/* fl_color( FL_DARK_CYAN ); */
fl_draw( s, x, y + h / 2 + fl_descent() );
}
@ -519,13 +522,13 @@ Canvas::draw_row_name ( int y, const char *name, int color )
if ( draw && name )
{
fl_rectf( bx, by, bw, bh, index(name, '#') ? FL_GRAY : FL_BLACK );
fl_rect( bx, by, bw, bh, FL_BLACK );
fl_rectf( bx, by, bw, bh, index(name, '#') ? FL_GRAY : FL_BACKGROUND_COLOR );
fl_rect( bx, by, bw, bh, FL_BACKGROUND_COLOR );
}
m.margin_left = max( m.margin_left, gui_draw_string( bx + 1, by + 2,
bw - 1, bh - 4,
color,
color,
name,
draw ) );
}
@ -617,14 +620,14 @@ Canvas::draw_dash ( tick_t x, int y, tick_t w, int color, int selected ) const
if ( w > 4 )
{
fl_draw_box( FL_ROUNDED_BOX, x, y + 1, w, m.div_h - 1, color );
fl_draw_box( FL_UP_BOX, x, y + 1, w, m.div_h - 1, color );
if ( selected )
{
cairo_set_operator( Fl::cairo_cc(),CAIRO_OPERATOR_HSL_COLOR );
fl_draw_box( FL_ROUNDED_BOX, x, y + 1, w, m.div_h - 1, FL_MAGENTA );
fl_rectf( x, y + 1, w, m.div_h - 1, FL_MAGENTA );
cairo_set_operator( Fl::cairo_cc(),CAIRO_OPERATOR_OVER);
}
/* if ( selected ) */
@ -767,7 +770,7 @@ Canvas::draw_clip ( int X, int Y, int W, int H )
w() - m.margin_left,
h() - m.margin_top - panzoomer->h() );
fl_rectf( m.origin_x + m.margin_left, m.origin_y + m.margin_top, w(), h(), FL_BLACK );
fl_rectf( m.origin_x + m.margin_left, m.origin_y + m.margin_top, w(), h(), this->color() );
/* draw bar/beat lines */
@ -800,7 +803,7 @@ Canvas::draw_clip ( int X, int Y, int W, int H )
ghost_note->velocity,
1 );
fl_color( fl_color_add_alpha( fl_rgb_color( 127,127,127 ), 50 ));
fl_color( fl_color_add_alpha( fl_rgb_color( 127,127,127 ), 25 ));
/* draw grid */
@ -1585,12 +1588,12 @@ Canvas::handle ( int m )
ghost_note->start = this->m.grid->x_to_ts( dx );
ghost_note->note = dy;
ghost_note->duration = this->m.grid->default_length();
ghost_note->duration = this->m.grid->default_length() - 1;
ghost_note->velocity = 64;
drag_note->start = this->m.grid->x_to_ts( dx );
drag_note->note = dy;
drag_note->duration = this->m.grid->default_length();
drag_note->duration = this->m.grid->default_length() - 1;
drag_note->velocity = 64;

View File

@ -38,4 +38,3 @@ const char COPYRIGHT[] = "Copyright (c) 2007-2013 Jonathan Moore Liles";
/* directories */
#define USER_CONFIG_DIR ".non/"
#define INSTRUMENT_DIR "instruments/"

View File

@ -314,6 +314,7 @@ name->value( e->selected() );
// display the proper subtype
switch ( e->opcode() )
{
\#define TWO d1 = (Fl_Valuator*)tab->child( 0 ); d2 = (Fl_Valuator*)tab->child( 1 )
\#define ONE d1 = (Fl_Valuator*)tab->child( 0 ); d2 = NULL
@ -354,11 +355,16 @@ switch ( e->opcode() )
case midievent::PITCH_WHEEL:
tab = pitch_tab;
name->color( pitch_color );
ONE;
d1->value( e->pitch() );
goto pitch;
break;
default:
WARNING("Encountered unknown opcode");
return;
break;
}

View File

@ -98,14 +98,21 @@ Function {init_colors()} {open private C return_type {static void}
} {
code {unsigned int i;
/* velocity colors */
Fl_Color lo = fl_color_average( FL_CYAN, FL_BLACK, 0.10 );
Fl_Color hi = fl_color_average( FL_CYAN, FL_WHITE, 0.80 );
Fl_Color c[] = { FL_BLUE, FL_GREEN, FL_RED };
int b[] = {0, 64, 127 };
int nbreaks = 3;
for ( int i = 0; i < nbreaks - 1; i++ )
{
int k = 0;
for ( int j = b[i]; j <= b[i+1]; j++, k++ )
velocity_colors[ j ] = fl_color_average( c[i+1], c[i], ( k ) / (float)(b[i+1] - b[i] ));
}
for ( i = 128; i--; )
{
velocity_colors[i] = fl_color_average( hi, lo, 1.0 * ((float)i / 128) );
}} {}
} {}
}
widget_class Visual_Metronome {open
@ -847,6 +854,12 @@ o->maximum( pattern::patterns() );}
char picked[80];
mapping_menu->item_pathname(picked, sizeof(picked)-1 );
const char *text = o->text();
if ( ! strcmp( text, picked ) )
// nothing picked...
return;
if ( 0 == strncmp( picked, "Instrument", strlen( "Instrument" ) ) )
{
((pattern*)pattern_canvas_widget->grid())->mapping.open( Mapping::INSTRUMENT, o->text() );

View File

@ -160,7 +160,7 @@ Instrument::read ( const char *s )
if ( ! ( fp = fopen( pat, "r" ) ) )
{
sprintf( pat, "%s/%s/%s.inst", SYSTEM_PATH, INSTRUMENT_DIR, s );
sprintf( pat, "%s/%s.inst", INSTRUMENTS_PATH, s );
if ( ! ( fp = fopen( pat, "r" ) ) )
return false;
@ -261,7 +261,7 @@ get_listing( const char *dir )
if ( 0 > ( n = scandir( dir, &names, instrument_filter, alphasort ) ) )
{
WARNING( "couldn't open instrument directory" );
WARNING( "couldn't open instrument directory: %s", dir );
return NULL;
}
else
@ -291,7 +291,7 @@ get_listing( const char *dir )
char **
Instrument::listing ( void )
{
list <string> *sys = get_listing( SYSTEM_PATH "/" INSTRUMENT_DIR );
list <string> *sys = get_listing( INSTRUMENTS_PATH );
list <string> *usr = get_listing( config.user_config_dir );
if ( ! ( usr || sys ) )

View File

@ -371,51 +371,69 @@ sequence::load ( const char *name )
void
sequence::save ( const char *name ) const
{
smf f;
char *tmp = NULL;
/* open for writing */
f.open( name, smf::WRITE );
f.write_header( 2 );
DMESSAGE( "saving playlist" );
f.open_track( NULL, -1 );
DMESSAGE( "saving song info" );
f.write_song_info( song.play_mode, phrase::phrases(), pattern::patterns(), this->name(), notes() );
for ( int i = 0; i < _rd->num; ++i )
{
char pat[256];
const char *filename = basename(name);
char *dir = (char*)malloc( (strlen(name) - strlen(filename)) + 1 );
strncpy( dir, name, strlen(name) - strlen(filename) );
asprintf( &tmp, "%s#%s", dir, filename );
free(dir);
}
{
smf f;
phrase *p = phrase::phrase_by_number( _rd->phrases[ i ] );
/* open for writing */
f.open( tmp, smf::WRITE );
snprintf( pat, 256, "%d: %s", p->number(), p->name() );
f.write_header( 2 );
f.write_meta_event( smf::CUEPOINT, pat );
DMESSAGE( "saving playlist" );
f.open_track( NULL, -1 );
DMESSAGE( "saving song info" );
f.write_song_info( song.play_mode, phrase::phrases(), pattern::patterns(), this->name(), notes() );
for ( int i = 0; i < _rd->num; ++i )
{
char pat[256];
phrase *p = phrase::phrase_by_number( _rd->phrases[ i ] );
snprintf( pat, 256, "%d: %s", p->number(), p->name() );
f.write_meta_event( smf::CUEPOINT, pat );
}
f.close_track( 0 );
DMESSAGE( "saving phrases" );
for ( int i = 0; i < phrase::phrases(); i++ )
{
phrase *p = phrase::phrase_by_number( i + 1 );
p->dump( &f );
}
DMESSAGE( "saving patterns" );
for ( int i = 0; i < pattern::patterns(); i++ )
{
pattern *p = pattern::pattern_by_number( i + 1 );
p->dump( &f );
}
}
f.close_track( 0 );
rename(tmp,name);
DMESSAGE( "saving phrases" );
for ( int i = 0; i < phrase::phrases(); i++ )
{
phrase *p = phrase::phrase_by_number( i + 1 );
p->dump( &f );
}
DMESSAGE( "saving patterns" );
for ( int i = 0; i < pattern::patterns(); i++ )
{
pattern *p = pattern::pattern_by_number( i + 1 );
p->dump( &f );
}
free(tmp);
}

View File

@ -20,6 +20,7 @@
#include "smf.H"
#include "phrase.H"
#include "pattern.H"
#include <math.h>
using namespace MIDI;
@ -143,11 +144,11 @@ smf::read_byte ( void )
}
void
smf::write_var ( long var )
smf::write_var ( unsigned long var )
{
long buffer;
buffer = var & 0x7F;
unsigned long buffer = var & 0x7F;
byte_t buf[4];
/* we shift it right 7, if there is
still set bits, encode into buffer
in reverse order */
@ -157,15 +158,19 @@ smf::write_var ( long var )
buffer |= ( var & 0x7F ) | 0x80;
}
for ( ;; )
int i = 0;
while ( i < 4 )
{
write_byte( buffer );
buf[i++] = buffer;
if ( buffer & 0x80 )
buffer >>= 8;
else
break;
}
write_bytes( buf, i );
}
@ -182,15 +187,6 @@ smf::write_long ( unsigned long x )
write_bytes( buf, 4 );
}
void
smf::write_ascii ( const char *buf )
{
if ( strlen( buf ) != 4 )
ASSERTION( "invalid MIDI value" );
write_bytes( (void *)buf, 4 );
}
void
smf::write_short ( unsigned short x )
{
@ -208,6 +204,15 @@ smf::write_byte ( byte_t b )
write_bytes( &b, 1 );
}
void
smf::write_ascii ( const char *buf )
{
if ( strlen( buf ) != 4 )
ASSERTION( "invalid MIDI value" );
write_bytes( (void *)buf, 4 );
}
void
smf::write_bytes ( const void *p, size_t l )
@ -231,7 +236,7 @@ smf::write_event ( const midievent *e )
tick_t delta = ts - _time;
_time = ts;
write_var( delta );
write_var( floor(delta) );
if ( _cue && (e->is_note_off() || e->is_note_on() ) )
{

View File

@ -64,7 +64,7 @@ public:
void read_bytes ( void *p, int l );
byte_t read_byte ( void );
void write_var ( long var );
void write_var ( unsigned long var );
void write_long ( unsigned long x );
void write_ascii ( const char *buf );
void write_short ( unsigned short x );

View File

@ -5,7 +5,7 @@ import string
import os
# Version of this package (even if built as a child)
PACKAGE_VERSION = '1.9.5'
PACKAGE_VERSION = '1.10.0'
# Variables for 'waf dist'
APPNAME = 'non-sequencer'
@ -32,6 +32,7 @@ def configure(conf):
conf.define('SYSTEM_PATH', '/'.join( [ conf.env.DATADIR, APPNAME ] ) )
conf.define('DOCUMENT_PATH', '/'.join( [ conf.env.DATADIR, 'doc' ] ) )
conf.define('PIXMAP_PATH', '/'.join( [ conf.env.DATADIR, 'pixmaps' ] ) )
conf.define('INSTRUMENTS_PATH', '/'.join( [ conf.env.DATADIR, APPNAME, 'instruments' ] ) )
conf.write_config_header('config.h', remove=False)

View File

@ -1,6 +1,7 @@
[Desktop Entry]
Name=Non Session Manager
Comment=Audio session manager from the land of Non
Comment[fr]=Gestionnaire de session audio pour les terres de Non
Exec=@BIN_PATH@/non-session-manager
Terminal=false
Type=Application

View File

@ -138,7 +138,10 @@ class NSM_Client : public Fl_Group
if ( img )
{
icon_box->image( img );
if ( img->w() > 32 || img->h() > 32 )
WARNING("Client %s has stupidly large icon (%ix%i), ignoring.", _client_name, img->w(), img->h() );
else
icon_box->image( img );
}
}

View File

@ -5,7 +5,7 @@ import string
import os
# Version of this package (even if built as a child)
PACKAGE_VERSION = '1.2.0'
PACKAGE_VERSION = '1.3.0'
# Variables for 'waf dist'
APPNAME = 'non-session-manager'

View File

@ -74,7 +74,7 @@ PROJECT="$1"
cd "$PROJECT" || fatal "No such project"
[ -f history ] && [ -f info ] || fatal "Not a Non-DAW project?"
[ -f history ] && [ -f info ] || fatal "Not a Non-Timeline project?"
[ -f .lock ] && fatal "Project appears to be in use"

View File

@ -1,6 +1,7 @@
[Desktop Entry]
Name=Non Timeline
Comment=Modular Digital Audio Workstation - Timeline Editor
Comment[fr]=Station de travail audio-numérique modulaire - Éditeur à ligne temporelle
Exec=@BIN_PATH@/non-timeline
Terminal=false
Type=Application

View File

@ -224,6 +224,8 @@ Audio_Region::menu_cb ( const Fl_Menu_ *m )
_fade_in.type = Fade::Logarithmic;
else if ( ! strcmp( picked, "Fade/In/Parabolic" ) )
_fade_in.type = Fade::Parabolic;
else if ( ! strcmp( picked, "Fade/In/Disabled" ) )
_fade_in.type = Fade::Disabled;
else if ( ! strcmp( picked, "Fade/Out/Linear" ) )
_fade_out.type = Fade::Linear;
else if ( ! strcmp( picked, "Fade/Out/Sigmoid" ) )
@ -232,6 +234,8 @@ Audio_Region::menu_cb ( const Fl_Menu_ *m )
_fade_out.type = Fade::Logarithmic;
else if ( ! strcmp( picked, "Fade/Out/Parabolic" ) )
_fade_out.type = Fade::Parabolic;
else if ( ! strcmp( picked, "Fade/Out/Disabled" ) )
_fade_out.type = Fade::Disabled;
else if ( ! strcmp( picked, "/Color" ) )
box_color( fl_show_colormap( box_color() ) );
else if ( ! strcmp( picked, "/Split at mouse" ) )
@ -351,12 +355,16 @@ Audio_Region::menu ( void )
{ "Sigmoid", 0, 0, 0, FL_MENU_RADIO | ( it == Fade::Sigmoid ? FL_MENU_VALUE : 0 ) },
{ "Logarithmic", 0, 0, 0, FL_MENU_RADIO | ( it == Fade::Logarithmic ? FL_MENU_VALUE : 0 ) },
{ "Parabolic", 0, 0, 0, FL_MENU_RADIO | ( it == Fade::Parabolic ? FL_MENU_VALUE : 0 ) },
{ "Disabled", 0, 0, 0, FL_MENU_RADIO | ( it == Fade::Disabled ? FL_MENU_VALUE : 0 ) },
{ 0 },
{ "Out", 0, 0, 0, FL_SUBMENU },
{ "Linear", 0, 0, 0, FL_MENU_RADIO | ( ot == Fade::Linear ? FL_MENU_VALUE : 0 ) },
{ "Sigmoid", 0, 0, 0, FL_MENU_RADIO | ( ot == Fade::Sigmoid ? FL_MENU_VALUE : 0 ) },
{ "Logarithmic", 0, 0, 0, FL_MENU_RADIO | ( ot == Fade::Logarithmic ? FL_MENU_VALUE : 0 ) },
{ "Parabolic", 0, 0, 0, FL_MENU_RADIO | ( ot == Fade::Parabolic ? FL_MENU_VALUE : 0 ) },
{ "Disabled", 0, 0, 0, FL_MENU_RADIO | ( ot == Fade::Disabled ? FL_MENU_VALUE : 0 ) },
{ 0 },
{ 0 },
{ "Color", 0, 0, 0, inherit_track_color ? FL_MENU_INACTIVE : 0 },
@ -398,6 +406,9 @@ Audio_Region::draw_fade ( const Fade &fade, Fade::fade_dir_e dir, bool line, int
const int height = dh;
const int width = timeline->ts_to_x( fade.length );
if ( Fade::Disabled == fade.type )
return;
if ( width < 4 )
/* too small to draw */
return;
@ -409,7 +420,7 @@ Audio_Region::draw_fade ( const Fade &fade, Fade::fade_dir_e dir, bool line, int
fx = curve_x();
if ( fx + width < X ||
fx > X + W )
fx > X + W )
/* clipped */
return;
}
@ -477,7 +488,7 @@ Audio_Region::draw_box( void )
}
Fl_Boxtype b;
Fl_Color c = selected() ? fl_color_average( color, fl_rgb_color(10,10,10), 0.4f ) : color;
Fl_Color c = color;// selected() ? fl_color_average( color, fl_rgb_color(10,10,10), 0.4f ) : color;
if ( Audio_Region::show_box )
{
@ -566,7 +577,7 @@ Audio_Region::draw ( void )
/* Audio_Region::inherit_track_color ? sequence()->track()->color() : _box_color, */
/* 0.75f ); */
fl_color( fl_color_add_alpha( FL_DARK1, 127 ) );
fl_color( fl_color_add_alpha( fl_rgb_color( 20,20,20 ), 127 ) );
draw_fade( _fade_in, Fade::In, false, X, W );
draw_fade( _fade_out, Fade::Out, false, X, W );
@ -665,21 +676,8 @@ Audio_Region::draw ( void )
;
// WARNING( "Pbuf == %p, peaks = %lu", pbuf, (unsigned long)peaks );
if ( _loop )
{
const int lx = sequence()->drawable_x() + timeline->ts_to_x( ( this->start() + _loop ) - timeline->xoffset );
if ( lx < X + W )
{
fl_color( fl_darker( FL_CYAN ) );
fl_line( lx, y(), lx, y() + h() );
fl_line( lx - 3, y(), lx + 3, y() );
fl_line( lx - 3, y() + h() - 1, lx + 3, y() + h() - 1 );
}
}
if ( peaks < loop_peaks_needed )
{
@ -691,6 +689,31 @@ Audio_Region::draw ( void )
}
while ( _loop && fo < total_frames_needed );
if ( _loop )
{
/* draw loop point indicator */
const int lx = sequence()->drawable_x() + timeline->ts_to_x( ( this->start() + _loop ) - timeline->xoffset );
const int pw = 8;
fl_color( fl_color_add_alpha( fl_color_average( FL_CYAN, FL_WHITE, 0.80f ), 127 ) );
fl_begin_polygon();
fl_vertex( lx + Fl::box_dx(box()),
y() + Fl::box_dy(box()) );
fl_vertex( pw + lx + Fl::box_dx(box()),
y() + Fl::box_dy(box()) );
fl_vertex( lx + Fl::box_dx(box()),
pw + y() + Fl::box_dy(box()) );
fl_end_polygon();
fl_line( lx, y() + Fl::box_dy(box()), lx, y() + h() - Fl::box_dy(box()) * 2 );
}
if ( _adjusting_gain > 0.0f )
@ -713,6 +736,29 @@ Audio_Region::draw ( void )
fl_line_style( FL_SOLID, 0 );
}
/* draw dog ear */
{
const int pw = 8;
/* fl_color( fl_color_add_alpha( FL_WHITE, 127 ) ); */
/* fl_color( FL_BACKGROUND_COLOR ); */
fl_color( fl_color_add_alpha( FL_WHITE, 127 ) );
fl_begin_polygon();
fl_vertex( line_x() + Fl::box_dx(box()),
y() + Fl::box_dy(box()) );
fl_vertex( pw + line_x() + Fl::box_dx(box()),
y() + Fl::box_dy(box()) );
fl_vertex( line_x() + Fl::box_dx(box()),
pw + y() + Fl::box_dy(box()) );
fl_end_polygon();
}
if ( selected() )
draw_selection_frame( line_x() + Fl::box_dx(box()),
y() + Fl::box_dy(box()),
@ -738,7 +784,7 @@ Audio_Region::draw ( void )
void
Audio_Region::draw_label ( void )
{
if ( _clip->dummy() )
if ( _clip->dummy() )
{
char pat[256];
snprintf( pat, sizeof( pat ), "Missing Source!: %s", _clip->name() );
@ -760,6 +806,8 @@ Audio_Region::split ( nframes_t where )
Audio_Region *copy = new Audio_Region( *this );
timeline->sequence_lock.wrlock();
{
Logger _log( copy );
@ -769,6 +817,8 @@ Audio_Region::split ( nframes_t where )
Sequence_Region::split( copy, where );
}
timeline->sequence_lock.unlock();
log_end();
block_end();
@ -784,6 +834,10 @@ Audio_Region::handle ( int m )
static bool copied = false;
static nframes_t os;
if ( !active_r() )
/* don't mess with anything while recording... */
return 0;
int X = Fl::event_x();
int Y = Fl::event_y();

View File

@ -42,7 +42,7 @@ public:
struct Fade
{
enum fade_type_e { Linear = 0, Sigmoid, Logarithmic, Parabolic };
enum fade_type_e { Linear = 0, Sigmoid, Logarithmic, Parabolic, Disabled };
enum fade_dir_e { In, Out };
fade_type_e type;

View File

@ -177,7 +177,8 @@ Audio_Sequence::set ( Log_Entry &e )
assert( t );
t->sequence( this );
/* FIXME: this causes the sequences to be set twice in the replay logic, first when the sequence is created, then when track sequence is assigned. */
t->sequence( this );
}
else if ( ! strcmp( ":name", s ) )
name( v );

View File

@ -164,7 +164,7 @@ public:
fl_font( FL_COURIER_BOLD, 24 );
Fl_Color c = fl_color_average( FL_WHITE, FL_GRAY, 0.60 );
Fl_Color c = fl_color_average( fl_contrast(FL_WHITE, FL_BACKGROUND_COLOR) , FL_GRAY, 0.60 );
fl_color( c );

View File

@ -601,7 +601,7 @@ Control_Sequence::menu_cb ( const Fl_Menu_ *m )
void
Control_Sequence::connect_osc ( void )
{
timeline->osc_thread->lock();
timeline->osc_receive_thread->lock();
if ( _persistent_osc_connections.size() )
{
@ -623,7 +623,7 @@ Control_Sequence::connect_osc ( void )
/* header()->outputs_indicator->value( _osc_output() && _osc_output()->connected() ); */
timeline->osc_thread->unlock();
timeline->osc_receive_thread->unlock();
}
void
@ -634,12 +634,15 @@ Control_Sequence::process_osc ( void )
if ( _osc_output() )
{
sample_t buf[1];
sample_t buf = 0;
play( &buf, (nframes_t)transport->frame, (nframes_t) 1 );
*buf = 0;
play( buf, (nframes_t)transport->frame, (nframes_t) 1 );
_osc_output()->value( (float)buf[0] );
/* only send value if it is significantly different from the last value sent */
if ( fabsf( _osc_output()->value() - (float)buf ) > 0.001 )
{
_osc_output()->value( (float)buf );
}
}
}

View File

@ -112,7 +112,10 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels
const Audio_File::format_desc *fd = Audio_File::find_format( Audio_File_SF::supported_formats, format );
if ( ! fd )
{
DMESSAGE( "Unsupported capture format: %s", format );
return (Audio_File_SF *)1;
}
si.samplerate = samplerate;
si.channels = channels;
@ -125,7 +128,7 @@ Audio_File_SF::create ( const char *filename, nframes_t samplerate, int channels
if ( ! ( out = sf_open( filepath, SFM_WRITE, &si ) ) )
{
printf( "couldn't create soundfile.\n" );
WARNING( "couldn't create soundfile \"%s\": libsndfile says: %s", filepath, sf_strerror(NULL) );
free( name );
return NULL;
}

View File

@ -118,10 +118,12 @@ Audio_Region::read ( sample_t *buf, bool buf_is_empty, nframes_t pos, nframes_t
const Range r = _range;
/* ASSERT( r.legnth > 0, "Region has zero length!" ); */
const nframes_t rS = r.start;
const nframes_t rE = r.start + r.length;
const nframes_t rE = r.start + r.length; /* one more than the last frame of the region! */
const nframes_t bS = pos;
const nframes_t bE = pos + nframes;
const nframes_t bE = pos + nframes; /* one more than the last frame of the buffer! */
/* do nothing if region isn't inside buffer */
if ( bS > rE || bE < rS )
@ -188,20 +190,42 @@ Audio_Region::read ( sample_t *buf, bool buf_is_empty, nframes_t pos, nframes_t
WARNING("Loop size (%lu) is smaller than buffer size (%lu). Behavior undefined.", _loop, nframes );
}
const nframes_t lO = sO % _loop; /* how far we are into the loop */
const nframes_t nthloop = sO / _loop; /* which loop iteration */
const nframes_t seam_L = rS + ( nthloop * _loop ); /* receding seam */
const nframes_t seam_R = rS + ( (nthloop + 1 ) * _loop ); /* upcoming seam */
/* read interleaved channels */
if ( seam_R > bS && seam_R < bE )
{
/* this buffer covers a loop boundary */
const nframes_t lO = sO % _loop, /* how far we are into the loop */
nthloop = sO / _loop, /* which loop iteration */
seam_L = rS + ( nthloop * _loop ), /* receding seam */
seam_R = rS + ( ( nthloop + 1 ) * _loop ); /* upcoming seam */
/* read interleaved channels */
if (
/* this buffer contains a loop boundary, which lies on neither the first or the last frame, and therefore requires a splice of two reads from separate parts of the region. */
seam_R > bS && seam_R < bE
&&
/* but if the end seam of the loop is also the end seam of the region, we only need one read */
seam_R != rE
&&
/* also, if the seam is within the buffer, but beyond the end of the region (as in last loop iteration), do the simpler read in the else clause */
seam_R <= rE
)
{
/* this buffer covers a loop boundary */
/* read the first part */
cnt = _clip->read( cbuf + ( _clip->channels() * bO ), -1, r.offset + lO, ( seam_R - bS ) - bO );
cnt = _clip->read(
cbuf + ( _clip->channels() * bO ), /* buf */
-1, /* chan */
r.offset + lO, /* start */
( seam_R - bS ) - bO /* len */
);
/* ASSERT( len > cnt, "Error in region looping calculations" ); */
/* read the second part */
cnt += _clip->read( cbuf + ( _clip->channels() * ( bO + cnt ) ), -1, r.offset + 0, ( len - cnt ) - bO );
cnt += _clip->read(
cbuf + ( _clip->channels() * ( bO + cnt ) ), /* buf */
-1, /* chan */
r.offset + 0, /* start */
( len - cnt ) - bO /* len */
);
/* assert( cnt == len ); */
}
@ -247,17 +271,21 @@ Audio_Region::read ( sample_t *buf, bool buf_is_empty, nframes_t pos, nframes_t
Fade fade;
fade = declick < _fade_in ? _fade_in : declick;
/* do fade in if necessary */
if ( sO < fade.length )
apply_fade( cbuf, _clip->channels(), fade, bS, bE, rS, Fade::In );
fade = declick < _fade_out ? _fade_out : declick;
/* do fade out if necessary */
if ( sO + cnt + fade.length > r.length )
apply_fade( cbuf, _clip->channels(), fade, bS, bE, rE, Fade::Out );
/* disabling fade also disables de-clicking for perfectly abutted edits. */
if ( fade.type != Fade::Disabled )
{
fade = declick < _fade_in ? _fade_in : declick;
/* do fade in if necessary */
if ( sO < fade.length )
apply_fade( cbuf, _clip->channels(), fade, bS, bE, rS, Fade::In );
fade = declick < _fade_out ? _fade_out : declick;
/* do fade out if necessary */
if ( sO + cnt + fade.length > r.length )
apply_fade( cbuf, _clip->channels(), fade, bS, bE, rE, Fade::Out );
}
}
if ( buf != cbuf )

View File

@ -188,7 +188,10 @@ public:
}
if ( ! blocks.size() )
FATAL( "Peak file contains no blocks!" );
{
DWARNING( "Peak file contains no blocks, maybe it's still being generated?");
return;
}
blocks.sort();
@ -258,9 +261,19 @@ public:
scan( chunksize );
assert( _chunksize );
/* assert( _chunksize ); */
return true;
if ( blocks.size() )
{
return true;
}
else
{
DWARNING( "Peak file could not be opened: no blocks" );
fclose(_fp);
_fp = NULL;
return false;
}
}
bool

View File

@ -287,7 +287,7 @@ Track::record ( Capture *c, nframes_t frame )
free( pat );
if ( ! c->audio_file )
FATAL( "Could not create file for new capture!" );
FATAL( "Could not create file for new capture! (%s)", pat );
/* open it again for reading in the GUI thread */
// Audio_File *af = Audio_File::from_file( c->audio_file->name() );

View File

@ -0,0 +1,87 @@
/*******************************************************************************/
/* Copyright (C) 2012 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 "OSC_Receive_Thread.H"
#include "Timeline.H"
#include <stdlib.h>
#include <unistd.h>
#include "debug.h"
#include "OSC/Endpoint.H"
extern Timeline *timeline;
OSC_Receive_Thread::OSC_Receive_Thread ( )
{
// _thread.init();
_shutdown = false;
}
OSC_Receive_Thread::~OSC_Receive_Thread ( )
{
lock();
if ( _shutdown == false )
{
_shutdown = true;
_thread.join();
}
unlock();
}
void
OSC_Receive_Thread::start ( )
{
_thread.clone( &OSC_Receive_Thread::process, this );
}
void
OSC_Receive_Thread::join ( )
{
_thread.join();
}
void
OSC_Receive_Thread::process ( void )
{
_thread.name( "OSC_Receive" );
DMESSAGE( "OSC Thread starting" );
while ( !_shutdown )
{
timeline->osc->wait(20);
}
DMESSAGE( "OSC Thread stopping." );
}
void *
OSC_Receive_Thread::process ( void *v )
{
OSC_Receive_Thread *t = (OSC_Receive_Thread*)v;
t->process();
return NULL;
}

View File

@ -22,7 +22,7 @@
#include "Thread.H"
#include "Mutex.H"
class OSC_Thread : public Mutex
class OSC_Receive_Thread : public Mutex
{
Thread _thread; /* io thread */
@ -30,9 +30,9 @@ class OSC_Thread : public Mutex
public:
OSC_Thread ( );
OSC_Receive_Thread ( );
virtual ~OSC_Thread ( );
virtual ~OSC_Receive_Thread ( );
void join ( void );
void shutdown ( void ) { _shutdown = true; }

View File

@ -17,7 +17,7 @@
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
#include "OSC_Thread.H"
#include "OSC_Transmit_Thread.H"
#include "Timeline.H"
@ -30,13 +30,13 @@
extern Timeline *timeline;
OSC_Thread::OSC_Thread ( )
OSC_Transmit_Thread::OSC_Transmit_Thread ( )
{
// _thread.init();
_shutdown = false;
}
OSC_Thread::~OSC_Thread ( )
OSC_Transmit_Thread::~OSC_Transmit_Thread ( )
{
lock();
if ( _shutdown == false )
@ -49,29 +49,29 @@ OSC_Thread::~OSC_Thread ( )
void
OSC_Thread::start ( )
OSC_Transmit_Thread::start ( )
{
_thread.clone( &OSC_Thread::process, this );
_thread.clone( &OSC_Transmit_Thread::process, this );
}
void
OSC_Thread::join ( )
OSC_Transmit_Thread::join ( )
{
_thread.join();
}
void
OSC_Thread::process ( void )
OSC_Transmit_Thread::process ( void )
{
_thread.name( "OSC" );
_thread.name( "OSC_Transmit" );
DMESSAGE( "OSC Thread starting" );
while ( !_shutdown )
{
if ( trylock() )
{
timeline->osc->check();
timeline->process_osc();
unlock();
}
@ -83,9 +83,9 @@ OSC_Thread::process ( void )
}
void *
OSC_Thread::process ( void *v )
OSC_Transmit_Thread::process ( void *v )
{
OSC_Thread *t = (OSC_Thread*)v;
OSC_Transmit_Thread *t = (OSC_Transmit_Thread*)v;
t->process();

View File

@ -0,0 +1,42 @@
/*******************************************************************************/
/* Copyright (C) 2012 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. */
/*******************************************************************************/
#pragma once
#include "Thread.H"
#include "Mutex.H"
class OSC_Transmit_Thread : public Mutex
{
Thread _thread; /* io thread */
volatile bool _shutdown;
public:
OSC_Transmit_Thread ( );
virtual ~OSC_Transmit_Thread ( );
void join ( void );
void shutdown ( void ) { _shutdown = true; }
void start ( void );
void process ( void );
static void *process ( void * );
};

View File

@ -19,6 +19,7 @@
#include "Sequence_Region.H"
#include "Track.H"
#include "debug.h"
#include <stdint.h>
@ -128,6 +129,7 @@ Sequence_Region::split ( Sequence_Region * copy, nframes_t where )
trim_right( where );
copy->trim_left( where );
sequence()->add( copy );
copy->redraw();
}
@ -141,6 +143,10 @@ Sequence_Region::handle ( int m )
int X = Fl::event_x();
int Y = Fl::event_y();
if ( !active_r() )
/* don't mess with anything while recording... */
return 0;
Logger _log( this );
switch ( m )

View File

@ -391,6 +391,10 @@ Sequence_Widget::handle ( int m )
int X = Fl::event_x();
int Y = Fl::event_y();
if ( !active_r() )
/* don't mess with anything while recording... */
return 0;
Logger _log( this );
switch ( m )

View File

@ -53,7 +53,7 @@
#include "TLE.H"
/* */
#include "OSC_Thread.H"
#include "OSC/Endpoint.H"
#include <unistd.h>
@ -612,8 +612,10 @@ Timeline::ntracks ( void ) const
Timeline::~Timeline ( )
{
delete osc_thread;
osc_thread = 0;
delete osc_transmit_thread;
osc_transmit_thread = 0;
delete osc_receive_thread;
osc_receive_thread = 0;
delete osc;
osc = 0;
}
@ -627,7 +629,8 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W
play_cursor_track = NULL;
_created_new_takes = 0;
osc_thread = 0;
osc_transmit_thread = 0;
osc_receive_thread = 0;
_sample_rate = 44100;
box( FL_FLAT_BOX );
@ -997,20 +1000,32 @@ Timeline::draw_measure_cb ( nframes_t frame, const BBT &bbt, void *v )
{
Timeline *o = (Timeline*)v;
Fl_Color c = FL_LIGHT3;
if ( o->panzoomer->zoom() >= 15 )
return;
Fl_Color mc = FL_LIGHT3;
Fl_Color bc = FL_LIGHT2;
Fl_Color c;
Fl_Color ct = fl_contrast( mc, FL_BACKGROUND_COLOR );
if ( FL_BLACK == ct )
{
/* in a light color scheme mode */
mc = fl_rgb_color(30,30,30);
bc = FL_DARK3;
}
if ( bbt.beat )
{
if ( o->panzoomer->zoom() > 12 )
return;
else
c = FL_DARK1;
c = bc;
}
else
c = mc;
fl_color( fl_color_add_alpha( c, 64 ) );
fl_color( fl_color_add_alpha( c, 127 ) );
const int x = timeline->ts_to_x( frame - timeline->xoffset ) + Track::width();
@ -2167,11 +2182,18 @@ Timeline::init_osc ( const char *osc_port )
// osc->start();
if ( ! osc_thread )
if ( ! osc_transmit_thread )
{
osc_thread = new OSC_Thread();
osc_transmit_thread = new OSC_Transmit_Thread();
osc_thread->start();
osc_transmit_thread->start();
}
if ( ! osc_receive_thread )
{
osc_receive_thread = new OSC_Receive_Thread();
osc_receive_thread->start();
}
return 0;
@ -2250,7 +2272,7 @@ Timeline::update_osc_connection_state ( void )
void
Timeline::process_osc ( void )
{
THREAD_ASSERT( OSC );
THREAD_ASSERT( OSC_Transmit );
sequence_lock.rdlock();

View File

@ -31,7 +31,8 @@
#include <assert.h>
#include <list>
#include "OSC_Thread.H"
#include "OSC_Transmit_Thread.H"
#include "OSC_Receive_Thread.H"
class Fl_Scroll;
class Fl_Pack;
@ -136,7 +137,8 @@ public:
void damage_sequence ( void );
OSC::Endpoint *osc;
OSC_Thread *osc_thread;
OSC_Transmit_Thread *osc_transmit_thread;
OSC_Receive_Thread *osc_receive_thread;
void process_osc ( void );
#undef Bars

View File

@ -134,7 +134,7 @@ Track::init ( void )
_name = NULL;
_selected = false;
_size = 1;
record_ds = NULL;
playback_ds = NULL;
@ -604,6 +604,10 @@ Track::remove ( Audio_Sequence *t )
if ( ! takes )
return;
Loggable::block_start();
Logger log(this);
if ( sequence() == t )
{
pack->remove( t );
@ -617,8 +621,11 @@ Track::remove ( Audio_Sequence *t )
else
takes->remove( t );
/* delete t; */
/* doing this here creates a cycle */
/* delete t; */
Loggable::block_end();
adjust_size();
}
@ -647,9 +654,12 @@ Track::remove ( Control_Sequence *t )
void
Track::sequence ( Audio_Sequence * t )
{
Logger log(this);
if ( sequence() == t )
{
DMESSAGE( "Attempt to set sequence twice" );
/* ASSERT( false, "Attempt to set same sequence twice" ); */
DMESSAGE( "Attempt to set same sequence twice, %p == %p", t, sequence() );
return;
}
@ -873,8 +883,13 @@ Track::menu_cb ( const Fl_Menu_ *m )
else if ( !strcmp( picked, "Takes/New" ) )
{
timeline->track_lock.wrlock();
Loggable::block_start();
sequence( (Audio_Sequence*)sequence()->clone_empty() );
timeline->track_lock.unlock();
Loggable::block_end();
}
else if ( !strcmp( picked, "Takes/Remove" ) )
{
@ -909,7 +924,7 @@ Track::menu_cb ( const Fl_Menu_ *m )
else if ( !strncmp( picked, "Takes/", sizeof( "Takes/" ) - 1 ) )
{
Audio_Sequence* s = (Audio_Sequence*)m->mvalue()->user_data();
timeline->track_lock.wrlock();
sequence( s );
timeline->track_lock.unlock();
@ -1044,7 +1059,10 @@ Track::draw ( void )
int
Track::handle ( int m )
{
if ( !active_r() )
/* don't mess with anything while recording... */
return 0;
/* if ( m != FL_NO_EVENT ) */
/* DMESSAGE( "%s", event_name( m ) ); */
static Fl_Widget *dragging = NULL;
@ -1056,7 +1074,8 @@ Track::handle ( int m )
case FL_DND_DRAG:
case FL_DND_RELEASE:
case FL_PASTE:
if ( Fl::event_x() > Track::width() )
if ( dragging != ((Track_Header*)child(0))->output_connector_handle &&
Fl::event_x() > Track::width() )
return sequence()->handle(m);
default:
break;
@ -1097,6 +1116,7 @@ Track::handle ( int m )
if ( Fl::event_button1() && Fl::event_inside( ((Track_Header*)child(0))->color_box ) )
{
dragging = this;
fl_cursor( FL_CURSOR_MOVE );
return 1;
}
if ( Fl::event_button1() && Fl::event_inside( ((Track_Header*)child(0))->output_connector_handle ) )
@ -1119,32 +1139,50 @@ Track::handle ( int m )
case FL_ENTER:
case FL_LEAVE:
case FL_MOVE:
if ( Fl::event_x() >= Track::width() )
if ( dragging != ((Track_Header*)child(0))->output_connector_handle &&
Fl::event_x() >= Track::width() )
{
return Fl_Group::handle(m);
}
else
{
if ( Fl::event_inside( ((Track_Header*)child(0))->output_connector_handle ) ||
Fl::event_inside( ((Track_Header*)child(0))->input_connector_handle ) ||
Fl::event_inside( ((Track_Header*)child(0))->color_box ) )
fl_cursor( FL_CURSOR_HAND );
}
return 1;
case FL_DND_ENTER:
return 1;
case FL_DND_LEAVE:
if ( ! Fl::event_inside(this) && this == receptive_to_drop )
{
/* if ( ! Fl::event_inside(this) )// && this == receptive_to_drop ) */
/* { */
receptive_to_drop = 0;
redraw();
Fl::selection_owner(0);
}
/* } */
return 1;
case FL_RELEASE:
if ( dragging == this )
{
dragging = NULL;
timeline->insert_track( this, timeline->event_inside() );
return 1;
fl_cursor( FL_CURSOR_DEFAULT );
return 1;
}
else if ( dragging == ((Track_Header*)child(0))->output_connector_handle )
{
dragging = NULL;
fl_cursor( FL_CURSOR_DEFAULT );
return 1;
}
return Fl_Group::handle( m );
break;
case FL_DND_RELEASE:
dragging = NULL;
receptive_to_drop = 0;
redraw();
Fl::selection_owner(0);
@ -1228,6 +1266,9 @@ Track::handle ( int m )
}
case FL_DRAG:
{
if ( Fl::event_is_click() )
return 1;
if ( this != Fl::selection_owner() &&
Fl::event_inside( ((Track_Header*)child(0))->output_connector_handle ) )
{
@ -1237,8 +1278,9 @@ Track::handle ( int m )
for ( unsigned int i = 0; i < output.size(); ++i )
{
char *s2;
asprintf(&s2, "jack.port://%s:%s\r\n", instance_name, output[i].name() );
asprintf(&s2, "jack.port://%s\r\n",
output[i].jack_name() );
s = (char*)realloc( s, strlen( s ) + strlen( s2 ) + 1 );
strcat( s, s2 );
@ -1250,14 +1292,12 @@ Track::handle ( int m )
free( s );
dragging = ((Track_Header*)child(0))->output_connector_handle;
Fl::dnd();
return 1;
}
else
{
return 1;
}
}
return 1;
}
default:
return Fl_Group::handle( m );

View File

@ -5,7 +5,7 @@ import string
import os;
# Version of this package (even if built as a child)
PACKAGE_VERSION = '1.2.0'
PACKAGE_VERSION = '1.3.0'
# Variables for 'waf dist'
APPNAME = 'non-timeline'
@ -76,7 +76,8 @@ src/Engine/Record_DS.C
src/Engine/Timeline.C
src/Engine/Track.C
src/NSM.C
src/OSC_Thread.C
src/OSC_Transmit_Thread.C
src/OSC_Receive_Thread.C
src/Project.C
src/Sequence.C
src/Sequence_Point.C
@ -108,8 +109,8 @@ src/main.C
## use = [ 'fl_widgets', 'nonlib'],
install_path = '${BINDIR}')
bld.install_files('${BINDIR}', 'import-ardour-session', chmod=0o0555,
cwd=bld.path.find_dir('bin'), relative_trick=True)
bld.install_files('${BINDIR}', 'bin/import-ardour-session', chmod=0o0555,
relative_trick=True)
bld( features = 'subst',
source = 'non-timeline.desktop.in',

18
tools.waf/ntk_fluid.py Normal file
View File

@ -0,0 +1,18 @@
from waflib import Task
from waflib.TaskGen import extension
class ntk_fluid(Task.Task):
color = 'BLUE'
ext_out = ['.h']
run_str = '${NTK_FLUID} -c -o ${TGT[0].abspath()} -h ${TGT[1].abspath()} ${SRC}'
@extension('.fl')
def fluid(self, node):
"""add the .fl to the source list; the cxx file generated will be compiled when possible"""
cpp = node.change_ext('.C')
hpp = node.change_ext('.H')
self.create_task('ntk_fluid', node, [cpp, hpp])
if 'cxx' in self.features:
self.source.append(cpp)

BIN
waf vendored

Binary file not shown.

11
wscript
View File

@ -21,6 +21,8 @@ def options(opt):
help='Build for debugging')
opt.add_option('--disable-sse', action='store_false', default=True, dest='sse',
help='Disable SSE optimization')
opt.add_option('--disable-native-cpu-optimization', action='store_false', default=True, dest='native',
help='Disable native CPU optimziation (e.g. for generic binary packaging)')
opt.add_option('--project', action='store', default=False, dest='project',
help='Limit build to a single project (' + ', '.join( projects ) + ')')
@ -31,7 +33,7 @@ def configure(conf):
conf.load('compiler_c')
conf.load('compiler_cxx')
conf.load('gnu_dirs')
conf.load('ntk_fluid')
conf.load('ntk_fluid',tooldir='tools.waf')
conf.load('gccdeps')
conf.line_just = 52
@ -94,6 +96,13 @@ def configure(conf):
"-ffast-math",
"-pipe"
]
if Options.options.native:
print('Using native CPU optimization')
optimization_flags.extend( [
"-march=native",
"-mtune=native", # ~200% DSP performance increase on AMD bulldozer...
]);
if Options.options.sse:
print('Using SSE optimization')