non/mixer/src/Mixer_Strip.C

653 lines
17 KiB
C
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*******************************************************************************/
/* Copyright (C) 2009 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. */
/*******************************************************************************/
/* Mixer strip control. Handles GUI and control I/O for this strip. */
/* A mixer strip is home to some (JACK) input ports, a fader, some
* meters, and a filter chain which can terminate either at the input
* to the spacializer or some (JACK) output ports. Since mixer strips
* are not necessarily in a 1:1 association with Non-DAW tracks, there
* is no need for busses per se. If you want to route the output of
* several strips into a single fader or filter chain, then you just
* gives those strips JACK outputs and connect them to the common
* inputs. This mechanism can also do away with the need for 'sends'
* and 'inserts'.
*/
/* Each mixer strip comprises a fader and a panner */
#include "Mixer_Strip.H"
#include "Engine/Engine.H"
#include <dsp.h>
#include <string.h>
#include "debug.h"
#include "FL/Fl_Flowpack.H"
#include <FL/Fl_Input.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Color_Chooser.H>
#include <FL/Fl.H>
#include "Mixer.H"
#include "Chain.H"
#include "Gain_Module.H"
#include "Meter_Module.H"
#include "Controller_Module.H"
#include "Meter_Indicator_Module.H"
#include "debug.h"
#include <FL/Fl_Menu_Button.H>
#include "FL/test_press.H"
#include "FL/menu_popup.H"
extern Mixer *mixer;
/* add a new mixer strip (with default configuration) */
Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
{
label( strdup( strip_name ) );
labeltype( FL_NO_LABEL );
init();
chain( new Chain() );
_chain->initialize_with_default();
_chain->configure_ports();
color( (Fl_Color)rand() );
// name( strdup( strip_name ) );
log_create();
}
/* virgin strip created from journal */
Mixer_Strip::Mixer_Strip() : Fl_Group( 0, 0, 120, 600 )
{
init();
log_create();
}
Mixer_Strip::~Mixer_Strip ( )
{
DMESSAGE( "Destroying mixer strip" );
delete _chain;
_chain = NULL;
log_destroy();
mixer->remove( this );
}
void
Mixer_Strip::get ( Log_Entry &e ) const
{
e.add( ":name", name() );
e.add( ":width", width_button->value() ? "wide" : "narrow" );
e.add( ":tab", tab_button->value() ? "signal" : "fader" );
e.add( ":color", (unsigned long)color());
}
void
Mixer_Strip::set ( Log_Entry &e )
{
for ( int i = 0; i < e.size(); ++i )
{
const char *s, *v;
e.get( i, &s, &v );
if ( ! strcmp( s, ":name" ) )
name( v );
else if ( ! strcmp( s, ":width" ) )
{
width_button->value( strcmp( v, "wide" ) == 0 );
width_button->do_callback();
}
else if ( ! strcmp( s, ":tab" ) )
{
tab_button->value( strcmp( v, "signal" ) == 0 );
tab_button->do_callback();
}
else if ( ! strcmp( s, ":color" ) )
{
color( (Fl_Color)atoll( v ) );
redraw();
}
}
if ( ! mixer->contains( this ) )
mixer->add( this );
}
void
Mixer_Strip::log_children ( void )
{
log_create();
_chain->log_children();
}
void
Mixer_Strip::color ( Fl_Color c )
{
_color = c;
name_field->color( _color );
name_field->redraw();
}
Fl_Color
Mixer_Strip::color ( void ) const
{
return _color;
}
void
Mixer_Strip::chain ( Chain *c )
{
if ( _chain )
delete _chain;
_chain = c;
c->strip( this );
Fl_Group *g = signal_tab;
c->resize( g->x(), g->y(), g->w(), g->h() );
g->add( c );
g->resizable( c );
c->labelsize( 10 );
c->align( FL_ALIGN_TOP );
c->color( FL_RED );
c->configure_outputs_callback( configure_outputs, this );
c->name( name() );
gain_controller->chain( c );
jack_input_controller->chain( c );
meter_indicator->chain( c );
}
void Mixer_Strip::cb_handle(Fl_Widget* o) {
// parent()->parent()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() );
if ( o == tab_button )
{
if ( tab_button->value() == 0 )
{
fader_tab->show();
signal_tab->hide();
}
else
{
signal_tab->show();
fader_tab->hide();
}
}
else if ( o == left_button )
command_move_left();
else if ( o == right_button )
command_move_right();
else if ( o == close_button )
{
if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
command_close();
}
else if ( o == name_field )
name( name_field->value() );
else if ( o == width_button )
{
if ( ((Fl_Button*)o)->value() )
size( 220, h() );
else
size( 96, h() );
if ( parent() )
parent()->parent()->redraw();
}
}
void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
((Mixer_Strip*)(v))->cb_handle(o);
}
void
Mixer_Strip::name ( const char *name ) {
char *s = strdup( name );
if ( strlen( s ) > Chain::maximum_name_length() )
{
s[Chain::maximum_name_length() - 1] = '\0';
fl_alert( "Name \"%s\" is too long, truncating to \"%s\"", name, s );
}
name_field->value( s );
label( s );
if ( _chain )
_chain->name( s );
}
void
Mixer_Strip::configure_outputs ( Fl_Widget *, void *v )
{
((Mixer_Strip*)v)->configure_outputs();
}
void
Mixer_Strip::configure_outputs ( void )
{
DMESSAGE( "Got signal to configure outputs" );
}
/* called by the chain to let us know that a module has been added */
void
Mixer_Strip::handle_module_added ( Module *m )
{
if ( m->is_default() )
{
DMESSAGE( "Connecting controls to default module \"%s\"", m->name() );
/* connect default modules to their default controllers/indicators */
if ( 0 == strcmp( m->name(), "JACK" ) && m->ninputs() == 0 )
{
if ( !jack_input_controller->control_output[0].connected() )
jack_input_controller->connect_to( &m->control_input[1] );
}
else if ( 0 == strcmp( m->name(), "Gain" ) )
{
gain_controller->connect_to( &m->control_input[0] );
}
else if ( 0 == strcmp( m->name(), "Meter" ) )
{
meter_indicator->connect_to( &m->control_output[0] );
}
}
}
/* update GUI with values from RT thread */
void
Mixer_Strip::update ( void )
{
THREAD_ASSERT( UI );
}
void
Mixer_Strip::init ( )
{
selection_color( FL_RED );
_chain = 0;
// box(FL_THIN_UP_BOX);
box( FL_RFLAT_BOX );
labeltype( FL_NO_LABEL );
Fl_Group::color( FL_BACKGROUND_COLOR );
set_visible_focus();
clip_children( 1 );
{ Fl_Pack *o = new Fl_Pack( 2, 2, 114, 100 );
o->type( Fl_Pack::VERTICAL );
o->spacing( 2 );
{
Fl_Sometimes_Input *o = new Fl_Sometimes_Input( 2, 2, 144, 24 );
name_field = o;
o->color( color() );
o->up_box( FL_ROUNDED_BOX );
o->box( FL_ROUNDED_BOX );
o->labeltype( FL_NO_LABEL );
o->labelcolor( FL_GRAY0 );
o->textcolor( FL_FOREGROUND_COLOR );
o->value( name() );
o->callback( cb_handle, (void*)this );
}
{ Fl_Scalepack *o = new Fl_Scalepack( 7, 143, 110, 25 );
o->type( Fl_Pack::HORIZONTAL );
{ Fl_Button* o = left_button = new Fl_Button(7, 143, 35, 25, "@<-");
o->tooltip( "Move left" );
o->type(0);
o->labelsize(10);
o->when( FL_WHEN_RELEASE );
o->callback( ((Fl_Callback*)cb_handle), this );
} // Fl_Button* o
{ Fl_Button* o = close_button = new Fl_Button(7, 143, 35, 25, "X");
o->tooltip( "Remove strip" );
o->type(0);
o->labeltype( FL_EMBOSSED_LABEL );
o->color( FL_LIGHT1 );
o->selection_color( FL_RED );
o->labelsize(10);
o->when( FL_WHEN_RELEASE );
o->callback( ((Fl_Callback*)cb_handle), this );
} // Fl_Button* o
{ Fl_Button* o = right_button = new Fl_Button(7, 143, 35, 25, "@->");
o->tooltip( "Move right" );
o->type(0);
o->labelsize(10);
o->when( FL_WHEN_RELEASE );
o->callback( ((Fl_Callback*)cb_handle), this );
} // Fl_Button* o
o->end();
} // Fl_Group* o
{ Fl_Flip_Button* o = width_button = new Fl_Flip_Button(61, 183, 45, 22, "narrow/wide");
o->type(1);
o->labelsize(14);
o->callback( ((Fl_Callback*)cb_handle), this );
o->when(FL_WHEN_RELEASE);
} // Fl_Flip_Button* o
{ Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "fader/signal");
o->type(1);
o->labelsize( 14 );
o->callback( cb_handle, this );
o->when(FL_WHEN_RELEASE);
}
o->end();
}
Fl_Pack *fader_pack;
{ Fl_Group *o = fader_tab = new Fl_Group( 7, 115, 105, 330, "Fader" );
o->box( FL_NO_BOX );
o->labeltype( FL_NO_LABEL );
{ Fl_Pack* o = fader_pack = new Fl_Pack(7, 116, 103, 330 );
o->spacing( 20 );
o->type( Fl_Pack::HORIZONTAL );
{ Controller_Module *o = gain_controller = new Controller_Module( true );
o->pad( false );
o->size( 33, 0 );
}
{ Meter_Indicator_Module *o = meter_indicator = new Meter_Indicator_Module( true );
o->pad( false );
o->size( 58, 0 );
o->clip_children( 0 );
Fl_Group::current()->resizable(o);
}
o->end();
Fl_Group::current()->resizable(o);
} // Fl_Group* o
o->end();
Fl_Group::current()->resizable(o);
}
{ Fl_Group *o = signal_tab = new Fl_Group( 7, 115, 105, 330 );
o->box( FL_NO_BOX );
o->labeltype( FL_NO_LABEL );
o->hide();
o->end();
}
{ Fl_Pack *o = panner_pack = new Fl_Pack( 2, 443, 114, 40 );
o->spacing( 2 );
o->type( Fl_Pack::VERTICAL );
o->box( FL_NO_BOX );
{ Fl_Box *o = new Fl_Box( 0, 0, 100, 24 );
o->align( (Fl_Align)(FL_ALIGN_BOTTOM | FL_ALIGN_INSIDE) );
o->labelsize( 10 );
o->label( "Spatialization" );
}
{ Panner* o = new Panner(0, 0, 110, 90);
o->deactivate();
o->box(FL_THIN_UP_BOX);
o->color(FL_GRAY0);
o->selection_color(FL_BACKGROUND_COLOR);
o->labeltype(FL_NORMAL_LABEL);
o->labelfont(0);
o->labelsize(11);
o->labelcolor(FL_FOREGROUND_COLOR);
o->align(FL_ALIGN_TOP);
o->when(FL_WHEN_RELEASE);
} // Panner* o
{ Fl_Box *o = new Fl_Box( 0, 0, 100, 12 );
o->align( (Fl_Align)(FL_ALIGN_BOTTOM | FL_ALIGN_INSIDE) );
o->labelsize( 10 );
o->label( "Inputs" );
}
{
Controller_Module *m = jack_input_controller = new Controller_Module( true );
m->labeltype( FL_NO_LABEL );
m->chain( _chain );
m->pad( false );
// m->connect_to( &_chain->module( 0 )->control_input[1] );
m->size( 33, 24 );
}
o->end();
}
end();
color( FL_BLACK );
size( 96, h() );
// _chain->configure_ports();
}
void
Mixer_Strip::draw ( void )
{
if ( !fl_not_clipped( x(), y(), w(), h() ) )
return;
/* don't bother drawing anything else, all we're doing is drawing the focus. */
if ( damage() != FL_DAMAGE_USER1 )
Fl_Group::draw();
Fl_Group::draw_box( FL_UP_FRAME, x(), y(), w(), h(), Fl::focus() == this ? Fl_Group::selection_color() : FL_BLACK );
}
void
Mixer_Strip::menu_cb ( const Fl_Menu_ *m )
{
char picked[256];
m->item_pathname( picked, sizeof( picked ) );
Logger log( this );
if ( ! strcmp( picked, "Width/Narrow" ) )
command_width( false );
else if ( ! strcmp( picked, "Width/Wide" ) )
command_width( true );
else if ( ! strcmp( picked, "View/Fader" ) )
command_view( false );
else if ( ! strcmp( picked, "View/Signal" ) )
command_view( true );
else if ( ! strcmp( picked, "/Move Left" ) )
command_move_left();
else if ( ! strcmp( picked, "/Move Right" ) )
command_move_right();
else if ( ! strcmp( picked, "/Rename" ) )
{
((Fl_Sometimes_Input*)name_field)->take_focus();
}
else if ( ! strcmp( picked, "/Color" ) )
{
unsigned char r, g, b;
Fl::get_color( color(), r, g, b );
if ( fl_color_chooser( "Strip Color", r, g, b ) )
color( fl_rgb_color( r, g, b ) );
redraw();
}
else if ( ! strcmp( picked, "/Remove" ) )
{
if ( Fl::event_shift() || 1 == fl_choice( "Are you sure you want to remove this strip?\n\n(this action cannot be undone)", "Cancel", "Remove", NULL ) )
command_close();
}
}
void
Mixer_Strip::menu_cb ( Fl_Widget *w, void *v )
{
((Mixer_Strip*)v)->menu_cb( (Fl_Menu_*) w );
}
/** build the context menu */
Fl_Menu_Button &
Mixer_Strip::menu ( void ) const
{
static Fl_Menu_Button m( 0, 0, 0, 0, "Strip" );
static char label[256];
snprintf( label, sizeof(label), "Strip/%s", name() );
m.label( label );
// int c = output.size();
Fl_Menu_Item menu[] =
{
{ "Width", 0, 0, 0, FL_SUBMENU },
{ "Narrow", 'n', 0, 0, FL_MENU_RADIO | ( ! width_button->value() ? FL_MENU_VALUE : 0 ) },
{ "Wide", 'w', 0, 0, FL_MENU_RADIO | ( width_button->value() ? FL_MENU_VALUE : 0 ) },
{ 0 },
{ "View", 0, 0, 0, FL_SUBMENU },
{ "Fader", 'f', 0, 0, FL_MENU_RADIO | ( 0 == tab_button->value() ? FL_MENU_VALUE : 0 ) },
{ "Signal", 's', 0, 0, FL_MENU_RADIO | ( 1 == tab_button->value() ? FL_MENU_VALUE : 0 ) },
{ 0 },
{ "Move Left", '[', 0, 0 },
{ "Move Right", ']', 0, 0 },
{ "Color", 0, 0, 0 },
{ "Rename", FL_CTRL + 'n', 0, 0 },
{ "Remove", FL_Delete, 0, 0 },
{ 0 },
};
menu_set_callback( menu, &Mixer_Strip::menu_cb, (void*)this );
m.copy( menu, (void*)this );
return m;
}
int
Mixer_Strip::handle ( int m )
{
Logger log( this );
switch ( m )
{
case FL_KEYBOARD:
{
if ( Fl_Group::handle( m ) )
return 1;
if ( Fl::event_key() == FL_Menu )
{
menu_popup( &menu(), x(), y() );
return 1;
}
else
return menu().test_shortcut() != 0;
}
break;
case FL_PUSH:
{
take_focus();
if ( Fl_Group::handle( m ) )
return 1;
if ( test_press( FL_BUTTON3 ) )
{
menu_popup( &menu() );
return 1;
}
return 0;
}
case FL_FOCUS:
damage( FL_DAMAGE_USER1 );
return Fl_Group::handle( m ) || 1;
case FL_UNFOCUS:
damage( FL_DAMAGE_USER1 );
return Fl_Group::handle( m ) || 1;
}
return Fl_Group::handle( m );
}
/************/
/* Commands */
/************/
void
Mixer_Strip::command_move_left ( void )
{
mixer->move_left( this );
}
void
Mixer_Strip::command_move_right ( void )
{
mixer->move_right( this );
}
void
Mixer_Strip::command_close ( void )
{
mixer->remove( this );
Fl::delete_widget( this );
}
void
Mixer_Strip::command_rename ( const char * s )
{
name( s );
}
void
Mixer_Strip::command_width ( bool b )
{
width_button->value( b );
width_button->do_callback();
}
void
Mixer_Strip::command_view ( bool b )
{
tab_button->value( b );
tab_button->do_callback();
}