[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Date Index][Thread Index][Author Index]

(LONG) MIDI control (for loopers and other devices)



[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>...