Some people have expressed interest in implementing multiple-output MIDI support for Hatari.
I know very little about the innards of Hatari, but so far I've managed to implement emulation of the Friend Chip MM1 MIDI expander in Hatari. This device attaches to the printer port and gives you 8 extra MIDI outputs for Cubase and other MROS software.
At present, it only outputs data to stdout rather than a real MIDI device. I'd need the help of someone with knowledge of PortMIDI to make it output to the outside world. And of course a suitable entry in the GUI. Another shortcoming of my emulation is that it only works in ST high (since I hook the horizontal blanking call to calculate timings). This code would need to be moved to somewhere else in Hatari where it can be called on a frequent, predictable time schedule.
I can share the sourcecode for my emulation, but I'll probably bring it across to the latest Hatari version first. But considering the protocol is so simple, it might be easier for an expert to re-implement it.
Data is written as you would with a printer - place the data on the data lines, then pulse strobe low and high (with no extra delay).
First byte is the MIDI data byte you wish to output.
Second byte is the port number (0-7). It appears to be possible to daisy-chain 4 devices, in which case I'm fairly certain that the port number can range from 0-31. However, the existing Friend Chip MM1 driver does not support daisy-chaining. The compatible StartPort driver does - but it may be lost to time by now.
Normally, the busy line is low. Upon writing the first byte, the busy line immediately goes high and remains high for exactly 320 microseconds. Further data can be written while the line is high - but only for the other ports. You can only write one byte per port for each cycle of the busy line. This is because there is only a one byte buffer for each port.
The Cubase driver typically waits for the busy line to go low, then writes one byte of data for each of the ports being used at that moment. The process then repeats when busy goes low again. It uses both interrupts and polling to determine the state of the busy line at various points in the driver. The driver also toggles the active edge register in the MFP to force an interrupt to occur when the first byte is written.
Writing additional bytes to the same port while busy is high causes the data to be lost - and the timer is NOT reset (so the line goes low 320 microseconds after the first write - not the subsequent writes). If you write data to multiple ports, I'm presently uncertain what happens. My guess is the timer gets reset each time you write - so the busy line goes low 320 microseconds after the last write. But it might be based on the first byte written instead. I'm presently writing a test program which will determine which behaviour the hardware exhibits.
It's absolutely essential that the busy line behaves similar to the above. If you attempt to hold the busy line low, data will get lost. Likewise, if you pulse the busy line for each byte written (as you would with a printer) then data gets lost. If the busy line remains high for too long, Cubase will lock up.
In the event the host operating system's MIDI buffer is full and data cannot be written, I would recommend the busy line should remain high longer than necessary until the buffer has space for one byte. But preferably for not much more than 500 microseconds otherwise you risk causing Cubase to misbehave. In general, there should be a large buffer in between the data sniffed from the printer port and the host operating system to prevent stalling - 8KB should be sufficient. The real Friend Chip MM1 has no buffer at all, but then real time performance is guaranteed. I don't think modern host operating systems make any guarantee about how quickly MIDI data will be delivered hence the need for a buffer.
Resynchronisation: The Friend Chip MM1 has no timeout. You can write the data byte and port selection bytes with any delay between them. Therefore it's possible (even likely) at startup the MM1 will be expecting a port selection byte while the software is writing a data byte. The MM1 has some kind of detection for this - if it sees a port selection byte with the upper bit set, it will almost certainly resynchronise by assuming the byte is actually data. This is subject to further tests with the real hardware. If you write both a port selection byte and a data byte with both of their upper bits set, busy goes high for 8ms. I'm not certain what purpose this serves - it might be a signal to the driver that a desynchronisation has occurred.
Other means of getting extra MIDI outs from Hatari:
A very common add-on is a simple modem port to MIDI cable. This is supported by a vast amount of Atari MIDI software. The software sets the UART divider in the MFP to /1 instead of /16, which allows baud rates up to 307,200 (1/3rd of a megabaud) to be selected. A baud rate timer of 10 is used for MIDI, giving you a baud rate of 30,720 - close enough to the MIDI standard rate of 31,250. The port is only used for output - because when in /1 mode, the MFP cannot accept an asynchronous input. Some software absolutely requires RTS to be looped back to CD in order to detect such a cable. I would expect emulation needs to be pretty accurate - trigger a buffer empty interrupt 325.5 microseconds after the buffer is filled (or immediately if the buffer is presently empty and the data moves directly to the output shift register).
A similar add-on is the C-Lab Export. This works in exactly the same way as above, except it provides three multiplexed MIDI outputs. The desired output is selected by various combinations of the RTS and DTR pins. The values are as follows:
MIDI out B: DTR=negative RTS=positive
MIDI out C: DTR=positive RTS=negative
MIDI out D: DTR=positive RTS=positive
Note that the MC1488 inverts the DTR and RTS lines from their TTL levels. Therefore the register bits in the YM chip are as follows:
MIDI out B: DTR=1 RTS=0
MIDI out C: DTR=0 RTS=1
MIDI out D: DTR=0 RTS=0
The DTR/RTS lines are set prior to transmission of a byte, and remain set to that state until the byte has finished transmitting. Like the simple MIDI output cable, the software expects RTS to be looped back to CD. DTR is NOT looped back.
Obviously neither of these will work with the real Falcon due to the missing MFP modem port. But in fact Hatari could still support it since the MFP UART is dormant.
Performance-wise the Export is a pretty bad way to drive three MIDI outputs - because it can only drive one at a time. But it's fine for one extra MIDI out.
Export and the modem to MIDI cable are supported by Cubase, Notator, Notator Logic, Sweet Sixteen, Master Tracks Pro, and many more.
It may be possible to get one extra MIDI output via the modem port already in Hatari - by pointing the modem data to a MIDI device. This will only work on platforms where MIDI devices show up as device files. I haven't tested this.
The other option for extra MIDI outs is emulating the C-Lab Unitor. This is a cartridge port device which gives you two extra MIDI inputs and two extra MIDI outputs.
I've had a brief look at the hardware for the Unitor, and it's based around a PAL for address decoding and an off-the-shelf UART chip. Later, I will turn my attention to reverse-engineering how the reads and writes are done.
It appears to write to the cartridge port in a similar way to the Steinberg Midex. You access a "magic register" then write the desired word into ST RAM. The hardware gets primed by the magic register being accessed and then sniffs the data written to ST RAM directly from the data bus by watching /UDS and /LDS.
The Unitor works with Notator, Notator Logic and Cubase. There is also a "Director" program which allows some other MIDI software (that uses TOS) to use the Unitor.
Another device specifically for Notator and Notator Logic is the Log3. It doesn't work with Cubase. I don't know anything about the protocol it uses - it will be proprietary because it uses a small MCU instead of a UART. Log3 can be used alongside Unitor to give you five extra MIDI outs.