#include "mscHack.hpp" //#include "mscHack_Controls.hpp" #include "dsp/digital.hpp" //#include "CLog.h" namespace rack_plugin_mscHack { #define GROUPS 4 #define CH_PER_GROUP 4 #define CHANNELS ( GROUPS * CH_PER_GROUP ) #define nAUX 4 #define GROUP_OFF_X 52 #define CHANNEL_OFF_X 34 #define FADE_MULT (0.0005f) #define L 0 #define R 1 #define MUTE_FADE_STATE_IDLE 0 #define MUTE_FADE_STATE_INC 1 #define MUTE_FADE_STATE_DEC 2 //----------------------------------------------------- // Module Definition // //----------------------------------------------------- struct Mix_4x4_Stereo : Module { enum ParamIds { PARAM_MAIN_LEVEL, PARAM_LEVEL_IN, PARAM_PAN_IN = PARAM_LEVEL_IN + CHANNELS, PARAM_GROUP_LEVEL_IN = PARAM_PAN_IN + CHANNELS, PARAM_GROUP_PAN_IN = PARAM_GROUP_LEVEL_IN + GROUPS, PARAM_MUTE_BUTTON = PARAM_GROUP_PAN_IN + GROUPS, PARAM_SOLO_BUTTON = PARAM_MUTE_BUTTON + CHANNELS, PARAM_GROUP_MUTE = PARAM_SOLO_BUTTON + CHANNELS, PARAM_GROUP_SOLO = PARAM_GROUP_MUTE + GROUPS, PARAM_EQ_HI = PARAM_GROUP_SOLO + GROUPS, PARAM_EQ_MD = PARAM_EQ_HI + CHANNELS, PARAM_EQ_LO = PARAM_EQ_MD + CHANNELS, PARAM_AUX_KNOB = PARAM_EQ_LO + CHANNELS, PARAM_AUX_PREFADE = PARAM_AUX_KNOB + (GROUPS * nAUX), PARAM_AUX_OUT = PARAM_AUX_PREFADE + (GROUPS * nAUX), nPARAMS = PARAM_AUX_OUT + (nAUX) }; enum InputIds { IN_LEFT, IN_RIGHT = IN_LEFT + CHANNELS, IN_LEVEL = IN_RIGHT + CHANNELS, IN_PAN = IN_LEVEL + CHANNELS, IN_GROUP_LEVEL = IN_PAN + CHANNELS, IN_GROUP_PAN = IN_GROUP_LEVEL + GROUPS, nINPUTS = IN_GROUP_PAN + GROUPS }; enum OutputIds { OUT_MAINL, OUT_MAINR, OUT_AUXL, OUT_AUXR = OUT_AUXL + nAUX, nOUTPUTS = OUT_AUXR + nAUX }; bool m_bInitialized = false; CLog lg; // mute buttons bool m_bMuteStates[ CHANNELS ] = {}; float m_fMuteFade[ CHANNELS ] = {}; int m_FadeState[ CHANNELS ] = {MUTE_FADE_STATE_IDLE}; // solo buttons bool m_bSoloStates[ CHANNELS ] = {}; // group mute buttons bool m_bGroupMuteStates[ GROUPS ] = {}; float m_fGroupMuteFade[ GROUPS ] = {}; int m_GroupFadeState[ GROUPS ] = {MUTE_FADE_STATE_IDLE}; // group solo buttons bool m_bGroupSoloStates[ GROUPS ] = {}; // processing bool m_bMono[ CHANNELS ]; float m_fSubMix[ GROUPS ][ 3 ] = {}; // aux bool m_bGroupPreFadeAuxStates[ GROUPS ][ nAUX ] = {}; // LED Meters LEDMeterWidget *m_pLEDMeterChannel[ CHANNELS ][ 2 ] ={}; LEDMeterWidget *m_pLEDMeterGroup[ GROUPS ][ 2 ] ={}; LEDMeterWidget *m_pLEDMeterMain[ 2 ] ={}; // EQ Rez float lp1[ CHANNELS ][ 2 ] = {}, bp1[ CHANNELS ][ 2 ] = {}; float m_hpIn[ CHANNELS ]; float m_lpIn[ CHANNELS ]; float m_mpIn[ CHANNELS ]; float m_rezIn[ CHANNELS ] = {0}; float m_Freq; // buttons MyLEDButton *m_pButtonChannelMute[ CHANNELS ] = {}; MyLEDButton *m_pButtonChannelSolo[ CHANNELS ] = {}; MyLEDButton *m_pButtonGroupMute[ GROUPS ] = {}; MyLEDButton *m_pButtonGroupSolo[ GROUPS ] = {}; MyLEDButton *m_pButtonAuxPreFader[ GROUPS ][ nAUX ] = {}; #define L 0 #define R 1 // Contructor Mix_4x4_Stereo() : Module(nPARAMS, nINPUTS, nOUTPUTS, 0){} //----------------------------------------------------- // MyEQHi_Knob //----------------------------------------------------- struct MyEQHi_Knob : Knob_Green1_15 { Mix_4x4_Stereo *mymodule; int param; void onChange( EventChange &e ) override { mymodule = (Mix_4x4_Stereo*)module; if( mymodule ) { param = paramId - Mix_4x4_Stereo::PARAM_EQ_HI; mymodule->m_hpIn[ param ] = value; } RoundKnob::onChange( e ); } }; //----------------------------------------------------- // MyEQHi_Knob //----------------------------------------------------- struct MyEQMid_Knob : Knob_Green1_15 { Mix_4x4_Stereo *mymodule; int param; void onChange( EventChange &e ) override { mymodule = (Mix_4x4_Stereo*)module; if( mymodule ) { param = paramId - Mix_4x4_Stereo::PARAM_EQ_MD; mymodule->m_mpIn[ param ] = value; } RoundKnob::onChange( e ); } }; //----------------------------------------------------- // MyEQHi_Knob //----------------------------------------------------- struct MyEQLo_Knob : Knob_Green1_15 { Mix_4x4_Stereo *mymodule; int param; void onChange( EventChange &e ) override { mymodule = (Mix_4x4_Stereo*)module; if( mymodule ) { param = paramId - Mix_4x4_Stereo::PARAM_EQ_LO; mymodule->m_lpIn[ param ] = value; } RoundKnob::onChange( e ); } }; // Overrides void step() override; json_t* toJson() override; void fromJson(json_t *rootJ) override; void onRandomize() override{} void onReset() override; void ProcessMuteSolo( int channel, bool bMute, bool bGroup ); void ProcessEQ( int ch, float *pL, float *pR ); }; //----------------------------------------------------- // MyLEDButton_Aux //----------------------------------------------------- void Mix_4x4_Stereo_MyLEDButton_Aux( void *pClass, int id, bool bOn ) { int ch, i; Mix_4x4_Stereo *mymodule; mymodule = (Mix_4x4_Stereo*)pClass; ch = id / nAUX; i = id - (nAUX * ch); mymodule->m_bGroupPreFadeAuxStates[ ch ][ i ] = !mymodule->m_bGroupPreFadeAuxStates[ ch ][ i ]; mymodule->m_pButtonAuxPreFader[ ch ][ i ]->Set( mymodule->m_bGroupPreFadeAuxStates[ ch ][ i ] ); } //----------------------------------------------------- // MyLEDButton_ChMute //----------------------------------------------------- void Mix_4x4_Stereo_MyLEDButton_ChMute( void *pClass, int id, bool bOn ) { Mix_4x4_Stereo *mymodule; mymodule = (Mix_4x4_Stereo*)pClass; mymodule->ProcessMuteSolo( id, true, false ); } //----------------------------------------------------- // MyLEDButton_ChSolo //----------------------------------------------------- void Mix_4x4_Stereo_MyLEDButton_ChSolo( void *pClass, int id, bool bOn ) { Mix_4x4_Stereo *mymodule; mymodule = (Mix_4x4_Stereo*)pClass; mymodule->ProcessMuteSolo( id, false, false ); } //----------------------------------------------------- // MyLEDButton_GroupMute //----------------------------------------------------- void Mix_4x4_Stereo_MyLEDButton_GroupMute( void *pClass, int id, bool bOn ) { Mix_4x4_Stereo *mymodule; mymodule = (Mix_4x4_Stereo*)pClass; mymodule->ProcessMuteSolo( id, true, true ); } //----------------------------------------------------- // MyLEDButton_GroupSolo //----------------------------------------------------- void Mix_4x4_Stereo_MyLEDButton_GroupSolo( void *pClass, int id, bool bOn ) { Mix_4x4_Stereo *mymodule; mymodule = (Mix_4x4_Stereo*)pClass; mymodule->ProcessMuteSolo( id, false, true ); } #define CUTOFF (0.025f) //----------------------------------------------------- // Procedure: Widget // //----------------------------------------------------- struct Mix_4x4_Stereo_Widget : ModuleWidget { Mix_4x4_Stereo_Widget( Mix_4x4_Stereo *module ); }; Mix_4x4_Stereo_Widget::Mix_4x4_Stereo_Widget( Mix_4x4_Stereo *module ) : ModuleWidget(module) { float fx, fx2, fx3, fx5, fx7; int ch, x, y, i, ybase, x2, y2; box.size = Vec( 15*47, 380); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/Mix_4x4_Stereo.svg"))); addChild(panel); } //module->lg.Open("Mix_4x4_Stereo.txt"); addChild(Widget::create(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x-30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x-30, 365))); //---------------------------------------------------- // Add mix sliders x = 23; y = 38; // main channel for ( ch = 0; ch < CHANNELS; ch++ ) { // Left channel inputs addInput(Port::create( Vec( x, y ), Port::INPUT, module, Mix_4x4_Stereo::IN_LEFT + ch ) ); y += 25; // Right channel inputs addInput(Port::create( Vec( x, y ), Port::INPUT, module, Mix_4x4_Stereo::IN_RIGHT + ch ) ); y += 26; // Level knobs addParam(ParamWidget::create( Vec( x - 5, y ), module, Mix_4x4_Stereo::PARAM_LEVEL_IN + ch, 0.0, AMP_MAX, 0.0 ) ); y += 31; // Level inputs addInput(Port::create( Vec( x, y ), Port::INPUT, module, Mix_4x4_Stereo::IN_LEVEL + ch ) ); y += 23; // pan knobs addParam(ParamWidget::create( Vec( x - 5, y ), module, Mix_4x4_Stereo::PARAM_PAN_IN + ch, -1.0, 1.0, 0.0 ) ); y += 31; // Pan inputs addInput(Port::create( Vec( x, y ), Port::INPUT, module, Mix_4x4_Stereo::IN_PAN + ch ) ); y += 22; // mute buttons module->m_pButtonChannelMute[ ch ] = new MyLEDButton( x - 5, y, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, ch, module, Mix_4x4_Stereo_MyLEDButton_ChMute ); addChild( module->m_pButtonChannelMute[ ch ] ); //y += 26; // solo buttons module->m_pButtonChannelSolo[ ch ] = new MyLEDButton( x + 11, y, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_SWITCH, ch, module, Mix_4x4_Stereo_MyLEDButton_ChSolo ); addChild( module->m_pButtonChannelSolo[ ch ] ); y += 22; y2 = y; // eq and rez addParam(ParamWidget::create( Vec( x - 5, y ), module, Mix_4x4_Stereo::PARAM_EQ_HI + ch, 0.0, 1.0, 0.5 ) ); y += 19; addParam(ParamWidget::create( Vec( x - 5, y ), module, Mix_4x4_Stereo::PARAM_EQ_MD + ch, 0.0, 1.0, 0.5 ) ); y += 19; addParam(ParamWidget::create( Vec( x - 5, y ), module, Mix_4x4_Stereo::PARAM_EQ_LO + ch, 0.0, 1.0, 0.5 ) ); // LED Meters module->m_pLEDMeterChannel[ ch ][ 0 ] = new LEDMeterWidget( x + 13, y2 + 30, 4, 1, 1, true ); addChild( module->m_pLEDMeterChannel[ ch ][ 0 ] ); module->m_pLEDMeterChannel[ ch ][ 1 ] = new LEDMeterWidget( x + 18, y2 + 30, 4, 1, 1, true ); addChild( module->m_pLEDMeterChannel[ ch ][ 1 ] ); if( ( ch & 3 ) == 3 ) { x += GROUP_OFF_X; } else { x += CHANNEL_OFF_X; } y = 38; } // group mixera ybase = 278; x = 12; for( i = 0; i < GROUPS; i++ ) { // mute/solo buttons x2 = x + 81; y2 = ybase; module->m_pButtonGroupMute[ i ] = new MyLEDButton( x2, y2 + 4, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, i, module, Mix_4x4_Stereo_MyLEDButton_GroupMute ); addChild( module->m_pButtonGroupMute[ i ] ); x2 += 28; module->m_pButtonGroupSolo[ i ] = new MyLEDButton( x2, y2 + 4, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButton::TYPE_SWITCH, i, module, Mix_4x4_Stereo_MyLEDButton_GroupSolo ); addChild( module->m_pButtonGroupSolo[ i ] ); // group level and pan inputs x2 = x + 79; y2 = ybase + 23; // group VU Meters module->m_pLEDMeterGroup[ i ][ 0 ] = new LEDMeterWidget( x2 + 2, y2 + 21, 5, 2, 1, true ); addChild( module->m_pLEDMeterGroup[ i ][ 0 ] ); module->m_pLEDMeterGroup[ i ][ 1 ] = new LEDMeterWidget( x2 + 9, y2 + 21, 5, 2, 1, true ); addChild( module->m_pLEDMeterGroup[ i ][ 1 ] ); // group level and pan knobs x2 = x + 105; y2 = ybase + 17; addParam(ParamWidget::create( Vec( x2, y2 + 3 ), module, Mix_4x4_Stereo::PARAM_GROUP_LEVEL_IN + i, 0.0, AMP_MAX, 0.0 ) ); y2 += 32; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_GROUP_PAN_IN + i, -1.0, 1.0, 0.0 ) ); // aux 1/3 #define AUX_H 29 x2 = x + 6; y2 = ybase + 20; module->m_pButtonAuxPreFader[ i ][ 0 ] = new MyLEDButton( x2, y2, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, (i * nAUX) + 0, module, Mix_4x4_Stereo_MyLEDButton_Aux ); addChild( module->m_pButtonAuxPreFader[ i ][ 0 ] ); y2 += AUX_H; module->m_pButtonAuxPreFader[ i ][ 2 ] = new MyLEDButton( x2, y2, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, (i * nAUX) + 2, module, Mix_4x4_Stereo_MyLEDButton_Aux ); addChild( module->m_pButtonAuxPreFader[ i ][ 2 ] ); x2 = x + 20; y2 = ybase + 16; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_KNOB + (i * nAUX) + 0, 0.0, AMP_MAX, 0.0 ) ); y2 += AUX_H; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_KNOB + (i * nAUX) + 2, 0.0, AMP_MAX, 0.0 ) ); // aux 2/4 x2 = x + 38; y2 = ybase + 28; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_KNOB + (i * nAUX) + 1, 0.0, AMP_MAX, 0.0 ) ); y2 += AUX_H; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_KNOB + (i * nAUX) + 3, 0.0, AMP_MAX, 0.0 ) ); x2 = x + 62; y2 = ybase + 32; module->m_pButtonAuxPreFader[ i ][ 1 ] = new MyLEDButton( x2, y2, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, (i * nAUX) + 1, module, Mix_4x4_Stereo_MyLEDButton_Aux ); addChild( module->m_pButtonAuxPreFader[ i ][ 1 ] ); y2 += AUX_H; module->m_pButtonAuxPreFader[ i ][ 3 ] = new MyLEDButton( x2, y2, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 255, 0 ), MyLEDButton::TYPE_SWITCH, (i * nAUX) + 3, module, Mix_4x4_Stereo_MyLEDButton_Aux ); addChild( module->m_pButtonAuxPreFader[ i ][ 3 ] ); // account for slight error in pixel conversion to svg area x += 155; } //for( int i = 0; i < 15; i++ ) //module->lg.f("level %d = %.3f\n", i, module->m_pLEDMeterChannel[ 0 ][ 0 ]->flevels[ i ] ); // main mixer knob addParam(ParamWidget::create( Vec( 626, 237 ), module, Mix_4x4_Stereo::PARAM_MAIN_LEVEL, 0.0, AMP_MAX, 0.0 ) ); module->m_pLEDMeterMain[ 0 ] = new LEDMeterWidget( 684, 242, 5, 3, 2, true ); addChild( module->m_pLEDMeterMain[ 0 ] ); module->m_pLEDMeterMain[ 1 ] = new LEDMeterWidget( 691, 242, 5, 3, 2, true ); addChild( module->m_pLEDMeterMain[ 1 ] ); // outputs addOutput(Port::create( Vec( 636, 305 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_MAINL ) ); addOutput(Port::create( Vec( 668, 335 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_MAINR ) ); // AUX out #define AUX_OUT_H 42 x2 = 649; y2 = 25; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_OUT + 0, 0.0, AMP_MAX, 0.0 ) ); y2 += AUX_OUT_H; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_OUT + 1, 0.0, AMP_MAX, 0.0 ) ); y2 += AUX_OUT_H; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_OUT + 2, 0.0, AMP_MAX, 0.0 ) ); y2 += AUX_OUT_H; addParam(ParamWidget::create( Vec( x2, y2 ), module, Mix_4x4_Stereo::PARAM_AUX_OUT + 3, 0.0, AMP_MAX, 0.0 ) ); x2 = 635; y2 = 45; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXL ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXL + 1 ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXL + 2 ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXL + 3 ) ); x2 = 664; y2 = 45; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXR ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXR + 1 ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXR + 2 ) ); y2 += AUX_OUT_H; addOutput(Port::create( Vec( x2, y2 ), Port::OUTPUT, module, Mix_4x4_Stereo::OUT_AUXR + 3 ) ); // calculate eq rez freq fx = 3.141592 * (CUTOFF * 0.026315789473684210526315789473684) * 2 * 3.141592; fx2 = fx*fx; fx3 = fx2*fx; fx5 = fx3*fx2; fx7 = fx5*fx2; module->m_Freq = 2.0 * (fx - (fx3 * 0.16666666666666666666666666666667) + (fx5 * 0.0083333333333333333333333333333333) - (fx7 * 0.0001984126984126984126984126984127)); module->m_bInitialized = true; module->onReset(); } //----------------------------------------------------- // Procedure: reset // //----------------------------------------------------- void Mix_4x4_Stereo::onReset() { int ch, i, aux; if( !m_bInitialized ) return; for( ch = 0; ch < CHANNELS; ch++ ) { m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; m_pButtonChannelMute[ ch ]->Set( false ); m_pButtonChannelSolo[ ch ]->Set( false ); m_bMuteStates[ ch ] = false; m_bSoloStates[ ch ] = false; m_fMuteFade[ ch ] = 1.0; } for( i = 0; i < GROUPS; i++ ) { for( aux = 0; aux < nAUX; aux++ ) { m_bGroupPreFadeAuxStates[ i ][ aux ] = false; m_pButtonAuxPreFader[ i ][ aux ]->Set( false ); } m_GroupFadeState[ i ] = MUTE_FADE_STATE_IDLE; m_pButtonGroupMute[ i ]->Set( false ); m_pButtonGroupSolo[ i ]->Set( false ); m_bGroupMuteStates[ i ] = false; m_fGroupMuteFade[ i ] = 1.0; } } //----------------------------------------------------- // Procedure: // //----------------------------------------------------- json_t *Mix_4x4_Stereo::toJson() { bool *pbool; json_t *gatesJ; json_t *rootJ = json_object(); // channel mutes pbool = &m_bMuteStates[ 0 ]; gatesJ = json_array(); for (int i = 0; i < CHANNELS; i++) { json_t *gateJ = json_integer( (int) pbool[ i ] ); json_array_append_new( gatesJ, gateJ ); } json_object_set_new( rootJ, "channel mutes", gatesJ ); // channel solos pbool = &m_bSoloStates[ 0 ]; gatesJ = json_array(); for (int i = 0; i < CHANNELS; i++) { json_t *gateJ = json_integer( (int) pbool[ i ] ); json_array_append_new( gatesJ, gateJ ); } json_object_set_new( rootJ, "channel solos", gatesJ ); // group mutes pbool = &m_bGroupMuteStates[ 0 ]; gatesJ = json_array(); for (int i = 0; i < GROUPS; i++) { json_t *gateJ = json_integer( (int) pbool[ i ] ); json_array_append_new( gatesJ, gateJ ); } json_object_set_new( rootJ, "group mutes", gatesJ ); // group solos pbool = &m_bGroupSoloStates[ 0 ]; gatesJ = json_array(); for (int i = 0; i < GROUPS; i++) { json_t *gateJ = json_integer( (int) pbool[ i ] ); json_array_append_new( gatesJ, gateJ ); } json_object_set_new( rootJ, "group solos", gatesJ ); // AUX states pbool = &m_bGroupPreFadeAuxStates[ 0 ][ 0 ]; gatesJ = json_array(); for (int i = 0; i < GROUPS * nAUX; i++) { json_t *gateJ = json_integer( (int) pbool[ i ] ); json_array_append_new( gatesJ, gateJ ); } json_object_set_new( rootJ, "group AUX prefade states", gatesJ ); return rootJ; } //----------------------------------------------------- // Procedure: fromJson // //----------------------------------------------------- void Mix_4x4_Stereo::fromJson(json_t *rootJ) { int ch, i, aux; bool *pbool; json_t *StepsJ; bool bSolo[ GROUPS ] = {0}, bGroupSolo = false; // channel mutes pbool = &m_bMuteStates[ 0 ]; StepsJ = json_object_get( rootJ, "channel mutes" ); if (StepsJ) { for ( i = 0; i < CHANNELS; i++) { json_t *gateJ = json_array_get(StepsJ, i); if (gateJ) pbool[ i ] = json_integer_value( gateJ ); } } // channel solos pbool = &m_bSoloStates[ 0 ]; StepsJ = json_object_get( rootJ, "channel solos" ); if (StepsJ) { for ( i = 0; i < CHANNELS; i++) { json_t *gateJ = json_array_get(StepsJ, i); if (gateJ) pbool[ i ] = json_integer_value( gateJ ); } } // group mutes pbool = &m_bGroupMuteStates[ 0 ]; StepsJ = json_object_get( rootJ, "group mutes" ); if (StepsJ) { for ( i = 0; i < GROUPS; i++) { json_t *gateJ = json_array_get(StepsJ, i); if (gateJ) pbool[ i ] = json_integer_value( gateJ ); } } // group solos pbool = &m_bGroupSoloStates[ 0 ]; StepsJ = json_object_get( rootJ, "group solos" ); if (StepsJ) { for ( i = 0; i < GROUPS; i++) { json_t *gateJ = json_array_get(StepsJ, i); if (gateJ) pbool[ i ] = json_integer_value( gateJ ); } } // AUX states pbool = &m_bGroupPreFadeAuxStates[ 0 ][ 0 ]; StepsJ = json_object_get( rootJ, "group AUX prefade states" ); if (StepsJ) { for ( i = 0; i < GROUPS * nAUX; i++) { json_t *gateJ = json_array_get(StepsJ, i); if (gateJ) pbool[ i ] = json_integer_value( gateJ ); } } // anybody soloing? for( ch = 0; ch < CHANNELS; ch++ ) { if( m_bSoloStates[ ch ] ) { bSolo[ ch / CH_PER_GROUP ] = true; } } for( ch = 0; ch < CHANNELS; ch++ ) { if( bSolo[ ch / CH_PER_GROUP ] ) { // only open soloing channels if( m_bSoloStates[ ch ] ) m_fMuteFade[ ch ] = 1.0; else m_fMuteFade[ ch ] = 0.0; } else { // nobody is soloing so just open the non muted channels m_fMuteFade[ ch ] = m_bMuteStates[ ch ] ? 0.0: 1.0; } m_pButtonChannelMute[ ch ]->Set( m_bMuteStates[ ch ] ); m_pButtonChannelSolo[ ch ]->Set( m_bSoloStates[ ch ] ); //lg.f("channel mute fade = %.3f\n", m_fMuteFade[ ch ] ); } // anybody group soloing? for( i = 0; i < GROUPS; i++ ) { if( m_bGroupSoloStates[ i ] ) { bGroupSolo = true; break; } } for( i = 0; i < GROUPS; i++ ) { for( aux = 0; aux < nAUX; aux++ ) m_pButtonAuxPreFader[ i ][ aux ]->Set( m_bGroupPreFadeAuxStates[ i ][ aux ] ); if( bGroupSolo ) { // only open soloing channels if( m_bGroupSoloStates[ i ] ) m_fGroupMuteFade[ i ] = 1.0; else m_fGroupMuteFade[ i ] = 0.0; } else { // nobody is soloing so just open the non muted channels m_fGroupMuteFade[ i ] = m_bGroupMuteStates[ i ] ? 0.0: 1.0; } m_pButtonGroupMute[ i ]->Set( m_bGroupMuteStates[ i ] ); m_pButtonGroupSolo[ i ]->Set( m_bGroupSoloStates[ i ] ); //lg.f("group mute fade = %.3f\n", m_fGroupMuteFade[ i ] ); } } //----------------------------------------------------- // Procedure: ProcessMuteSolo // //----------------------------------------------------- void Mix_4x4_Stereo::ProcessMuteSolo( int index, bool bMute, bool bGroup ) { int i, group, si, ei; bool bSoloEnabled = false, bSoloOff = false; if( bGroup ) { if( bMute ) { m_bGroupMuteStates[ index ] = !m_bGroupMuteStates[ index ]; // turn solo off if( m_bGroupSoloStates[ index ] ) { bSoloOff = true; m_bGroupSoloStates[ index ] = false; m_pButtonGroupSolo[ index ]->Set( false ); } // if mute is off then set volume if( m_bGroupMuteStates[ index ] ) { m_pButtonGroupMute[ index ]->Set( true ); m_GroupFadeState[ index ] = MUTE_FADE_STATE_DEC; } else { m_pButtonGroupMute[ index ]->Set( false ); m_GroupFadeState[ index ] = MUTE_FADE_STATE_INC; } } else { m_bGroupSoloStates[ index ] = !m_bGroupSoloStates[ index ]; // turn mute off if( m_bGroupMuteStates[ index ] ) { m_bGroupMuteStates[ index ] = false; m_pButtonGroupMute[ index ]->Set( false ); } // shut down volume of all groups not in solo if( !m_bGroupSoloStates[ index ] ) { bSoloOff = true; m_pButtonGroupSolo[ index ]->Set( false ); } else { m_pButtonGroupSolo[ index ]->Set( true ); } } // is a track soloing? for( i = 0; i < GROUPS; i++ ) { if( m_bGroupSoloStates[ i ] ) { bSoloEnabled = true; break; } } if( bSoloEnabled ) { // process solo for( i = 0; i < GROUPS; i++ ) { // shut down volume of all groups not in solo if( !m_bGroupSoloStates[ i ] ) { m_GroupFadeState[ i ] = MUTE_FADE_STATE_DEC; } else { m_GroupFadeState[ i ] = MUTE_FADE_STATE_INC; } } } // nobody soloing and just turned solo off then enable all channels that aren't muted else if( bSoloOff ) { // process solo for( i = 0; i < GROUPS; i++ ) { // bring back if not muted if( !m_bGroupMuteStates[ i ] ) { m_GroupFadeState[ i ] = MUTE_FADE_STATE_INC; } } } } // !bGroup else { group = index / CH_PER_GROUP; si = group * CH_PER_GROUP; ei = si + CH_PER_GROUP; if( bMute ) { m_bMuteStates[ index ] = !m_bMuteStates[ index ]; // turn solo off if( m_bSoloStates[ index ] ) { bSoloOff = true; m_bSoloStates[ index ] = false; m_pButtonChannelSolo[ index ]->Set( false ); } // if mute is off then set volume if( m_bMuteStates[ index ] ) { m_pButtonChannelMute[ index ]->Set( true ); m_FadeState[ index ] = MUTE_FADE_STATE_DEC; } else { m_pButtonChannelMute[ index ]->Set( false ); m_FadeState[ index ] = MUTE_FADE_STATE_INC; } } else { m_bSoloStates[ index ] = !m_bSoloStates[ index ]; // turn mute off if( m_bMuteStates[ index ] ) { m_bMuteStates[ index ] = false; m_pButtonChannelMute[ index ]->Set( false ); } // toggle solo if( !m_bSoloStates[ index ] ) { bSoloOff = true; m_pButtonChannelSolo[ index ]->Set( false ); } else { m_pButtonChannelSolo[ index ]->Set( true ); } } // is a track soloing? for( i = si; i < ei; i++ ) { if( m_bSoloStates[ i ] ) { bSoloEnabled = true; break; } } if( bSoloEnabled ) { // process solo for( i = si; i < ei; i++ ) { // shut down volume of all not in solo if( !m_bSoloStates[ i ] ) { m_FadeState[ i ] = MUTE_FADE_STATE_DEC; } else { m_FadeState[ i ] = MUTE_FADE_STATE_INC; } } } // nobody soloing and just turned solo off then enable all channels that aren't muted else if( bSoloOff ) { // process solo for( i = si; i < ei; i++ ) { // bring back if not muted if( !m_bMuteStates[ i ] ) { m_FadeState[ i ] = MUTE_FADE_STATE_INC; } } } } } //----------------------------------------------------- // Procedure: ProcessEQ // //----------------------------------------------------- #define MULTI (0.33333333333333333333333333333333f) void Mix_4x4_Stereo::ProcessEQ( int ch, float *pL, float *pR ) { float rez, hp1; float input[ 2 ], out[ 2 ], lowpass, bandpass, highpass; input[ L ] = *pL / AUDIO_MAX; input[ R ] = *pR / AUDIO_MAX; rez = 1.00; // do left and right channels for( int i = 0; i < 2; i++ ) { input[ i ] = input[ i ] + 0.000000001; lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; lowpass = lp1[ ch ][ i ]; highpass = hp1; bandpass = bp1[ ch ][ i ]; lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; lowpass = lowpass + lp1[ ch ][ i ]; highpass = highpass + hp1; bandpass = bandpass + bp1[ ch ][ i ]; input[ i ] = input[ i ] - 0.000000001; lp1[ ch ][ i ] = lp1[ ch ][ i ] + m_Freq * bp1[ ch ][ i ]; hp1 = input[ i ] - lp1[ ch ][ i ] - rez * bp1[ ch ][ i ]; bp1[ ch ][ i ] = m_Freq * hp1 + bp1[ ch ][ i ]; lowpass = (lowpass + lp1[ ch ][ i ]) * MULTI; highpass = (highpass + hp1) * MULTI; bandpass = (bandpass + bp1[ ch ][ i ]) * MULTI; out[ i ] = ( highpass * m_hpIn[ ch ] ) + ( lowpass * m_lpIn[ ch ] ) + ( bandpass * m_mpIn[ ch ] ); } *pL = clamp( out[ L ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); *pR = clamp( out[ R ] * AUDIO_MAX, -AUDIO_MAX, AUDIO_MAX ); } //----------------------------------------------------- // Procedure: step // //----------------------------------------------------- void Mix_4x4_Stereo::step() { int ch, group, aux; float inL = 0.0, inR = 0.0, inLClean, inRClean, outL, outR, mainL = 0.0, mainR = 0.0; float inLvl, inPan; float auxL[ nAUX ] = {}, auxR[ nAUX ] = {}; bool bGroupActive[ GROUPS ] = {0}; if( !m_bInitialized ) return; memset( m_fSubMix, 0, sizeof(m_fSubMix) ); // channel mixers for ( ch = 0; ch < CHANNELS; ch++ ) { group = ch / CH_PER_GROUP; inLClean = 0.0; inRClean = 0.0; inL = 0.0; inR = 0.0; if( inputs[ IN_RIGHT + ch ].active || inputs[ IN_LEFT + ch ].active ) { inLvl = clamp( ( params[ PARAM_LEVEL_IN + ch ].value + ( inputs[ IN_LEVEL + ch ].normalize( 0.0f ) / CV_MAX ) ), 0.0f, AMP_MAX ); bGroupActive[ group ] = true; // check right channel first for possible mono if( inputs[ IN_RIGHT + ch ].active ) { inRClean = inputs[ IN_RIGHT + ch ].value; inR = inRClean * inLvl; m_bMono[ ch ] = false; } else m_bMono[ ch ] = true; // left channel if( inputs[ IN_LEFT + ch ].active ) { inLClean = inputs[ IN_LEFT + ch ].value; inL = inLClean * inLvl; if( m_bMono[ ch ] ) { inRClean = inLClean; inR = inL; } } // put output to aux if pre fader for ( aux = 0; aux < nAUX; aux++ ) { if( m_bGroupPreFadeAuxStates[ group ][ aux ] ) { auxL[ aux ] += inLClean * params[ PARAM_AUX_KNOB + (group * nAUX) + aux ].value; auxR[ aux ] += inRClean * params[ PARAM_AUX_KNOB + (group * nAUX) + aux ].value; } } if( m_FadeState[ ch ] == MUTE_FADE_STATE_DEC ) { m_fMuteFade[ ch ] -= FADE_MULT; if( m_fMuteFade[ ch ] <= 0.0 ) { m_fMuteFade[ ch ] = 0.0; m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; } } else if( m_FadeState[ ch ] == MUTE_FADE_STATE_INC ) { m_fMuteFade[ ch ] += FADE_MULT; if( m_fMuteFade[ ch ] >= 1.0 ) { m_fMuteFade[ ch ] = 1.0; m_FadeState[ ch ] = MUTE_FADE_STATE_IDLE; } } ProcessEQ( ch, &inL, &inR ); inL *= m_fMuteFade[ ch ]; inR *= m_fMuteFade[ ch ]; // pan inPan = clamp( params[ PARAM_PAN_IN + ch ].value + ( inputs[ IN_PAN + ch ].normalize( 0.0f ) / CV_MAX ), -1.0f, 1.0f ); //lg.f("pan = %.3f\n", inputs[ IN_PAN + ch ].value ); if( inPan <= 0.0 ) inR *= ( 1.0 + inPan ); else inL *= ( 1.0 - inPan ); // put output to aux if not pre fader for ( aux = 0; aux < nAUX; aux++ ) { if( !m_bGroupPreFadeAuxStates[ group ][ aux ] ) { auxL[ aux ] += inL * params[ PARAM_AUX_KNOB + (group * nAUX) + aux ].value; auxR[ aux ] += inR * params[ PARAM_AUX_KNOB + (group * nAUX) + aux ].value; } } } // this channel not active else { } m_fSubMix[ group ][ L ] += inL; m_fSubMix[ group ][ R ] += inR; if( m_pLEDMeterChannel[ ch ][ 0 ] ) m_pLEDMeterChannel[ ch ][ 0 ]->Process( inL / AUDIO_MAX ); if( m_pLEDMeterChannel[ ch ][ 1 ] ) m_pLEDMeterChannel[ ch ][ 1 ]->Process( inR / AUDIO_MAX); } // group mixers for ( group = 0; group < GROUPS; group++ ) { outL = 0.0; outR = 0.0; if( bGroupActive[ group ] ) { inLvl = clamp( ( params[ PARAM_GROUP_LEVEL_IN + group ].value + ( inputs[ IN_GROUP_LEVEL + group ].normalize( 0.0f ) / CV_MAX ) ), 0.0f, AMP_MAX ); outL = m_fSubMix[ group ][ L ] * inLvl; outR = m_fSubMix[ group ][ R ] * inLvl; // pan inPan = clamp( params[ PARAM_GROUP_PAN_IN + group ].value + ( inputs[ IN_GROUP_PAN + group ].normalize( 0.0f ) / CV_MAX ), -1.0f, 1.0f ); if( inPan <= 0.0 ) outR *= ( 1.0 + inPan ); else outL *= ( 1.0 - inPan ); if( m_GroupFadeState[ group ] == MUTE_FADE_STATE_DEC ) { m_fGroupMuteFade[ group ] -= FADE_MULT; if( m_fGroupMuteFade[ group ] <= 0.0 ) { m_fGroupMuteFade[ group ] = 0.0; m_GroupFadeState[ group ] = MUTE_FADE_STATE_IDLE; } } else if( m_GroupFadeState[ group ] == MUTE_FADE_STATE_INC ) { m_fGroupMuteFade[ group ] += FADE_MULT; if( m_fGroupMuteFade[ group ] >= 1.0 ) { m_fGroupMuteFade[ group ] = 1.0; m_GroupFadeState[ group ] = MUTE_FADE_STATE_IDLE; } } outL *= m_fGroupMuteFade[ group ]; outR *= m_fGroupMuteFade[ group ]; } if( m_pLEDMeterGroup[ group ][ 0 ] ) m_pLEDMeterGroup[ group ][ 0 ]->Process( outL / AUDIO_MAX ); if( m_pLEDMeterGroup[ group ][ 1 ] ) m_pLEDMeterGroup[ group ][ 1 ]->Process( outR / AUDIO_MAX ); mainL += outL; mainR += outR; } if( m_pLEDMeterMain[ 0 ] ) m_pLEDMeterMain[ 0 ]->Process( ( mainL / AUDIO_MAX ) * params[ PARAM_MAIN_LEVEL ].value ); if( m_pLEDMeterMain[ 1 ] ) m_pLEDMeterMain[ 1 ]->Process( ( mainR / AUDIO_MAX ) * params[ PARAM_MAIN_LEVEL ].value ); // put aux output for ( aux = 0; aux < nAUX; aux++ ) { outputs[ OUT_AUXL + aux ].value = clamp( auxL[ aux ] * params[ PARAM_AUX_OUT + aux ].value, -AUDIO_MAX, AUDIO_MAX ); outputs[ OUT_AUXR + aux ].value = clamp( auxR[ aux ] * params[ PARAM_AUX_OUT + aux ].value, -AUDIO_MAX, AUDIO_MAX ); } outputs[ OUT_MAINL ].value = clamp( mainL * params[ PARAM_MAIN_LEVEL ].value, -AUDIO_MAX, AUDIO_MAX ); outputs[ OUT_MAINR ].value = clamp( mainR * params[ PARAM_MAIN_LEVEL ].value, -AUDIO_MAX, AUDIO_MAX ); } } // namespace rack_plugin_mscHack using namespace rack_plugin_mscHack; RACK_PLUGIN_MODEL_INIT(mscHack, Mix_4x4_Stereo) { Model *modelMix_4x4_Stereo = Model::create( "mscHack", "Mix_4x4_Stereo(2)", "MIXER 4x4 Stereo/Mono", MIXER_TAG, EQUALIZER_TAG, QUAD_TAG, PANNING_TAG, AMPLIFIER_TAG, MULTIPLE_TAG ); return modelMix_4x4_Stereo; }