Xrenoise To Mid?

(Malcolm Jacobson) #21

Hi Conner,

This is great stuff. :) I am not a coder, but I’d be happy to help out where I can.

The minimum value is 0, the maximum is 127.

There’s a good reference to the MIDI spec here


that explains most of the parameters.

This is the time base for the MIDI file. It’s usually expressed as “clicks per quarter note”. Renoise uses “Ticks” as the time basis, and the time is a factor of BPM, Lines Per Beat and the Speed setting. There’s an ongoing discussion about it here:


You really need a Renoise dev to define this for you, unless you can comprehend the maths. I can’t. :blink:

I don’t know if there is any way to convert the Renoise concept of instruments to the MIDI spec, which is based on General MIDI instruments. They don’t have any simple correlation to the Renoise sampler or to VSTi’s, though you might be able to extract the patch information from the VSTi data if you really wanted to. I think most people would be happy with just the note information.

I would extract the Track information from within the tags rather than worrying about assigning instruments.

BTW, what made you choose MF2T/T2MF over MIDI XML?



(Conner_Bw) #22

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.

(Conner_Bw) #23

Version 0.02

Edit: Scroll down for download...  
  • Imitate sample collision with MIDI off notes
  • Volume column exported to MIDI
  • Code clean up and refactoring which will make it easy to add the other stuff when I (or you?) figure it out

I still need the BPM question answered, and testers.

(Malcolm Jacobson) #24

Do you have a server you can host this script on to test, or do you need people who can test locally?

I can set up my own server to test, but it would take a couple of days to organise.

(Conner_Bw) #25

If you run windows,

  1. Download the Beatslaughter XRNS Scripting GUI: http://www.beatslaughter.de/dl.php?id=0009
  2. Put all the files/dirs from the aformentioned xrns2mid_ver.zip in ./xrns-sf/scripts/
  3. Make a file called xrns2midi.cfg and put the following lines in it:
caption=XRNS 2 MIDI  
author=Coded by Dac Chartrand.  
description=XRNS 2 MIDI Description  
gui=label(Select the file you want to convert:); file; label(Specify the destination file:); output;  

Put it next to the other config files in that directory

  1. launch xrns-sf.exe
  2. Show console
  3. Test

Thanks for pitching in.

(Malcolm Jacobson) #26

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?



P.S. - If not, I can test the GUI alternative on another machine in a couple of days time.

(Conner_Bw) #27

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 run OS X myself. It’s all about bash shell. :slight_smile:

(Malcolm Jacobson) #28

Hi Conner,

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 …



(Conner_Bw) #29

Be my guest, it’s a public domain script. If you figure out the tempo algorithm please share it too.

(Conner_Bw) #30

xrns2midi 0.02 (ALPHA!) is now available for MS Windows users in the Beatslaughter GUI.


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.

(Conner_Bw) #31

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  
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.

(Conner_Bw) #32

I found this thread:



“…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.”

So, this seems to work:

$bpm = (string) $sx1->GlobalSongData->BeatsPerMin;  
$ticks = (string) $sx1->GlobalSongData->TicksPerLine;  
// Lines per beat, default is 4  
$lpb = 4;  
if ($ticks <= 6 && (6 % $ticks == 0)) {  
 $lpb = (6 / $ticks) * 4;  
$text = "Mfile 1 " . count($data) . " $lpb\n";  
$key = round($key + ($bpm / ($lpb * 1000)));  

I will test more this evening and update accordingly. Peer review greatly appreciated.

(Conner_Bw) #33

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! :slight_smile:

(Conner_Bw) #34

xrns2midi version 0.03, choose one:

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:

  1. Division = MIDI ticks per quarter note / beat
  2. Line Per Beat = The amount of Renoise lines it takes to have 1 quarter note / beat
  3. If division is 1 beat, then it follows that 1 line is a percentage of that beat, so:
    Resolution = (Division / Lines Per Beat)
  4. MIDI Tempo = 60,000,000 microseconds / BPM
  5. 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.

Thanks for the help for those who did.

(Malcolm Jacobson) #35

Hi Conner,

The link to the v0.03 zip file gives me a “page not found”.



(Conner_Bw) #36

Link fixed.

(Conner_Bw) #37

Simple patch, implemented in downloads above.

if ($lastnote) {  
 $tmp .= "-1 PrCh ch=$c p=$p\n"; // -1 to be replaced with 0, used for sorting   
$tmp = explode("\n", $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.


(Conner_Bw) #38

Also, just now, fixed redundant tempo tracks. Download the update anyone who cares.

I’m signing off, for real, now.


(Malcolm Jacobson) #39

That would be great. MIDI XML is definitely easier for non-programmers to understand.

(Malcolm Jacobson) #40

Great! :)

Does that mean you’re rewriting the midi class?