TheMooseman Posted October 29, 2018 Share Posted October 29, 2018 The idea would be to have a set of note length values and a set of pitches. These arrays could be of different lengths, let's say there are 3 note lengths and 5 pitches. The pitches would be placed on the note lengths but the lengths would go back to the beginning of the array before the pitches would. Does anyone have ideas about how to structure this? Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 29, 2018 Share Posted October 29, 2018 sounds feasible but I need more information. Are you wanting something that plays back a hard coded sequence of pitches and durations or something that responds? Please describe more about how you want the script to work...this is exactly the kind of thing that scripter can definitely do though. Quote Link to comment Share on other sites More sharing options...
TheMooseman Posted October 29, 2018 Author Share Posted October 29, 2018 Hard coded sequence of pitches and durations, I can convert those to accessible variables to the user. The "on" switch would be a midi event Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 29, 2018 Share Posted October 29, 2018 Here's a simple example that does what you are wanting. Should give you an idea how to go about it and you can expand it as needed. Let me know if you have any questions. // // Simple example to show loops through a given array of pitches // and for each one sustains it with the length given by second array // assumings to be monophonic var pitches = [ MIDI.noteNumber("C4"), MIDI.noteNumber("D4"), MIDI.noteNumber("E4") ] // array of durations as fractions of a beat var durations = [ 1, 0.5 ]; var pi = 0; var di = 0; var nextOn = 1; var note = new NoteOn; note.channel = 1; var NeedsTimingInfo = true; function ProcessMIDI() { var trans = GetTimingInfo(); if(!trans.playing) { return; } if(nextOn >= trans.blockStartBeat && nextOn <= trans.blockEndBeat) { sendNextNote(); } } function sendNextNote() { note.pitch = nextPitch(); note.velocity = 100; note.beatPos = nextOn; note.send(); var thisDuration = nextDuration(); note.velocity = 0; note.sendAfterBeats(thisDuration); nextOn = nextOn+thisDuration; } function nextPitch() { var out = pitches[pi]; if(pi >= pitches.length-1) { pi=0; } else { pi++; } return out; } function nextDuration() { var out = durations[di]; if(di >= durations.length-1) { di=0; } else { di++; } return out; } function Reset() { MIDI.allNotesOff(); nextOn = 1; // only handles starting from bar 1 pi = 0; di = 0; } Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 30, 2018 Share Posted October 30, 2018 (edited) If your brain didn't explode from the last one...here is another example that is based on a more OOP approach. OOP requires a bit more code to realize and if you don't know OOP you might not understand it...but the power of this is that its pretty easy to setup two completely independent canon's that play at the same time, for example. // // OOP example of Mensuration Canon // //================================ // Array Iterator class //================================ var ArrayIterator = function(array) { this.idx = 0; this.range = array; }; ArrayIterator.prototype.next = function() { var out = this.range[this.idx]; if(this.idx >= this.range.length-1) { this.idx=0; } else { this.idx++; } return out; }; ArrayIterator.prototype.reset = function() { this.idx = 0; }; //================================ // Player class //================================ var MPlayer = function(p,d) { this.nextOn = 1; this.started = false; this.note = new NoteOn; this.note.channel = 1; this.pitches = new ArrayIterator(p); this.durations = new ArrayIterator(d); }; MPlayer.prototype.reset = function() { this.nextOn = 1; this.started = false; this.pitches.reset(); this.durations.reset(); } MPlayer.prototype.playNext = function() { var trans = GetTimingInfo(); if(!trans.playing) { this.started = false; return; } if(!this.started) { this.nextOn = trans.blockStartBeat; this.started = true; } if(this.nextOn >= trans.blockStartBeat && this.nextOn <= trans.blockEndBeat) { this.note.pitch = this.pitches.next(); this.note.velocity = 100; this.note.beatPos = this.nextOn; this.note.send(); var currDuration = this.durations.next(); this.note.velocity = 0; this.note.sendAfterBeats(currDuration); this.nextOn = this.nextOn+currDuration; } }; //============================================ // Create a new MPlayer, pass in array of // pitches and array of durations //============================================ var player = new MPlayer([ MIDI.noteNumber("C4"), MIDI.noteNumber("D4"), MIDI.noteNumber("E4")], [ 1, 0.5]); var player2 = new MPlayer([ MIDI.noteNumber("F4"), MIDI.noteNumber("G#4"), MIDI.noteNumber("A4")], [ 1, 0.5, .25, .75]); //============================ // callback functions //============================= var NeedsTimingInfo = true; function ProcessMIDI() { player.playNext(); player2.playNext(); } function Reset() { player.reset(); } Let me know if you have any questions about either two. The OOP example is a bit cleaner, it can be started from anywhere in the sequence, hit PLAY to hear it. The first simple example has to start at Bar 1, beat 1 when you hit play for it to work Edited October 30, 2018 by Dewdman42 Quote Link to comment Share on other sites More sharing options...
TheMooseman Posted October 30, 2018 Author Share Posted October 30, 2018 Cool, I'll take a look at this tonight and tomorrow morning and let you know how it goes! The second one actually makes more sense to me, but I work in game audio so building things modularly is a bit more familiar, to me at least. Quote Link to comment Share on other sites More sharing options...
Dewdman42 Posted October 30, 2018 Share Posted October 30, 2018 The first one was just avoiding OOP, using some global variables instead. In general I have found with Scripter that often its not worth the extra code it takes to do things the OOP way. Sometimes it is. But its usually also confusing to most musicians who are barely hanging on to understand simple scripter tasks. The important point, regardless of whether you want to write a simple script without OOP principles or with... is that in Scripter you have to maintain some global state of things, then the callback functions are called as Logic runs along and inside the call back function you look at those global variables to do what you need to do. For example, rather then having a simple FOR loop to go through the pitches array, each time the ProcessMIDI() callback function is called, you see if you have work to do and if so, then do it, then get out and wait for another callback, etc. Its an event driven engine, so you have to keep track of running state in some kind of global variables and then provide code in the callback functions which will get executed by Logic as it runs along. Using OOP objects to keep track of that global state, requires more code in the single case, but as shown, it does make it a lot simpler and even less code if you end up reusing the same structure more than once... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.