|
- #include "mscHack.hpp"
- //#include "mscHack_Controls.hpp"
- #include "dsp/digital.hpp"
- //#include "CLog.h"
- #include "window.hpp"
- namespace rack_plugin_mscHack {
-
- #define nKEYBOARDS 3
- #define nKEYS 37
- #define nOCTAVESEL 5
- #define nPATTERNS 16
- #define nPHRASE_SAVES 8
- #define SEMI ( 1.0f / 12.0f )
-
- typedef struct
- {
- float fsemi;
-
- }KEYBOARD_KEY_STRUCT;
-
- typedef struct
- {
- int note;
- bool bTrigOff;
- int pad[ 6 ];
-
- }PATTERN_STRUCT;
-
- typedef struct
- {
- bool bPending;
- int phrase;
- }PHRASE_CHANGE_STRUCT;
-
- //-----------------------------------------------------
- // Module Definition
- //
- //-----------------------------------------------------
- struct Seq_Triad2 : Module
- {
- #define NO_COPY -1
-
- enum ParamIds
- {
- PARAM_PAUSE,
- PARAM_OCTAVES = PARAM_PAUSE + ( nKEYBOARDS ),
- PARAM_GLIDE = PARAM_OCTAVES + (nOCTAVESEL * nKEYBOARDS),
- PARAM_TRIGOFF = PARAM_GLIDE + ( nKEYBOARDS ),
- nPARAMS = PARAM_TRIGOFF + ( nKEYBOARDS )
- };
-
- enum InputIds
- {
- IN_PATTERN_TRIG,
- IN_VOCT_OFF = IN_PATTERN_TRIG + ( nKEYBOARDS ),
- IN_PROG_CHANGE = IN_VOCT_OFF + ( nKEYBOARDS ),
- IN_CLOCK_RESET = IN_PROG_CHANGE + ( nKEYBOARDS ),
- IN_GLOBAL_PAT_CLK,
- IN_GLOBAL_TRIG_MUTE,
- IN_CHANNEL_TRIG_MUTE,
- nINPUTS = IN_CHANNEL_TRIG_MUTE + ( nKEYBOARDS )
- };
-
- enum OutputIds
- {
- OUT_TRIG,
- OUT_VOCTS = OUT_TRIG + nKEYBOARDS,
- nOUTPUTS = OUT_VOCTS + nKEYBOARDS
- };
-
- CLog lg;
- bool m_bInitialized = false;
-
- // octaves
- int m_Octave[ nKEYBOARDS ] = {};
- float m_fCvStartOut[ nKEYBOARDS ] = {};
- float m_fCvEndOut[ nKEYBOARDS ] = {};
-
- // patterns
- int m_CurrentPattern[ nKEYBOARDS ] = {};
- PATTERN_STRUCT m_PatternNotes[ nKEYBOARDS ][ nPHRASE_SAVES ][ nPATTERNS ] = {};
- SchmittTrigger m_SchTrigPatternSelectInput[ nKEYBOARDS ];
- PatternSelectStrip *m_pPatternSelect[ nKEYBOARDS ] = {};
-
- int m_CopySrc = NO_COPY;
-
- // phrase save
- int m_CurrentPhrase[ nKEYBOARDS ] = {};
- PHRASE_CHANGE_STRUCT m_PhrasePending[ nKEYBOARDS ] = {};
- SchmittTrigger m_SchTrigPhraseSelect[ nKEYBOARDS ] = {};
- int m_PhrasesUsed[ nKEYBOARDS ] = {0};
- PatternSelectStrip *m_pPhraseSelect[ nKEYBOARDS ] = {};
-
- // number of steps
- int m_nSteps[ nKEYBOARDS ][ nPHRASE_SAVES ] = {};
-
- // pause button
- bool m_bPause[ nKEYBOARDS ] = {};
-
- // trig mute
- bool m_bTrigMute = false;
- MyLEDButton *m_pButtonTrigMute = NULL;
-
- // channel trig mute
- bool m_bChTrigMute[ nKEYBOARDS ] = {};
- MyLEDButton *m_pButtonChTrigMute[ nKEYBOARDS ] = {};
-
- // triggers
- bool m_bTrig[ nKEYBOARDS ] = {};
- PulseGenerator m_gatePulse[ nKEYBOARDS ];
-
- // global triggers
- SchmittTrigger m_SchTrigGlobalClkReset;
- SchmittTrigger m_SchTrigGlobalPatChange;
- bool m_GlobalClkResetPending = false;
-
- // glide
- float m_fglideInc[ nKEYBOARDS ] = {};
- int m_glideCount[ nKEYBOARDS ] = {};
- float m_fglide[ nKEYBOARDS ] = {};
- float m_fLastNotePlayed[ nKEYBOARDS ];
- bool m_bWasLastNotePlayed[ nKEYBOARDS ] = {};
-
- Keyboard_3Oct_Widget *pKeyboardWidget[ nKEYBOARDS ];
- float m_fKeyNotes[ 37 ];
-
- float m_VoctOffsetIn[ nKEYBOARDS ] = {};
-
- // buttons
- MyLEDButtonStrip *m_pButtonOctaveSelect[ nKEYBOARDS ] = {};
- MyLEDButton *m_pButtonPause[ nKEYBOARDS ] = {};
- MyLEDButton *m_pButtonTrig[ nKEYBOARDS ] = {};
- MyLEDButton *m_pButtonCopy[ nKEYBOARDS ] = {};
-
- float flast[ nKEYBOARDS ] = {};
-
- // Constructor
- Seq_Triad2() : Module( nPARAMS, nINPUTS, nOUTPUTS, 0 )
- {
- int i;
-
- for( i = 0; i < 37; i++ )
- m_fKeyNotes[ i ] = (float)i * SEMI;
-
- }
-
- // Overrides
- void step() override;
- json_t* toJson() override;
- void fromJson(json_t *rootJ) override;
- void onRandomize() override;
- void onReset() override;
-
- void SetPhraseSteps( int kb, int nSteps );
- void SetSteps( int kb, int steps );
- void SetKey( int kb );
- void SetOut( int kb );
- void ChangePattern( int kb, int index, bool bForce, bool bPlay );
- void ChangePhrase( int kb, int index, bool bForce );
- void SetPendingPhrase( int kb, int phrase );
- void Copy( int kb, bool bOn );
- };
-
- //-----------------------------------------------------
- // Seq_Triad2_OctSelect
- //-----------------------------------------------------
- void Seq_Triad2_OctSelect( void *pClass, int id, int nbutton, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
-
- mymodule->m_Octave[ id ] = nbutton;
- mymodule->SetOut( id );
- }
-
- //-----------------------------------------------------
- // Seq_Triad2_Pause
- //-----------------------------------------------------
- void Seq_Triad2_Pause( void *pClass, int id, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
- mymodule->m_bPause[ id ] = !mymodule->m_bPause[ id ];
- }
-
- //-----------------------------------------------------
- // Seq_Triad2_TrigMute
- //-----------------------------------------------------
- void Seq_Triad2_TrigMute( void *pClass, int id, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
- mymodule->m_bTrigMute = bOn;
- }
-
- //-----------------------------------------------------
- // Seq_Triad2_ChTrigMute
- //-----------------------------------------------------
- void Seq_Triad2_ChTrigMute( void *pClass, int id, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
- mymodule->m_bChTrigMute[ id ] = bOn;
- }
-
- //-----------------------------------------------------
- // Seq_Triad2_Trig
- //-----------------------------------------------------
- void Seq_Triad2_Trig( void *pClass, int id, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
- mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff = bOn;//!mymodule->m_PatternNotes[ id ][ mymodule->m_CurrentPhrase[ id ] ][ mymodule->m_CurrentPattern[ id ] ].bTrigOff;
- }
-
- //-----------------------------------------------------
- // Procedure: Widget
- //
- //-----------------------------------------------------
- void Seq_Triad2_Widget_NoteChangeCallback ( void *pClass, int kb, int notepressed, int *pnotes, bool bOn, int button )
- {
- bool bCtrl = false;
- Seq_Triad2 *mymodule = (Seq_Triad2 *)pClass;
-
- if( !pClass )
- return;
-
- // don't allow program unless paused
- if( button == 1 && !mymodule->m_bPause[ kb ] )
- return;
-
- // right click advance step
- if( button == 1 )
- {
- if( windowIsModPressed() )
- bCtrl = true;
-
- mymodule->ChangePattern( kb, mymodule->m_CurrentPattern[ kb ] + 1, true, false );
-
- if( mymodule->m_CurrentPattern[ kb ] == 0 )
- mymodule->ChangePhrase( kb, mymodule->m_CurrentPhrase[ kb ] + 1, true );
-
- // hit control to set trig off
- if( bCtrl )
- mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].bTrigOff = true;
- else
- mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].bTrigOff = false;
-
- mymodule->m_pButtonTrig[ kb ]->Set( bCtrl );
-
- mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].note = notepressed;
- mymodule->SetKey( kb );
- }
- else
- mymodule->m_PatternNotes[ kb ][ mymodule->m_CurrentPhrase[ kb ] ][ mymodule->m_CurrentPattern[ kb ] ].note = notepressed;
-
- mymodule->SetOut( kb );
- }
-
- //-----------------------------------------------------
- // Procedure: PatternChangeCallback
- //
- //-----------------------------------------------------
- void Seq_Triad2_Widget_PatternChangeCallback ( void *pClass, int kb, int pat, int max )
- {
- Seq_Triad2 *mymodule = (Seq_Triad2 *)pClass;
-
- if( !mymodule || !mymodule->m_bInitialized )
- return;
-
- if( mymodule->m_CurrentPattern[ kb ] != pat )
- mymodule->ChangePattern( kb, pat, false, true );
- else if( mymodule->m_nSteps[ kb ][ mymodule->m_CurrentPhrase[ kb ] ] != max )
- mymodule->SetSteps( kb, max );
- }
-
- //-----------------------------------------------------
- // Procedure: PhraseChangeCallback
- //
- //-----------------------------------------------------
- void Seq_Triad2_Widget_PhraseChangeCallback ( void *pClass, int kb, int pat, int max )
- {
- Seq_Triad2 *mymodule = (Seq_Triad2 *)pClass;
-
- if( !mymodule || !mymodule->m_bInitialized )
- return;
-
- if( mymodule->m_PhrasesUsed[ kb ] != max )
- {
- mymodule->SetPhraseSteps( kb, max );
- }
- else if( mymodule->m_CurrentPhrase[ kb ] == pat && mymodule->m_bPause[ kb ] && mymodule->m_CopySrc != NO_COPY )
- {
- mymodule->ChangePhrase( kb, pat, true );
- }
- else if( mymodule->m_CurrentPhrase[ kb ] != pat )
- {
- if( !mymodule->m_bPause[ kb ] && mymodule->inputs[ Seq_Triad2::IN_PATTERN_TRIG + kb ].active )
- mymodule->SetPendingPhrase( kb, pat );
- else
- mymodule->ChangePhrase( kb, pat, false );
-
- }
- }
-
- //-----------------------------------------------------
- // MyLEDButton_Copy
- //-----------------------------------------------------
- void MyLEDButton_Copy( void *pClass, int id, bool bOn )
- {
- Seq_Triad2 *mymodule;
- mymodule = (Seq_Triad2*)pClass;
- mymodule->Copy( id, bOn );
- }
-
- //-----------------------------------------------------
- // Procedure: Widget
- //
- //-----------------------------------------------------
-
- struct Seq_Triad2_Widget : ModuleWidget {
- Seq_Triad2_Widget( Seq_Triad2 *module );
- };
-
- Seq_Triad2_Widget::Seq_Triad2_Widget( Seq_Triad2 *module ) : ModuleWidget(module)
- {
- int kb, x, x2, y, y2;
-
- box.size = Vec( 15*25, 380);
-
- {
- SVGPanel *panel = new SVGPanel();
- panel->box.size = box.size;
- panel->setBackground(SVG::load(assetPlugin(plugin, "res/TriadSequencer2.svg")));
- addChild(panel);
- }
-
- //module->lg.Open("TriadSequencer2.txt");
-
- //----------------------------------------------------
- // Keyboard Keys
- y = 21;
- x = 11;
-
- for( kb = 0; kb < nKEYBOARDS; kb++ )
- {
- // channel trig mute
- module->m_pButtonChTrigMute[ kb ] = new MyLEDButton( x + 310, y + 3, 15, 15, 13.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_ChTrigMute );
- addChild( module->m_pButtonChTrigMute[ kb ] );
-
- addInput(Port::create<MyPortInSmall>( Vec( x + 285, y + 1 ), Port::INPUT, module, Seq_Triad2::IN_CHANNEL_TRIG_MUTE + kb ) );
-
- // pause button
- module->m_pButtonPause[ kb ] = new MyLEDButton( x + 60, y + 4, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_Pause );
- addChild( module->m_pButtonPause[ kb ] );
-
- // trig button
- module->m_pButtonTrig[ kb ] = new MyLEDButton( x + 260, y + 5, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, kb, module, Seq_Triad2_Trig );
- addChild( module->m_pButtonTrig[ kb ] );
-
- // glide knob
- addParam( ParamWidget::create<Knob_Yellow1_15>( Vec( x + 235, y + 86 ), module, Seq_Triad2::PARAM_GLIDE + kb, 0.0, 1.0, 0.0 ) );
-
- module->m_pButtonCopy[ kb ] = new MyLEDButton( x + 194, y + 89, 11, 11, 8.0, DWRGB( 180, 180, 180 ), DWRGB( 0, 244, 244 ), MyLEDButton::TYPE_SWITCH, kb, module, MyLEDButton_Copy );
- addChild( module->m_pButtonCopy[ kb ] );
-
- x2 = x + 274;
-
- // octave select
- module->m_pButtonOctaveSelect[ kb ] = new MyLEDButtonStrip( x2, y + 90, 11, 11, 3, 8.0, nOCTAVESEL, false, DWRGB( 180, 180, 180 ), DWRGB( 0, 255, 255 ), MyLEDButtonStrip::TYPE_EXCLUSIVE, kb, module, Seq_Triad2_OctSelect );
- addChild( module->m_pButtonOctaveSelect[ kb ] );
-
- // keyboard widget
- module->pKeyboardWidget[ kb ] = new Keyboard_3Oct_Widget( x + 39, y + 19, 1, kb, DWRGB( 255, 128, 64 ), module, Seq_Triad2_Widget_NoteChangeCallback, &module->lg );
- addChild( module->pKeyboardWidget[ kb ] );
-
- // pattern selects
- module->m_pPatternSelect[ kb ] = new PatternSelectStrip( x + 79, y + 1, 9, 7, DWRGB( 255, 128, 64 ), DWRGB( 128, 64, 0 ), DWRGB( 255, 0, 128 ), DWRGB( 128, 0, 64 ), nPATTERNS, kb, module, Seq_Triad2_Widget_PatternChangeCallback );
- addChild( module->m_pPatternSelect[ kb ] );
-
- // phrase selects
- module->m_pPhraseSelect[ kb ] = new PatternSelectStrip( x + 79, y + 86, 9, 7, DWRGB( 255, 255, 0 ), DWRGB( 128, 128, 64 ), DWRGB( 0, 255, 255 ), DWRGB( 0, 128, 128 ), nPHRASE_SAVES, kb, module, Seq_Triad2_Widget_PhraseChangeCallback );
- addChild( module->m_pPhraseSelect[ kb ] );
-
- x2 = x + 9;
- y2 = y + 4;
- // prog change trigger
- addInput(Port::create<MyPortInSmall>( Vec( x2, y2 ), Port::INPUT, module, Seq_Triad2::IN_PATTERN_TRIG + kb ) ); y2 += 40;
-
- // VOCT offset input
- addInput(Port::create<MyPortInSmall>( Vec( x2, y2 ), Port::INPUT, module, Seq_Triad2::IN_VOCT_OFF + kb ) ); y2 += 40;
-
- // prog change trigger
- addInput(Port::create<MyPortInSmall>( Vec( x2, y2 ), Port::INPUT, module, Seq_Triad2::IN_PROG_CHANGE + kb ) );
-
- // outputs
- x2 = x + 330;
- addOutput(Port::create<MyPortOutSmall>( Vec( x2, y + 27 ), Port::OUTPUT, module, Seq_Triad2::OUT_VOCTS + kb ) );
- addOutput(Port::create<MyPortOutSmall>( Vec( x2, y + 68 ), Port::OUTPUT, module, Seq_Triad2::OUT_TRIG + kb ) );
-
- y += 111;
- }
-
- // trig mute
- module->m_pButtonTrigMute = new MyLEDButton( x + 310, 3, 15, 15, 13.0, DWRGB( 180, 180, 180 ), DWRGB( 255, 0, 0 ), MyLEDButton::TYPE_SWITCH, 0, module, Seq_Triad2_TrigMute );
- addChild( module->m_pButtonTrigMute );
-
- addInput(Port::create<MyPortInSmall>( Vec( x + 285, 1 ), Port::INPUT, module, Seq_Triad2::IN_GLOBAL_TRIG_MUTE ) );
-
- // reset inputs
- y2 = 357;
- addInput(Port::create<MyPortInSmall>( Vec( x + 89, y2 ), Port::INPUT, module, Seq_Triad2::IN_CLOCK_RESET ) );
- addInput(Port::create<MyPortInSmall>( Vec( x + 166, y2 ), Port::INPUT, module, Seq_Triad2::IN_GLOBAL_PAT_CLK ) );
-
- addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
- addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
- addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
- addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
-
- module->m_bInitialized = true;
-
- module->onReset();
- }
-
- //-----------------------------------------------------
- // Procedure: reset
- //
- //-----------------------------------------------------
- void Seq_Triad2::onReset()
- {
- if( !m_bInitialized )
- return;
-
- for( int kb = 0; kb < nKEYBOARDS; kb++ )
- m_pButtonOctaveSelect[ kb ]->Set( 0, true );
-
- memset( m_fCvStartOut, 0, sizeof(m_fCvStartOut) );
- memset( m_fCvEndOut, 0, sizeof(m_fCvEndOut) );
- memset( m_PatternNotes, 0, sizeof(m_PatternNotes) );
-
- for( int kb = 0; kb < nKEYBOARDS; kb++ )
- {
- for( int pat = 0; pat < nPHRASE_SAVES; pat++ )
- m_nSteps[ kb ][ pat ] = 3;
-
- SetPhraseSteps( kb, 3 );
- ChangePattern( kb, 0, true, true );
- ChangePhrase( kb, 0, true );
- }
- }
-
- //-----------------------------------------------------
- // Procedure: randomize
- //
- //-----------------------------------------------------
- const int keyscalenotes[ 7 ] = { 0, 2, 4, 5, 7, 9, 11};
- const int keyscalenotes_minor[ 7 ] = { 0, 2, 3, 5, 7, 9, 11};
- void Seq_Triad2::onRandomize()
- {
- int kb, pat, phrase, basekey, note;
-
- for( int kb = 0; kb < nKEYBOARDS; kb++ )
- m_pButtonOctaveSelect[ kb ]->Set( 0, true );
-
- memset( m_fCvStartOut, 0, sizeof(m_fCvStartOut) );
- memset( m_fCvEndOut, 0, sizeof(m_fCvEndOut) );
- memset( m_PatternNotes, 0, sizeof(m_PatternNotes) );
-
- basekey = (int)(randomUniform() * 24.0);
-
- for( kb = 0; kb < nKEYBOARDS; kb++ )
- {
- m_Octave[ kb ] = (int)( randomUniform() * 4.0 );
-
- for( pat = 0; pat < nPATTERNS; pat++ )
- {
- for( phrase = 0; phrase < nPHRASE_SAVES; phrase++ )
- {
- if( randomUniform() > 0.7 )
- note = keyscalenotes_minor[ (int)(randomUniform() * 7.0 ) ];
- else
- note = keyscalenotes[ (int)(randomUniform() * 7.0 ) ];
-
- m_PatternNotes[ kb ][ phrase ][ pat ].bTrigOff = ( randomUniform() < 0.10 );
- m_PatternNotes[ kb ][ phrase ][ pat ].note = basekey + note;
- }
- }
-
- ChangePattern( kb, 0, true, true );
- }
- }
-
- //-----------------------------------------------------
- // Procedure: SetPhraseSteps
- //
- //-----------------------------------------------------
- void Seq_Triad2::SetPhraseSteps( int kb, int nSteps )
- {
- if( nSteps < 0 || nSteps >= nPHRASE_SAVES )
- nSteps = 0;
-
- m_PhrasesUsed[ kb ] = nSteps;
- }
-
- //-----------------------------------------------------
- // Procedure: SetSteps
- //
- //-----------------------------------------------------
- void Seq_Triad2::SetSteps( int kb, int nSteps )
- {
- if( nSteps < 0 || nSteps >= nPATTERNS )
- nSteps = 0;
-
- m_nSteps[ kb ][ m_CurrentPhrase[ kb ] ] = nSteps;
- }
-
- //-----------------------------------------------------
- // Procedure: Copy
- //
- //-----------------------------------------------------
- void Seq_Triad2::Copy( int kb, bool bOn )
- {
- if( kb < 0 || kb >= nKEYBOARDS )
- return;
-
- if( !m_bPause[ kb ] || !bOn || m_CopySrc != NO_COPY )
- {
- if( m_CopySrc != NO_COPY )
- m_pButtonCopy[ m_CopySrc ]->Set( false );
-
- m_CopySrc = NO_COPY;
- m_pButtonCopy[ kb ]->Set( false );
- }
- else if( bOn )
- {
- m_CopySrc = kb;
- }
- }
-
- //-----------------------------------------------------
- // Procedure: SetOut
- //
- //-----------------------------------------------------
- void Seq_Triad2::SetOut( int kb )
- {
- int note;
- float foct;
-
- if( kb < 0 || kb >= nKEYBOARDS )
- return;
-
- // end glide note (current pattern note)
- foct = (float)m_Octave[ kb ];
-
- note = m_PatternNotes[ kb ][ m_CurrentPhrase[ kb ] ][ m_CurrentPattern[ kb ] ].note;
-
- if( note > 36 || note < 0 )
- note = 0;
-
- m_fCvEndOut[ kb ] = foct + m_fKeyNotes[ note ] + m_VoctOffsetIn[ kb ];
-
- // start glide note (last pattern note)
- if( m_bWasLastNotePlayed[ kb ] )
- {
- m_fCvStartOut[ kb ] = m_fLastNotePlayed[ kb ] + m_VoctOffsetIn[ kb ];
- }
- else
- {
- m_bWasLastNotePlayed[ kb ] = true;
- m_fCvStartOut[ kb ] = m_fCvEndOut[ kb ] + m_VoctOffsetIn[ kb ];
- }
-
- m_fLastNotePlayed[ kb ] = m_fCvEndOut[ kb ] + m_VoctOffsetIn[ kb ];
-
- // glide time ( max glide = 0.5 seconds )
- m_glideCount[ kb ] = 1 + (int)( ( params[ PARAM_GLIDE + kb ].value * 0.5 ) * engineGetSampleRate());
-
- m_fglideInc[ kb ] = 1.0 / (float)m_glideCount[ kb ];
-
- m_fglide[ kb ] = 1.0;
-
- // always trig on pause
- if( m_bPause[ kb ] )
- m_bTrig[ kb ] = true;
- else if( !m_PatternNotes[ kb ][ m_CurrentPhrase[ kb ] ][ m_CurrentPattern[ kb ] ].bTrigOff )
- m_bTrig[ kb ] = true;
- else
- m_bTrig[ kb ] = false;
- }
-
- //-----------------------------------------------------
- // Procedure: SetKey
- //
- //-----------------------------------------------------
- void Seq_Triad2::SetKey( int kb )
- {
- pKeyboardWidget[ kb ]->setkey( &m_PatternNotes[ kb ][ m_CurrentPhrase[ kb ] ][ m_CurrentPattern[ kb ] ].note );
- }
-
- //-----------------------------------------------------
- // Procedure: SetPendingPhrase
- //
- //-----------------------------------------------------
- void Seq_Triad2::SetPendingPhrase( int kb, int phraseIn )
- {
- int phrase;
-
- if( phraseIn < 0 || phraseIn >= nPHRASE_SAVES )
- phrase = ( m_CurrentPhrase[ kb ] + 1 ) & 0x7;
- else
- phrase = phraseIn;
-
- if( phrase > m_PhrasesUsed[ kb ] )
- phrase = 0;
-
- m_PhrasePending[ kb ].bPending = true;
- m_PhrasePending[ kb ].phrase = phrase;
- m_pPhraseSelect[ kb ]->SetPat( m_CurrentPhrase[ kb ], false );
- m_pPhraseSelect[ kb ]->SetPat( phrase, true );
- }
-
- //-----------------------------------------------------
- // Procedure: ChangePhrase
- //
- //-----------------------------------------------------
- void Seq_Triad2::ChangePhrase( int kb, int index, bool bForce )
- {
- if( kb < 0 || kb >= nKEYBOARDS )
- return;
-
- if( !bForce && index == m_CurrentPhrase[ kb ] )
- return;
-
- if( index < 0 )
- index = nPHRASE_SAVES - 1;
- else if( index >= nPHRASE_SAVES )
- index = 0;
-
- if( m_CopySrc != NO_COPY )
- {
- // do not copy if we are not paused
- if( m_bPause[ kb ] )
- {
- memcpy( m_PatternNotes[ kb ][ index ], m_PatternNotes[ m_CopySrc ][ m_CurrentPhrase[ m_CopySrc ] ], sizeof(PATTERN_STRUCT) * nPATTERNS );
- m_pButtonCopy[ m_CopySrc ]->Set( false );
- m_nSteps[ kb ][ index ] = m_nSteps[ m_CopySrc ][ m_CurrentPhrase[ m_CopySrc ] ];
- m_CopySrc = NO_COPY;
- }
- }
-
- m_CurrentPhrase[ kb ] = index;
-
- m_pPhraseSelect[ kb ]->SetPat( index, false );
- m_pPhraseSelect[ kb ]->SetMax( m_PhrasesUsed[ kb ] );
- m_pPatternSelect[ kb ]->SetMax( m_nSteps[ kb ][ index ] );
-
- // set keyboard key
- SetKey( kb );
-
- m_pButtonTrig[ kb ]->Set( m_PatternNotes[ kb ][ m_CurrentPhrase[ kb ] ][ m_CurrentPattern[ kb ] ].bTrigOff );
-
- // change octave light
- m_pButtonOctaveSelect[ kb ]->Set( m_Octave[ kb ], true );
-
- // set output note
- SetOut( kb );
- }
-
- //-----------------------------------------------------
- // Procedure: ChangePattern
- //
- //-----------------------------------------------------
- void Seq_Triad2::ChangePattern( int kb, int index, bool bForce, bool bPlay )
- {
- if( kb < 0 || kb >= nKEYBOARDS )
- return;
-
- if( !bForce && index == m_CurrentPattern[ kb ] )
- return;
-
- if( index < 0 )
- index = nPATTERNS - 1;
- else if( index >= nPATTERNS )
- index = 0;
-
- // update octave offset immediately when not running
- m_VoctOffsetIn[ kb ] = inputs[ IN_VOCT_OFF + kb ].normalize( 0.0 );
-
- m_CurrentPattern[ kb ] = index;
-
- m_pPatternSelect[ kb ]->SetPat( index, false );
-
- // set keyboard key
- SetKey( kb );
-
- m_pButtonTrig[ kb ]->Set( m_PatternNotes[ kb ][ m_CurrentPhrase[ kb ] ][ m_CurrentPattern[ kb ] ].bTrigOff );
-
- // change octave light
- m_pButtonOctaveSelect[ kb ]->Set( m_Octave[ kb ], true );
-
- // set outputted note
- if( bPlay )
- SetOut( kb );
- }
-
- //-----------------------------------------------------
- // Procedure:
- //
- //-----------------------------------------------------
- json_t *Seq_Triad2::toJson()
- {
- int *pint;
- bool *pbool;
- json_t *gatesJ;
- json_t *rootJ = json_object();
-
- // pauses
- pbool = &m_bPause[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( (int)pbool[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_bPause", gatesJ );
-
- // number of steps
- pint = (int*)&m_nSteps[ 0 ][ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS * nPHRASE_SAVES; i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_nSteps", gatesJ );
-
- // octaves
- pint = (int*)&m_Octave[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_Octave", gatesJ );
-
- // phrase select
- pint = (int*)&m_CurrentPhrase[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_CurrentPhrase", gatesJ );
-
- // patterns
- pint = (int*)&m_PatternNotes[ 0 ][ 0 ][ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < (nPHRASE_SAVES * nPATTERNS * nKEYBOARDS * 8); i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_PatternNotes", gatesJ );
-
-
- // phrase used
- pint = (int*)&m_PhrasesUsed[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_PhrasesUsed", gatesJ );
-
- // current pattern
- pint = (int*)&m_CurrentPattern[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( pint[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_CurrentPattern", gatesJ );
-
- // trig mute
- gatesJ = json_array();
-
- json_t *gateJ = json_boolean( m_bTrigMute );
- json_array_append_new( gatesJ, gateJ );
- json_object_set_new( rootJ, "m_bTrigMute", gatesJ );
-
- // channel trig mute
- pbool = &m_bChTrigMute[ 0 ];
-
- gatesJ = json_array();
-
- for (int i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_integer( pbool[ i ] );
- json_array_append_new( gatesJ, gateJ );
- }
-
- json_object_set_new( rootJ, "m_bChTrigMute", gatesJ );
-
- return rootJ;
- }
-
- //-----------------------------------------------------
- // Procedure: fromJson
- //
- //-----------------------------------------------------
- void Seq_Triad2::fromJson(json_t *rootJ)
- {
- bool *pbool;
- int *pint;
- int i;
- json_t *StepsJ;
-
- // pauses
- pbool = &m_bPause[ 0 ];
- StepsJ = json_object_get( rootJ, "m_bPause" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pbool[ i ] = json_integer_value( gateJ );
- }
- }
-
- // number of steps
- pint = (int*)&m_nSteps[ 0 ][ 0 ];
- StepsJ = json_object_get( rootJ, "m_nSteps" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS * nPHRASE_SAVES; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- // octaves
- pint = (int*)&m_Octave[ 0 ];
- StepsJ = json_object_get( rootJ, "m_Octave" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- // phrase select
- pint = (int*)&m_CurrentPhrase[ 0 ];
- StepsJ = json_object_get( rootJ, "m_CurrentPhrase" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- // all patterns and phrases
- pint = (int*)&m_PatternNotes[ 0 ][ 0 ][ 0 ];
-
- StepsJ = json_object_get( rootJ, "m_PatternNotes" );
-
- if (StepsJ)
- {
- for ( i = 0; i < (nPHRASE_SAVES * nPATTERNS * nKEYBOARDS * 8); i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- // phrase steps
- pint = (int*)&m_PhrasesUsed[ 0 ];
-
- StepsJ = json_object_get( rootJ, "m_PhrasesUsed" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- // current pattern
- pint = (int*)&m_CurrentPattern[ 0 ];
-
- StepsJ = json_object_get( rootJ, "m_CurrentPattern" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pint[ i ] = json_integer_value( gateJ );
- }
- }
-
- for( i = 0; i < nKEYBOARDS; i++ )
- {
- m_pPhraseSelect[ i ]->SetMax( m_PhrasesUsed[ i ] );
- m_pPhraseSelect[ i ]->SetPat( m_CurrentPhrase[ i ], false );
-
- m_pPatternSelect[ i ]->SetMax( m_nSteps[ i ][ m_CurrentPhrase[ i ] ] );
- m_pPatternSelect[ i ]->SetPat( m_CurrentPattern[ i ], false );
-
- m_pButtonPause[ i ]->Set( m_bPause[ i ] );
-
- SetPhraseSteps( i, m_PhrasesUsed[ i ] );
- ChangePhrase( i, m_CurrentPhrase[ i ], true );
- ChangePattern( i, m_CurrentPattern[ i ], true, false );
- }
-
- // pauses
- StepsJ = json_object_get( rootJ, "m_bTrigMute" );
-
- if (StepsJ)
- {
- json_t *gateJ = json_array_get( StepsJ, 0 );
-
- if (gateJ)
- m_bTrigMute = json_boolean_value( gateJ );
- }
-
- if( m_bTrigMute )
- m_pButtonTrigMute->Set( m_bTrigMute );
-
- // channel trig mute
- pbool = &m_bChTrigMute[ 0 ];
- StepsJ = json_object_get( rootJ, "m_bChTrigMute" );
-
- if (StepsJ)
- {
- for ( i = 0; i < nKEYBOARDS; i++)
- {
- json_t *gateJ = json_array_get(StepsJ, i);
-
- if (gateJ)
- pbool[ i ] = json_integer_value( gateJ );
- }
- }
-
- for( i = 0; i < nKEYBOARDS; i++ )
- {
- if( m_bChTrigMute[ i ] )
- m_pButtonChTrigMute[ i ]->Set( m_bChTrigMute[ i ] );
- }
- }
-
- //-----------------------------------------------------
- // Procedure: step
- //
- //-----------------------------------------------------
- #define LIGHT_LAMBDA ( 0.065f )
- void Seq_Triad2::step()
- {
- int kb, useclock;
- bool bGlobalPatChange = false, bGlobalClkTriggered = false, PatTrig[ nKEYBOARDS ] = {};
- float trigout = 0.0f;
-
- if( !m_bInitialized )
- return;
-
- if( inputs[ IN_GLOBAL_TRIG_MUTE ].active )
- {
- if( inputs[ IN_GLOBAL_TRIG_MUTE ].value >= 0.00001 )
- {
- m_bTrigMute = true;
- m_pButtonTrigMute->Set( true );
- }
- else if( inputs[ IN_GLOBAL_TRIG_MUTE ].value < 0.00001 )
- {
- m_bTrigMute = false;
- m_pButtonTrigMute->Set( false );
- }
- }
-
- // global phrase change trigger
- if( inputs[ IN_GLOBAL_PAT_CLK ].active )
- {
- if( m_SchTrigGlobalPatChange.process( inputs[ IN_GLOBAL_PAT_CLK ].value ) )
- bGlobalPatChange = true;
- }
-
- // global clock reset
- if( inputs[ IN_CLOCK_RESET ].active )
- {
- if( m_SchTrigGlobalClkReset.process( inputs[ IN_CLOCK_RESET ].value ) )
- m_GlobalClkResetPending = true;
- }
-
- // get trigs
- for( kb = 0; kb < nKEYBOARDS; kb++ )
- PatTrig[ kb ] = m_SchTrigPatternSelectInput[ kb ].process( inputs[ IN_PATTERN_TRIG + kb ].value );
-
- // process triggered phrase changes
- for( kb = 0; kb < nKEYBOARDS; kb++ )
- {
- useclock = kb;
-
- if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].active )
- {
- if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].value >= 0.00001 )
- {
- m_bChTrigMute[ kb ] = true;
- m_pButtonChTrigMute[ kb ]->Set( true );
- }
- else if( inputs[ IN_CHANNEL_TRIG_MUTE + kb ].value < 0.00001 )
- {
- m_bChTrigMute[ kb ] = false;
- m_pButtonChTrigMute[ kb ]->Set( false );
- }
- }
-
- // if no keyboard clock active then use kb 0's clock
- if( !inputs[ IN_PATTERN_TRIG + kb ].active && inputs[ IN_PATTERN_TRIG + 0 ].active )
- useclock = 0;
-
- // phrase change trigger
- if( bGlobalPatChange && !m_bPause[ kb ] && inputs[ IN_PATTERN_TRIG + useclock ].active )
- {
- SetPendingPhrase( kb, -1 );
- }
- else if( inputs[ IN_PROG_CHANGE + kb ].active && !m_bPause[ kb ] && inputs[ IN_PATTERN_TRIG + useclock ].active )
- {
- if( m_SchTrigPhraseSelect[ kb ].process( inputs[ IN_PROG_CHANGE + kb ].value ) )
- SetPendingPhrase( kb, -1 );
- }
-
- // pat change trigger - ignore if already pending
- if( inputs[ IN_PATTERN_TRIG + useclock ].active && !m_bPause[ kb ] )
- {
- if( PatTrig[ useclock ] )
- {
- if( m_GlobalClkResetPending )
- {
- bGlobalClkTriggered = true;
- m_CurrentPattern[ kb ] = -1;
- }
- else if( m_CurrentPattern[ kb ] >= ( m_nSteps[ kb ][ m_CurrentPhrase[ kb ] ] ) )
- {
- m_CurrentPattern[ kb ] = (nPATTERNS - 1);
- }
-
- ChangePattern( kb, m_CurrentPattern[ kb ] + 1, true, true );
-
- if( m_CurrentPattern[ kb ] == 0 )
- {
- if( m_PhrasePending[ kb ].bPending )
- {
- m_PhrasePending[ kb ].bPending = false;
- ChangePhrase( kb, m_PhrasePending[ kb ].phrase, false );
- }
- }
- }
- }
- else
- {
- // resolve any left over phrase triggers
- if( m_PhrasePending[ kb ].bPending )
- {
- m_PhrasePending[ kb ].bPending = false;
- ChangePhrase( kb, m_PhrasePending[ kb ].phrase, false );
- }
- }
-
- if( m_bTrig[ kb ] )
- {
- m_bTrig[ kb ] = false;
- m_gatePulse[ kb ].trigger( 0.050f );
- }
-
- trigout = m_gatePulse[ kb ].process( 1.0 / engineGetSampleRate() ) ? CV_MAX : 0.0;
-
- if( !m_bTrigMute && !m_bChTrigMute[ kb ] )
- outputs[ OUT_TRIG + kb ].value = trigout;
- else
- outputs[ OUT_TRIG + kb ].value = 0.0f;
-
- if( --m_glideCount[ kb ] > 0 )
- m_fglide[ kb ] -= m_fglideInc[ kb ];
- else
- m_fglide[ kb ] = 0.0;
-
- if( m_bTrigMute || m_bChTrigMute[ kb ] )
- outputs[ OUT_VOCTS + kb ].value = flast[ kb ];
- else
- {
- flast[ kb ] = ( m_fCvStartOut[ kb ] * m_fglide[ kb ] ) + ( m_fCvEndOut[ kb ] * ( 1.0 - m_fglide[ kb ] ) );
- outputs[ OUT_VOCTS + kb ].value = flast[ kb ];
- }
- }
-
- if( bGlobalClkTriggered )
- m_GlobalClkResetPending = false;
- }
-
- } // namespace rack_plugin_mscHack
-
- using namespace rack_plugin_mscHack;
-
- RACK_PLUGIN_MODEL_INIT(mscHack, Seq_Triad2) {
- Model *modelSeq_Triad2 = Model::create<Seq_Triad2, Seq_Triad2_Widget>( "mscHack", "TriadSeq2", "SEQ Triad 2", SEQUENCER_TAG, MULTIPLE_TAG );
- return modelSeq_Triad2;
- }
|