Last active
June 12, 2019 08:24
-
-
Save rrc2soft/ea9a7e2dbdc117b9946bb115ae9fd98c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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