For me, it’s easier to deal with text for procedural conversions, XML has document formating and validating overhead, MF2T/T2MF had several examples that I was able to tutor myself from, the output looks like debug code so I could just read what I was doing wrong as it happened, etc.
Thanks for the advice. It’s great help. I will get back to this shortly.
I’d rather test a server-based option if possible. I have XAMPP on an XP box and a Fedora box running PHP 5. I tried a quick test on the XAMPP box and I got the following error message:
“Error: expects at least 2 parameters. Usage: php /path/to/file1.xrns file2.txt will output txt file (file2.txt) to current working directory.”
Is there another file required for server based use to prompt for input?
Cheers,
Malcolm.
P.S. - If not, I can test the GUI alternative on another machine in a couple of days time.
This is not a server side app. This is a command line script.
If you have xampp and/or run redhat , drop to the prompt, cd to the dir and type
php xrns2midi.php /path/to/file.xrns output.midi
The file(s) will be created in the current working directory. On windows you need infozip (unzip.exe) to get this to work. See this thread for more info:
I ended up downloading Beatslaughters scripting GUI thing to do some quick testing using a very simple one instrument one track XRNS. Results varied depending on the host I tried the MIDI file in.
Reaper opened the file as a single track. Reason opened the file and created 16 sequencer tracks - one for each MIDI channel, I assume. FL Studio opened the file as a single track.
All hosts ended up with incorrect tempo information. The tempo was about 2.2 times faster than the original.
The note information was correct in each host.
Overall it’s a great start. Getting the tempo information sorted seems to be the key.
Do you mind if I try to hack this into something that will run from a web server? I like the idea of being able to put this up on a server that anyone can upload XRNS files to …
Easier for those who want to test it without figuring out how to install it. Maybe hack away at the script(s)? Download the RAR file above and provide feedback please.
I don’t get the calculation… I tried the following and it didn’t work:
$bpm = (string) $sx1->GlobalSongData->BeatsPerMin;
$ticks = (string) $sx1->GlobalSongData->TicksPerLine;
$lpb = 4;
if ($ticks <= 6 && (6 % $ticks == 0)) {
$lpb = (6 / $ticks) * 4;
}
$div = $bpm * $lpb;
$text = "Mfile 1 " . count($data) . " $div\n"; // Third parameter (div) has something to do with BPM
$key = $key + $div; // $key is the renoise line number, I need to multiply it by something
With the above changes, the incorrectly generated BPM midi for “DemoSong - Diggin for Gold.xrns” looks like this:
Mfile 1 15 920
MTrk
0 Meta Text ""
0 PrCh ch=1 p=0
0 PrCh ch=2 p=0
0 PrCh ch=3 p=0
0 PrCh ch=4 p=0
920 Off ch=2 n=50 v=127
920 On ch=1 n=50 v=127
920 On ch=2 n=50 v=127
932 Off ch=1 n=50 v=127
932 Off ch=2 n=50 v=0
932 On ch=1 n=50 v=127
932 On ch=2 n=50 v=127
938 Off ch=1 n=50 v=127
938 Off ch=2 n=50 v=127
938 On ch=1 n=50 v=127
938 On ch=2 n=50 v=127
...
I’m looking for the bold numbers “Mfile 1 15 920” and “932 On ch=1 n=50 v=127” i.e. [$div = (???)] and [$key = $key + (???)] in the above code. $key is the corresponding Renoise line number. It needs to be multiplied by something.
“…it should be tempo / (division * 1000). Since tempo is in microseconds per quarter-note, and division is in ticks per quarter-note, you should divide them to get the microseconds per tick, then divide by 1000 to get milliseconds per tick.”
The current conversion is not faithful to Renoise tracks & columns, as I don’t think it’s the same approach to laying down data for MIDI.
The current conversion is based on Renoise instruments being isolated into their own MIDI tracks. In the conversion, each MIDI track actually the data for a single Renoise instrument.
Take for example Garageband, you can’t put notes everywhere, you have to keep them in the same track as the instrument, the instrument defines the track. Renoise, on the other hand, allows you to put notes everywhere and anywhere. I had to figure out a way to change this, as well as adjust for colliding samples and multi-timbral i.e. the sample sample being played on two tracks at the same time.
I don’t think i’ll be changing the meta data to reflect this because I want to maintain the flexibility of being wrong. I’m not preserving track data because Renoise tracks and MIDI tracks are not the same thing
I’m also open to the idea of handing this script off to someone else! If someone wants to take over because I’m way off base then by all means. I’m only doing this for proof of concept and hopefully to motivate others. I don’t plan on supporting this one as I really have no interest in MIDI other than it’s fun to program.
Thanks for the BPM advice. I’ll keep hacking away. But I’m open to code edits and hostile forking here. By all means!
I believe I have a coherent BPM algorithm, it’s not perfect, but it is based on my understanding of what I believe to be correct. Coders, have a look at the code and tweak it, pretty please. Anyway, here’s the algorithm:
Division = MIDI ticks per quarter note / beat
Line Per Beat = The amount of Renoise lines it takes to have 1 quarter note / beat
If division is 1 beat, then it follows that 1 line is a percentage of that beat, so:
Resolution = (Division / Lines Per Beat)
MIDI Tempo = 60,000,000 microseconds / BPM
MIDI chunk = Renoise Line Number * Resolution
In MIDI, Division can be an arbitrary number, it’s the similar to Renoise speed. I’ve set it at 96 to get a reasonable resolution. In the code, if you change $division to be higher or lower, it doesn’t affect anything.
Each Renoise line, known as $key in the part of the code that matters, is multiplied by $resolution.
The MIDI tempo is manually set.
Those three elements produce a BPM that makes sense for every test I have made (check out BOTB from BB5 as a Midi). The BPM is definitely not perfect but I believe that this is due to a rounding error in Lines Per Beat. If someone can figure this out, hook me up.
Also, if you change the BPM in the song, swing the beat using speed changes, these changes will not be picker up at the moment. Initial BPM only at this point in time.
This script has a long way to go… I will be taking a break. Coders who want to pick up the torch, by all means, do.
if ($lastnote) {
$tmp .= "-1 PrCh ch=$c p=$p\n"; // -1 to be replaced with 0, used for sorting
++$c;
}
$tmp = explode("\n", $tmp);
natsort($tmp);
$tmp = str_replace('-1 PrCh', '0 PrCh', $tmp); // -1 was used for sorting, replace with 0
foreach ($tmp as $sorted) {
if (trim($sorted)) $text .= $sorted . "\n";
}
But, yeah, I agree with what you are saying.
Anyone wanting to inherit this project be my guest as I don’t think I will working on this anymore. For now, it’s a proof of concept.
A lot of the code could be handled via the PHP Midi Class. A simple example is that $tempo = round(60000000/$bpm); $text .= “0 Tempo $tempo\n”; is the same as $midi->setBpm($bpm); MIDI-XML is very desired but I went with the MF2T/T2MF format because I was learning about midi and needed a loose and choppy intermediate format in order to fail with.
I notice that the MIDI Class uses the 0.9 MusicXML schema. If I wanted to replace this with the latest version (2.0), would I need to edit the MIDI class, or XRNS2MIDI?