The problem
I have a whole bunch of audiobooks that I want to listen to in the car. However, they are distributed in longer chunks than I would like -- typically 25 to 50 minutes per mp3 file. I tried out a few mp3 slicers, but they generally didn't work very well. Eventually I decided to use cdrdao directly to cut the two second pause between tracks and standardise on a five minute track length.
This left me with the problem of generating the TOC files cdrdao reads to decide what it is going to burn.
The solution
The following python script takes a list of WAV files in the order they are to be burned and writes as many TOC files as are needed. The code isn't as neat or documented as it should be, but I'm too tired and busy to do that now. Please bug me about it later if it hasn't been fixed...
#!/usr/bin/python import sys import wave files = sys.argv[1:] class CD(object): def __init__(self): self.tracks = [] self.maxLen = 79 * 60 self.trackLen = 5 * 60 def getRemainingSize(self): size = 0 for track in self.tracks: if track['length'] == None: size += self.trackLen else: size += track['length'] return self.maxLen - size def getNextTrackLen(self): return min(self.trackLen, self.getRemainingSize(self)) def addTrack(self, wavfile, start, length=None, end=None): if length == None: length = self.trackLen if self.getRemainingSize() == 0: return None if length > self.getRemainingSize(): length = self.getRemainingSize() if end: tlength = None else: tlength = length self.tracks.append({'file': wavfile, 'start': start, 'length': tlength}) return length def getTOC(self): toc = 'CD_DA\n' for track in self.tracks: trackBlock = '\nTRACK AUDIO\n FILE "' trackBlock += track['file'] + '" ' trackBlock += '%s:%s:0' % (int(track['start']/60), track['start']%60) if track['length'] != None: trackBlock += ' %s:%s:0' % (int(track['length']/60), track['length']%60) toc += trackBlock return toc class CDs(object): def __init__(self): self.cds = [] def addWav(self, wavfile): if len(self.cds) == 0: self.cds.append(CD()) CDRem = self.cds[-1].getRemainingSize() print wavfile wav = wave.open(wavfile) wavPos = 0 wavLen = wav.getnframes()/wav.getframerate() end = None while 1: print wavPos, "of", wavLen if (wavLen - wavPos) < self.cds[-1].trackLen: end = 1 result = self.cds[-1].addTrack(wavfile, wavPos, end=end) if result == None: wavPos = max(0, wavPos-15) self.cds.append(CD()) continue wavPos += result if end: break cdCollection = CDs() for wavfile in files: cdCollection.addWav(wavfile) tocnum = 0 for cd in cdCollection.cds: tocnum += 1 tocfile = open('cd%02d.toc'%(tocnum), 'w') tocfile.write(cd.getTOC()) tocfile.close()