Skip to content

Instantly share code, notes, and snippets.

@rrc2soft
Last active June 12, 2019 08:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rrc2soft/ea9a7e2dbdc117b9946bb115ae9fd98c to your computer and use it in GitHub Desktop.
Save rrc2soft/ea9a7e2dbdc117b9946bb115ae9fd98c to your computer and use it in GitHub Desktop.
// Minimalism wizard, by rrc2soft. v1.31
// Requires Mozaic 1.03 or higher
// AU Parameters:
// User 0: PLAY ON/OFF
// User 1: PHASE ON/OFF
// User 2: SUBSTRACTION ON/OFF
// User 3: LENGTH ON/OFF
// User 4: SCALE ON/OFF
// User 5: TRANSPOSITION (64 = 0, 0 = -12, 127 = +12)
// User 6: HUMANIZATION
// USER EVENTS
//============
@MyEvolutionKnob
if _val = 0 or _emptyFound
_emptyFound = YES
LabelKnob _it, _it2, {) —}
else
LabelKnob _it, _it2, {) Eights: }, _val
Inc evolutionLen
endif
@End
@MyMutationKnob
if _val = -1 or _emptyFound
_emptyFound = YES
LabelKnob _it, _it, {) —}
else
Inc mutationLen
if _val % 10 = 0
LabelKnob _it, _it, {) E}, (Div _val, 10) + 1, {=>}
elseif _val % 10 = 1
LabelKnob _it, _it, {) E}, (Div _val, 10) + 1, {<=}
elseif _val % 10 = 2
LabelKnob _it, _it, {) E}, (Div _val, 10) + 1
elseif _val % 10 = 3
LabelKnob _it, _it, {) N=>}
elseif _val % 10 = 4
LabelKnob _it, _it, {) N<=}
elseif _val % 10 = 5
LabelKnob _it, _it, {) N}
endif
endif
@End
@MyScaleKnob
if _val = -1 or _emptyFound
_emptyFound = YES
LabelKnob _it, _it2, {) —}
else
// (Chrom.), Lydian, Major, Mixolydian, Dorian, Minor, Phrygian, Bhairavi, Pelog, Hirajōshi
if _val = 0
LabelKnob _it, _it2, {) Lydian}
elseif _val = 1
LabelKnob _it, _it2, {) Major}
elseif _val = 2
LabelKnob _it, _it2, {) Mixolyd.}
elseif _val = 3
LabelKnob _it, _it2, {) Dorian}
elseif _val = 4
LabelKnob _it, _it2, {) Minor}
elseif _val = 5
LabelKnob _it, _it2, {) Phrygian}
elseif _val = 6
LabelKnob _it, _it2, {) Bhairavi}
elseif _val = 7
LabelKnob _it, _it2, {) Pelog}
elseif _val = 8
LabelKnob _it, _it2, {) Hirajōshi}
endif
Inc scaleLen
endif
@End
// MOZAIC EVENTS
//==============
@OnLoad
SetShortName {Minim}
// Initialize variables (first time)
if Unassigned page
// Initialize page
page = 0 // Current page (PLAY/PHASE)
window = 0 // Current window (0: main, 1: about/description)
// Initialize knobs, XY
FillArray pKnobs, 64
// PLAY - Initialize parameters (some are in knobs)
playON = YES
playCh = 0
pKnobs[5] = 0 // playCh = 0
// PHASE - Initialize note arrays, parameters (some are in knobs)
phaseON = NO
phaseCh = 1
FillArray phaseCurrentNote
phaseCurrent = -1
phaseBarLen = 32
phaseGradual = YES
pKnobs[3] = phaseBarLen
pKnobs[7] = (128 / 16) * 1 // phaseCh = 1
// EVOLUTION (Note substraction) - Initialize note arrays, parameters (some are in knobs)
evolutionON = NO
evolutionBar = 4
FillArray evolutionArray, 0
evolutionLen = 0
pKnobs[10 + 5] = (128 / 16) * (evolutionBar - 1)
// MUTATION (Note Length) - Initialize note arrays, parameters (some are in knobs)
// -1: None, X0: EE=>, X1: EE<=, X2: EE, X3: N=>, X4: N<=, X5: N,
// 0X: 1 Q, 1X: 2 Q
mutationON = NO
mutationBarPerStep = 2
FillArray mutationArray, -1
mutationLen = 0
pKnobs[20 + 5] = (128 / 8) * (mutationBarPerStep - 1)
// SCALE - Initialize scale arrays, parameters (some are in knobs)
// (Chrom.), Lydian, Major, Mixolydian, Dorian, Minor, Phrygian, Bhairavi, Pelog, Hirajōshi
scaleON = NO
scaleBar = 4
FillArray scaleArray, -1
scaleLen = 0
scaleRoot = 0 // C
scaleGlobalTranspose = 0
pKnobs[30 + 5] = (128 / 16) * (scaleBar - 1)
pKnobs[30 + 1] = 0
// OPTIONS
optionInputBars = 1
optionHumanize = 0
pKnobs[40] = 0
pKnobs[40 + 1] = 0
endif
SetRootNote scaleRoot
PresetScale {Chromatic}
// Initialize temporal variables
if Unassigned evolutionCurrent
evolutionCurrent = 0
evolutionCurrentBar = -1
FillArray evolutionPlayed, NO
endif
if Unassigned mutationCurrent
mutationCurrent = 0
mutationPreviousDelay = 0
mutationCurrentNote = 0
mutationBarPerStepCurrent = -1
FillArray mutationNoteType, -1
endif
if Unassigned scaleCurrent
scaleCurrent = 0
scaleCurrentBar = -1
endif
FillArray arrayPreviousNotePlayed, -1
FillArray arrayPreviousNoteHuman, 0
notesPreviousBar = 0
ctrNotesBar = 0
FillArray notesOrder, -1
// FINAL (Timer for GUI and changes to internal arrays)
// Internal variables will be updated in the Timer
// This helps to limit the number of updates after moving a knob.
SetTimerInterval 125
SetMetroPPQN 2
StartTimer
updateWINDOW = YES
updatePAGE = NO
updatePLAYPHASE = NO
updateEVOLUTION = NO
updateMUTATION = NO
updateSCALE = NO
updateOPTIONS = NO
@End
@OnTimer
// We update the current window
if updateWINDOW
if window = 0
ShowLayout 0
LabelPad 0, {Phasing}
LabelPad 1, {Subtraction}
LabelPad 2, {Length}
LabelPad 3, {Scale}
elseif window = 1
ShowLayout 4
endif
// Now, update contents
updateWINDOW = NO
updatePAGE = YES
endif
// In case of page change, we change everything
if updatePAGE and window = 0
_pf = page * 10
for _it = 0 to 3
LatchPad _it, (_it = page)
endfor
for _it = 0 to 9
SetKnobValue _it, pKnobs[_pf + _it]
LabelKnob _it, {—}
endfor
LabelXY {X (Humanization), Y (Transpose)}
if page = 0
LabelKnobs {Phasing parameters}
LabelPads {PAGE: Phasing}
updatePLAYPHASE = YES
elseif page = 1
LabelKnobs {Evolution (Subtract) parameters}
LabelPads {PAGE: Note Subtraction}
updateEVOLUTION = YES
elseif page = 2
LabelKnobs {Evolution (Length) parameters}
LabelPads {PAGE: Note Length}
updateMUTATION = YES
elseif page = 3
LabelKnobs {Evolution (Scale) parameters}
LabelPads {PAGE: Note Scale}
updateSCALE = YES
endif
// This task is done
updatePAGE = NO
elseif updatePAGE and window = 1
for _it = 0 to 3
_pf = 40 // the “page” for window 1 is 4
SetKnobValue _it, pKnobs[_pf + _it]
LabelKnob _it, {—}
endfor
LabelKnobs {Options}
// In window 1, we always update the options
updateOPTIONS = YES
// This task is done
updatePAGE = NO
endif
// ALWAYS update the XY pad
SetXYValues (pKnobs[40 + 1]), (pKnobs[30 + 6])
// Now, update subsystems
if updatePLAYPHASE
_pf = 0 * 10
// Update PLAY Variables and GUI
playON = pKnobs[_pf + 0] >= 64 // By default, play is ON
playCh = Div pKnobs[_pf + 5], 8
if window = 0
if playON
LabelKnob 0, {Play: ON}
else
LabelKnob 0, {Play: OFF}
endif
LabelKnob 5, {Ch OUT: }, playCh + 1
endif
// Update PHASE Variables and GUI
// Logic
newPhaseON = pKnobs[_pf + 2] > 64 // Little trick here, by default phase is off
phaseCurrent = -1
// Updating
phaseON = newPhaseON
phaseCh = Div pKnobs[_pf + 7], 8
phaseBarLen = Clip (RoundDown pKnobs[_pf + 3]), 1, 128
phaseGradual = pKnobs[_pf + 8] >= 64 // By default, change is gradual
if window = 0 and page = 0
if phaseON
LabelKnob 2, {Phase: ON}
else
LabelKnob 2, {Phase: OFF}
endif
LabelKnob 7, {Ch OUT: }, phaseCh + 1
LabelKnob 3, {Length:}, phaseBarLen
if phaseGradual
LabelKnob 8, {Gradual}
else
LabelKnob 8, {Process}
endif
endif
// Finish
updatePLAYPHASE = NO
endif
if updateEVOLUTION
_pf = 1 * 10
// Update EVOLUTION variables and GUI
evolutionON = pKnobs[_pf + 0] > 64 // By default, evolution is OFF
evolutionBar = (Div pKnobs[_pf + 5], 8) + 1
for _it = 1 to 4
evolutionArray[_it - 1] = pKnobs[_pf + _it]
endfor
for _it = 6 to 9
evolutionArray[_it - 2] = pKnobs[_pf + _it]
endfor
for _it = 0 to 7
_val = evolutionArray[_it]
_res = 0
if _val > 64
_res = (Div (_val - 65) , ((127 - 65) / 8)) + 1
elseif _val < 64
_res = (Div (63 - _val) , (63 / 8)) + 1
endif
evolutionArray[_it] = _res
endfor
if window = 0 and page = 1
if evolutionON
LabelKnob 0, {Subs: ON}
else
LabelKnob 0, {Subs: OFF}
endif
LabelKnob 5, {Bar|Step:}, evolutionBar
_emptyFound = NO
evolutionLen = 0
for _it = 1 to 4
_val = evolutionArray[_it - 1]
_it2 = _it
Call @MyEvolutionKnob
endfor
for _it = 6 to 9
_val = evolutionArray[_it - 2]
_it2 = _it - 1
Call @MyEvolutionKnob
endfor
endif
// Finish
updateEVOLUTION = NO
endif
if updateMUTATION
_pf = 2 * 10
// Update MUTATION variables and GUI
mutationON = pKnobs[_pf + 0] > 64 // By default, mutation is OFF
mutationBarPerStep = (Div pKnobs[_pf + 5], 16) + 1
for _it = 1 to 4
mutationArray[_it - 1] = pKnobs[_pf + _it]
endfor
for _it = 6 to 9
mutationArray[_it - 2] = pKnobs[_pf + _it]
endfor
for _it = 0 to 7
// -1: None, X0: EE=>, X1: EE<=, X2: EE, X3: N=>, X4: N<=, X5: N,
// 0X: 1 Q, 1X: 2 Q
_val = mutationArray[_it]
_res = -1
if _val > 64
// 1 Q
_res = (Div (_val - 65) , ((127 - 65) / 6))
elseif _val < 64
// 2 Q
_res = (Div (63 - _val) , (63 / 6))
_res = _res + 10
endif
mutationArray[_it] = _res
endfor
if window = 0 and page = 2
if mutationON
LabelKnob 0, {Len: ON}
else
LabelKnob 0, {Len: OFF}
endif
LabelKnob 5, {Bar|Step:}, mutationBarPerStep
_emptyFound = NO
mutationLen = 0
for _it = 1 to 4
_val = mutationArray[_it - 1]
Call @MyMutationKnob
endfor
for _it = 6 to 9
_val = mutationArray[_it - 2]
Call @MyMutationKnob
endfor
endif
// Finish
updateMUTATION = NO
endif
if updateSCALE
_pf = 3 * 10
// Update SCALE variables and GUI
scaleON = pKnobs[_pf + 0] > 64 // By default, scale is OFF
scaleBar = (Div pKnobs[_pf + 5], 8) + 1
scaleRoot = (Div pKnobs[_pf + 1], (128 / 12))
_val = pKnobs[_pf + 6]
if _val > 126
scaleGlobalTranspose = 12
elseif _val > 68
_res = (Div (_val - 69) , ((127 - 69) / 12))
scaleGlobalTranspose = Clip _res, 1, 12
elseif _val < 1
scaleGlobalTranspose = -12
elseif _val < 62
_res = (Div (61 - _val) , (61 / 12))
scaleGlobalTranspose = 0 - (Clip _res, 1, 12)
else
scaleGlobalTranspose = 0
endif
SetRootNote scaleRoot
for _it = 2 to 4
scaleArray[_it - 2] = pKnobs[_pf + _it]
endfor
for _it = 7 to 9
scaleArray[_it - 4] = pKnobs[_pf + _it]
endfor
for _it = 0 to 5
_val = scaleArray[_it]
_res = 0
if _val = 64
_res = -1
else
_res = Div _val , (128 / 9)
_res = Clip _res, 0, 8
endif
scaleArray[_it] = _res
endfor
if window = 0 and page = 3
if scaleON
LabelKnob 0, {Sca: ON}
else
LabelKnob 0, {Sca: OFF}
endif
LabelKnob 5, {Bar|Step:}, scaleBar
LabelKnob 6, {Transp: }, scaleGlobalTranspose
rootNote = scaleRoot // Thanks to wim (Audiobus forum) for this code
if rootNote=0
LabelKnob 1, {Root (C)}
elseif rootNote=1
LabelKnob 1, {Root (C#)}
elseif rootNote=2
LabelKnob 1, {Root (D)}
elseif rootNote=3
LabelKnob 1, {Root (Eb)}
elseif rootNote=4
LabelKnob 1, {Root (E)}
elseif rootNote=5
LabelKnob 1, {Root (F)}
elseif rootNote=6
LabelKnob 1, {Root (F#)}
elseif rootNote=7
LabelKnob 1, {Root (G)}
elseif rootNote=8
LabelKnob 1, {Root (G#)}
elseif rootNote=9
LabelKnob 1, {Root (A)}
elseif rootNote=10
LabelKnob 1, {Root (Bb)}
elseif rootNote=11
LabelKnob 1, {Root (B)}
endif
_emptyFound = NO
scaleLen = 0
for _it = 2 to 4
_val = scaleArray[_it - 2]
_it2 = _it - 2
Call @MyScaleKnob
endfor
for _it = 7 to 9
_val = scaleArray[_it - 4]
_it2 = _it - 4
Call @MyScaleKnob
endfor
endif
// Finish
updateSCALE = NO
endif
if updateOPTIONS
// Update SCALE variables and GUI
_pf = 4 * 10
optionInputBars = 1 + (Div pKnobs[_pf + 0], (128 / 16))
optionHumanize = RoundDown TranslateScale pKnobs[_pf + 1], 0, 127, 0, 100 // by wim
if window = 1
LabelKnob 0, {Bars IN: }, optionInputBars
LabelKnob 1, {Humanize}
endif
// Finish
updateOPTIONS = NO
endif
// Last step: Update all AU Parameters
// 0: PLAY ON/OFF
SetAUParameter 0, pKnobs[0 + 0]
// 1: PHASE ON/OFF
SetAUParameter 1, pKnobs[0 + 2]
// 2: SUBSTRACTION ON/OFF
SetAUParameter 2, pKnobs[10 + 0]
// 3: LENGTH ON/OFF
SetAUParameter 3, pKnobs[20 + 0]
// 4: SCALE ON/OFF
SetAUParameter 4, pKnobs[30 + 0]
// 5: TRANSPOSITION (64 = 0, 0 = -12, 127 = +12)
SetAUParameter 5, pKnobs[30 + 6]
// 6: HUMANIZATION
SetAUParameter 6, pKnobs[40 + 1]
@End
@OnMidiNoteOn
// Always update array and increment counter (first position is 0)
notesOrder[MIDINote] = ctrNotesBar
Inc ctrNotesBar
if mutationON and mutationLen > 0
// Also update the current mutation of this note, we will use it on NoteOff
mutationNoteType[MIDINote] = mutationArray[mutationCurrent]
endif
// Check if we can play this note
_play = YES
if evolutionON and evolutionCurrent <> -1
_eight = evolutionArray[evolutionCurrent]
_play = (CurrentMetroPulse + (8 * (HostBar % optionInputBars))) < (_eight * optionInputBars)
evolutionPlayed[MIDINote] = _play
if _play
log {==OK play note at Pulse:}, CurrentMetroPulse, {with Max Phase:}, _eight
endif
endif
_note = MIDINote + scaleGlobalTranspose
// Check if we have to play the note in a different scale
if _play and scaleON
_note = ScaleQuantize _note
endif
// Check if we have two consecutive NoteON! We have to turn off the previous one, NOW
if arrayPreviousNotePlayed[MIDINote] <> -1
SendMIDINoteOff playCh, arrayPreviousNotePlayed[MIDINote], MIDIVelocity
SendMIDINoteOff phaseCh, arrayPreviousNotePlayed[MIDINote], MIDIVelocity
endif
// PLAY and PHASE
_delayHumanize = 0
if optionHumanize > 0
_delayHumanize = optionHumanize * (Random 0,500) / 1000 // Thanks, wim :-)
endif
if _play and playON
// PLAY mode - Simply send the MIDI
SendMIDINoteOn playCh, _note, MIDIVelocity, _delayHumanize
arrayPreviousNotePlayed[MIDINote] = _note
arrayPreviousNoteHuman[MIDINote] = _delayHumanize
endif
if _play and phaseON and phaseCurrent >= 0
// PHASING mode - Phases the note to a new channel
phaseCurrentNote[MIDINote] = phaseCurrent
msPerBar = (HostBeatsPerMeasure / (HostTempo / 60)) * 1000
_delay = (msPerBar / phaseBarLen) * phaseCurrent
if not phaseGradual
msPerBeat = msPerBar / HostBeatsPerMeasure
_delay = (Div _delay, msPerBeat) * msPerBeat // delay ONLY on new beats
endif
SendMIDINoteOn phaseCh, _note, MIDIVelocity, _delayHumanize + _delay - 0.1
arrayPreviousNotePlayed[MIDINote] = _note
arrayPreviousNoteHuman[MIDINote] = _delayHumanize
endif
@End
@OnMidiNoteOff
// Check if we can play this note
_stop = YES
if evolutionON and evolutionCurrent <> -1
_stop = evolutionPlayed[MIDINote]
endif
// MUTATE - Calculate potential note extension (delay to note off)
// -1: None, X0: EE=>, X1: EE<=, X2: EE, X3: N=>, X4: N<=, X5: N,
// 0X: 1 Q, 1X: 2 Q
_mutateDelay = 0
if _stop and mutationON and mutationLen > 0
mutationCurrentType = mutationNoteType[MIDINote]
if mutationCurrentType <> -1
_mutateSubtype = mutationCurrentType % 10
_mutateQuarter = 0
if _mutateSubtype < 3 and notesPreviousBar > 0
// Only start changing if we have counted the notes before
_mutateQuarter = (Div mutationCurrentType, 10) + 1
endif
if _mutateSubtype = 2 or _mutateSubtype = 5
_mutateDelay = _mutateQuarter // EE|N
elseif _mutateSubtype = 0 or _mutateSubtype = 3
if mutationCurrentNote >= notesOrder[MIDINote]
_mutateDelay = _mutateQuarter // EE|N =>
else
_mutateDelay = mutationPreviousDelay
endif
elseif _mutateSubtype = 1 or _mutateSubtype = 4
if mutationCurrentNote >= (notesPreviousBar - 1 - notesOrder[MIDINote])
_mutateDelay = _mutateQuarter // EE|N <=
else
_mutateDelay = mutationPreviousDelay
endif
endif
//Log {—[}, mutationCurrentType, {]:}, MIDINote, { = }, _mutateDelay, {:}, mutationCurrentNote, {/}, notesOrder[MIDINote]
_mutateDelay = _mutateDelay * QuarterNote
endif
endif
// Check what is the actual note we need to stop! (we might have changed the scale, transposed it...)
_note = arrayPreviousNotePlayed[MIDINote]
if _note = -1
_note = MIDINote
endif
// PLAY and PHASE
_delayHumanize = arrayPreviousNoteHuman[MIDINote]
if _stop and playON
// PLAY mode - Simply send the MIDI
SendMIDINoteOff playCh, _note, MIDIVelocity, _delayHumanize + _mutateDelay
arrayPreviousNotePlayed[MIDINote] = -1
arrayPreviousNoteHuman[MIDINote] = 0
endif
if _stop and phaseON and phaseCurrent >= 0
// PHASING mode - Phases the note to a new channel
msPerBar = (HostBeatsPerMeasure / (HostTempo / 60)) * 1000
_delay = (msPerBar / phaseBarLen) * phaseCurrentNote[MIDINote]
if not phaseGradual
msPerBeat = msPerBar / HostBeatsPerMeasure
_delay = (Div _delay, msPerBeat) * msPerBeat // delay ONLY on new beats
endif
SendMIDINoteOff phaseCh, _note, MIDIVelocity, _delayHumanize + _delay + _mutateDelay - 0.1
arrayPreviousNotePlayed[MIDINote] = -1
arrayPreviousNoteHuman[MIDINote] = 0
endif
@End
@OnNewBar
// INITIALIZATION (if HostBar = 0, user has rewind / the song has looped)
if HostBar = 0
// PHASING - Temporal variables
// If we are in the first bar, we *assume* the user wants to starts again
// As such, we initialize these temporal variables
phaseCurrent = -1
// EVOLUTION - Temporal variables
// Same as before: If you are at the beginning, you want to start again
evolutionCurrent = 0
evolutionCurrentBar = -1
FillArray evolutionPlayed, NO
// MUTATION - Temporal variables
// Same as before: If you are at the beginning, you want to start again
mutationCurrent = 0
mutationCurrentNote = 0
mutationBarPerStepCurrent = -1 // It will be incremented in @OnNewBar
mutationPreviousDelay = 0
FillArray mutationNoteType, -1
// SCALE
scaleCurrent = 0
scaleCurrentBar = -1
PresetScale {Chromatic}
// OTHER
// There are no “previous notes”
notesPreviousBar = 0
ctrNotesBar = 0
endif
// BAR MANAGEMENT
if (HostBar % optionInputBars) = 0
FlashUserLed
// Tmp variables
notesPreviousBar = ctrNotesBar
ctrNotesBar = 0
// LOGIC
if phaseON
// PHASING mode - Increment the phasing counter
phaseCurrent = (phaseCurrent + 1) % phaseBarLen
endif
if evolutionON
// EVOLUTION mode - Update the “current evolution” counter
if evolutionLen = 0
evolutionCurrent = -1
else
Inc evolutionCurrentBar
if (evolutionCurrentBar >= evolutionBar)
evolutionCurrent = (evolutionCurrent + 1) % evolutionLen
evolutionCurrentBar = 0
endif
endif
endif
if mutationON
// MUTATION mode
// -1: None, X0: EE=>, X1: EE<=, X2: EE, X3: N=>, X4: N<=, X5: N,
// 0X: 1 Q, 1X: 2 Q
if mutationLen > 0
// Advance the current step (bars I stay in the same note)
Inc mutationBarPerStepCurrent
// Check if we need to advance to the next note (bars per step)
_nextNote = NO
if mutationBarPerStepCurrent >= mutationBarPerStep
mutationBarPerStepCurrent = 0
_nextNote = YES
endif
if _nextNote
// Advance the current note
Inc mutationCurrentNote
// Check if we need to move to the next mutation state
if notesPreviousBar <> 0 and mutationCurrentNote >= notesPreviousBar
mutationCurrentType = mutationArray[mutationCurrent]
if (mutationCurrentType % 10) >= 0 and (mutationCurrentType % 10) < 3
mutationPreviousDelay = (Div mutationCurrentType, 10) + 1 // We were in (E)xtended
else
mutationPreviousDelay = 0 // We were in (N)ormal
endif
mutationCurrent = (mutationCurrent + 1) % mutationLen
if mutationCurrent = 0
mutationPreviousDelay = 0 // Reset the previous delay if we looped in the Array
endif
mutationCurrentNote = 0
endif
endif
log {[}, HostBar, {] C:}, mutationCurrent, {/}, mutationLen, { N:}, mutationCurrentNote, {/}, notesPreviousBar, { S:}, mutationBarPerStepCurrent
endif
endif
if scaleON
// SCALE mode - Update the “current scale” counter
_val = -1
if scaleLen = 0
scaleCurrent = -1
else
Inc scaleCurrentBar
if (scaleCurrentBar >= scaleBar)
scaleCurrent = (scaleCurrent + 1) % scaleLen
scaleCurrentBar = 0
endif
if scaleCurrent >= 0
_val = scaleArray[scaleCurrent]
endif
endif
// ...we actually apply the scale here, at the beginning of the bar
if _val = -1
PresetScale {Chromatic}
elseif _val = 0
PresetScale {Lydian}
elseif _val = 1
PresetScale {Major}
elseif _val = 2
PresetScale {Mixolydian}
elseif _val = 3
PresetScale {Dorian}
elseif _val = 4
PresetScale {Minor}
elseif _val = 5
PresetScale {Phrygian}
elseif _val = 6
PresetScale {Bhairavi}
elseif _val = 7
PresetScale {Pelog}
elseif _val = 8
PresetScale {HiraJoshi}
endif
Log {Scale Applied: }, _val
endif
endif
@End
@OnPadDown
if LastPad <> page and window = 0
// Change parameters, tell GUI
page = LastPad
updatePAGE = YES
endif
@End
@OnKnobChange
// Change parameters, tell GUI
if window = 0
_previous = pKnobs[(page * 10) + LastKnob]
pKnobs[(page * 10) + LastKnob] = GetKnobValue LastKnob
elseif window = 1
_pf = 4
_previous = pKnobs[(_pf * 10) + LastKnob]
pKnobs[(_pf * 10) + LastKnob] = GetKnobValue LastKnob
endif
if window = 0 and page = 0
// Execute some logic before calling the GUI update
if LastKnob = 0
// Phase ON OFF Knob
_prev = _previous > 64
_now = (GetKnobValue LastKnob) > 64
if _prev <> _now
// PHASE CHANGE: Always initialize phase temporal variables
phaseCurrent = -1
endif
endif
updatePLAYPHASE = YES
elseif window = 0 and page = 1
// Execute some logic before calling the GUI update
if LastKnob = 0
// Evolution ON OFF Knob
_prev = _previous > 64
_now = (GetKnobValue LastKnob) > 64
if _prev <> _now
// EVOLUTION CHANGE: Always initialize evolution temporal variables
evolutionCurrent = 0
evolutionCurrentBar = -1
FillArray evolutionPlayed, NO
endif
endif
updateEVOLUTION = YES
elseif window = 0 and page = 2
// Execute some logic before calling the GUI update
if LastKnob = 0
// Mutation ON OFF Knob
_prev = _previous > 64
_now = (GetKnobValue LastKnob) > 64
if _prev <> _now
// MUTATION CHANGE: Always initialize mutation temporal variables
mutationCurrent = 0
mutationCurrentNote = 0
mutationBarPerStepCurrent = -1 // It will be incremented in @OnNewBar
mutationPreviousDelay = 0
FillArray mutationNoteType, -1
endif
endif
// Tell GUI
updateMUTATION = YES
elseif window = 0 and page = 3
// Execute some logic before calling the GUI update
if LastKnob = 0
// Scale ON OFF Knob
_prev = _previous > 64
_now = (GetKnobValue LastKnob) > 64
if _prev <> _now
// SCALE CHANGE: Always initialize scale temporal variables
scaleCurrent = 0
scaleCurrentBar = -1
PresetScale {Chromatic}
endif
endif
updateSCALE = YES
elseif window = 1
updateOPTIONS = YES
endif
@End
@OnXYChange
// X - Change humanization
pKnobs[40 + 1] = GetXValue
updateOPTIONS = YES
// Y - Change transposition
pKnobs[30 + 6] = GetYValue
if window = 0 and page = 3
SetKnobValue 6, pKnobs[30 + 6]
endif
updateSCALE = YES
@End
@OnShiftDown
// CHANGE THE WINDOW
window = Abs (window - 1)
updateWINDOW = YES
@End
@OnAUParameter
// 0: PLAY ON/OFF
if LastAUParameter = 0
pKnobs[0 + 0] = GetAUParameter LastAUParameter
if window = 0 and page = 0
SetKnobValue 0, pKnobs[0 + 0]
endif
updatePLAYPHASE = YES
endif
// 1: PHASE ON/OFF
if LastAUParameter = 1
pKnobs[0 + 2] = GetAUParameter LastAUParameter
if window = 0 and page = 0
SetKnobValue 2, pKnobs[0 + 2]
endif
updatePLAYPHASE = YES
endif
// 2: SUBSTRACTION ON/OFF
if LastAUParameter = 2
pKnobs[10 + 0] = GetAUParameter LastAUParameter
if window = 0 and page = 1
SetKnobValue 0, pKnobs[10 + 0]
endif
updateEVOLUTION = YES
endif
// 3: LENGTH ON/OFF
if LastAUParameter = 3
pKnobs[20 + 0] = GetAUParameter LastAUParameter
if window = 0 and page = 2
SetKnobValue 0, pKnobs[20 + 0]
endif
updateMUTATION = YES
endif
// 4: SCALE ON/OFF
if LastAUParameter = 4
pKnobs[30 + 0] = GetAUParameter LastAUParameter
if window = 0 and page = 3
SetKnobValue 0, pKnobs[30 + 0]
endif
updateSCALE = YES
endif
// 5: TRANSPOSITION (64 = 0, 0 = -12, 127 = +12)
if LastAUParameter = 5
pKnobs[30 + 6] = GetAUParameter LastAUParameter
if window = 0 and page = 3
SetKnobValue 6, pKnobs[30 + 6]
endif
updateSCALE = YES
endif
// 6: HUMANIZATION
if LastAUParameter = 6
pKnobs[40 + 1] = GetAUParameter LastAUParameter
if window = 0 and page = 4
SetKnobValue 1, pKnobs[40 + 1]
endif
updateOPTIONS = YES
endif
@End
@Description
Minimalism wizard, by rrc2soft. v1.31. Requires Mozaic 1.0.3.
Press SHIFT to read these instructions again, and to change the global options (Input bars, humanize)
This script takes as an input one or more bars of MIDI notes, and then transforms them according to various minimalism techniques from the late 60’s / 70’s such as phasing, note substraction, note length, plus scale modification and global transposing.
This will allow you not only to create simple pieces in the vein of early Steve Reich and Philip Glass, but also to create interesting textures with digital arpeggio/pluck patches.
In the first page (PHASING), you can activate the phasing, and indicate i) its length, ii) its output channel, and iii) whether the phasing is done in a gradual way or in a ‘process’ way (i.e. only apply phasing when the notes shift an full beat). Moreover, you can configure if the original MIDI input is played, and on which channel.
In the second page (SUBSTRACT), you can program how many notes are played from the original input. For example, an input of “Eights: 4” will indicate that notes located in the first 4/8 of the input bar(s) will be played - all other notes will be silenced. Bar|Step indicates how many bar(s) we stay in every step of the program.
In the third page (LENGTH), we can program variations of the lenght of the notes. For example, EX=> indicates that every “Bar|Step” bars, we will change the duration of a note in the input - for all input notes from the left to the right. Something like this:
Note 1: 0 beat, 1 quarter => 0 beat, 3 quarter => 0 beat, 3 quarter
Note 2: 2 beat, 1 quarter => 2 beat, 1 quarter => 2 beat, 3 quarter
(In case of doubt, try a piano patch with the phasing turned off. This setting is specially useful with arpeggiated patches)
In the fourth page (SCALE), we can program changes to the current scale of the output, which will be applied every “Bar|Step” bars. This way, we can quantize the input notes to another scale. Besides, in this page we can also configure a global transposition setting, which will be applied to all input notes. This can also be changed by changing the Y coordinate of the XY Pad.
Finally, in the global options page, you can configure how many bars are considered as an input to this MIDI script, and also the humanization of the input notes (thanks to ‘wim’ for the code and other code snippets). Note that the humanization of the notes can also be changed using the X coordinate of the XY pad: the more to the right, the more humanization.
AU Parameters:
0: PLAY ON/OFF (127, 0)
1: PHASE ON/OFF (127, 0)
2: SUBSTRACTION ON/OFF (127, 0)
3: LENGTH ON/OFF (127, 0)
4: SCALE ON/OFF (127, 0)
5: TRANSPOSITION (64 = 0, 0 = -12, 127 = +12)
6: HUMANIZATION (0 -> 127)
@End
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment