Batch applying tempo data to audio files

This forum is for discussing Reason. Questions, answers, ideas, and opinions... all apply.
Post Reply
User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

14 May 2021

I asked this a while ago but didn't seem to make much progress, now I'm facing the prospect of having to manually re-bounce thousands of audio files to embed tempo data for use in Reason and figured I'd see if anyone has come across a solution to this.

So - I have a ton of audio files that I'm sorting into my sample library, all of which include the tempo in the filename prefix (so like 110 Loopname, 135 Breakbeat, whatever). I love being able to drag audio files directly into Reason and have it tempo matched correctly, but none of this audio was bounced out of Reason and, as such, doesn't have any tempo information included.

In the past I've just imported said audio into Reason and bounced it straight out with the correct tempo information applied, but I don't have the time or inclination to do that manually here (I've done it in the past for MUCH smaller batches, but I don't quite hate myself enough to do it here).

Has anyone ever tried adding this tempo information to WAV files outside of Reason? Does anyone know where it would even reside in the file? I can't view it as a standard tag, and I don't really have a clue where to even begin. It's infuriating because I'm sure this could be done via a script or something similar in a manner of seconds as opposed to the days it would take me to do manually!

User avatar
DaveyG
Posts: 2599
Joined: 03 May 2020

14 May 2021

It's not quite what you are asking for but if you install something like the free ADSR Sample Manager and point it at your samples then anything you drag and drop from it will be stretched on the fly to match the BPM in the host DAW, and you can preview it before dragging. I used to use Loopcloud in the same way but they have just (stupidly!) stopped us importing our own samples.

Another idea. I've successfully batch processed audio files in the past with Audacity. You write a macro to do whatever and then you can feed it a long list of files to process. However, I don't know if Audacity can detect BPM.

User avatar
orthodox
RE Developer
Posts: 2286
Joined: 22 Jan 2015
Location: 55°09'24.5"N 37°27'41.4"E

14 May 2021

adfielding wrote:
14 May 2021
Does anyone know where it would even reside in the file?
I've just checked it out, Reason writes the tempo in the "JUNK" RIFF-chunk, section "TEMPOMAP". In case the tempo is constant, it's at the file offset 0x70, stored as big-endian 4-byte integer representing the tempo in 1/1000 BPM (i.e. 135 bpm stored as integer 135000).

The script would have to insert a "JUNK"-chunk with the needed tempo value into a wav file.

User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

14 May 2021

DaveyG wrote:
14 May 2021
It's not quite what you are asking for but if you install something like the free ADSR Sample Manager and point it at your samples then anything you drag and drop from it will be stretched on the fly to match the BPM in the host DAW, and you can preview it before dragging. I used to use Loopcloud in the same way but they have just (stupidly!) stopped us importing our own samples.

Another idea. I've successfully batch processed audio files in the past with Audacity. You write a macro to do whatever and then you can feed it a long list of files to process. However, I don't know if Audacity can detect BPM.
I don't think Audacity has the means with which to embed the necessary information. Those are totally solid ideas, but to be honest there's nothing stopping me from just stretching the audio out once I import it into Reason - I just really like being able to drop stuff straight into Reason and having it all sync'd without any extra input on my part. It's great for workflow.
orthodox wrote:
14 May 2021
adfielding wrote:
14 May 2021
Does anyone know where it would even reside in the file?
I've just checked it out, Reason writes the tempo in the "JUNK" RIFF-chunk, section "TEMPOMAP". In case the tempo is constant, it's at the file offset 0x70, stored as big-endian 4-byte integer representing the tempo in 1/1000 BPM (i.e. 135 bpm stored as integer 135000).
Oh nice, that'll be a great place to start - thanks for checking this out! I'll update if/when I manage to figure something out :)

User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

15 May 2021

GOT IT. I've managed to create a Python script that does what I'm after - if the file contains a tempo value at the start of the filename and doesn't already contain a junk chunk, it creates an updated version with the junk chunk and appropriate tempo. Seems to work in Reason. It's super-duper janky and contains way, WAY too many nested if statements, but the fact that it even works at all is such a relief. This is going to save me a ton of time.

Thanks so much orthodox for providing me with a perfect starting point! I'm thinking I might try and clean it up and make it a little less janky at some point but, damn. What a relief.

User avatar
orthodox
RE Developer
Posts: 2286
Joined: 22 Jan 2015
Location: 55°09'24.5"N 37°27'41.4"E

15 May 2021

adfielding wrote:
15 May 2021
GOT IT. I've managed to create a Python script that does what I'm after - if the file contains a tempo value at the start of the filename and doesn't already contain a junk chunk, it creates an updated version with the junk chunk and appropriate tempo.
Just in case you missed it, do you update the total-size-of-chunks field at 0x04 in the file after the insert?

User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

15 May 2021

orthodox wrote:
15 May 2021
Just in case you missed it, do you update the total-size-of-chunks field at 0x04 in the file after the insert?
Yeah, what I did wasn't particularly elegant - I basically just took the junk chunk from an exported Reason file (minus the final four bytes) and used that as a base, so all my script is doing is inserting that at a particular point along with the necessary tempo value at the end. Right now it's just inserting that data at a pre-determined offset (pre-data chunk), so I'd like to tweak it to find the data chunk and insert it based on actually finding that rather than relying on a pre-determined offset. That said, it's worked without any problems here so far. (edit: on reflection that sounds pointless, I'm not going to bother doing that!)

I've attached the Python 3 script in case anyone fancies a giggle. It is absolutely 100% a bodge job, but it's already saved me an absolute ton of time - just stick the .wav files you want to process (tempo should be at the start of the filename, so like 125 Filename.wav) in the same directory as the script and off you go. If you're brave enough to try it yourself, there are a few caveats.

1. It overwrites the original files. Absolutely don't use this without making a copy of the files first!
2. It only works with .wav files. It could probably be modified to work with .aif files, but I have no inclination to do it myself.
3. It doesn't work with files containing tempo data already. You should get an error if it spots that but, again, make a copy first.
4. I can't guarantee this won't just ruin your files so make a copy and if it doesn't work, hey, you're welcome to fiddle with the script yourself.
5. I've only tested this in Windows, in theory it should work in macOS but make sure you're using Python 3.

I can't stress this enough - I am not a dev, this was only really intended for personal use - but if someone else gets use out of it then that's nice, too.

edit: based on input from orthodox I've updated the script to correctly update the file-size field at the start of the file. Big thanks to orthodox for providing the starting point for this whole exercise!
Attachments
Reason Tempo Embed 210516.zip
(1006 Bytes) Downloaded 57 times
Last edited by adfielding on 16 May 2021, edited 2 times in total.

User avatar
orthodox
RE Developer
Posts: 2286
Joined: 22 Jan 2015
Location: 55°09'24.5"N 37°27'41.4"E

15 May 2021

adfielding wrote:
15 May 2021
I've attached the Python 3 script in case anyone fancies a giggle.
Giggles aside, it does not correct the chunk size field at file offset 4, the size should be increased by 36 (number of bytes inserted). That may be a problem with some application opening it, it can alert or simply chop the tail of audio data.
Unfortunately, I can't write in Python, so I can't fix it.

User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

15 May 2021

orthodox wrote:
15 May 2021
adfielding wrote:
15 May 2021
I've attached the Python 3 script in case anyone fancies a giggle.
Giggles aside, it does not correct the chunk size field at file offset 4, the size should be increased by 36 (number of bytes inserted). That may be a problem with some application opening it, it can alert or simply chop the tail of audio data.
Unfortunately, I can't write in Python, so I can't fix it.
D'OH! I haven't had any issues so far, but I might check back into that and maybe retroactively fix what I've processed already.

Appreciate the help! :)

User avatar
jam-s
Posts: 3084
Joined: 17 Apr 2015
Location: Aachen, Germany
Contact:

15 May 2021

https://docs.python.org/3/library/wave.html in combination with https://docs.python.org/3/library/chunk.html might be of help to dig deeper into the wav files.

Also this script here could be extended to include the junk chunk.
Last edited by jam-s on 15 May 2021, edited 1 time in total.

User avatar
Karim
Competition Winner
Posts: 964
Joined: 16 Jan 2015
Location: Italy
Contact:

15 May 2021

Did you know (and I made a video on my youtube channel that I have to publish) that mp3 files match the tempo on Reason (like ABleton) unlike wav files? I was hoping that someone would unravel this problem anyway. This What is also feasible on Mac? :clap:

adfielding wrote:
15 May 2021
orthodox wrote:
15 May 2021
Just in case you missed it, do you update the total-size-of-chunks field at 0x04 in the file after the insert?
Yeah, what I did wasn't particularly elegant - I basically just took the junk chunk from an exported Reason file (minus the final four bytes) and used that as a base, so all my script is doing is inserting that at a particular point along with the necessary tempo value at the end. Right now it's just inserting that data at a pre-determined offset (pre-data chunk), so I'd like to tweak it to find the data chunk and insert it based on actually finding that rather than relying on a pre-determined offset. That said, it's worked without any problems here so far.

I've attached the Python 3 script in case anyone fancies a giggle. It is absolutely 100% a bodge job, but it's already saved me an absolute ton of time - just stick the .wav files you want to process (tempo should be at the start of the filename, so like 125 Filename.wav) in the same directory as the script and off you go. If you're brave enough to try it yourself, there are a few caveats.

1. It overwrites the original files. Absolutely don't use this without making a copy of the files first!
2. It only works with .wav files. I haven't tried it with .aif files, you're on your own there.
3. It doesn't work with files containing tempo data already. You should get an error if it spots that but, again, make a copy first.
4. I can't guarantee this won't just ruin your files so make a copy and if it doesn't work, hey, you're welcome to fiddle with the script yourself.

I can't stress this enough - I am not a dev, this was only really intended for personal use - but if someone else gets use out of it then that's nice, too.
Karim Le Mec : Dj/Producer/Label Owner ( :reason: 11.3 + R12.x + IMac 2016 21")
FOLLOW Karim Le Mec
https://www.youtube.com/user/lemecdj
https://karimlemec.weebly.com/
https://soundcloud.com/karimlemec
https://t.me/reasonstudiosworld

User avatar
moneykube
Posts: 3473
Joined: 15 Jan 2015

15 May 2021

cool script... could be very useful to me... thank you and yes of course will make copies first :thumbup: :puf_smile:
https://soundcloud.com/moneykube-qube/s ... d-playlist
Proud Member Of The Awesome League Of Perpetuals

User avatar
adfielding
Posts: 959
Joined: 19 May 2015
Contact:

16 May 2021

Right, I've updated the script to also update the chunk size field. Again, not pretty, but it works. Check the earlier post for the updated version. Big thanks again to orthodox for pointing it out! If you were brave enough to use the old script, you might want to restore your original files and run them through this version instead.
jam-s wrote:
15 May 2021
https://docs.python.org/3/library/wave.html in combination with https://docs.python.org/3/library/chunk.html might be of help to dig deeper into the wav files.

Also this script here could be extended to include the junk chunk.
I sort of wish I'd come across this sooner, but it's been a nice learning exercise and I feel like I've learned a little more about the structure of WAV files, which is always nice. Also I hadn't written anything in Python for a while (which is probably incredibly apparent if you look at the script), so it's nice to have an excuse to throw something together :)
Karim wrote:
15 May 2021
Did you know (and I made a video on my youtube channel that I have to publish) that mp3 files match the tempo on Reason (like ABleton) unlike wav files? I was hoping that someone would unravel this problem anyway. This What is also feasible on Mac? :clap:
I didn't know that, that's interesting! I don't think I'm using anything platform specific so I imagine it should work in macOS... but I haven't tested it. Also, I can't remember if macOS comes with Python 2 or 3 as standard nowadays, if you try running it with Python 2 you might be in for a bad time.
moneykube wrote:
15 May 2021
cool script... could be very useful to me... thank you and yes of course will make copies first :thumbup: :puf_smile:
If you do decide to use it let me know how you get on with it, I'm curious to see if it works for anybody else :)

Post Reply
  • Information
  • Who is online

    Users browsing this forum: Bes, Google [Bot] and 12 guests