#!/bin/bash # ==================================================================================== # # License for this script is CC0 # and you as the user assume all responsibility by using it. # # Please read carefully before using. # # ============ # DESCRIPTION: # ============ # # Linux Bash script to take Audacity exported timing file and convert # to a single wav file with drum beats seperated by the # timing in LabelTrack.txt # # The resulting wav file can then be dragged back into Audacity. # # The original version of this script was actually a compiled C pgm. # However after re-reading comments by @Steve and @christop on the # Audacity forum, I realize that compiling and indeed knowing C and having # the tool chain, may be a problem for many. # So here is a Bash only version, the downside is it has some dependencies # and some are version specific due to bugs in them. # This script is also orders of magnitude slower than the compiled C pgm. # I guess that is the price to be paid for convinience ;-) # # Dependencies for this script are Sox, bc and ffmpeg # # Very N.B. The latest version of sox (14.x) has many bugs, # I used v12.18.2 # bc version is 1.07.1 but most will do. # ffmpeg is version 4.1.10 but most newer ones will be OK. # # Note that silence.wav and beat.wav must be mono and originally created by you. # # To change the drum sample, just overwrite the current one # but keep the name the same, i.e. beat.wav or change the script. # Remember, must be mono 16 bit wav. # Must also compensate for it's length when we send to bc. # (Watch out for this or you will get wrong timing placements) # # ================ # NOTES ON USING: # ================ # # Create a folder, I called mine TimingsToBeats (same as this script) # and in there place this script (with exec permissions), and silence.wav # which is just a mono 10 sec clip of silence which this script will # create temp files from with needed durations and then delete the temp files. # It will not delete silence.wav itself. # # Make sure you create a 10 sec silence mono file before running this script. # Easy enough in Audacity, just export as Mono, wav (16 bit) at 44.1KHz # The exported LabelTrack.txt file from Audacity should also be saved in this folder. # # Also ensure you have a short, mono "beat.wav" file in the same folder. # This is the audio clip that this script will insert at the timings in the LabelTrack.txt # # To execute the script, open a command prompt in the folder and type: # ./TimingsToBeats.sh # # If all goes well, you should see a printout for each "time" entry and a # "Conversion Complete" message at the end. # # ========================== # MORE NOTES AND DISCLAIMER: # ========================== # # I wrote this for a specific need I have, i.e. to add extra percussion to existing # audio tracks. # As such, percussion sounds tend to be short (50 - 100 mS in most cases) and also, # and this is important, percussion is mono in a mix (i.e. center). # With that in mind, this script is only meant for mono files, starting with the # LabelTrack.txt file, to the silence and the extra percussion sound to add. # It will not work with ultra long sounds or stereo tracks as is. # # The script is simple enough and well commented so if it does not work for you, # modify it until it does. # # Also, please don't ask for help or send bug reports and expect a reply from me. # I don't mean to come across as rude, but I simply don't have the time to tend to them. # From time to time, I do visit the forum and may comment but don't hold me to it. # You are of course free to discuss, modify and comment amongst yourselves for the # benefit of yourself and others. # # As I mentioned before, this in the Bash version and as such, will not be as quick # or as efficiently coded as it's C version. # # Are there bugs? Probably but it does the job for me so mission accomplished. # Please also be aware that there is no error checking whatsoever, originally # this script (pgm actually) was only for my own use until I was convinced to # publicly release it. ;-) # # Lastly, keep in mind that when used to add percussion sounds to an existing # audio track, there will be drift over time. # This is due to the slight timing differences of the system where the audio track # was created versus the new track. # # For example, let's say you download a song from YT and it should be 120 BPM, # I can guarantee that it's not exactly at that BPM and as the track progresses, # the error will accumulate and drift out of time more and more. # In practice, it's not a big deal to cut and then "nudge" bits of the newly created # track to match up. # # For an average song of say 4 minutes, you will only need to make 15 or so cuts # and "nudges". # A lot less time consuming than manually having to add each new "drum" sound by hand. # Do the math, a four minute song at 120 BPM with 4/4 timing, there will be close to # several hundred drum beats. # Something you don't want to do by hand, and hence the reason for this script. # # There are of course other ways to do something similar but they all have certain disadvantages. # One example is Audacity's "Generate Rhythm Track" but you will be limited by the sounds it adds # and drift will still be a problem. # # Hope it's of some use to others as is or you may find other uses for it. # Paulo-V # ==================================================================================== Input="LabelTrack.txt" Silence="silence.wav" DrumBeat="beat.wav" OutputFileRaw="TheOutput.raw" OutputFile="TheOutput.wav" TempFileRaw="Temp.raw" TempSilence="TempSilence.wav" ThisLine=0 PreviousLine="000.000000" CurrentLine="000.000000" # ====================================================================== # Begin file read loop. # Note that Bash will work out that LabelTrack.txt has 3 columns # # This is the format that Audacity spits out the labels track and I haven't # found a way to change it. # Also make sure that there is no space between Label and Track in the text # file name when you export it. # # Since we only want the middle column, we still assign 3 vars to the read loop # i.e. Ignore, ThisLine, IgnoreThisToo. # but only use ThisLine. # # We should actually only use the first column (which is identical to the second) # but for some reason the Bash read command truncates the first number. # Didn't want to waste time finding out, so just used the second column. # ======================================================================= while read -r Ignore ThisLine IgnoreThisToo do # ======================================================================= # Send to bc to do the maths, subtract length of actual drum beat (50 mS) # and the sed at the end is to add a leading zero else sox complains. # ======================================================================= CurrentLine=$(echo "scale=9;($ThisLine - $PreviousLine - 0.05)" | bc -l | sed 's/^\./0./') # ======================================================================== # The line below is just a visual sanity timings check. # ======================================================================== echo "current ---> "$CurrentLine " this ----> "$ThisLine " previous ---> " $PreviousLine # ========================================================================= # Create temp silence file of duration picked up by timings, # Add that to drum beat and save in output file. # ========================================================================= sox $Silence $TempSilence trim 0 $CurrentLine sox $TempSilence $DrumBeat $OutputFile # ========================================================================== # Now, it will convert that wav to raw pcm so we can just keep appending # without worring about headers. # ffmpeg works better than sox for this. # The -y at the end tells ffmpeg to overwrite any existing files # and the > /dev/null thing surpresses all the cli output garbage. # ========================================================================== ffmpeg -i $OutputFile -f s16le -acodec pcm_s16le $OutputFileRaw -y > /dev/null 2>&1 # =========================================================================== # Do the actual concatinating (appending) with cat. # could have also used dd # dd if="$OutputFileRaw" of="$TempFileRaw" status=none conv=notrunc oflag=append # =========================================================================== cat $OutputFileRaw >> $TempFileRaw PreviousLine=$ThisLine done < "$Input" # ============================================================================ # End of timings file read loop so convert the raw pcm back to wav with ffmpeg # This is now the wav we import back into Audacity or other DAW. # ============================================================================ ffmpeg -f s16le -ar 44.1k -ac 1 -i $TempFileRaw $OutputFile -y > /dev/null 2>&1 # ============================================================================ # Remove temp files. # The wav file to be dragged back into Audacity is called TheOutput.wav # ============================================================================ rm $TempFileRaw rm $OutputFileRaw rm $TempSilence echo "========== Conversion Complete ============="