// Allows users to create a sequence that keeps repeating. Example use case: to test out melodies. var NeedsTimingInfo = true; var activeNotes = []; function HandleMIDI(event) { if (event instanceof NoteOn) { // add note to array activeNotes.push(event); } // else if (event instanceof NoteOff) { // // remove note from array // for (i = 0; i < activeNotes.length; i++) { // if (activeNotes[i].pitch == event.pitch) { // activeNotes.splice (i, 1); // break; // } // } // } // pass non-note events through else event.send(); // sort array of active notes // activeNotes.sort(sortByPitchAscending); // Remove the '//' above to force the note to be in order by pitch } //----------------------------------------------------------------------------- function sortByPitchAscending(a,b) { if (a.pitch < b.pitch) return -1; if (a.pitch > b.pitch) return 1; return 0; } //----------------------------------------------------------------------------- var wasPlaying = false; function ProcessMIDI() { // Get timing information from the host application var musicInfo = GetTimingInfo(); // clear activeNotes[] when the transport stops and send any remaining note off events if (wasPlaying && !musicInfo.playing){ for(i=0;i= musicInfo.rightCycleBeat) { if (lookAheadEnd >= musicInfo.rightCycleBeat) { var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat; var cycleEnd = lookAheadEnd - cycleBeats; } } var state = GetParameter("Reset"); if (state == 1) { Reset(); } // loop through the beats that fall within this buffer while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd && state == 0) // including beats that wrap around the cycle point || (musicInfo.cycling && nextBeat < cycleEnd)) { // adjust for cycle if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat) nextBeat -= cycleBeats; // calculate step var step = Math.floor(nextBeat / (1 / division) - division); var chosenNote = chooseNote(noteOrder, step); // send events var noteOn = new NoteOn(chosenNote); noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave); noteOn.sendAtBeat(nextBeat + randomDelay); var noteOff = new NoteOff(noteOn); noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength) // advance to next beat nextBeat += 0.001; nextBeat = Math.ceil(nextBeat * division) / division; } } } function Reset() { NeedsTimingInfo = true; activeNotes = []; SetParameter ("Reset", 0); } //----------------------------------------------------------------------------- var noteOrders = ["up", "down", "random"]; function chooseNote(noteOrder, step) { var order = noteOrders[noteOrder]; var length = activeNotes.length if (order == "up") return activeNotes[step % length]; if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))]; if (order == "random") return activeNotes[Math.floor(Math.random() * length)]; else return 0; } //----------------------------------------------------------------------------- var PluginParameters = [ {name:"Reset", type:"menu", valueStrings:["Off", "On"], minValue:0, maxValue:1, numberOfSteps: 2, defaultValue:0}, {name:"Beat Division", type:"linear", minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1}, {name:"Note Order", type:"menu", valueStrings:noteOrders, minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0}, {name:"Note Length", unit:"%", type:"linear", minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199}, {name:"Random Length", unit:"%", type:"linear", minValue:0, maxValue:200, numberOfSteps: 200, defaultValue:0}, {name:"Random Delay", unit:"%", type:"linear", minValue:0, maxValue:200, numberOfSteps:200, defaultValue:0}, {name:"Random Octave", type:"linear", minValue:1, maxValue:4, defaultValue:1, numberOfSteps:3} ]; // ---------------------------------------------------------------------------- // Code from plugin.js // Copy and paste this chunk of code into your script editor to create controls in your plugin // var PluginParameters = []; // Types of Plugin Parameters const LINEAR_FADER = "lin"; const LOGARITHMIC_FADER = "log"; const MOMENTARY_BUTTON = "momentary"; const MENU = "menu"; const NOT_NEEDED = ""; /* To create a plugin parameter (a fader or knob that changes something is a basic way of desribing it), call the createPluginParameter function as follows: createPluginParameter("Enter a name in quotes", Enter a type from above in quotes (for example: LINEAR_FADER), Enter a minimum value, Enter a maximum value, Enter a default value, enter the number of steps, "Enter a unit in quotes", "Enter text to create a divider/header in the plug-in", Enter a list of value strings if you are creating a menu as follows: ["something", "something", "something"]); */ function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { if (type == MENU) { PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings)); } else { PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text)); } } function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text}; } function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings}; } //Parameters for the plugin // Triggers chords derived from played note // Chordtypes var maj_Chord = [4, 7]; var min_Chord = [3, 7]; var dim_Chord = [3, 6]; var maj7th_Chord = [4, 7, 11]; var min7th_Chord = [3, 7, 10]; var dom7th_Chord = [4, 7, 10]; var dim7th_Chord = [3, 6, 10]; var activeNotes = []; function HandleMIDI(event) { if (GetParameter("Flavour") == 0) { if (GetParameter("Mode") == 0) { // MAJOR switch (event.pitch % 12) { // I case (GetParameter("Root") % 12): buildChord(event, maj_Chord); break; // ii case ((GetParameter("Root") + 2) % 12): buildChord(event, min_Chord); break; // iii case ((GetParameter("Root") + 4) % 12): buildChord(event, min_Chord); break; // IV case ((GetParameter("Root") + 5) % 12): buildChord(event, maj_Chord); break; // V case ((GetParameter("Root") + 7) % 12): buildChord(event, maj_Chord); break; // vi case ((GetParameter("Root") + 9) % 12): buildChord(event, min_Chord); break; // vii° case ((GetParameter("Root") + 11) % 12): buildChord(event, dim_Chord); break; // Default default: break; } } else if (GetParameter("Mode") == 1) { // MINOR switch (event.pitch % 12) { // i case (GetParameter("Root") % 12): buildChord(event, min_Chord); break; // ii° case ((GetParameter("Root") + 2) % 12): buildChord(event, dim_Chord); break; // III case ((GetParameter("Root") + 3) % 12): buildChord(event, maj_Chord); break; // iv case ((GetParameter("Root") + 5) % 12): buildChord(event, min_Chord); break; // v case ((GetParameter("Root") + 7) % 12): buildChord(event, min_Chord); break; // VI case ((GetParameter("Root") + 8) % 12): buildChord(event, maj_Chord); break; // VII case ((GetParameter("Root") + 10) % 12): buildChord(event, maj_Chord); break; // Default default: break; } } } if (GetParameter("Flavour") == 1) { if (GetParameter("Mode") == 0) { // MAJOR switch (event.pitch % 12) { // I7 case (GetParameter("Root") % 12): buildChord(event, maj7th_Chord); break; // ii7 case ((GetParameter("Root") + 2) % 12): buildChord(event, min7th_Chord); break; // iii7 case ((GetParameter("Root") + 4) % 12): buildChord(event, min7th_Chord); break; // IV7 case ((GetParameter("Root") + 5) % 12): buildChord(event, maj7th_Chord); break; // V7 case ((GetParameter("Root") + 7) % 12): buildChord(event, dom7th_Chord); break; // vi7 case ((GetParameter("Root") + 9) % 12): buildChord(event, min7th_Chord); break; // vii°7 case ((GetParameter("Root") + 11) % 12): buildChord(event, dim7th_Chord); break; // Default default: break; } } else if (GetParameter("Mode") == 1) { // MINOR switch (event.pitch % 12) { // i7 case (GetParameter("Root") % 12): buildChord(event, min7th_Chord); break; // ii°7 case ((GetParameter("Root") + 2) % 12): buildChord(event, dim7th_Chord); break; // III7 case ((GetParameter("Root") + 3) % 12): buildChord(event, maj7th_Chord); break; // iv7 case ((GetParameter("Root") + 5) % 12): buildChord(event, min7th_Chord); break; // v7 case ((GetParameter("Root") + 7) % 12): buildChord(event, min7th_Chord); break; // VI7 case ((GetParameter("Root") + 8) % 12): buildChord(event, maj7th_Chord); break; // VII7 case ((GetParameter("Root") + 10) % 12): buildChord(event, dom7th_Chord); break; // Default default: break; } } } } function buildChord(root, chordtype) { if (root instanceof NoteOn) { var originalNote = new NoteOn(root); var record = { originalPitch: root.pitch, events: [originalNote] }; root.send(); for (var i = 0; i < chordtype.length; i++) { var harmony = new NoteOn(root); harmony.pitch += chordtype[i]; record.events.push(harmony); harmony.send(); } activeNotes.push(record); } else if (root instanceof NoteOff) { for (var i in activeNotes) { if (activeNotes[i].originalPitch == root.pitch) { for (var j = 0; j < activeNotes[i].events.length; j++) { var noteOff = new NoteOff(activeNotes[i].events[j]); noteOff.send(); } activeNotes.splice(i, 1); break; } } } } ResetParameterDefaults = true; var PluginParameters = [{ name: "Chords", type: "text" }, { name: "Root", type: "menu", valueStrings: ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"], defaultValue: 0, minValue: 0, maxValue: 11, numberOfSteps: 12 }, { name: "Mode", type: "menu", valueStrings: ["Major", "Minor"], defaultValue: 0, minValue: 0, maxValue: 1, numberOfSteps: 2 }, { name: "Flavour", type: "menu", valueStrings: ["Normal", "Jazzy"], defaultValue: 0, minValue: 0, maxValue: 1, numberOfSteps: 2 }]; // Copy and paste this chunk of code into your script editor to create controls in your plugin var NeedsTimingInfo = true; var PluginParameters = []; // Types of Plugin Parameters const LINEAR_FADER = "lin"; const LOGARITHMIC_FADER = "log"; const MOMENTARY_BUTTON = "momentary"; const MENU = "menu"; const NOT_NEEDED = ""; /* To create a plugin parameter (a fader or knob that changes something is a basic way of desribing it), call the createPluginParameter function as follows: createPluginParameter("Enter a name in quotes", Enter a type from above in quotes (for example: LINEAR_FADER), Enter a minimum value, Enter a maximum value, Enter a default value, enter the number of steps, "Enter a unit in quotes", "Enter text to create a divider/header in the plug-in", Enter a list of value strings if you are creating a menu as follows: ["something", "something", "something"]); */ function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { if (type == MENU) { PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings)); } else { PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text)); } } function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text}; } function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings}; } //Parameters for the plugin // Repeats note that is played with specified beat divisions var NeedsTimingInfo = true; var activeNotes = []; function HandleMIDI(event) { if (event instanceof NoteOn) { // add note to array activeNotes.push(event); } else if (event instanceof NoteOff) { // remove note from array for (i = 0; i < activeNotes.length; i++) { if (activeNotes[i].pitch == event.pitch) { activeNotes.splice (i, 1); break; } } } // pass non-note events through else event.send(); // sort array of active notes activeNotes.sort(sortByPitchAscending); } //----------------------------------------------------------------------------- function sortByPitchAscending (a, b) { if (a.pitch < b.pitch) { return -1; } if (a.pitch > b.pitch) { return 1; } return 0; } //----------------------------------------------------------------------------- var wasPlaying = false; function ProcessMIDI() { // Get timing information from the host application var musicInfo = GetTimingInfo(); // clear activeNotes[] when the transport stops and send any remaining note off events if (wasPlaying && !musicInfo.playing) { for(i = 0;i < activeNotes.length; i++) { var off = new NoteOff(activeNotes[i]); off.send(); } } wasPlaying = musicInfo.playing; if (activeNotes.length != 0) { // get parameters var division = GetParameter("Beat Division"); var noteOrder = GetParameter("Note Order"); var noteLength = (GetParameter("Note Length") / 100) * (1 / division); // var randomLength = Math.random() * ((GetParameter("Random Length") / 100) * (1 / division)); // var randomDelay = Math.random() * ((GetParameter("Random Delay") / 100) * (1 / division)); // var randomOctave = Math.floor(Math.random() * GetParameter("Random Octave")) * 12; // calculate beat to schedule var lookAheadEnd = musicInfo.blockEndBeat; var nextBeat = Math.ceil(musicInfo.blockStartBeat * division) / division; // var nextBeat = musicInfo.blockStartBeat; // when cycling, find the beats that wrap around the last buffer if (musicInfo.cycling && lookAheadEnd >= musicInfo.rightCycleBeat && lookAheadEnd >= musicInfo.rightCycleBeat) { var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat; var cycleEnd = lookAheadEnd - cycleBeats; } var state = GetParameter("Reset"); if (state == 1) { Reset(); } // loop through the beats that fall within this buffer while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd && state == 0) // including beats that wrap around the cycle point || (musicInfo.cycling && nextBeat < cycleEnd)) { // adjust for cycle if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat) nextBeat -= cycleBeats; // calculate step var step = Math.floor(nextBeat / (1 / division) - division); var chosenNote = chooseNote(noteOrder, step); // send events var noteOn = new NoteOn(chosenNote); // noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave); noteOn.pitch = MIDI.normalizeData(noteOn.pitch); // noteOn.sendAtBeat(nextBeat + randomDelay); noteOn.sendAtBeat(nextBeat); var noteOff = new NoteOff(noteOn); // noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength); noteOff.sendAtBeat(nextBeat + noteLength); // advance to next beat nextBeat += 0.001; nextBeat = Math.ceil(nextBeat * division) / division; } } } function Reset() { NeedsTimingInfo = true; activeNotes = []; SetParameter ("Reset", 0); } //----------------------------------------------------------------------------- var noteOrders = ["up", "down", "random"]; function chooseNote(noteOrder, step) { var order = noteOrders[noteOrder]; var length = activeNotes.length if (order == "up") return activeNotes[step % length]; if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))]; if (order == "random") return activeNotes[Math.floor(Math.random() * length)]; else return 0; } //----------------------------------------------------------------------------- // var PluginParameters = // [ // {name:"Beat Division", type:"linear", // minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1}, // // {name:"Note Order", type:"menu", valueStrings:noteOrders, // minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0}, // // {name:"Note Length", unit:"%", type:"linear", // minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199}, // // {name:"Random Length", unit:"%", type:"linear", // minValue:0, maxValue:200, numberOfSteps: 200, defaultValue:0}, // // {name:"Random Delay", unit:"%", type:"linear", // minValue:0, maxValue:200, numberOfSteps:200, defaultValue:0}, // // {name:"Random Octave", type:"linear", // minValue:1, maxValue:4, defaultValue:1, numberOfSteps:3} // ]; var PluginParameters = [ {name:"Beat Division", type:"linear", minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1}, {name:"Note Order", type:"menu", valueStrings:noteOrders, minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0}, {name:"Reset", type:"menu", valueStrings:["Off", "On"], minValue:0, maxValue:1, numberOfSteps: 2, defaultValue:0}, {name:"Note Length", unit:"%", type:"linear", minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199} ]; // ---------------------------------------------------------------------------- // Code from plugin.js // Copy and paste this chunk of code into your script editor to create controls in your plugin // var PluginParameters = []; // Types of Plugin Parameters const LINEAR_FADER = "lin"; const LOGARITHMIC_FADER = "log"; const MOMENTARY_BUTTON = "momentary"; const MENU = "menu"; const NOT_NEEDED = ""; /* To create a plugin parameter (a fader or knob that changes something is a basic way of desribing it), call the createPluginParameter function as follows: createPluginParameter("Enter a name in quotes", Enter a type from above in quotes (for example: LINEAR_FADER), Enter a minimum value, Enter a maximum value, Enter a default value, enter the number of steps, "Enter a unit in quotes", "Enter text to create a divider/header in the plug-in", Enter a list of value strings if you are creating a menu as follows: ["something", "something", "something"]); */ function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { if (type == MENU) { PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings)); } else { PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text)); } } function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text}; } function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings}; } //Parameters for the plugin // Constructs a sequence of notes triggered relative to the base note var NeedsTimingInfo = true; var activeNotes = []; var sequence = [2, 2, 1, 2, 2, 2, 1]; // Choose your sequence here. Enter integers for ups or downs /* needed to make beatPos work */ function HandleMIDI(event) { if (event instanceof NoteOn) { constructSequence(event); // activeNotes.push(event); // for (var i = 0; i < sequence.length; i++) { // var on = new NoteOn (activeNotes[i]); // var previous = new NoteOn (activeNotes[i]) // on.pitch = MIDI.normalizeData(previous.pitch + sequence[i]); // activeNotes.push (on); // on.sendAtBeat(previous.beatPos + 2); // } } else if (event instanceof NoteOff) { // remove note from array Reset(); for (i = 0; i < activeNotes.length; i++) { if (activeNotes[i].pitch == event.pitch) { activeNotes.splice(i, 1); break; } } } else { event.send(); } } function Reset() { activeNotes = []; } // function ProcessMIDI() { // for (var i = 0; i < activeNotes.length; i++) { // var currentNote = new NoteOn (sequence[i]); // currentNote.send(); // } // } function constructSequence(event) { activeNotes.push (event); for (var i = 0; i < sequence.length; i++) { var on = new NoteOn; on.pitch = MIDI.normalizeData(activeNotes[i].pitch + sequence[i]); activeNotes.push (on); } } var wasPlaying = false; function ProcessMIDI() { // Get timing information from the host application var musicInfo = GetTimingInfo(); // clear activeNotes[] when the transport stops and send any remaining note off events if (wasPlaying && !musicInfo.playing){ for(i=0;i= musicInfo.rightCycleBeat) { if (lookAheadEnd >= musicInfo.rightCycleBeat) { var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat; var cycleEnd = lookAheadEnd - cycleBeats; } } // var state = GetParameter("Reset"); // if (state == 1) { // Reset(); // } // loop through the beats that fall within this buffer while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd) // including beats that wrap around the cycle point || (musicInfo.cycling && nextBeat < cycleEnd)) { // adjust for cycle if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat) nextBeat -= cycleBeats; // calculate step var step = Math.floor(nextBeat / (1 / division) - division); var chosenNote = chooseNote(noteOrder, step); // send events var noteOn = new NoteOn(chosenNote); // noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave); noteOn.pitch = (noteOn.pitch + randomOctave); noteOn.sendAtBeat(nextBeat + randomDelay); var noteOff = new NoteOff(noteOn); noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength) // advance to next beat nextBeat += 0.001; nextBeat = Math.ceil(nextBeat * division) / division; } } } var noteOrders = ["up", "down", "random"]; function chooseNote(noteOrder, step) { var order = noteOrders[noteOrder]; var length = activeNotes.length if (order == "up") return activeNotes[step % length]; if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))]; if (order == "random") return activeNotes[Math.floor(Math.random() * length)]; else return 0; } // function constructSequence(event) { // activeNotes.push (event); // for (var i = 0; i < sequence.length; i++) { // var on = new NoteOn; // on.pitch = MIDI.normalizeData(activeNotes[i].pitch + sequence[i]); // on.beatPos = activeNotes[i].beatPos + 1; // activeNotes.push (on); // } // }