[sorry... this is very long but I hope quite clear. as you can see, I've been thinking about this for a long while... /t] GOALS IN WRITING MIDI CONTROL PROGRAMS zeroth priority: ACHIEVABLE. must be able to make it work without too much work. first priority: COMPLETE. as much functionality as possible needs to be accessible from MIDI. second priority CLEAR. it should be "obvious" (to a reasonably technical person) how to access these functions from MIDI. More common functions need to be "more obvious". third priority EFFICIENT. it needs to make reasonably efficient usage of the memory, computational, audio and display facilities of the machine. DEFINING OUR TERMS A "MIDI command" or just a command is some bit of MIDI generated by the user that's supposed to control the machine (ie, program changes, control changes, pitch bends, NRPNs, system exclusives, etc...) Conceptually, you can think of the machine's controls as having a "state". (For the looper's MIDI control, the audio in the machine isn't really part of the state.) You can talk about the state of the whole machine. You can talk about the state of a part of the machine, like the state of one channel. Or, you can talk about the state of a single control. Finally, "internal settings" or "settings" come in two flavours. Switches have two or more discrete settings, like "on"/"off" or "audio/tap/internal". Dials have "continuous" settings, even though the granularity of this might be quite small (or quite large...) For example, dials would be "loop time (0.000-128.000 seconds)" or "feedback level (1-8)". So, we put together settings (switches or dials) into parts, and then assemble the parts into the whole state of the machine. WHAT IS THE PROBLEM AT HAND? We want to see how to map "MIDI commands" into changes to "internal settings". SAMPLE MEMORY IS EXPENSIVE, USER TIME IS EXPENSIVE, CONTROL MEMORY IS CHEAP, CONTROL PROCESSING IS CHEAP Suppose a user command is represented by a (wildly generous) 100 bytes on average, and the user has programmed 1000 commands, surely quite a few. The total memory consumed here is a measly 100K, or about one second of stereo sampling. Users (ie "musicians") are really unable to generate too many different sorts of streams of information while actually using equipment. You can't generate hex code on the fly! Modern processors perform hundreds of millions of operations a second. Processing audio takes many hundreds of thousands of operations a second. One user has trouble generating a thousand control operations. This means techniques like "table lookups" or "linear interpolation" are essentially "free" (a table lookup on a modern microprocessor might take 100 nanoseconds!) and can be used if at all helpful. ON WITH IT! Without further ado, I'll present a nice, simple and general model for the MIDI control of a machine. A LIBRARY OF STATES You need to be able to recall the state of the entire machine by some sort of name. It's fine if these names are "1", "2", "3", etc. but text would be nice too. BANKS OF COMMANDS Commands need to be organized by banks. (see control processing is cheap above..) There need to be a lot of banks possible. Informally, one bank == one song. A "bank" of commands describes exactly how "commands" are mapped into "changes to the settings". A bank might conceptually say something like Program Change 1: recall state 1 Program Change 2: set record on loop 1 to on Program Change 3: set record on loop 1 to off Program Change 4: - Program Change 5: - ... CC1: loop 1 output (0-100) CC2: - CC3: - PITCH: - where of course we just don't store the empty areas in a bank. WHY BANKS? It corresponds to the needs of your average player, where you have a limited selection of controls that you need to behave differently for different songs. ANY CHANGE CAN BE MADE FROM ANY COMMAND Remember, your average guy has a few fairly limited control sources so if he can only generate, say, program changes, then he should be able to set all levels this way. Banks should be able to handle any MIDI data if at all possible: PC, CC, note-on/off, aftertouch, you name it. Seems ridiculous but you have to parse the MIDI stream anyway, it's very little work to cover ALL the cases at the end. WHAT SORT OF CHANGES ARE ALLOWED? any list of the following changes: set state to (value) set bank to (value) set dial/switch to (value) increment/decrement dial by (value) toggle switch up/down // loops through all possible values set dial to (start:end) // maps a controller linearly SUMMARY A simple model of any MIDI machine is presented where a user sends MIDI commands to change the state of discrete switches and continuous dials. At any time, the machine has a "state" of all its switches and dials. The user can store and recall multiple states in memory. The MIDI behaviour is controlled by a "bank" which maps MIDI commands into state changes. APPENDIX: SUGGESTIONS FOR ENHANCEMENT Presets: There need to be some decent "preset banks" that expose the most common functions to MIDI and to the most common foot pedals in their initialized format. This idea pays for the bank idea on its own, if it works "out of the box" with "all" the foot pedals "out of the box". The Bank Command: There needs to be a command that goes off when you select a bank. If the rest of this worked, that would take 10 minutes to implement. Default Bank: If you had a little extra time, you could have a "default bank" that would be searched if you didn't find the incoming command in the current bank. Curves for dials: In the case of the "linear values" for the dial, it would be very nice to have arithmetic maps that would let you remap an incoming controller. This sort of thing is very useful because things like "velocity" or "breath control" (my favorite) are not linear in nature. Rev 2.0: In a later rev, once you had this structure, it might not be to hard to actually create some LFOs, envelopes, other free-running gizmos... ...electronic a capella madness <http://volectrix.com>......... ...extreme internet radio <http://extremeNY.com/radio>...