* morituri/image/table.py:

Add logging.
	  Add methods to clear a table of files, and to absolutize indexes
	  as long as the source is the same file, and to set a File on a
	  given index, adjusting all following indexes that match the
	  duration, and check if the IndexTable has all information for a TOC.
	* morituri/image/toc.py:
	  Add logging.
	  Use a counter for the source.
	  Fix up index offset calculation.
	* morituri/program/cdrdao.py:
	  Use a real IndexTable as the result, instead of a TocFile.
	* morituri/image/cue.py:
	  Use a real IndexTable to store tracks.
	* morituri/test/test_image_toc.py:
	  The toc file now has a table which has the tracks.
	  Fix the tests to adjust for wrong index calculations.
	* morituri/test/test_image_cue.py:
	* morituri/test/test_image_image.py:
	* morituri/image/image.py:
	  The cue file now has a table which has the tracks.
	* morituri/test/test_image_table.py:
	  Add assertions to make sure when the table can serve as a TOC.
	* examples/readdisc.py:
	  Adjust for changes.  Fix up to include AccurateRip results.
	  First time we can do a complete normal rip including verifying
	  against AccurateRip results!
This commit is contained in:
Thomas Vander Stichele
2009-05-05 10:01:41 +00:00
parent a5d70dd317
commit 2f464207db
11 changed files with 403 additions and 109 deletions

View File

@@ -1,3 +1,33 @@
2009-05-05 Thomas Vander Stichele <thomas at apestaart dot org>
* morituri/image/table.py:
Add logging.
Add methods to clear a table of files, and to absolutize indexes
as long as the source is the same file, and to set a File on a
given index, adjusting all following indexes that match the
duration, and check if the IndexTable has all information for a TOC.
* morituri/image/toc.py:
Add logging.
Use a counter for the source.
Fix up index offset calculation.
* morituri/program/cdrdao.py:
Use a real IndexTable as the result, instead of a TocFile.
* morituri/image/cue.py:
Use a real IndexTable to store tracks.
* morituri/test/test_image_toc.py:
The toc file now has a table which has the tracks.
Fix the tests to adjust for wrong index calculations.
* morituri/test/test_image_cue.py:
* morituri/test/test_image_image.py:
* morituri/image/image.py:
The cue file now has a table which has the tracks.
* morituri/test/test_image_table.py:
Add assertions to make sure when the table can serve as a TOC.
* examples/readdisc.py:
Adjust for changes. Fix up to include AccurateRip results.
First time we can do a complete normal rip including verifying
against AccurateRip results!
2009-05-05 Thomas Vander Stichele <thomas at apestaart dot org>
* examples/readdisc.py:

View File

@@ -121,9 +121,11 @@ def main(argv):
if not ptable.object:
t = cdrdao.ReadIndexTableTask()
function(runner, t)
ptable.persist(t.toc)
ptable.persist(t.table)
itable = ptable.object
assert itable.hasTOC()
lastTrackStart = 0
for i, track in enumerate(itable.tracks):
@@ -139,36 +141,16 @@ def main(argv):
if t.checksum:
print 'Checksums match for track %d' % (i + 1)
ittrack = table.ITTrack(i + 1)
# we know the .toc file represents a single wav rip, so all offsets
# are absolute since beginning of disc
# overlay this rip onto the IndexTable
itable.setFile(i + 1, 1, path, ittoc.getTrackLength(i + 1))
# copy over indexes, adjusting the offset
tocTrack = itable.tracks[i]
print itable.tracks
for t in itable.tracks:
print t, t.indexes.values()
# first copy over index 0 if there is any
try:
sector, _ = tocTrack.getIndex(0)
ittrack.index(0, path=path, relative=sector - lastTrackStart)
except KeyError:
pass
lastTrackStart, _ = tocTrack.getIndex(1)
indexes = itable.tracks[i]._indexes
numbers = indexes.keys()
numbers.sort()
if 0 in numbers:
del numbers[0]
for number in numbers:
sector, _ = tocTrack.getIndex(number)
ittrack.index(number, path=path, relative=sector - lastTrackStart)
#itable.tracks.append(ittrack)
# FIXME: this is the part where our IndexTable reader should convert
# a .toc file to a IndexTable we can dump .cue from
print ittoc.cue()
handle = open('morituri.cue', 'w')
handle.write(itable.cue())
handle.close()
# verify using accuraterip
print "CDDB disc id", itable.getCDDBDiscId()
@@ -196,7 +178,55 @@ def main(argv):
responses[0].cddbDiscId
# FIXME: put accuraterip verification into a separate task/function
# and apply here
cueImage = image.Image('morituri.cue')
verifytask = image.ImageVerifyTask(cueImage)
cuetask = image.AccurateRipChecksumTask(cueImage)
function(runner, verifytask)
function(runner, cuetask)
response = None # track which response matches, for all tracks
# loop over tracks
for i, checksum in enumerate(cuetask.checksums):
status = 'rip NOT accurate'
confidence = None
archecksum = None
# match against each response's checksum
for j, r in enumerate(responses):
if "%08x" % checksum == r.checksums[i]:
if not response:
response = r
else:
assert r == response, \
"checksum %s for %d matches wrong response %d, "\
"checksum %s" % (
checksum, i + 1, j + 1, response.checksums[i])
status = 'rip accurate '
archecksum = checksum
confidence = response.confidences[i]
c = "(not found)"
ar = "(not in database)"
if responses:
if not response:
print 'ERROR: none of the responses matched.'
else:
maxConfidence = max(r.confidences[i] for r in responses)
c = "(confidence %3d)" % maxConfidence
if confidence is not None:
if confidence < maxConfidence:
c = "(confidence %3d of %3d)" % (confidence, maxConfidence)
ar = ", AR [%s]" % response.checksums[i]
print "Track %2d: %s %s [%08x]%s" % (
i + 1, status, c, checksum, ar)
main(sys.argv)

View File

@@ -58,12 +58,18 @@ _INDEX_RE = re.compile(r"""
class CueFile(object, log.Loggable):
"""
I represent a .cue file as an object.
@type table: L{table.IndexTable}
@ivar table: the index table.
"""
def __init__(self, path):
self._path = path
self._rems = {}
self._messages = []
self.tracks = []
self.leadout = None
self.table = table.IndexTable()
def parse(self):
state = 'HEADER'
@@ -109,7 +115,7 @@ class CueFile(object, log.Loggable):
self.debug('found track %d', trackNumber)
currentTrack = table.ITTrack(trackNumber)
self.tracks.append(currentTrack)
self.table.tracks.append(currentTrack)
continue
# look for INDEX lines
@@ -145,13 +151,13 @@ class CueFile(object, log.Loggable):
# returns track length in frames, or -1 if can't be determined and
# complete file should be assumed
# FIXME: this assumes a track can only be in one file; is this true ?
i = self.tracks.index(track)
if i == len(self.tracks) - 1:
i = self.table.tracks.index(track)
if i == len(self.table.tracks) - 1:
# last track, so no length known
return -1
thisIndex = track.indexes[1] # FIXME: could be more
nextIndex = self.tracks[i + 1].indexes[1] # FIXME: could be 0
nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0
c = thisIndex.counter
if c is not None and c == nextIndex.counter:

View File

@@ -73,19 +73,19 @@ class Image(object, log.Loggable):
# CD's have a standard lead-in time of 2 seconds;
# checksums that use it should add it there
offset = self.cue.tracks[0].getIndex(1).relative
offset = self.cue.table.tracks[0].getIndex(1).relative
tracks = []
for i in range(len(self.cue.tracks)):
length = self.cue.getTrackLength(self.cue.tracks[i])
for i in range(len(self.cue.table.tracks)):
length = self.cue.getTrackLength(self.cue.table.tracks[i])
if length == -1:
length = verify.lengths[i + 1]
t = table.ITTrack(i + 1, audio=True)
tracks.append(t)
# FIXME: this probably only works for non-compliant .CUE files
# where pregap is put at end of previous file
t.index(1, absolute=offset, path=self.cue.tracks[i].getIndex(1).path,
t.index(1, absolute=offset, path=self.cue.table.tracks[i].getIndex(1).path,
relative=0)
offset += length
@@ -107,15 +107,15 @@ class AccurateRipChecksumTask(task.MultiSeparateTask):
cue = image.cue
self.checksums = []
self.debug('Checksumming %d tracks' % len(cue.tracks))
for trackIndex, track in enumerate(cue.tracks):
self.debug('Checksumming %d tracks' % len(cue.table.tracks))
for trackIndex, track in enumerate(cue.table.tracks):
index = track.indexes[1]
length = cue.getTrackLength(track)
self.debug('track %d has length %d' % (trackIndex + 1, length))
path = image.getRealPath(index.path)
checksumTask = checksum.AccurateRipChecksumTask(path,
trackNumber=trackIndex + 1, trackCount=len(cue.tracks),
trackNumber=trackIndex + 1, trackCount=len(cue.table.tracks),
frameStart=index.relative * checksum.SAMPLES_PER_FRAME,
frameLength=length * checksum.SAMPLES_PER_FRAME)
self.addTask(checksumTask)
@@ -176,7 +176,7 @@ class ImageVerifyTask(task.MultiSeparateTask):
self._tasks = []
self.lengths = {}
for trackIndex, track in enumerate(cue.tracks):
for trackIndex, track in enumerate(cue.table.tracks):
self.debug('verifying track %d', trackIndex + 1)
index = track.indexes[1]
length = cue.getTrackLength(track)

View File

@@ -29,7 +29,9 @@ import struct
import gst
from morituri.common import task, checksum, common
from morituri.common import task, checksum, common, log
from morituri.test import common as tcommon
class DeleteMeTrack:
"""
@@ -249,12 +251,12 @@ class Index:
self.counter = counter
def __repr__(self):
return '<Index %02d, absolute %r, path %r, relative %r>' % (
self.number, self.absolute, self.path, self.relative)
return '<Index %02d, absolute %r, path %r, relative %r, counter %r>' % (
self.number, self.absolute, self.path, self.relative, self.counter)
class IndexTable:
class IndexTable(object, log.Loggable):
"""
I represent the Table of Contents of a CD.
I represent a table of indexes on a CD.
@ivar tracks: tracks on this CD
@type tracks: list of L{ITTrack}
@@ -417,6 +419,140 @@ class IndexTable:
common.framesToMSF(index.relative)))
lines.append("")
return "\n".join(lines)
### methods that modify the table
def clearFiles(self):
"""
Clear all file backings.
Resets indexes paths and relative offsets.
"""
# FIXME: do a loop over track indexes better, with a pythonic
# construct that allows you to do for t, i in ...
t = self.tracks[0].number
index = self.tracks[0].getFirstIndex()
i = index.number
# the first cut is the deepest
counter = index.counter
self.debug('clearing path')
while True:
track = self.tracks[t - 1]
index = track.getIndex(i)
self.debug('Clearing path on track %d, index %d', t, i)
index.path = None
index.relative = None
try:
t, i = self.getNextTrackIndex(t, i)
except IndexError:
break
def setFile(self, track, index, path, length):
"""
Sets the given file as the source from the given index on.
Will loop over all indexes that fall within the given length,
to adjust the path.
Assumes all indexes have an absolute offset and will raise if not.
"""
t = self.tracks[track - 1]
i = t.indexes[index]
start = i.absolute
assert start is not None, "index %r is missing absolute offset" % i
end = start + length
# FIXME: check border conditions here, esp. wrt. toc's off-by-one bug
while i.absolute <= end:
self.debug('Setting path and relative on track %d, index %d',
track, index)
i.path = path
i.relative = i.absolute - start
try:
track, index = self.getNextTrackIndex(track, index)
t = self.tracks[track - 1]
i = t.indexes[index]
except IndexError:
break
def absolutize(self):
"""
Calculate absolute offsets on indexes as much as possible.
Only possible for as long as tracks draw from the same file.
"""
t = self.tracks[0].number
index = self.tracks[0].getFirstIndex()
i = index.number
# the first cut is the deepest
counter = index.counter
self.debug('absolutizing')
while True:
if index.counter is None:
self.debug('Track %d, index %d has no counter', t, i)
break
if index.counter != counter:
self.debug('Track %d, index %d has a different counter', t, i)
break
track = self.tracks[t - 1]
index = track.getIndex(i)
assert track.number == t
assert index.number == i
self.debug('Setting absolute offset %d on track %d, index %d',
index.relative, t, i)
index.absolute = index.relative
try:
t, i = self.getNextTrackIndex(t, i)
except IndexError:
break
### lookups
def getNextTrackIndex(self, track, index):
"""
Return the next track and index.
@param track: track number, 1-based
@raises IndexError: on last index
@rtype: tuple of (int, int)
"""
t = self.tracks[track - 1]
indexes = t.indexes.keys()
position = indexes.index(index)
if position + 1 < len(indexes):
return track, indexes[position + 1]
track += 1
if track > len(self.tracks):
raise IndexError, "No index beyond track %d, index %d" % (
track - 1, index)
t = self.tracks[track - 1]
indexes = t.indexes.keys()
return track, indexes[0]
# various tests for types of IndexTable
def hasTOC(self):
"""
Check if the Index Table has a complete TOC.
a TOC is a list of all tracks and their Index 01, with absolute
offsets, as well as the leadout.
"""
if not self.leadout:
self.debug('no leadout, no TOC')
return False
for t in self.tracks:
if 1 not in t.indexes.keys():
self.debug('no index 1, no TOC')
return False
if t.indexes[1].absolute is None:
self.debug('no absolute index 1, no TOC')
return False
return True

View File

@@ -27,7 +27,8 @@ Reading .toc files
import os
import re
from morituri.common import common
from morituri.common import common, log
from morituri.image import table
# header
_CATALOG_RE = re.compile(r'^CATALOG "(?P<catalog>\d+)"$')
@@ -64,16 +65,17 @@ _INDEX_RE = re.compile(r"""
\s(?P<offset>.+)$ # start offset
""", re.VERBOSE)
class TocFile(object):
class TocFile(object, log.Loggable):
def __init__(self, path):
self._path = path
self._messages = []
self.tracks = []
self.table = table.IndexTable()
def parse(self):
state = 'HEADER'
currentFile = None
currentTrack = None
counter = 0
trackNumber = 0
indexNumber = 0
currentOffset = 0 # running absolute offset of where each track starts
@@ -100,8 +102,8 @@ class TocFile(object):
# handle index 1 of previous track, if any
if currentTrack:
currentTrack.index(1, currentOffset + pregapLength,
currentFile)
currentTrack.index(1, path=currentFile.path,
relative=currentOffset + pregapLength, counter=counter)
trackNumber += 1
currentOffset += currentLength
@@ -109,13 +111,18 @@ class TocFile(object):
indexNumber = 1
trackMode = m.group('mode')
currentTrack = Track(trackNumber)
self.tracks.append(currentTrack)
# FIXME: track mode
currentTrack = table.ITTrack(trackNumber)
self.table.tracks.append(currentTrack)
continue
# look for SILENCE lines
m = _SILENCE_RE.search(line)
if m:
if currentFile is not None:
self.debug('SILENCE after FILE, increasing counter')
counter += 1
currentFile = None
length = m.group('length')
currentLength += common.msfToFrames(length)
@@ -125,6 +132,13 @@ class TocFile(object):
filePath = m.group('name')
start = m.group('start')
length = m.group('length')
self.debug('FILE %s, start %r, length %r',
filePath, common.msfToFrames(start),
common.msfToFrames(length))
if not currentFile or filePath != currentFile.path:
counter += 1
self.debug('track %d, switched to new FILE, increased counter to %d',
trackNumber, counter)
currentFile = File(filePath, start, length)
#currentOffset += common.msfToFrames(start)
currentLength += common.msfToFrames(length)
@@ -138,8 +152,9 @@ class TocFile(object):
continue
length = common.msfToFrames(m.group('length'))
currentTrack.index(0, currentOffset, currentFile)
currentLength += length
currentTrack.index(0, path=currentFile.path,
relative=currentOffset - length, counter=counter)
#currentLength += length
pregapLength = length
# look for INDEX lines
@@ -149,11 +164,13 @@ class TocFile(object):
self.message(number, 'INDEX without preceding TRACK')
indexNumber += 1
offset = common.msfToFrames(m.group('offset'))
currentTrack.index(indexNumber, offset, currentFile)
currentTrack.index(indexNumber, path=currentFile.path,
relative=offset, counter=counter)
# handle index 1 of final track, if any
if currentTrack:
currentTrack.index(1, currentOffset + pregapLength, currentFile)
currentTrack.index(1, path=currentFile.path,
relative=currentOffset + pregapLength, counter=counter)
def message(self, number, message):
"""
@@ -167,16 +184,18 @@ class TocFile(object):
# returns track length in frames, or -1 if can't be determined and
# complete file should be assumed
# FIXME: this assumes a track can only be in one file; is this true ?
i = self.tracks.index(track)
if i == len(self.tracks) - 1:
i = self.table.tracks.index(track)
if i == len(self.table.tracks) - 1:
# last track, so no length known
return -1
thisIndex = track._indexes[1] # FIXME: could be more
nextIndex = self.tracks[i + 1]._indexes[1] # FIXME: could be 0
thisIndex = track.indexes[1] # FIXME: could be more
nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0
if thisIndex[1] == nextIndex[1]: # same file
return nextIndex[0] - thisIndex[0]
c = thisIndex.counter
if c is not None and c == nextIndex.counter:
# they belong to the same source, so their relative delta is length
return nextIndex.relative - thisIndex.relative
# FIXME: more logic
return -1
@@ -218,15 +237,15 @@ class File:
"""
def __init__(self, path, start, length):
self.path = path
self.start = start
self.length = length
#self.start = start
#self.length = length
def __repr__(self):
return '<File "%s">' % (self.path, )
# FIXME: add type ? separate AUDIO from others
class Track:
class DeleteMeTrack:
"""
I represent a track in a cue file.
I have index points.

View File

@@ -69,7 +69,7 @@ class OutputParser(object, log.Loggable):
self._track = None # which track are we analyzing?
self._task = taskk
self.toc = table.IndexTable() # the index table for the TOC
self.table = table.IndexTable() # the index table for the TOC
def read(self, bytes):
self.log('received %d bytes in state %s', len(bytes), self._state)
@@ -95,7 +95,7 @@ class OutputParser(object, log.Loggable):
# we need both a position reported and an Analyzing line
# to have been parsed to report progress
if m and self._track is not None:
track = self.toc.tracks[self._track - 1]
track = self.table.tracks[self._track - 1]
frame = (track.getIndex(1).absolute or 0) \
+ int(m.group('hh')) * 60 * 75 \
+ int(m.group('mm')) * 75 \
@@ -146,7 +146,7 @@ class OutputParser(object, log.Loggable):
self._tracks = int(m.group('track'))
track = table.ITTrack(self._tracks)
track.index(1, absolute=int(m.group('start')))
self.toc.tracks.append(track)
self.table.tracks.append(track)
self.debug('Found track %d', self._tracks)
m = _LEADOUT_RE.search(line)
@@ -155,7 +155,7 @@ class OutputParser(object, log.Loggable):
self._state = 'LEADOUT'
self._frames = int(m.group('start'))
self.debug('Found leadout at offset %r', self._frames)
self.toc.leadout = self._frames
self.table.leadout = self._frames
self.info('%d tracks found', self._tracks)
return
@@ -238,21 +238,21 @@ class ReadIndexTableTask(CDRDAOTask):
"""
I am a task that reads all indexes of a CD.
@ivar toc: the .toc file object
@type toc: L{toc.TOC}
@ivar table: the index table
@type table: L{table.IndexTable}
"""
description = "Scanning indexes..."
table = None
def __init__(self):
CDRDAOTask.__init__(self)
self.parser = OutputParser(self)
self.toc = None # result
(fd, self._toc) = tempfile.mkstemp(suffix='.morituri')
(fd, self._tocfilepath) = tempfile.mkstemp(suffix='.morituri')
os.close(fd)
os.unlink(self._toc)
os.unlink(self._tocfilepath)
self.options = ['read-toc', self._toc]
self.options = ['read-toc', self._tocfilepath]
def readbytes(self, bytes):
self.parser.read(bytes)
@@ -260,13 +260,34 @@ class ReadIndexTableTask(CDRDAOTask):
def done(self):
# FIXME: instead of reading only a TOC, output a complete IndexTable
# by merging the TOC info.
self.toc = toc.TocFile(self._toc)
self.toc.parse()
os.unlink(self._toc)
self._tocfile = toc.TocFile(self._tocfilepath)
self._tocfile.parse()
os.unlink(self._tocfilepath)
self.table = self._tocfile.table
# we know the .toc file represents a single wav rip, so all offsets
# are absolute since beginning of disc
self.table.absolutize()
# we unset relative since there is no real file backing this toc
for t in self.table.tracks:
for i in t.indexes.values():
#i.absolute = i.relative
i.relative = None
# copy the leadout from the parser's table
# FIXME: how do we get the length of the last audio track in the case
# of a data track ?
self.table.leadout = self.parser.table.leadout
# we should have parsed it from the initial output
assert self.table.leadout is not None
class ReadTOCTask(CDRDAOTask):
"""
I am a task that reads the TOC of a CD, without pregaps.
@ivar table: the index table that matches the TOC.
@type table: L{table.IndexTable}
"""
description = "Reading TOC..."
@@ -287,4 +308,6 @@ class ReadTOCTask(CDRDAOTask):
def done(self):
os.unlink(self._toc)
self.table = self.parser.toc
self.table = self.parser.table
assert self.table.hasTOC(), "This Table Index should be a TOC"

View File

@@ -14,13 +14,13 @@ class KingsSingleTestCase(unittest.TestCase):
self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
'kings-single.cue'))
self.cue.parse()
self.assertEquals(len(self.cue.tracks), 11)
self.assertEquals(len(self.cue.table.tracks), 11)
def testGetTrackLength(self):
t = self.cue.tracks[0]
t = self.cue.table.tracks[0]
self.assertEquals(self.cue.getTrackLength(t), 17811)
# last track has unknown length
t = self.cue.tracks[-1]
t = self.cue.table.tracks[-1]
self.assertEquals(self.cue.getTrackLength(t), -1)
class KingsSeparateTestCase(unittest.TestCase):
@@ -28,13 +28,13 @@ class KingsSeparateTestCase(unittest.TestCase):
self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
'kings-separate.cue'))
self.cue.parse()
self.assertEquals(len(self.cue.tracks), 11)
self.assertEquals(len(self.cue.table.tracks), 11)
def testGetTrackLength(self):
# all tracks have unknown length
t = self.cue.tracks[0]
t = self.cue.table.tracks[0]
self.assertEquals(self.cue.getTrackLength(t), -1)
t = self.cue.tracks[-1]
t = self.cue.table.tracks[-1]
self.assertEquals(self.cue.getTrackLength(t), -1)
class KanyeMixedTestCase(unittest.TestCase):
@@ -42,10 +42,10 @@ class KanyeMixedTestCase(unittest.TestCase):
self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
'kanye.cue'))
self.cue.parse()
self.assertEquals(len(self.cue.tracks), 13)
self.assertEquals(len(self.cue.table.tracks), 13)
def testGetTrackLength(self):
t = self.cue.tracks[0]
t = self.cue.table.tracks[0]
self.assertEquals(self.cue.getTrackLength(t), -1)

View File

@@ -61,7 +61,7 @@ class TrackSeparateTestCase(unittest.TestCase):
self.assertEquals(h(checksumtask.checksums[3]), '0x7271db39')
def testLength(self):
tracks = self.image.cue.tracks
tracks = self.image.cue.table.tracks
self.assertEquals(self.image.table.getTrackLength(1), 10)
self.assertEquals(self.image.table.getTrackLength(2), 10)
self.assertEquals(self.image.table.getTrackLength(3), 10)

View File

@@ -30,8 +30,12 @@ class LadyhawkeTestCase(unittest.TestCase):
for i, offset in enumerate(offsets):
t[i].index(1, absolute=offset)
self.failIf(self.table.hasTOC())
self.table.leadout = 210385
self.failUnless(self.table.hasTOC())
def testCDDB(self):
self.assertEquals(self.table.getCDDBDiscId(), "c60af50d")

View File

@@ -11,24 +11,71 @@ class CureTestCase(unittest.TestCase):
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
'cure.toc'))
self.toc.parse()
self.assertEquals(len(self.toc.tracks), 13)
self.assertEquals(len(self.toc.table.tracks), 13)
def testGetTrackLength(self):
t = self.toc.tracks[0]
self.assertEquals(self.toc.getTrackLength(t), -1)
t = self.toc.table.tracks[0]
# first track has known length because the .toc is a single file
self.assertEquals(self.toc.getTrackLength(t), 28324)
# last track has unknown length
t = self.toc.tracks[-1]
t = self.toc.table.tracks[-1]
self.assertEquals(self.toc.getTrackLength(t), -1)
def testIndexes(self):
# track 2, index 0 is at 06:16:45
# FIXME: cdrdao seems to get length of FILE 1 frame too many,
# and START value one frame less
t = self.toc.tracks[1]
(offset, file) = t.getIndex(0)
self.assertEquals(offset, 28245)
(offset, file) = t.getIndex(1)
self.assertEquals(offset, 28324)
t = self.toc.table.tracks[1]
self.assertEquals(t.getIndex(0).relative, 28245)
self.assertEquals(t.getIndex(1).relative, 28324)
def _getIndex(self, t, i):
track = self.toc.table.tracks[t - 1]
return track.getIndex(i)
def _assertAbsolute(self, t, i, value):
index = self._getIndex(t, i)
self.assertEquals(index.absolute, value)
def _assertPath(self, t, i, value):
index = self._getIndex(t, i)
self.assertEquals(index.path, value)
def _assertRelative(self, t, i, value):
index = self._getIndex(t, i)
self.assertEquals(index.relative, value)
def testSetFile(self):
self._assertAbsolute(1, 1, None)
self._assertAbsolute(2, 0, None)
self._assertAbsolute(2, 1, None)
self._assertPath(1, 1, "data.wav")
def dump():
for t in self.toc.table.tracks:
print t
print t.indexes.values()
self.toc.table.absolutize()
self.toc.table.clearFiles()
self._assertAbsolute(1, 1, 0)
self._assertAbsolute(2, 0, 28166)
self._assertAbsolute(2, 1, 28324)
self._assertAbsolute(3, 1, 46110)
self._assertAbsolute(4, 1, 66767)
self._assertPath(1, 1, None)
self._assertRelative(1, 1, None)
# adding a file to the table should fix up to including 2, 0
self.toc.table.setFile(1, 1, 'track01.wav', 28245)
self._assertPath(1, 1, 'track01.wav')
self._assertRelative(1, 1, 0)
self._assertPath(2, 0, 'track01.wav')
self._assertAbsolute(2, 0, 28166)
self._assertPath(2, 1, None)
self._assertRelative(2, 1, None)
# Bloc Party - Silent Alarm has a Hidden Track One Audio
class BlocTestCase(unittest.TestCase):
@@ -36,18 +83,17 @@ class BlocTestCase(unittest.TestCase):
self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
'bloc.toc'))
self.toc.parse()
self.assertEquals(len(self.toc.tracks), 13)
self.assertEquals(len(self.toc.table.tracks), 13)
def testGetTrackLength(self):
t = self.toc.tracks[0]
self.assertEquals(self.toc.getTrackLength(t), -1)
t = self.toc.table.tracks[0]
# first track has known length because the .toc is a single file
self.assertEquals(self.toc.getTrackLength(t), 50089)
# last track has unknown length
t = self.toc.tracks[-1]
t = self.toc.table.tracks[-1]
self.assertEquals(self.toc.getTrackLength(t), -1)
def testIndexes(self):
t = self.toc.tracks[0]
(offset, file) = t.getIndex(0)
self.assertEquals(offset, 0)
(offset, file) = t.getIndex(1)
self.assertEquals(offset, 15220)
t = self.toc.table.tracks[0]
self.assertEquals(t.getIndex(0).relative, 0)
self.assertEquals(t.getIndex(1).relative, 15220)