duck_waddle wrote:oldgearguy wrote:To continue along what Softcore said -- if you find yourself cutting and pasting the exact same (or almost exactly the same) set of lines in a script, you should consider making it a 'subroutine' (really in Lemur they are all just scripts).
For example, your chord() and chordOFF() are exactly the same with the exception of 0 or 127. you could create a new script called sendChord(velocity) that had the same guts except that in place of the 0/127 you use the velocity parameter: noteout(lemurPort,a,velocity,midiChannel);
Make that script execute manually and then your chord() and chordOFF() scripts are reduced to simply:
<SCRIPT name="chord()" script="
sendChord(127);
" trigger_script="x" trigger_type="0" trigger="2" clock="0" clock_div="4" osc_message="/maj7/chord" midi_message="0x90,0x90,0,0" midi_target="-1" flag="1"/>
<SCRIPT name="chordOFF()" script="
sendChord(0);
" trigger_script="x" trigger_type="0" trigger="3" clock="0" clock_div="4" osc_message="/maj7/chordOFF" midi_message="0x90,0x90,0,0" midi_target="-1" flag="1"/>
The beauty of doing something like this is that later if you wanted to send a chord with a different velocity, you can call sendChord() with the new number without having to change it in multiple places.
That's a simple optimization, but if you start thinking like that, you'll make it easier to do updates/fixes since you don't have to hunt through all your scripts looking for the same change. Plus if you create a core set of scripts, then adding new functionality becomes much easier since you already did the hard work creating the core pieces.
Once you get comfortable with that, you could pass in values that make up the triad for that particular core type or create an array of triads and then reference which set to use at any given time.
Hey thank you so much for your time! That kind of constructive advice is exactly what I need - I think I'm almost comfortable enough with some syntax and programming concepts and techniques that I really just need some thoughtful feedback. Your second post, about being bulletproof was awesome. I will do my best to think like that from now on.
The first post, though, left me with a few questions. I knew my code repeated itself way too much, but I wasn't quite sure how to address that. The script you suggest, sendChord(), would that live globally? Is that where I should be putting my "functions?" I've seen some people mention that they write scripts in containers that apply to the objects inside the container. Is that technique interchangeable with global scripts (at least in this example)?
Also, that language you're writing in that resembles HTML - where and when can I use that? Can you point me in the direction to read more about those tags and syntax you used? Again, I can't thank you enough!
In reverse order -- the syntax was actually cut-n-pasted out of the raw .jzml file. Under the hood, Lemur uses an XML style formatting for all the objects and scripts you create in the editor. If you are somewhere (like a workplace) that doesn't allow you to install Lemur to view/edit, you can still work with the raw .jzml file. It's more dangerous since there's no syntax checking or anything, but for quick views or checking something, it is fine. Once you get comfortable, it's sometimes faster to work with the rawjzml if you want to do something like rename a script and all the places that call it or if you have some tedious editing to do. Wordpad/notepad supports things like Home/End, cut/paste, and other standard editing conventions that either don't work or work weirdly in the Lemur editor.
Given the way you coded the objects, each fader would need its own sendChord(velocity) script. To use a global script (i.e. just have one copy), it would have to be smarter and/or take more parameters to distinguish between the various types (maj7, min6, etc).
I'll often take multiple passes through the code if I'm not sure - bang out a 'it just works but it is ugly' version to get a proof of concept, then go back and clean up the code by pulling obviously common things out into a single script. Then later, once I have a good handle on where the app is going and what functionality I need, I'll look at it to determine if further consolidation makes sense and is possible.
Since chord and scale structure is all about the math and intervals, you should be able to consolidate even more if you wanted by setting up arrays (vectors) with the various offsets and then passing in an index to the array based on whether you want major, minor, 6th, 7th, etc. On the flip side, if you want to just get something done and move on and use it, what you have certainly is good enough.
If you just want to use what you wrote, spending days preventing unlikely combinations from causing unexpected behavior might be overkill. The worst that happens (in this case) is hung notes. If you are writing an editor or realtime recorder, loss of data is a bigger deal. In addition to writing software as my day job, I have done a lot of beta testing for Alesis, Akai, and other companies. Once you get good at exploring edge cases and what-if's, you become adept at breaking things. If you can document how to break it, then the developer can usually figure out a way to prevent/fix the break. That's how this TX-802 editor I've been writing turned into a 7 month long job (working in various free moments over that time). The core functionality was there in the first month or two. The rest of the time has been spent adding some features and making it more bulletproof as I tested it and broke stuff.