Sounds like a PIC 18F2550 is just the thing, or maybe a 18F4550 if the extra I/O lines are needed. I don't know why you say a PIC 18 is not easy. You say you are a programmer, so I don't see what you're afraid of. Perhaps nobody has done a MIDI USB interface ready for you to add the keyboard scanning code to, but certainly there are various examples of the basic USB driver out there. Microchip has some code, and so do I. My 18F USB firmware is available from the downloads page, and fits into our PIC development environment.
I've never done a MIDI device, but I sortof vaguely remember there is a USB class standard for that. If so, then it's really easy since you don't have to write a host driver and it will work with any OS that implements that USB class. All you have to do is look at the class definition, fill in the right enumeration data in the include file for that purpose, then send/receive data over the appropriate endpoints according to the standard.
Any other microcontroller will require something similar. Again, short of finding free USB MIDI firmware out there (which you say you can't find), you need to do pretty much what I said above regardless of what flavor microcontroller you use. USB is USB, so all the USB device peripherals in microcontrollers do pretty much the same thing with only a few details different.
Playing polyphonic music by using separate circuitry for each "voice" works very nicely when music is logically subdivided into a number of single-voice channels. In many cases, one not only won't care if the hardware voices aren't perfectly matched--one may even want to have some of them be a little louder than others.
When using a polyphonic instrument to play MIDI data, however, it's important to ensure that all voices behave equivalently, and the easiest way to accomplish that is to use the same circuitry to implement all of them, typically with some sort of wave-table generation.
There are many ways to perform wave-table-based music, which trade off sophistication for CPU time and memory requirements. I've written a four-voice wave-table generator for the 6502 which used twelve instructions (46 cycles) for each output sample [an average of only three per voice!] but it required almost 3K worth of data tables. I've also written an 8-voice wave-table generator for a 10MHz PIC and a 16-voice one for the PSOC. I've not done much with the Arduino, but I would guess an eight-voice wave-table synth would be workable.
There's an important thing to note, however, when doing a wave-table synth: square waves often sound bad if timing is quantized to something that isn't a multiple of their frequency. If you wish to generate clean square waves for a five-octave MIDI keyboard, you may need to use a rather high sampling rate. If you want to generate smoother waves instead you can get by with a lower sampling rate.
I've not used the Arduino, so I don't know what sorts of constructs in C would yield the best code, but a typical wave-table implementation on the ARM would look like:
uint32_t freq[8],phase[8];
int32_t volume[8];
int8_t *table[8]; // Pointer to 256-byte array
int32_t total;
total = 0;
phase[0] += freq[0]; total += table[0][phase[0] >> 8]*volume[0];
phase[1] += freq[1]; total += table[1][phase[1] >> 8]*volume[1];
...
phase[7] += freq[7]; total += table[7][phase[7] >> 8]*volume[7];
After the above code, total
will hold a value which may be scaled (if needed) and either output to a DAC or used to set a PWM duty cycle.
The above code assumes that the wave table is exactly 256 bytes long; other approaches can be used if that isn't the case. If the Arduino can't efficiently perform the multiplication by volume
, it's possible to use a different table for each volume level (my 6502 code used two sets of tables--one for "loud" and one for "soft").
An additional consideration if you're using a DAC (less applicable if you're using a PWM) is that rather than summing together all the individual values generated for each wave and outputting them as a group, it may be helpful have an interrupt which happens eight times as fast, and outputs the value for one wave each time. Doing that will effectively gain three more bits of ADC precision. Also, if you happen to want sine waves and your hardware doesn't support fast multiplication, generating two full-amplitude sine waves whose frequencies match but whose phases differ, is equivalent to generating one sine wave whose phase is the average of the two full-strength ones, and whose amplitude is proportional to the quantity "one plus the cosine of the phase difference". My PIC-based waveform generator used that trick.
Best Answer
No, combining them in hardware is not possible. Normal way of doing this is to have two MIDI inputs, and two UARTs on a microcontroller receiving messages from both inputs. Then the microprocessor merges the messages so that correct MIDI data bytes belong to correct MIDI status bytes. These merged messages are then sent to one (or several) MIDI outputs.