MIDI and the organ project

From Fernseher
Jump to navigationJump to search

MIDI standard is out there. Also good is the RTP-MIDI RFC, for putting MIDI data into a stream and whatnot.

The basics, as I think we will be using them:

Packet basics (we'll only be using 3 byte packet forms):

1 <3: opcode> <4: channel> 0 <7: arg1> 0 <7: arg2>

Essentially, a status byte, with the high bit on (0x80-0xFF), and two argument bytes, with the high bit off (0x00-0x7F).

opcodes of relevance:

  • 0x0: key off. arg1 is the key number, arg2 is the velocity. We will always use velocity of 0x40.
  • 0x1: key on. arg1 is the key number, arg2 is the velocity. We will always use the velocity of 0x40.
  • 0x3: control change. arg1 is the control number (0x01 is modulation wheel, 0x0B is the expression pedal), arg2 is the new control value, from 0x00 - 0x7F (Note: If we need more than 127 steps, add 0x20 to the control number, and thats the control number to use to send the least significant 7-bits of the value. The value sent with the base control number is considered to be the most significant 7-bits of the value. This ensures that if just read the base control number, you set the control to approximately the correct percentage of fully off/fully on.)

For channels, we will use:

  • 0x0: Great (Solo) Manual
  • 0x1: Swell (Accompaniment) Manual
  • 0x2: Choir (below Great) Manual, if present
  • 0x3: Solo (above Swell) Manual, if present
  • 0x4: Echo (above Solo) Manual, if present
  • 0x5: Third Pedalboard, if present, or the auxilary stop channel, covering additional stops for all manuals and pedals.
  • 0x6: Second Pedalboard, if present, or the main stop channel, covering all stops for all manuals and pedals.
  • 0x7: Main Pedalboard
  • 0x8: Great stops only
  • 0x9: Swell stops only
  • 0xA: Choir stops only
  • 0xB: Solo stops only
  • 0xC: Echo stops only
  • 0xD: Third Pedalboard stops only
  • 0xE: Second Pedalboard stops only
  • 0xF: Main Pedalboard stops only

Our initial organ will only use channels 0x0-0x1, 0x6-0x7.

Each keyboard channel (0x0-0x7) gets its own control set. For our organ, where the modulation wheel and expression pedal control all divisions equally, each control change gets sent for each active channel... or maybe just for great, and the software will figure out that they control all the stuff. Note, we may not hook up the modulation wheel when we begin. It'd be kinda a lot harder to make work right, I think.

We will be building channel combination boards, that take an enable and a sub-channel address, and read back the contents of the addressed buffer. 4 bits of address gets 16 buffers. At 8 bits per buffer, thats 128 inputs for each channel. That matches with midi's numbering scheme. Alternatively, if you take the LSB of the true channel, and feed it to the 4th address bit of the channel board, and only decode the top 3 bits of the channel to determine channel board enable, you can duplex your channel boards, since we will only be using under 64 inputs per channel. The AVR firmware will have an MIDI offset value for each channel to add to the number received from the board before sending as part of a MIDI command. For most subchannels, this will be 36. Will probably just use an offset of 0 for the stop channels.

Using the split channel board design, we only need two channel boards for our organ. The main board will be designed to use the channel boards in split mode, and will never probably use the split-mode stop channels (0x8-0xF), so it will only have 4 plugs for channel boards, 0x0-0x1, 0x2-0x3, 0x4-0x5, and 0x6-0x7. The initial organ will only use the first and last of these plugs, so we don't even need to populate the board positions for the other channel boards.

Also, I think we might want to put all the switch pull-up resistors on the manuals themselves, soldered to the key tabs. This will eliminate a lot of crap on the boards, and keep the board design uniform, since the different keys will need different pull-ups. The manuals, with their 5k internal resistance, will need 50k (or so) pull-ups to 5V, and the pedals and stops, with no internal resistance, will need just 10k (or so) pull-ups to 5V. Each manual will get a separate power and ground plug for the pull-ups and grounds, so the connectors for the keys don't need a pin for ground or power, I don't think... Though if there is room, I guess we could send it along there, too. Can't hurt anything, provided the wires support enough current for the crazy case of all the stop pulled or keys pressed or something. Given a max of 64 inputs to a half-channel, and only 61 keys on a full manual, we can use 2x36 pin connectors for the manuals, and 1x36 pin connector for the pedalboards, and 1x36 pin connector for the stop boards. Thats 6 total 36 pin connectors, male and female, solder cup and through-hole.

Channel board to main board connectors will have an 8-bit data bus, 4-bit address bus, a power, ground, enable, and identify(?) pins (16 total). Should be able to use IDC connectors and ribbon cable here.

Simple algorithm for key change detection

After reading a byte from the buffers, we xor it with the copy of the byte from last time, then store the new version in the copy location. We then start looking at the lsb of the xor'ed byte. If its a 1, we send a key on if the lsb of the read byte is a 1, and a key off if the lsb of the read byte is a 0. We then shift right and do that again. We do that 8 times, once for each bit in that byte. Then we can move on to the next valid address for that channel, write out the address, read back the buffer value, xor, store, analyze, etc. Note, we can speed this up by checking if the xor byte is identically 0x00, in which case we don't have to analyze it, it hasn't changed. This will be the usual case! Only occasionally (in sample time), will things change, and usually only on one bit, and thus one buffer, amongst all the channels and buffers. This should help us keep up to speed.

Once we are done reading all the channel board buffers, we can check the expression pedals and other variable controls for new values, and possibly send control change events. After all this, we actually send the MIDI bytes as we have determined them to need to be for this time around, and go to sleep until our next sample time.

Not sure what the latency of the serial to USB conversion is in FTDI, but it could be as bad as a single byte in a single USB message.... Anyway, we want to build a buffer of bytes that need to get send over each sample time, with the RTP-MIDI spec used to make it a stream type thing. This means: packet length, "timestamp", first MIDI event, relative timestamps (should all be zero), subsequent MIDI events.

Chips to use

  • 16x? 74HCT540 for the octal tri-state buffers, inverting (0.54, 20 pin dip)
  • 1x? 74HCT138 for 1 to 8 decoder (0.40, 16 pin dip)
  • 1x? 74HCT154 for 1 to 16 decoder (0.80, 24 pin dip)
  • 1x ATMega164P-20P for AVR controller, 20MHz, (4.82, 40 pin dip)