Mixer: Add new module "Aux" to allow creation of "send" topology without requiring an extra strip to control the send gain.

pull/59/head
Jonathan Moore Liles 2013-04-16 22:42:28 -07:00
parent 7900ef6add
commit fc5ef8f9f9
10 changed files with 393 additions and 119 deletions

179
mixer/src/AUX_Module.C Normal file
View File

@ -0,0 +1,179 @@
/*******************************************************************************/
/* Copyright (C) 2013 Jonathan Moore Liles */
/* */
/* This program is free software; you can redistribute it and/or modify it */
/* under the terms of the GNU General Public License as published by the */
/* Free Software Foundation; either version 2 of the License, or (at your */
/* option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
/* more details. */
/* */
/* You should have received a copy of the GNU General Public License along */
/* with This program; see the file COPYING. If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
#include <FL/fl_draw.H>
#include "AUX_Module.H"
#include "dsp.h"
/* The purpose of this module is to provide auxiliary outputs, with
* gain. This allows one to create a 'send' type topology without
* having to use an extra strip to control the 'send' gain. */
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::LOGARITHMIC;
p.hints.ranged = true;
p.hints.minimum = -70.0f;
p.hints.maximum = 6.0f;
p.hints.default_value = 0.0f;
p.connect_to( new float );
p.control_value( p.hints.default_value );
add_port( p );
}
log_create();
copy_label( "Aux" );
}
AUX_Module::~AUX_Module ( )
{
configure_outputs(0);
delete (float*)control_input[0].buffer();
}
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;
char s[10];
snprintf( s, sizeof(s), "aux-%c", 'A' + n );
prefix( s );
snprintf( s, sizeof(s), "Aux (%c)", 'A' + n );
copy_label( s );
}
void
AUX_Module::process ( nframes_t nframes )
{
if ( !bypass() )
{
float g = DB_CO( control_input[0].control_value() );
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
if ( audio_input[i].connected() )
buffer_copy_and_apply_gain( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), nframes, g );
}
}
else
{
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
if ( audio_input[i].connected() )
buffer_fill_with_silence( (sample_t*)jack_output[i].buffer( nframes ), nframes );
}
}
}
void
AUX_Module::draw ( void )
{
int W = 5;
Module::draw_box(x(),y(),w() - W,h());
Module::draw_label(x(),y(),w() - W,h());
Module *m = this;
fl_color( fl_darker( FL_FOREGROUND_COLOR ) );
int spacing, offset;
spacing = h() / m->ninputs();
offset = spacing / 2;
for ( int i = m->ninputs(); i--; )
{
int xi = offset + ( spacing * i );
fl_rectf( m->x() + m->w() - W, m->y() + xi, W, 2 );
}
}
bool
AUX_Module::configure_outputs ( int n )
{
int on = audio_output.size();
if ( n > on )
{
for ( int i = on; i < n; ++i )
{
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
}
}
else
{
for ( int i = on; i > n; --i )
{
audio_output.back().disconnect();
audio_output.pop_back();
}
}
return true;
}
bool
AUX_Module::configure_inputs ( int n )
{
bool b = JACK_Module::configure_inputs( n );
if ( b )
{
return configure_outputs( n );
}
return false;
}

54
mixer/src/AUX_Module.H Normal file
View File

@ -0,0 +1,54 @@
/*******************************************************************************/
/* Copyright (C) 2013 Jonathan Moore Liles */
/* */
/* This program is free software; you can redistribute it and/or modify it */
/* under the terms of the GNU General Public License as published by the */
/* Free Software Foundation; either version 2 of the License, or (at your */
/* option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
/* more details. */
/* */
/* You should have received a copy of the GNU General Public License along */
/* with This program; see the file COPYING. If not,write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
#pragma once
#include "JACK_Module.H"
class AUX_Module : public JACK_Module
{
int _number;
protected:
virtual void get ( Log_Entry &e ) const;
virtual void set ( Log_Entry &e );
public:
virtual const char *name ( void ) const { return "AUX"; }
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 ( );
LOG_CREATE_FUNC( AUX_Module );
protected:
virtual void draw ( void );
virtual void process ( nframes_t nframes );
};

View File

@ -91,7 +91,7 @@ public:
void draw ( void )
{
draw_box();
draw_box(x(),y(),w(),h());
Fl_Group::draw();
}

View File

@ -32,41 +32,47 @@
JACK_Module::JACK_Module ( )
JACK_Module::JACK_Module ( bool log )
: Module ( 50, 24, name() )
{
/* FIXME: how do Controls find out that a connected value has changed? How does this work in ladspa? */
_prefix = 0;
if ( log )
{
Port p( this, Port::INPUT, Port::CONTROL, "Inputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.ranged = true;
/* FIXME: how do Controls find out that a connected value has changed? How does this work in ladspa? */
{
Port p( this, Port::INPUT, Port::CONTROL, "Inputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.ranged = true;
p.hints.visible = false;
p.connect_to( new float );
p.control_value_no_callback( 0 );
p.connect_to( new float );
p.control_value_no_callback( 0 );
add_port( p );
add_port( p );
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Outputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.ranged = true;
p.hints.visible = false;
p.connect_to( new float );
p.control_value_no_callback( 0 );
add_port( p );
}
color( FL_BLACK );
log_create();
}
{
Port p( this, Port::INPUT, Port::CONTROL, "Outputs" );
p.hints.type = Port::Hints::INTEGER;
p.hints.minimum = 0;
p.hints.maximum = 16;
p.hints.ranged = true;
p.connect_to( new float );
p.control_value_no_callback( 0 );
add_port( p );
}
end();
color( FL_BLACK );
log_create();
end();
}
JACK_Module::~JACK_Module ( )
@ -74,6 +80,8 @@ JACK_Module::~JACK_Module ( )
log_destroy();
configure_inputs( 0 );
configure_outputs( 0 );
if ( _prefix )
free( _prefix );
}
@ -93,19 +101,26 @@ JACK_Module::configure_inputs ( int n )
{
for ( int i = on; i < n; ++i )
{
JACK::Port po( chain()->engine(), JACK::Port::Output, i );
JACK::Port *po = NULL;
if ( ! po.activate() )
if ( !_prefix )
po = new JACK::Port( chain()->engine(), JACK::Port::Output, i );
else
po = new JACK::Port( chain()->engine(), JACK::Port::Output, _prefix, i );
if ( ! po->activate() )
{
jack_port_activation_error( &po );
jack_port_activation_error( po );
return false;
}
if ( po.valid() )
if ( po->valid() )
{
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
jack_output.push_back( po );
jack_output.push_back( *po );
}
delete po;
}
}
else
@ -119,7 +134,8 @@ JACK_Module::configure_inputs ( int n )
}
}
control_input[0].control_value_no_callback( n );
if ( is_default() )
control_input[0].control_value_no_callback( n );
return true;
}
@ -139,19 +155,26 @@ JACK_Module::configure_outputs ( int n )
{
for ( int i = on; i < n; ++i )
{
JACK::Port po( chain()->engine(), JACK::Port::Input, i );
JACK::Port *po = NULL;
if ( ! po.activate() )
if ( !_prefix )
po = new JACK::Port( chain()->engine(), JACK::Port::Input, i );
else
po = new JACK::Port( chain()->engine(), JACK::Port::Input, _prefix, i );
if ( ! po->activate() )
{
jack_port_activation_error( &po );
jack_port_activation_error( po );
return false;
}
if ( po.valid() )
if ( po->valid() )
{
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
jack_input.push_back( po );
jack_input.push_back( *po );
}
delete po;
}
}
else
@ -165,7 +188,8 @@ JACK_Module::configure_outputs ( int n )
}
}
control_input[1].control_value_no_callback( n );
if ( is_default() )
control_input[1].control_value_no_callback( n );
return true;
}
@ -230,10 +254,19 @@ void
JACK_Module::process ( nframes_t nframes )
{
for ( unsigned int i = 0; i < audio_input.size(); ++i )
{
if ( audio_input[i].connected() )
buffer_copy( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), nframes );
buffer_copy( (sample_t*)jack_output[i].buffer( nframes ),
(sample_t*)audio_input[i].buffer(),
nframes );
}
for ( unsigned int i = 0; i < audio_output.size(); ++i )
{
if ( audio_output[i].connected() )
buffer_copy( (sample_t*)audio_output[i].buffer(), (sample_t*)jack_input[i].buffer( nframes ), nframes );
buffer_copy( (sample_t*)audio_output[i].buffer(),
(sample_t*)jack_input[i].buffer( nframes ),
nframes );
}
}

View File

@ -19,13 +19,27 @@
#pragma once
#include "Module.H"
#include "JACK/Port.H"
#include <vector>
class JACK_Module : public Module
{
char *_prefix;
protected:
void prefix ( const char *s )
{
if ( _prefix )
free( _prefix );
_prefix = NULL;
if ( s )
_prefix = strdup( s );
}
std::vector<JACK::Port> jack_input;
std::vector<JACK::Port> jack_output;
@ -33,21 +47,19 @@ class JACK_Module : public Module
public:
JACK_Module ( );
JACK_Module ( bool log = true );
virtual ~JACK_Module ( );
const char *name ( void ) const { return "JACK"; }
virtual const char *name ( void ) const { return "JACK"; }
bool initialize ( void );
virtual bool initialize ( void );
int can_support_inputs ( int );
bool configure_inputs ( int n );
bool configure_outputs ( int n );
virtual int can_support_inputs ( int );
virtual bool configure_inputs ( int n );
virtual bool configure_outputs ( int n );
void add_output ( void );
void handle_control_changed ( Port *p );
void handle_chain_name_changed ();
virtual void handle_control_changed ( Port *p );
virtual void handle_chain_name_changed ();
LOG_CREATE_FUNC( JACK_Module );

View File

@ -48,5 +48,5 @@ protected:
virtual int handle ( int m );
virtual void process ( nframes_t nframes );
virtual void draw ( void ) { draw_box(); }
virtual void draw ( void ) { draw_box(x(),y(),w(),h()); }
};

View File

@ -33,6 +33,7 @@
#include "Mono_Pan_Module.H"
#include "Meter_Module.H"
#include "Plugin_Module.H"
#include "AUX_Module.H"
#include <FL/Fl_Menu_Button.H>
#include "FL/test_press.H"
@ -395,7 +396,11 @@ Module::set ( Log_Entry &e )
e.get( i, &s, &v );
if ( ! strcmp( s, ":chain" ) )
if ( ! ( strcmp( s, ":is_default" ) ) )
{
is_default( atoi( v ) );
}
else if ( ! strcmp( s, ":chain" ) )
{
/* This trickiness is because we may need to know the name of
our chain before we actually get added to it. */
@ -421,10 +426,6 @@ Module::set ( Log_Entry &e )
{
set_parameters( v );
}
else if ( ! ( strcmp( s, ":is_default" ) ) )
{
is_default( atoi( v ) );
}
else if ( ! ( strcmp( s, ":active" ) ) )
{
bypass( ! atoi( v ) );
@ -527,17 +528,10 @@ Module::set_parameters ( const char *parameters )
void
Module::draw_box ( void )
Module::draw_box ( int tx, int ty, int tw, int th )
{
fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) );
int tw, th, tx, ty;
tw = w();
th = h();
ty = y();
tx = x();
fl_push_clip( tx, ty, tw, th );
Fl_Color c = color();
@ -575,10 +569,8 @@ Module::draw_box ( void )
}
void
Module::draw_label ( void )
Module::draw_label ( int tx, int ty, int tw, int th )
{
int tw, th, tx, ty;
bbox( tx, ty, tw, th );
const char *lp = label();
@ -616,47 +608,53 @@ Module::draw_label ( void )
void
Module::insert_menu_cb ( const Fl_Menu_ *m )
{
unsigned long id = Plugin_Chooser::plugin_chooser( this->ninputs() );
const char * picked = m->mvalue()->label();
DMESSAGE("picked = %s", picked );
Module *mod = NULL;
switch ( id )
if ( !strcmp( picked, "Aux" ) )
{
case 0:
return;
case 1:
mod = new JACK_Module();
break;
case 2:
mod = new Gain_Module();
break;
case 3:
mod = new Meter_Module();
break;
case 4:
mod = new Mono_Pan_Module();
break;
default:
int n = 0;
for ( int i = 0; i < chain()->modules(); i++ )
{
Plugin_Module *m = new Plugin_Module();
m->load( id );
mod = m;
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;
}
else if ( !strcmp( picked, "Gain" ) )
mod = new Gain_Module();
else if ( !strcmp( picked, "Meter" ) )
mod = new Meter_Module();
else if ( !strcmp( picked, "Mono Pan" ))
mod = new Mono_Pan_Module();
else if ( !strcmp(picked, "Plugin" ))
{
unsigned long id = Plugin_Chooser::plugin_chooser( this->ninputs() );
if ( id == 0 )
return;
Plugin_Module *m = new Plugin_Module();
m->load( id );
mod = m;
}
if ( mod )
{
if ( !strcmp( mod->name(), "JACK" ) )
{
DMESSAGE( "Special casing JACK module" );
JACK_Module *jm = (JACK_Module*)mod;
jm->chain( chain() );
jm->configure_inputs( ninputs() );
jm->configure_outputs( ninputs() );
}
if ( ! chain()->insert( this, mod ) )
{
fl_alert( "Cannot insert this module at this point in the chain" );
@ -737,16 +735,12 @@ Module::menu ( void ) const
{
insert_menu = new Fl_Menu_Button( 0, 0, 0, 0 );
insert_menu->add( "Gain", 0, 0, new unsigned long(2) );
insert_menu->add( "Meter", 0, 0, new unsigned long(3) );
insert_menu->add( "Mono Pan", 0, 0, new unsigned long(4) );
insert_menu->add( "Gain", 0, 0 );
insert_menu->add( "Meter", 0, 0 );
insert_menu->add( "Mono Pan", 0, 0 );
insert_menu->add( "Aux", 0, 0 );
insert_menu->add( "Plugin", 0, 0 );
insert_menu->add( "Plugin", 0, 0, new unsigned long(4) );
/* Plugin_Module::add_plugins_to_menu( insert_menu ); */
// menu_set_callback( insert_menu, &Module::insert_menu_cb, (void*)this );
insert_menu->callback( &Module::insert_menu_cb, (void*)this );
}

View File

@ -269,10 +269,10 @@ public:
void bbox ( int &X, int &Y, int &W, int &H )
{
X = x() + 5;
Y = y() + 5;
W = w() - 10;
H = h() - 10;
X += + 5;
Y += 5;
W -= 10;
H -= 10;
}
Module ( int W, int H, const char *L = 0 );
@ -435,10 +435,10 @@ public:
protected:
void draw_connections ( void );
void draw_label ( void );
void draw_box ( void );
void draw_label ( int X, int Y, int W, int H );
void draw_box ( int X, int Y, int W, int H );
virtual void draw ( void ) { Module::draw_box(); Module::draw_label(); }
virtual void draw ( void ) { Module::draw_box(x(),y(),w(),h()); Module::draw_label(x(),y(),w(),h()); }
virtual int handle ( int m );
virtual void get ( Log_Entry &e ) const;

View File

@ -51,7 +51,7 @@
#include "Mono_Pan_Module.H"
#include "Chain.H"
#include "Mixer_Strip.H"
#include "AUX_Module.H"
#include "NSM.H"
#include <signal.h>
@ -156,6 +156,7 @@ main ( int argc, char **argv )
LOG_REGISTER_CREATE( Mono_Pan_Module );
LOG_REGISTER_CREATE( Meter_Indicator_Module );
LOG_REGISTER_CREATE( Controller_Module );
LOG_REGISTER_CREATE( AUX_Module );
signal( SIGPIPE, SIG_IGN );

View File

@ -49,6 +49,7 @@ src/DPM.C
src/Engine/Engine.C
src/Gain_Module.C
src/JACK_Module.C
src/AUX_Module.C
src/LADSPAInfo.C
src/Meter_Indicator_Module.C
src/Meter_Module.C