Closed ghost closed 7 years ago
The DRO format is documented pretty well on this site: http://www.shikadi.net/moddingwiki/DRO_Format.
The main gist of it is that a registerMap is read from the file. This array contains the OPL2 registers that the data is sent to. The playDroSong function reads the code (index into the register map) and data byte to send to the OPL. If the code is a registerMap entry it retrieves the OPL register from the registerMap, sends the data byte and returns a 0ms delay. If the code is a short or a long delay the return value is the number of milliseconds to delay until the next data pair is sent to the OPL2.
The main loop keeps sending data until all song data is sent. for a 0ms delay the next pair will be sent immediately, otherwise the Arduino delays for the returned amount of milliseconds.
The routine assumes version 2.0 DRO files made with DosBox 0.73 or later
Hope that explains it...
Thanks for clearing that up. I think a script that runs on the PC that reads IMF and DRO files and sends the data to the Arduino in real-time via serial while the Arduino sends the data to the OPL2, rather than the Arduino reading the file from an SD card would be useful for the example folder in the OPL2 library. If such a script existed, what would the script and Arduino sketch look like?
The Arduino sketch would be very simple. Assuming you do all your decoding on the PC side you would just send register - data pairs over the line. In the main loop it would just wait for Serial.available() > 0
, read the incoming byte and as soon as 2 bytes are received it can write a register of the OPL2. You may need a special byte pair though to give the OPL2 a hard reset between songs.
If you find time, I'd be grateful if you were willing to create a sketch like that. The main reason I'd like to see a streaming program for this project is because patches could be made for programs like DosBox which would allow it to interface with the OPL2 board rather than relying on emulation.
I've made somewhat of a thing now. Here's the Arduino sketch for the streaming program:
OPL2 opl2;
void setup() { opl2.init(); Serial.begin(9600); }
void loop() { while (Serial.available() < 2) { byte reg = Serial.read(); byte data = Serial.read(); opl2.write(reg, data); } }
That would almost work :). If you change the condition of the while to while (Serial.available() > 1) {
it should work.
Okay, I've changed it. I'm now working on the Python script that is to decode an IMF music file and send the registers to the Arduino, but I'm having trouble getting it to work. If you can see any problems with it, tell me. Here's the code:
import serial import struct from time import sleep
file = open("k5t06.imf", "rb") (songLength,) = struct.unpack('<h', file.read(2)) imfSpeed = 560.0 arduino = serial.Serial('/dev/ttyACM0',9600)
if songLength == 0: songLength = 65535 file.seek(4, 0)
def playImfSong(songLength): (reg,) = struct.unpack('B', file.read(1)) (data,) = struct.unpack('B', file.read(1)) (wait,) = struct.unpack('f', file.read(4)) if reg != 0: arduino.write(reg) arduino.write(data) songLength -= 3 return round(wait * (1000 / imfSpeed));
while True: while songLength > 0: wait = playImfSong(songLength) if wait > 0: sleep(wait / 1000) songLength -= 1
Currently, when the program is ran, it throws an error:
Traceback (most recent call last):
File "Stream.py", line 27, in
Sorry I'm not a Python expert, but my best guess from looking at that error is that the write function expects something like a byte array...
Perhaps a C++ version of this program can be made then. I'm no Python expert either, and I'm still scratching my head as to why the code doesn't run.
The PlayDRO example sketch is neat, but it isn't very well documented. Could you explain how everything works?