# -*- Mode: Org -*- * Previous Issues ** DONE Fix WAVE/MP3 formats to support MP3 audio in a WAVE container Instead of WaveAudio generating a nasty "compression not supported" error, its is_type() classmethod should return False. And, MP3Audio's is_type() classmethod should check for MP3 compressed RIFF WAVE containers. This isn't likely to mess up decoding, but may confuse ID3 tagging. ** DONE Allow file template to be specified on the command line When making new files with track2track, cd2track, etc. ** DONE Update the website with the latest documentation ** DONE Allow a unified %(album_track_number)s file template field If there's no album number, it's simply 2 digits of track number. Otherwise, it's a combination of the two fields. For example, album_number = 2 and track_number = 13 results in "213" for a value. ** DONE Update trackcat to take a cuesheet argument when outputting FLACs Thus, one can perform: trackcat --cuesheet=file.cue file1.wav file2.wav file3.wav -t flac -o cd.flac which will embed "file.cue" into "cd.flac" using metaflac. Though no other format I'm aware of supports this kind of cuesheet handling, being able to easily build solid disc images of a single FLAC file is much of the reason for trackcat/tracksplit. ** DONE Don't remove undone tracklint entries from its undo DB Since its checksum will change anyway and no longer match, explicitly removing the entry is no longer necessary ** DONE Support FLAC padding If changes to FLAC metadata are small enough, write over the padding (if present) rather than rewrite the whole file - like metaflac. This approach should speed up tagging considerably. ** DONE Fix image support in ID3v2 Very large images can take a very long time to load. ** DONE Fix programs to key on album number and track number Certain programs, such as trackcmp, work on tracks across two directories and key on track number to determine which to compare to which. These need to be updated to use both track number and album number. ** DONE Adjust wave conversions to use album number, if present For example, converting track_number 15 and album_number 2 to WAVE should make a file "track215.cdda.wav" which then properly converts back to track_number 15 and album_number 2 if read. ** DONE Improve XMCD handling Support for XMCD files often breaks down if one or more tracks are missing. In some cases, there's no fix to be had (track2xmcd) but in most instances it should be made to work correctly. ** DONE Perform type inference wherever possible Anything with a single output file (trackcat and record2track) should be able to infer its output type from the track suffix, if possible. ** DONE Add "comment" field support to all metadata types Don't forget to add unit tests for comment field. *** TODO Sort "comment" fields correctly across all metadata types *** TODO Add --comment support to tracktag ** DONE Fix ID3v2 image support to handle Unicode descriptions The current implementation falls down on UTF-16 input, but I should have a solution from the COMM frame handler. ** DONE Limit ID3v2.2/2.3 to UCS-2 encoding The current implementation treats UCS-2 the same as UTF-16. This needs to be fixed so that really high unicode characters (above U+FFFF) are replaced with something within spec. ** DONE Unify ID3v2 frame handling In the beginning, there were text frames and Everything Else. Text frames were unicode strings, and Everything Else was a binary string of whatever. Now that ID3 is cluttered with APIC frames and COMM frames that need special treatment, ID3v2 needs an overhaul to more resemble FlacMetaData. *** DONE Ensure unknown frames are displayed correctly Anything that's not text, images or comments should get some sort of proper display instead of a Python object string. ** DONE Add app testing to the unit test suite Though not everything is unit-testable (such as the CD handling programs or anything X11) a lot of the batch programs are to some degree: - [X] coverdump - [X] track2track - [X] trackcat - [X] trackcmp - [X] tracklength - [X] tracklint - [X] trackrename - [X] tracksplit - [X] tracktag ** DONE Add verbosity levels to programs Every batch program should support a -V --verbose flag with options for "silence","normal" (the default) and "debug". Silence shuts off everything but error messages. Normal is standard output behavior. Debug for additional debugging output. - [X] cd2track - [X] cd2xmcd - [X] coverdump - [X] record2track - [X] track2cd (this will need to forward verbosity to cdrecord) - [X] track2track - [X] track2xmcd - [X] trackcmp - [X] trackrename - [X] tracksplit - [X] tracktag - [X] tracklint ** DONE Add compression percentage display to trackinfo Though not massively useful, it'd be neat to see just how compressed audio tracks are, as a percentage of their original size. ** DONE Add support for W??? frames to ID3v2 The various W??? frames are really just URLs and don't need to be displayed as hex-encoded blobs. ** DONE Add CUE/TOC support to track2cd It should be possible to burn a selection of tracks, or a disc image, from a cuesheet with all its indexes/ISRC/catalog data intact by passing --cue to track2cd. ** DONE Unify CUE/TOC support Cuesheets and cdrdao TOC files are largely interchangeable. They both feature a listing of track offsets and, optionally, CD-TEXT data, ISRCs and so on. These formats should be unified such that any program will handle them both automatically. - [X] tracksplit - [X] trackcat - [X] tracktag *** DONE Update docs to mention CUE/TOC interchangeability - [X] tracksplit - [X] trackcat - [X] tracktag *** DONE Support cuesheet from FlacMetaData directly Since we're parsing CUE/TOC files anyway, this data can be used to build FLAC CUESHEET blocks directly instead of punting this task to metaflac. *** DONE Add unit tests for TOC/CUE files, as well as embedded FLAC cuesheets ** DONE Update copyright text for 2009 ** DONE Preserve metadata when using trackcat Any fields shared by all tracks should be merged into metadata for the newly combined track. ** DONE Don't route data though WAVE files unless necessary Currently, track2track routes through WAVE if both ends happen to support foreign RIFF chunks, whether the files have such chunks or not. This behavior needs to be modified such that only source files which actually have foreign chunks, and a target format that supports them, results in a pass through RIFF WAVE. ** DONE Convert editxmcd to PyGTK Although the dialog(1)-based version works in terminals and is curses-based, it's extremely hokey, error-prone and doesn't support any cut & paste. This needs to be reimplemented in PyGTK (since coverview already uses it) and made into a stable app someone would want to use. *** DONE Update XMCD support The current handling of XMCD files treats them only as very primative AlbumMetaData implementations. This must be updated into something round-trippable if editxmcd is to be modernized. **** DONE Add XMCD unit tests **** DONE Update XMCD API documentation ** DONE Require Python 2.5 Since Python 2.4 is in bugfix-only mode and barely supported, it's best to move the minimum version to Python 2.5 or better (which has already been superceded by Python 2.6). This reduces the amount of Python versions to test on and allows the use of more modern Python features which makes the code less clunky. *** TODO Update documentation to mention Python 2.5 requirement. ** DONE Expand WavPack's APEv2 tag coverage WavPack's official specification defines APEv2 tags such as "Cuesheet" and "Cover Art" which the APEv2 standard does not. It would be helpful to make WavPack's APEv2 tags a superset of regular APEv2. *** DONE Add image support to WavePackAPEv2 *** DONE Add cuesheet support to WavePackAPEv2 ** DONE Build unified cuesheet interface Once both FLAC and WavPack support embedded cuesheets, there will need to be a unified interface to support them. I expect this will be a simple pair of get_cuesheet/set_cuesheet methods, probably attached to the AudioFiles themselves rather than to MetaData objects. *** DONE Alter FLAC-specific cuesheet documentation to be more general *** DONE Ensure cuesheets are transferred properly when transcoding *** DONE Update trackcat to use the interface *** DONE Update tracksplit to use the interface *** DONE Update track2cd to use the interface *** DONE Document cuesheet interface *** DONE Add unit tests for embedded cuesheets across all formats *** DONE Add cuesheet import option to tracktag This can also use the --cue flag, for consistency with other image-handling programs like tracksplit. If given with a single, album-length track, --cue will import a cuesheet. If given with multiple tracks or a single track that's too short, --cue will function like --xmcd and act as a metadata source. *** DONE Update track2xmcd to support getting an XMCD file from CD image ** DONE Convert to Muspack SV8 Now that Musepack SV8 is finalized, it should be the new default. The old SV7 command-line tools aren't well supported and don't seem to work outside of x86 platforms. SV7 streams are, in theory, backwards compatible so switching shouldn't be a problem. ** DONE Update coverview to look more standard It's currently a haphazard assortment of widgets rather than anything like a proper GTK app. It should be tweaked to look better. ** DONE Improve transcoding robustness Just about all of the to_pcm() and from_pcm() methods expect that their subprocess calls will work as expected. Though rare in practice, these need to be checked in case the child processes fail for any reason. *** DONE Check for invalid input/output files/permissions errors If an output file can't be read/written to for some reason (invalid permissions, etc.) generate a proper error message instead of throwing ugly IOExceptions or confusing errors. - [X] cd2track - [X] cd2xmcd - [X] coverdump - [X] editxmcd - [X] record2track - [X] track2cd - [X] track2track - [X] track2xmcd - [X] trackcat - [X] trackcmp - [X] trackinfo - [X] tracklength - [X] tracklint - [X] trackplay - [X] trackrename - [X] tracksplit - [X] tracktag ** DONE Make text output consistent Currently, command-line programs generate output using a selection of scattered print statements - often accompanied by if blocks when verbosity is indicated - and haphazardly filtered through unicode. This should be replaced by a unified message system similar to Python's built-in logging module which can abstract away these difficulties. *** DONE Convert tty output to gettext-based strings This will not only make output messages more consistent across the tools, but will also allow for foreign language translations in the future. - [X] cd2track - [X] cd2xmcd - [X] coverdump - [X] record2track - [X] track2cd - [X] track2track - [X] track2xmcd - [X] trackcat - [X] trackcmp - [X] trackinfo - [X] tracklength - [X] tracklint - [X] trackplay - [X] trackrename - [X] tracksplit - [X] tracktag **** DONE Convert output from audiotools module to gettext-based strings - [X] __aiff__.py - [X] __ape__.py - [X] __au__.py - [X] cue.py - [X] __flac__.py - [X] __freedb__.py - [X] __id3__.py - [X] __id3v1__.py - [X] __image__.py - [X] __init__.py - [X] __m4a__.py - [X] __mp3__.py - [X] __musepack__.py - [X] __speex__.py - [X] toc.py - [X] __vorbiscomment__.py - [X] __vorbis__.py - [X] __wavpack__.py - [X] __wav__.py *** DONE Add unit tests for tty output All programs which generate output should be unit tested so that all code paths are assured of printing the messages they're supposed to print, at the streams they're supposed to print on, and in the proper encoding settings. - [X] coverdump - [X] track2track - [X] track2xmcd - [X] trackcat - [X] trackcmp - [X] trackinfo - [X] tracklength - [X] tracklint - [X] trackrename - [X] tracksplit - [X] tracktag *** DONE Convert --help output to gettext-based strings *** DONE Convert GUI programs to gettext-based strings - [X] coverview - [X] editxmcd *** DONE Convert "Usage" output to gettext-based strings ** DONE Update tracksplit's man page It now supports more of track2track's options ** DONE Support total tracks/total albums metadata fields *** DONE Add support for fields in the metadata tags - [X] Add support in Vorbis Comments - [X] Add support in ID3v2 - [X] Add support in M4A - [X] Add support in APEv2 *** DONE Add support in utilities - [X] Add support in tracktag - [X] Add support in cd2track - [X] Add support in tracksplit - [X] Add support in trackcat *** DONE Add unit tests *** DONE Add fields to --format output *** DONE Update man pages with fields information ** DONE Integrate better MetaData merging There's a few areas in which MetaData from multiple sources must be merged in an intelligent manner, such as where tracksplit takes a source track an XMCD file. Now that a preliminary MetaData.merge() classmethod is in place, this process must be integrated consistently. - [X] track2track - [X] trackrename - [X] tracksplit - [X] tracktag *** DONE Add unit tests for MetaData merging process - [X] track2track - [X] trackrename - [X] tracksplit - [X] tracktag ** DONE Improve M4A metadata handling *** DONE Make M4A metadata updating less destructive Like FLAC, not all fields need to be wiped out when overwriting old metadata with new. *** DONE Add more M4A-specific unit tests ** DONE Add more system information to audiotools-config All BIN-referenced binaries should be accounted for. Thumbnailing status and requirements should be shown. ** DONE Add cdinfo utility Analagous to trackinfo, but for an inserted CD. This would be a better location for cd2xmcd's "-i" option. *** DONE Add cdinfo man page *** DONE Link cdinfo man page to other utility man pages ** DONE Add manual page for audiotools.cfg It'll be easier to check what the options are from a man page rather than having to check the website or PDF doc. ** DONE Convert vorbiscomment dependency to Python This would remove the last app-based MetaData-setting utility and may pave the way for adding cover art to Ogg Vorbis (assuming I can find the standard for a secondary stream of image data) ** DONE Add metadata deletion capability It would be helpful to have the low-level capability of deleting either part of a MetaData tag or the entire tag altogether. For example, deleting the "track_name" field would delete a Vorbis comment's "TITLE" field. Or, deleting the MetaData from MP3 would remove all the ID3v2/ID3v1 tags. *** DONE Add delattr to ID3v1 ** DONE Integrate pyconstruct as a submodule ** DONE Add undo capability to editxmcd ** DONE Add --cue option to track2xmcd One should be able to pull metadata from CD images without having to embed the cuesheet. *** DONE Add unit tests for track2xmcd's --cue option *** DONE Update man page ** DONE Group --help output more intelligently For tools with a large number of options (such as track2track or tracktag) the --help output is particularly jumbled. Use more of optparse's features to make this output clearer. - [X] cd2track - [X] cd2xmcd - [X] track2track - [X] track2xmcd - [X] tracksplit - [X] tracktag ** DONE Check for FLAC metadata chunk overflow Although APEv2 and ID3 tags support very large objects (hundreds of MB), FLAC metadata chunks have a maxmimum of about 16MB per chunk, which may be hit accidentally. ** DONE Fix or replace Python's built-in aifc module The current implementation suffers from bugs. *** DONE Document AIFF better ** DONE Add MusicBrainz support It would be helpful to have external metadata support beyond FreeDB, since FreeDB is very primitive. *** DONE Ensure that MusicBrainz is interchangeable with FreeDB/XMCD **** DONE Unify track2xmcd/track2mb, cd2xmcd/cd2mb Based on preliminary testing, MusicBrainz's output is better than FreeDB's but its album coverage is not as broad. In addition, nobody wants to run their albums through two separate tools in order to extract metadata for tagging. The best solution is for tools to try both and output the one that's most complete. **** DONE Extend editxmcd to MusicBrainz XML Although editxmcd was originally designed specifically for XMCD files and MusicBrainz's XML format differs radically, no one should have to know whether an album metadata file is one or the other. Therefore, editxmcd should be extended with additional fields to handle XML backend data if necessary. **** DONE Handle multiple Release entries with single Disc ID **** DONE Allow MusicBrainz XML output for new editxmcd files FreeDB output should also be an option, however. *** DONE Add MusicBrainz protocol/format documentation *** DONE Add MusicBrainz-specific unit tests - [X] track2track - [X] track2xmcd - [X] trackrename - [X] tracksplit - [X] tracktag *** DONE Update --help text to indicate MusicBrainz compatibility - [X] cd2xmcd - [X] editxmcd - [X] track2track - [X] track2xmcd - [X] trackrename - [X] tracksplit - [X] tracktag *** DONE Update man pages to indiciate MusicBrainz compatibility - [X] cd2xmcd - [X] editxmcd - [X] track2track - [X] track2xmcd - [X] trackrename - [X] tracksplit - [X] tracktag *** DONE Update documentation with MusicBrainz config file fields *** DONE Ensure missing XML fields are handled correctly The MusicBrainz XML spec allows most fields to be missing altogether (such as
- [X] alac.tex
- [X] dvda2.tex
- [X] flac.tex
- [X] shorten.tex
- [X] wavpack.tex
*** DONE Double-check codecs for consistency
- [X] alac.tex
- [X] dvda2.tex
- [X] flac.tex
- [X] shorten.tex
- [X] wavpack.tex
*** DONE Add hyperref linking
If one's browsing the PDF,
one should be able to click on operations directly
and go to a specific part of the doc.
- [X] alac.tex
- [X] dvda2.tex
- [X] flac.tex
- [X] shorten.tex
- [X] wavpack.tex
** DONE Tweak track labeling interactive mode for better usability
make return key move to the next line
** DONE Combine and simplify DVD-A decoding and documentation
The current routine bounces back and forth between Python and C
several times in order to generate output, overcomplicating the design.
I'd prefer to have a simpler, low-level, random-access reader hooked directly
to the DVDATrack object - analagous to audiotools.cdda.CDDA.
** DONE Overhaul decoding/encoding documentation
It needs to be cleaned up so one can better follow the entire
decoding process, as well as the entire encoding process.
Use a mix of pseudocode, bit diagrams, bit parsing diagrams
and examples so that it can be followed with as little effort as possible.
*** DONE FLAC
**** DONE decoding
**** DONE encoding
*** DONE ALAC
**** DONE decoding
**** DONE encoding
*** DONE WavPack
**** DONE decoding
**** DONE encoding
*** DONE Shorten
**** DONE decoding
**** DONE encoding
*** DONE DVD-A
**** DONE decoding
* DONE Finish version 2.18
** DONE Ensure audiotools works on FreeBSD
the unprotection module, in particular, needs additional testing
** DONE Ensure excessive zero residuals don't overflow output buffers
Certain formats provide "escape code" blocks of zeroes.
Ensure these routines don't generate more zeroes than are allowed
(either accidentally or deliberately).
*** DONE ALACDecoder
*** DONE WavPackDecoder
** DONE Cleaup documentation layout
Add subdirectories for format figures.
** DONE Spellcheck reference docs
- [X] introduction.tex
- [X] basics.tex
- [X] wav.tex
- [X] aiff.tex
- [X] au.tex
- [X] shorten.tex
- [X] flac.tex
- [X] wavpack.tex
- [X] ape.tex
- [X] mp3.tex
- [X] m4a.tex
- [X] alac.tex
- [X] vorbis.tex
- [X] oggflac.tex
- [X] speex.tex
- [X] musepack.tex
- [X] dvda2.tex
- [X] freedb.tex
- [X] musicbrainz.tex
- [X] replaygain.tex
** DONE Make ReplayGain a configurable option
Even tag-based ReplayGain should be something
users can turn on or off globally via audiotools-config
*** DONE add audiotools-config option
**** DONE document in audiotools-config man page
*** DONE update tools to use option
- [X] cdtrack
- [X] dvda2track
- [X] track2track
- [X] tracksplit
** DONE Add progress to track2cd audio file conversion
- [X] CD quality, embedded cuesheet
- [X] non-CD quality, embedded cuesheet
- [X] CD quality, external cuesheet
- [X] non-CD quality, external cuesheet
- [X] CD quality, multiple files
- [X] non-CD quality, multiple files
** DONE Improve .wav performance
don't read entire data chunk by default
** DONE Integrate MusicBrainz/FreeDB lookup with cd2track/dvda2track
The two step extraction process is a relic from when I'd do
batch lookups via modem.
Combining metadata querying with extraction lets me perform more
powerful lookups than are possible by using XMCD/XML file intermediaries.
However, CD lookups may be still be wrong.
Therefore, it's essential to have a simple, interactive
track metadata editor so that this data is very easy to populate.
*** DONE Add multi-track interactive editing mode to tracktag
**** DONE Update man page
*** DONE Build unified metadata selection widget for interactive modes
This is something that can be run while a disc is being extracted
or a track is being split which will drop the user back
into a progress indicator once completed and then
tag/rename the resulting tracks.
*** DONE Add MusicBrainz/FreeDB lookup options to audiotools-config
It should be possible to decide whether to query either or both
as a config option.
*** DONE Query MusicBrainz for album_number/album_total info
Given a particular disc ID, there must be some way to pull
the disc's album_number/album_total off MusicBrainz's servers
if it's one of a series of discs.
*** DONE Add pre-extraction metadata lookup to tracksplit
**** DONE Update man page
*** DONE Add pre-extraction metadata lookup to cd2track
**** DONE Update man page with new options
*** DONE Add pre-extraction metadata lookup to dvda2track
**** DONE Update man page with new options
*** DONE Update cdinfo to use new ID calculation routines
Ensure they handle the FreeDB test disc properly.
*** DONE Add pre-play metadata lookup to cdplay
**** DONE Update man page
*** DONE Add album-number/album-total options to tracksplit
Allow these values to be populated at split-time
if none can be found in metadata services
**** DONE Update man page
*** DONE Update album-number/album-total options in cd2track
*** DONE Remove xmcd-specific options
Automatic CD lookup should be folded into utilites as needed.
- [X] cd2track
- [X] cdplay
- [X] dvda2track
- [X] track2track
- [X] trackrename
- [X] tracksplit
- [X] tracktag
*** DONE Remove xmcd-specific tools
- [X] cd2xmcd
- [X] dvda2xmcd
- [X] editxmcd
- [X] track2xmcd
*** DONE Update unit tests
- [X] cd2track
- [X] dvda2track
- [X] tracksplit
*** DONE Deprecate xmcd-specific modules
Since metadata lookup handles files internally,
there's no need for metadata file handling classes/functions
at the Python level.
**** DONE Update documentation to indicate deprecation
** DONE Adjust album_number/track_number heuristics
these should be last-resort fields that apply
*only* if a track has no metadata of any kind
** DONE Don't port cuesheets with AudioFile.set_metadata()
This is mostly for WavPack since it embeds cuesheet data
in the APEv2 tag.
- [X] FlacAudio
- [X] OggFlacAudio
- [X] WavPackAudio
** DONE Ensure overly-long files are handled correctly
That is, anything larger than a .wav can typically handle
*** DONE wave should fail with error
*** DONE aiff should fail with error
*** DONE au should fail with error
*** DONE flac should work
*** DONE ogg flac should work
*** DONE wavpack should work
*** DONE alac should work
*** DONE shorten shouldn't begin
requires verbatim wave or aiff chunks
which can't be created because
the amount of PCM data is too large
** DONE Fix FLAC embedded cuesheets
** DONE Ensure files are PEP8-compliant
*** DONE check user-level scripts
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] record2track
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
- [X] setup.py
*** DONE check audiotools module
- [X] __aiff__.py
- [X] __ape__.py
- [X] __au__.py
- [X] __dvda__.py
- [X] __flac__.py
- [X] __freedb__.py
- [X] __id3__.py
- [X] __id3v1__.py
- [X] __image__.py
- [X] __init__.py
- [X] __m4a__.py
- [X] __m4a_atoms__.py
- [X] __mp3__.py
- [X] __musepack__.py
- [X] __musicbrainz__.py
- [X] __ogg__.py
- [X] __shn__.py
- [X] __vorbis__.py
- [X] __vorbiscomment__.py
- [X] __wav__.py
- [X] __wavpack__.py
- [X] cue.py
- [X] delta.py
- [X] freedb.py
- [X] musicbrainz.py
- [X] player.py
- [X] toc.py
- [X] ui.py
*** DONE check audiotools.py_decoders module
- [X] __init__.py
- [X] alac.py
- [X] flac.py
- [X] shn.py
- [X] wavpack.py
*** DONE check audiotools.py_encoders module
- [X] __init__.py
- [X] alac.py
- [X] flac.py
- [X] shn.py
- [X] wavpack.py
*** DONE check test
- [X] test.py
- [X] test_core.py
- [X] test_formats.py
- [X] test_metadata.py
- [X] test_streams.py
- [X] test_utils.py
** DONE Double-check reference docs one last time
*** DONE Ensure pages break correctly in letter mode
*** DONE Ensure pages break correctly in A4 mode
** DONE Fix FLAC seektable generation
Ensure new seektables are aligned properly.
*** DONE Ensure proper seektable written on from_pcm
*** DONE Add .offsets() method to FlacDecoder
Instead of decoding the file, this walks through it
and returns a list of absolute file offsets of all frames.
*** DONE Add method to generate Flac_SEEKTABLE from offset list
*** DONE Add tracklint check/fix for mis-aligned seektables
*** DONE Add unit tests for seektable errors
- [X] empty seekpoints
- [X] mis-ordered seekpoints
- [X] bad seekpoint destinations
** DONE Shift lint to the AudioFile and MetaData subclasses
Instead of having tracklint have to perform lots of built-in tests,
it would be better to have clean() functions added to the classes
themselves.
For MetaData, it could return a new object with fixed fields.
For AudioFile, it could function like convert() and build a new file
with fixes applied.
*** DONE Add clean() method to MetaData and subclasses
**** DONE MetaData
**** DONE ApeTag
**** DONE WavPackAPEv2
**** DONE FlacMetaData
**** DONE ID3v22Comment
**** DONE ID3v23Comment
**** DONE ID3v24Comment
**** DONE ID3v1Comment
**** DONE ID3CommentPair
**** DONE M4AMetaData
**** DONE VorbisComment
***** DONE FlacVorbisComment
***** DONE UnframedVorbisComment
*** DONE Add clean() method to AudioFile and subclasses
I expect a lot of these will do nothing in the short term.
**** DONE AudioFile
**** DONE AiffAudio
- [X] Reorder streams in which the COMM chunk doesn't come before data
- [X] remove duplicate COMM chunks
- [X] remove duplicate SSND chunks
***** DONE add unit test for verify()
- [X] multiple COMM chunks found
- [X] multiple SSND chunks found
- [X] SSND chunk before COMM chunk
***** DONE add unit test for clean()
- [X] multiple COMM chunks found
- [X] multiple SSND chunks found
- [X] SSND chunk before COMM chunk
**** DONE FlacAudio
**** DONE WaveAudio
- [X] reorder streams in which the fmt chunk doesn't come before data
- [X] remove duplicate fmt chunks
- [X] remove duplicate data chunks
***** DONE add unit test for verify()
- [X] multiple fmt chunks found
- [X] multiple data chunks found
- [X] data chunk before fmt chunk
***** DONE add unit test for clean()
- [X] multiple fmt chunks found
- [X] multiple data chunks found
- [X] data chunk before fmt chunk
*** DONE Document MetaData clean() method
*** DONE Document AudioFile clean() method
*** DONE Add more comprehensive unit tests for clean() methods
*** DONE Convert tracklint to use clean() methods
** DONE Ensure individual unit tests pass
*** DONE Lib
- [X] core
- [X] cuesheet
- [X] freedb
- [X] image
- [X] musicbrainz
- [X] pcm
- [X] bitstream
- [X] replaygain
- [X] resample
- [X] tocfile
- [X] verify
- [X] player
*** DONE Format
- [X] audiofile
- [X] lossless
- [X] lossy
- [X] aiff
- [X] alac
- [X] au
- [X] dvda
- [X] flac
- [X] m4a
- [X] mp2
- [X] mp3
- [X] oggflac
- [X] shorten
- [X] sines
- [X] vorbis
- [X] wave
- [X] wavpack
*** DONE Metadata
- [X] metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] m4a
*** DONE Util
- [X] audiotools_config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] record2track
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Ensure complete unit test passes
this includes some compound tests
which may not be covered by individual tests
** DONE Cleanup bitstream module
This is at the heart of a lot of things so it should be properly cleaned up.
*** DONE Merge bitstream_r and bitstream_w source files
*** DONE Make BitstreamReader and BitstreamWriter more symmetric
*** DONE Add placeholders to BitstreamWriter
These allow one to put temporary values in the stream
which can be automatically filled-in later on.
**** DONE Add write_placeholder method to BitstreamWriter
**** DONE Add fill_placeholder method to BitstreamWriter
**** DONE Add write_64_placeholder method to BitstreamWriter
**** DONE Add fill_64_placeholder method to BitstreamWriter
**** DONE Implement bw_write_placeholder_f
**** DONE Implement bw_write_64_placeholder_f
**** DONE Implement bw_fill_placeholder_f
**** DONE Implement bw_fill_64_placeholder_f
**** DONE Implement bw_write_placeholder_r
**** DONE Implement bw_write_64_placeholder_r
**** DONE Implement bw_fill_placeholder_r
**** DONE Implement bw_fill_64_placeholder_r
**** DONE Implement bw_write_placeholder_a
Should manage the placeholder stack, but only keep track of bits sent
**** DONE Implement bw_write_64_placeholder_a
Should manage the placeholder stack, but only keep track of bits sent
**** DONE Implement bw_fill_placeholder_a
Should manage the placeholder stack, but not do anything else
**** DONE Implement bw_fill_64_placeholder_a
Should manage the placeholder stack, but not do anything else
**** DONE Store filled placeholders in a stack for reuse
**** DONE Clean out allocated placeholders as close() time
***** DONE Trigger warnings if not all placeholders are used at close()
*** DONE Add C-based unit tests
This should be something I can compile into a standalone file
and run with no external dependencies.
The idea is to build something valgrind-able to ensure
there's no memory errors.
**** DONE BitstreamReader
***** DONE big-endian
- [X] read
- [X] read_signed
- [X] read_64
- [X] skip
- [X] skip_bytes
- [X] unread
- [X] read_unary
- [X] read_limited_unary
- [X] read_huffman_code
- [X] byte_align
- [X] read_bytes
- [X] set_endianness
- [X] mark
- [X] unmark
- [X] rewind
***** DONE little-endian
- [X] read
- [X] read_signed
- [X] read_64
- [X] skip
- [X] skip_bytes
- [X] unread
- [X] read_unary
- [X] read_limited_unary
- [X] read_huffman_code
- [X] byte_align
- [X] read_bytes
- [X] set_endianness
- [X] mark
- [X] unmark
- [X] rewind
***** DONE br_try/etry
- [X] read
- [X] read_signed
- [X] read_64
- [X] skip
- [X] skip_bytes
- [X] read_unary
- [X] read_limited_unary
- [X] read_huffman_code
- [X] read_bytes
- [X] substream_append
***** DONE Callbacks
- [X] read
- [X] read_signed
- [X] read_64
- [X] skip
- [X] skip_bytes
- [X] read_unary
- [X] read_limited_unary
- [X] read_huffman_code
- [X] read_bytes
**** DONE Substream BitstreamReader
**** DONE BitstreamWriter
***** DONE big-endian
***** DONE little-endian
***** DONE callbacks
**** DONE BitstreamRecorder
**** DONE BitstreamAccumulator
*** DONE Shift BitstreamReader/BitstreamWriters to audiotools.bitstream
*** DONE Add documentation for audiotools.bitstream
**** DONE BitstreamReader
- [X] add_callback
- [X] byte_align
- [X] call_callbacks
- [X] close
- [X] limited_unary
- [X] mark
- [X] parse
- [X] pop_callback
- [X] read
- [X] read64
- [X] read_bytes
- [X] read_huffman_code
- [X] read_signed
- [X] read_signed64
- [X] rewind
- [X] set_endianness
- [X] skip
- [X] skip_bytes
- [X] substream
- [X] substream_append
- [X] unary
- [X] unmark
- [X] unread
**** DONE BitstreamWriter
- [X] add_callback
- [X] build
- [X] byte_align
- [X] call_callbacks
- [X] close
- [X] flush
- [X] pop_callback
- [X] set_endianness
- [X] unary
- [X] write
- [X] write64
- [X] write_bytes
- [X] write_signed
- [X] write_signed64
**** DONE BitstreamRecorder
- [X] add_callback
- [X] bits
- [X] build
- [X] byte_align
- [X] bytes
- [X] call_callbacks
- [X] close
- [X] copy
- [X] data
- [X] flush
- [X] pop_callback
- [X] reset
- [X] set_endianness
- [X] split
- [X] swap
- [X] unary
- [X] write
- [X] write64
- [X] write_bytes
- [X] write_signed
- [X] write_signed64
**** DONE BitstreamAccumulator
- [X] bits
- [X] build
- [X] byte_align
- [X] bytes
- [X] close
- [X] reset
- [X] set_endianness
- [X] unary
- [X] write
- [X] write64
- [X] write_bytes
- [X] write_signed
- [X] write_signed64
**** DONE HuffmanTree
**** DONE Substream
**** DONE format_size
*** DONE Handle bitstream closing more consistently
The basic handle cycle is:
h = open_handle(substream); /*allocates space for handle*/
h->method(h); /*performs reads/writes on handle*/
...
h->close(h); /*closes substream and deallocates handle*/
But we also need two additional methods
for working with the handle and its substream seperately.
| method | substream | handle |
|-------------------+----------------+-------------|
| close() | flushed/closed | deallocated |
| close_substream() | flushed/closed | nothing |
| free() | nothing | deallocated |
|-------------------+----------------+-------------|
This is especially important for the Python wrappers
in which closing and dealloacting will come from different routines.
**** DONE Add functions to bitstream core
***** DONE BitstreamReader
- [X] br_close_substream_f
- [X] br_close_substream_s
- [X] br_close_substream_p
- [X] br_close_methods
- [X] br_free_f
- [X] br_free_s
- [X] br_free_p
- [X] br_close
- [X] br_read_bits_c
- [X] br_read_bits64_c
- [X] br_skip_bits_c
- [X] br_unread_c
- [X] br_read_unary_c
- [X] br_read_limited_unary_c
- [X] br_read_huffman_code_c
- [X] br_read_bytes_c
- [X] br_set_endianness_c
- [X] br_close_substream_c
- [X] br_mark_c
- [X] br_rewind_c
- [X] br_unmark_c
- [X] br_substream_append_c
***** DONE BitstreamWriter
- [X] bw_close_substream_f
- [X] bw_close_substream_r
- [X] bw_close_substream_p
- [X] bw_close_substream_a
- [X] bw_close_methods
- [X] bw_free_f_a
- [X] bw_free_r
- [X] bw_free_p
- [X] bw_close
- [X] bw_write_bits_c
- [X] bw_write_bits64_c
- [X] bw_write_bytes_c
- [X] bw_write_signed_bits_c
- [X] bw_write_signed_bits64_c
- [X] bw_write_unary_c
- [X] bw_set_endianness_c
- [X] bw_close_substream_c
- [X] bw_byte_align_c
***** DONE Ensure bw_rec_split detects closed stream(s) properly
Call bw_abort if one attempts to split from or to a closed stream.
***** DONE Ensure bw_dump_bytes detects closed stream properly
Call bw_abort if one attempts to dump bytes to a closed stream.
***** DONE Ensure bw_rec_copy detects closed stream properly
Call bw_abort if one attempts to copy records to a closed stream.
**** DONE Update mod_bitstream.c to use new hooks properly
***** DONE Add bw_try/bw_etry wrappers around write methods
- [X] BitstreamWriter_write
- [X] BitstreamWriter_write_signed
- [X] BitstreamWriter_write64
- [X] BitstreamWriter_write_signed64
- [X] BitstreamWriter_unary
- [X] BitstreamWriter_byte_align
- [X] BitstreamWriter_write_bytes
- [X] BitstreamWriter_flush
- [X] BitstreamRecorder_write
- [X] BitstreamRecorder_write_signed
- [X] BitstreamRecorder_write64
- [X] BitstreamRecorder_write_signed64
- [X] BitstreamRecorder_unary
- [X] BitstreamRecorder_byte_align
- [X] BitstreamRecorder_write_bytes
- [X] BitstreamRecorder_copy
- [X] BitstreamRecorder_split
- [X] bitstream_build
- [X] BitstreamAccumulator_write
- [X] BitstreamAccumulator_write_signed
- [X] BitstreamAccumulator_write64
- [X] BitstreamAccumulator_write_signed64
- [X] BitstreamAccumulator_unary
- [X] BitstreamAccumulator_byte_align
- [X] BitstreamAccumulator_write_bytes
***** DONE Ensure close() method calls bs->close_substream()
- [X] BitstreamWriter
- [X] BitstreamRecorder
- [X] BitstreamAccumulator
***** DONE Ensure dealloc method calls bs->free()
- [X] BitstreamWriter
- [X] BitstreamRecorder
- [X] BitstreamAccumulator
***** DONE Don't fclose() file objects from underneath Python file objects
Although we may convert a Python file object to a FILE struct,
we must not fclose that struct out from underneath its parent.
****** DONE BitstreamReader_close
- [X] call .close() method on Python file object
- [X] set read methods to raise errors
- [X] return result of .close() method
****** DONE BitstreamWriter_close
- [X] flush pending output
- [X] call .close() method on Python file object
- [X] set write methods to raise errors
- [X] return result of .close() method
****** DONE BitstreamRecorder_close
****** DONE BitstreamAccumulator_close
**** DONE Double-check existing C modules for proper free/close usage
- [X] bitstream.c
- [X] decoders/alac.c
- [X] decoders/flac.c
- [X] decoders/mlp.c
- [X] decoders/ogg.c
- [X] decoders/shn.c
- [X] decoders/wavpack.c
- [X] encoders/alac.c
- [X] encoders/flac.c
- [X] encoders/flac_lpc.c
- [X] encoders/shn.c
- [X] encoders/wavpack.c
- [X] mod_bitstream.c
- [X] verify/mpeg.c
- [X] verify/ogg.c
*** DONE Ensure that reading/writing closed streams always fails
Once a stream's been closed,
the bitstream should set I/O functions to error generators
and further closes should do nothing.
**** DONE Add unit test to bitstream.c
**** DONE Add unit test to Python side
** DONE Add update_metadata() method to AudioFile
Consider how AudioFile.set_metadata() handles six different cases:
Case 1: adjusting a file's own textual metadata (tracktag)
>>> m = flac1.get_metadata()
>>> m.track_name = u"Fixed Name"
>>> flac1.set_metadata(m)
Case 2: transferring metadata from the same audio type (track2track)
>>> flac1.set_metadata(flac2.get_metadata())
Case 3: transferring metadata from a different audio type (track2track)
>>> flac1.set_metadata(mp3.get_metadata())
Case 4: adjusting a file's own low-level metadata (tracklint)
>>> m = flac1.get_metadata()
>>> m.streaminfo.md5sum = fixed_md5sum
>>> flac1.set_metadata(m)
Case 5: building new metadata from scratch (cd2track)
>>> flac1 = FlacAudio.from_pcm(pcm_reader)
>>> flac1.set_metadata(MetaData(track_name=u"New Name", ...))
Case 6: transferring adjusted metadata from the same audio type
>>> m = flac2.get_metadata()
>>> m.track_name = u"Adjusted Name"
>>> flac1.set_metadata(m)
What happens to stuff like the STREAMINFO block
which contains track length, md5sum, etc.
and is part of FLAC's metadata?
If set_metadata() works naively and doesn't override any values,
case 2 breaks since flac1 suddenly has flac2's track length.
If set_metadata() overrides new metadata with stuff from the current file,
case 4 breaks since the fixed_md5sum gets overridden.
Counting on set_metadata() being smart enough to know what you mean
is a losing proposition for FLAC, M4A and other metadata formats
with embedded non-textual (side) metadata.
One solution is to add a low-level AudioFile.update_metadata() method
which takes only the AudioFile's required metadata type
and leaves side data as-is. So case 1 becomes:
>>> m = flac1.get_metadata()
>>> m.track_name = u"Fixed Name"
>>> flac1.update_metadata(m)
and case 4 becomes:
>>> m = flac1.get_metadata()
>>> m.streaminfo.md5sum = fixed_md5sum
>>> flac1.update_metadata(m)
while the other cases remain unchanged.
*** DONE Add update_metadata() method to AudioFile and subclasses
for formats which take metadata at all
- [X] ALACAudio
- [X] AiffAudio
- [X] AudioFile
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] VorbisAudio
- [X] WavPackAudio
*** DONE Update clean() method to use update_metadata()
for formats which implement clean() at all
- [X] ALACAudio
- [X] AiffAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] VorbisAudio
- [X] WavPackAudio
*** DONE Add update_metadata() to tracktag
when not using -r/--replace option
*** DONE Document new set_metadata() behavior
*** DONE Document update_metadata() method
*** DONE Add unit tests for update_metadata()
- [X] ALACAudio
- [X] AiffAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] VorbisAudio
- [X] WavPackAudio
** DONE Ensure Python API docs are updated if necessary
- [X] audiotools.rst
- [X] audiotools_bitstream.rst
- [X] audiotools_cdio.rst
- [X] audiotools_cue.rst
- [X] audiotools_pcm.rst
- [X] audiotools_player.rst
- [X] audiotools_replaygain.rst
- [X] audiotools_resample.rst
- [X] audiotools_toc.rst
- [X] index.rst
- [X] metadata.rst
** DONE Spellcheck Python API docs
- [X] audiotools.rst
- [X] audiotools_bitstream.rst
- [X] audiotools_cdio.rst
- [X] audiotools_cue.rst
- [X] audiotools_pcm.rst
- [X] audiotools_player.rst
- [X] audiotools_replaygain.rst
- [X] audiotools_resample.rst
- [X] audiotools_toc.rst
- [X] index.rst
- [X] metadata.rst
** DONE Eliminate all compiler warnings
- [X] check Ubuntu
- [X] check Fedora
- [X] check Mac OS X
** DONE Reduce load from progress updating routines
Send fewer progress updates from child to parent
when performing progress-based tasks.
This is harder than it sounds.
In an ideal world, I'd have the parent poll its children
on a regular basis and update the progress bars
and/or start more children.
In practice, this doesn't work with subprocesses and shared memory
because shared memory accumulators don't free themselves correctly
when working with more than one child process.
It works even less well with threading because subprocess.Popen
isn't thread-safe and will certainly deadlock if called often enough.
So although the current system is clunky and inefficient
at least it works.
** DONE Ensure all Python modules have up-to-date docstrings
- [X] __aiff__.py
- [X] __ape__.py
- [X] __au__.py
- [X] __dvda__.py
- [X] __flac__.py
- [X] __id3__.py
- [X] __id3v1__.py
- [X] __image__.py
- [X] __init__.py
- [X] __m4a__.py
- [X] __m4a_atoms__.py
- [X] __mp3__.py
- [X] __ogg__.py
- [X] __shn__.py
- [X] __vorbis__.py
- [X] __vorbiscomment__.py
- [X] __wav__.py
- [X] __wavpack__.py
- [X] cue.py
- [X] delta.py
- [X] freedb.py
- [X] musicbrainz.py
- [X] player.py
- [X] toc.py
- [X] ui.py
** DONE Ensure MANIFEST.in is complete
** DONE Update apptest.sh
It's not much of a test, but it's good to keep it around
as a last-resort check of things people normally run.
** DONE Run final batch of unit tests on different platforms
- [X] check Ubuntu
- [X] check Fedora
- [X] check Mac OS X
* DONE Finish version 2.19
** DONE Update PCMReader.read() to take a PCM frame count instead of bytes
Taking a byte count as an argument is a relic from the days
when most conversion happened through external programs.
It's time to update this function to work on PCM frames instead
which is much more natural fit and makes many calculations much easier.
*** DONE Update __init__.py
- [X] PCMReader.read
- [X] PCMReaderError.read
- [X] PCMReaderProgress.read
- [X] ReorderedPCMReader.read
- [X] transfer_framelist_data
- [X] threaded_transfer_framelist_data
- [X] pcm_cmp
- [X] pcm_frame_cmp
- [X] PCMCat.read
- [X] __buffer__.__init__
- [X] __buffer__.__len__
- [X] BufferedPCMReader.read
- [X] BufferedPCMReader.__fill__
- [X] LimitedPCMReader.read
- [X] pcm_split
- [X] PCMConverter.read
- [X] ReplayGainReader.read
- [X] calculate_replay_gain
- [X] AudioFile.verify
- [X] PCMReaderWindow.read
- [X] CDTrackReader.read
- [X] CDTrackReaderAccurateRipCRC.read
*** DONE Update __aiff__.py
- [X] AiffReader.read
- [X] AiffAudio.from_pcm
*** DONE Update __au__.py
- [X] AuReader.read
- [X] AuReader.from_pcm
*** DONE Update __flac__.py
- [X] FlacAudio.__eq__
- [X] FLAC_Data_Chunk.write
- [X] FLAC_SSND_Chunk.write
*** DONE Update __shn__.py
- [X] ShortenAudio.to_wave
- [X] ShortenAudio.to_aiff
*** DONE Update __wav__.py
- [X] WaveReader.read
- [X] WaveAudio.from_pcm
- [X] WaveAudio.add_replay_gain
*** DONE Update __wavpack__.py
- [X] WavPackAudio.to_wave
*** DONE Update py_decoders/alac.py
- [X] ALACDecoder.read
*** DONE Update py_decoders/flac.py
- [X] FlacDecoder.read
*** DONE Update py_decoders/shn.py
- [X] SHNDecoder.read
*** DONE Update py_decoders/wavpack.py
- [X] WavPackDecoder.read
*** DONE Update py_encoders/alac.py
- [X] encode_mdat
*** DONE Update py_encoders/flac.py
- [X] encode_flac
*** DONE Update py_encoders/shn.py
- [X] encode_shn
*** DONE Update py_encoders/wavpack.py
- [X] encode_wavpack
*** DONE Update src/pcmconv.c
- [X] pcmreader_read
- [X] pcmreader_read (alt version)
*** DONE Update src/replaygain.c
- [X] ReplayGainReader_read
*** DONE Update src/decoders/sine.c
- [X] Sine_Mono_read
- [X] Sine_Stereo_read
- [X] Sine_Simple_read
*** DONE Update test/test.py
- [X] BLANK_PCM_Reader
- [X] RANDOM_PCM_Reader
- [X] EXACT_BLANK_PCM_Reader
- [X] EXACT_SILENCE_PCM_Reader
- [X] EXACT_RANDOM_PCM_Reader
- [X] MD5_Reader
- [X] Variable_Reader
- [X] Join_Reader
- [X] MiniFrameReader
*** DONE Update test/test_core.py
- [X] BufferedPCMReader.test_pcm
- [X] LimitedPCMReader.test_read
- [X] PCMReaderWindow.__test_reader__
- [X] PCM_Reader_Multiplexer.read
- [X] TestMultiChannel.__test_assignment__
*** DONE Update test/test_formats.py
- [X] ERROR_PCM_Reader.read
- [X] ALACFileTest.__test_reader__
- [X] ALACFileTest.__test_reader_nonalac__
- [X] ALACFileTest.test_streams
- [X] FlacFileTest.test_streams
- [X] FlacFileTest.__test_reader__
- [X] ShortenFileTest.test_streams
- [X] ShortenFileTest.__test_reader__
- [X] WavPackFileTest.__test_reader__
*** DONE Update test/test_streams.py
- [X] FrameListReader.read
- [X] MD5Reader.read
- [X] Sine8_Mono.read
- [X] Sine8_Stereo.read
- [X] Simple_Sine.read
- [X] WastedBPS16.read
*** DONE Ensure all unit tests pass
**** DONE [Lib]
- [X] core
- [X] cuesheet
- [X] freedb
- [X] image
- [X] musicbrainz
- [X] pcm
- [X] bitstream
- [X] replaygain
- [X] resample
- [X] tocfile
- [X] verify
- [X] player
**** DONE [Format]
- [X] audiofile
- [X] lossless
- [X] lossy
- [X] aiff
- [X] alac
- [X] au
- [X] dvda
- [X] flac
- [X] m4a
- [X] mp2
- [X] mp3
- [X] oggflac
- [X] shorten
- [X] sines
- [X] vorbis
- [X] wave
- [X] wavpack
**** DONE [Metadata]
- [X] metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] m4a
**** DONE [Util]
- [X] audiotools_config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Update reference documentation
** DONE Remove the big pile of imports from various modules
Only import the stuff we need, when we need it.
*** DONE __init__.py
*** DONE accuraterip.py
*** DONE aiff.py
*** DONE ape.py
*** DONE au.py
*** DONE dvda.py
*** DONE flac.py
*** DONE id3.py
*** DONE id3v1.py
*** DONE image.py
*** DONE m4a.py
*** DONE m4a_atoms.py
*** DONE mp3.py
*** DONE ogg.py
*** DONE shn.py
*** DONE vorbis.py
*** DONE vorbiscomment.py
*** DONE wav.py
*** DONE wavpack.py
*** DONE cue.py
*** DONE delta.py
*** DONE freedb.py
*** DONE musicbrainz.py
*** DONE player.py
*** DONE toc.py
*** DONE ui.py
*** DONE ensure unit tests pass
**** DONE [Lib]
- [X] core
- [X] cuesheet
- [X] freedb
- [X] image
- [X] musicbrainz
- [X] pcm
- [X] bitstream
- [X] replaygain
- [X] resample
- [X] tocfile
- [X] verify
- [X] player
**** DONE [Format]
- [X] audiofile
- [X] lossless
- [X] lossy
- [X] aiff
- [X] alac
- [X] au
- [X] dvda
- [X] flac
- [X] m4a
- [X] mp2
- [X] mp3
- [X] oggflac
- [X] shorten
- [X] sines
- [X] vorbis
- [X] wave
- [X] wavpack
**** DONE [Metadata]
- [X] metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] m4a
**** DONE [Util]
- [X] audiotools_config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Integrate Filename object into utilities
This object should replace the Messenger.filename classmethod.
It automatically performs filename -> unicode conversion
and, when files are on disk, compares for equality by device/inode.
*** DONE Update utilities
**** DONE audiotools-config
**** DONE cd2track
**** DONE coverdump
**** DONE coverview
**** DONE dvda2track
**** DONE dvdainfo
**** DONE track2cd
**** DONE track2track
**** DONE trackcat
**** DONE trackcmp
**** DONE trackinfo
**** DONE tracklint
**** DONE trackrename
**** DONE tracksplit
**** DONE tracktag
**** DONE trackverify
*** DONE Add documentation for Filename
*** DONE Add unit tests for Filename
*** DONE Remove Messenger.filename classmethod
**** DONE remove mention in documentation
*** DONE Ensure all unit tests pass
** DONE Sanity check tool inputs/outputs
*** DONE Ensure input files are included only once
- [X] track2cd - generate warning
- [X] track2track - generate error
- [X] trackcat - generate warning
- [X] trackcmp - short-circuit same file comparison
- [X] tracklength - generate warning
- [X] tracklint - generate error
- [X] trackrename - generate error
- [X] tracktag - generate error
- [X] trackverify - skip duplicates
**** DONE Unit test new behavior
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] tracklint
- [X] trackrename
- [X] tracktag
- [X] trackverify
*** DONE Ensure input file(s) are different from output file(s)
Overwriting files is okay by default (in the Unix tradition)
but input and output as same file is not and should generate error.
- [X] coverdump
- [X] track2track
- [X] trackcat
- [X] tracksplit
**** DONE Unit test new behavior
- [X] coverdump
- [X] track2track
- [X] trackcat
- [X] tracksplit
*** DONE Ensure same file isn't written twice by the same utility
This would typically be the result of a misused "--format" argument.
- [X] cd2track
- [X] dvda2track
- [X] track2track
- [X] trackrename
- [X] tracksplit
**** DONE unit test new behavior
- [X] cd2track
- [X] track2track
- [X] trackrename
- [X] tracksplit
** DONE Ensure progress display doesn't overload terminal with rows
As more cores become commonplace, it's important not to
overload the screen with too many progress rows
in case the number of simultaneous jobs
exceeds the number of terminal rows.
** DONE Improve metadata tagging widget
I'm not convinced the current opened/closed bottom window
is the ideal design for editing extended album/track metadata.
Something more similar to a spreadsheet would be ideal
but that's complicated by the serious lack of space
in terminal windows.
** DONE Fix ReplayGain to work on files with different sample rates
This should handle a wider array of cases than it does now.
*** DONE Update can_add_replay_gain classmethod
It should take a list of tracks and return True
if ReplayGain can be added to them, False if not
which takes the place of applicable_replay_gain
- [X] AudioFile.can_add_replay_gain
- [X] FlacAudio.can_add_replay_gain
- [X] M4AAudio_faac.can_add_replay_gain
- [X] MP3Audio.can_add_replay_gain
- [X] VorbisAudio.can_add_replay_gain
- [X] WaveAudio.can_add_replay_gain
- [X] WavPackAudio.can_add_replay_gain
**** DONE update reference documentation
**** DONE update unit tests
- [X] test_formats.py AudioFileTest.test_replay_gain
- [X] test_utils.py track2track.test_options
- [X] test_utils.py tracktag.test_options
*** DONE Add supports_replay_gain() classmethod
Returns True if the class supports ReplayGain of any kind.
- [X] AudioFile
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
**** DONE Add documentation
*** DONE Remove audiotools.applicable_replay_gain function
this functionality is shifted to can_add_replay_gain
**** DONE remove from utilities
- [X] dvda2track
- [X] track2track
- [X] tracksplit
**** DONE update reference documentation
**** DONE update unit tests
*** DONE Update calculate_replay_gain function
**** DONE tracks with unsupported sample rates should be resampled
according to the nearest supported sample rate available
**** DONE tracks with different sample rates should be resampled
according to the most common sample rate available
**** DONE tracks with more than two channels should be culled
remove any channels above the first two during calculation
**** DONE update unit tests
- [X] test_core.py TestReplayGain.test_basics
*** DONE Update add_replay_gain classmethods as needed
- [X] AudioFile.add_replay_gain
- [X] FlacAudio.add_replay_gain
- [X] M4AAudio_faac.add_replay_gain
- [X] MP3Audio.add_replay_gain
- [X] VorbisAudio.add_replay_gain
- [X] WaveAudio.add_replay_gain
- [X] WavPackAudio.add_replay_gain
*** DONE Update utilities to use new ReplayGain application procedure
Given a list of tracks for a given album,
if all are the same format and can_add_replay_gain returns True,
queue a call to add_replay_gain on those tracks.
**** DONE audiotools-config
**** DONE cd2track
**** DONE dvda2track
**** DONE track2track
**** DONE tracksplit
**** DONE tracktag
** DONE Display X/Y progress during operations
When a track is finished transcoding, for instance, output:
[ 2 / 15 ] input.wav -> output.mp3
or something similar.
*** DONE Update utilities
- [X] cd2track
- [X] dvda2track
- [X] track2track
- [X] trackcmp
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Update unit tests
- [X] cd2track
- [X] dvda2track
- [X] track2track
- [X] trackcmp
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Update metadata documentation with examples
*** DONE FLAC
*** DONE MP3
- [X] ID3v1/ID3v1.1
- [X] ID3v2.2
- [X] ID3v2.3
- [X] ID3v2.4
*** DONE APEv2
*** DONE M4A
** DONE Remove Construct module
Convert all usage of Construct to BitstreamReader/BitstreamWriter.
Since this is unlikely to be updated for Python 3,
removing it should smooth that inevitable transition.
*** DONE __accuraterip__.py
*** DONE __aiff__.py
- [X] chunks
- [X] get_metadata
- [X] set_metadata
- [X] delete_metadata
- [X] to_pcm
- [X] from_pcm
- [X] pcm_split
- [X] aiff_from_chunks
**** DONE AiffReader
- [X] __init__
- [X] read
*** DONE __ape__.py
*** DONE __au__.py
*** DONE cue.py
*** DONE __dvda__.py
**** DONE DVDAudio
- [X] __titlesets__
- [X] __titles__
**** DONE DVDATitle
- [X] __parse_info__
*** DONE __flac__.py
*** DONE __freedb__.py
*** DONE __id3__.py
*** DONE __id3v1__.py
*** DONE __image__.py
- [X] __JPEG__
- [X] __PNG__
- [X] __GIF__
- [X] __BMP__
- [X] __TIFF__
**** DONE check these against PIL's output
**** DONE check against truncated images
*** DONE __init__.py
*** DONE __m4a__.py
**** DONE M4ATaggedAudio
- [X] get_metadata
- [X] set_metadata
- [X] delete_metadata
**** DONE M4A_META_Atom
- [X] __init__
- [X] __repr__
- [X] parse
- [X] __getattr__
- [X] __setattr__
- [X] __delattr__
- [X] images
- [X] add_image
- [X] delete_image
- [X] converted
- [X] __comment_name__
- [X] supports_images
- [X] __by_pair__
- [X] __comment_pairs__
- [X] clean
**** DONE M4AAudio_faac
- [X] __init__
- [X] is_type
**** DONE ALACAudio
- [X] __init__
- [X] is_type
- [X] to_pcm
- [X] from_pcm
- [X] __ftyp_atom__
- [X] __moov_atom__
- [X] __free_atom__
*** DONE __m4a_atoms__.py
Re-implement atom parsing/building without Construct
**** DONE ftyp
**** DONE moov
***** DONE mvhd
***** DONE trak
****** DONE tkhd
****** DONE mdia
******* DONE mdhd
******* DONE hdlr
******* DONE minf
******** DONE smhd
******** DONE dinf
********* DONE dref
******** DONE stbl
********* DONE stsd
********** DONE alac
********* DONE stts
********* DONE stsc
********* DONE stsz
********* DONE stco
***** DONE udta
****** DONE meta
**** DONE free
**** DONE Rename __m4a_atoms2__.py to __m4a_atoms__.py
*** DONE __mp3__.py
**** DONE MP3
- [X] __init__
- [X] is_type
- [X] __find_next_mp3_frame__
- [X] __find_mp3_start__
- [X] __find_last_mp3_frame__
- [X] verify
**** DONE MP2
- [X] is_type
*** DONE __musepack__.py
*** DONE __musicbrainz__.py
*** DONE __ogg__.py
*** DONE player.py
*** DONE __shn__.py
*** DONE toc.py
*** DONE __vorbis__.py
**** DONE VorbisAudio
- [X] __read_metadata__
- [X] total_frames
- [X] get_metadata
- [X] set_metadata
**** DONE Remove cruft
- [X] OggStreamReader
- [X] OggStreamWriter
*** DONE __vorbiscomment__.py
*** DONE __wav__.py
*** DONE __wavpack__.py
*** DONE test/test_core.py
**** DONE TestFrameList
- [X] test_8bit_roundtrip
- [X] test_16bit_roundtrip
- [X] test_24bit_roundtrip
*** DONE test/test_formats.py
**** DONE ALACFileTest
- [X] test_blocksizes
**** DONE FlacFileTest
- [X] test_blocksizes
**** DONE ShortenFileTest
- [X] test_blocksizes
**** DONE WavpackFileTest
- [X] test_blocksizes
** DONE Replace gettext with string constants
Transforming _(u"some text") to SOME_TEXT
where SOME_TEXT is a predefined unicode string
in an audiotools sub-module.
This makes text more consistent *and* easier to modify.
*** DONE Update utilities
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Update modules
- [X] __init__.py
- [X] aiff.py
- [X] ape.py
- [X] au.py
- [X] cue.py
- [X] dvda.py
- [X] flac.py
- [X] image.py
- [X] m4a.py
- [X] m4a_atoms.py
- [X] mp3.py
- [X] ogg.py
- [X] toc.py
- [X] ui.py
- [X] vorbis.py
- [X] vorbiscomment.py
- [X] wav.py
- [X] wavpack.py
*** DONE Remove gettext
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
- [X] audiotools/__init__.py
- [X] audiotools/aiff.py
- [X] audiotools/ape.py
- [X] audiotools/au.py
- [X] audiotools/cue.py
- [X] audiotools/flac.py
- [X] audiotools/id3.py
- [X] audiotools/image.py
- [X] audiotools/m4a.py
- [X] audiotools/mp3.py
- [X] audiotools/toc.py
- [X] audiotools/vorbis.py
- [X] audiotools/wav.py
- [X] audiotools/wavpack.py
*** DONE Update unit tests
- [X] test_formats.py
- [X] test_metadata.py
- [X] test_utils.py
*** DONE Reduce big import chunks
Convert "from audiotools.text import (CONSTANT, ...)"
to "import audiotools.text as t" and "t.CONSTANT"
to avoid having huge import blocks at the start of utilities.
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Ensure unit tests pass
** DONE Update C-based ReplayGainReader
Use a lot of the new C-based facilities to make it simpler.
** DONE Fix --number=0 argument to tracktag
I'd like to make track_number=0 a valid value
and have track_number=None indicate a missing field.
The problem is maintaining consistency between
metadata formats that store track numbers as text (like ID3v2)
and those that store track numbers as integers (like M4A).
- [X] MetaData
- [X] ApeTag
- [X] FlacMetaData
- [X] ID3CommentPair
- [X] ID3v1Comment
- [X] ID3v22Comment
- [X] ID3v23Comment
- [X] ID3v24Comment
- [X] M4A_META_Atom
- [X] VorbisComment
*** DONE Update utilities
*** DONE Update documentation
*** DONE Update unit tests
**** DONE Add getitem/setitem/getattr/setattr/delattr tests to metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] m4a
** DONE Remove Python Imaging Library requirement
This is only used for thumbnailing
and for TKinter-based image display.
Since a Python3 version doesn't seem to be pending,
it would be better to remove the requirement.
*** DONE Remove thumbnail functions from audiotools.image
- [X] can_thumbnail
- [X] thumbnail_formats
- [X] thumbnail_image
*** DONE Remove thumbnail method from audiotools.Image
*** DONE Remove thumbnail config options
- [X] audiotools.THUMBNAIL_FORMAT
- [X] audiotools.THUMBNAIL_SIZE
*** DONE Update utilities
- [X] audiotools-config
- [X] track2track
- [X] tracktag
*** DONE Update utility man pages
- [X] audiotools-config
- [X] track2track
- [X] tracktag
*** DONE Update programming documentation
*** DONE Update unit tests
** DONE Update cuesheet interface to handle non-CD sheets
Though rare, non-CD audio is sometimes combined
with cuesheets and should be handled properly
in those instances.
*** DONE Add sample_rate field to cuesheet pcm_lengths() method
- [X] Cuesheet.pcm_lengths
- [X] Flac_CUESHEET.pcm_lengths
- [X] TOCFile.pcm_lengths
**** DONE Update documentation
**** DONE Update unit tests
*** DONE Remove sheet_to_unicode function
*** DONE Update utilities to use sample_rate field with pcm_lengths
- [X] trackinfo
- [X] tracksplit
- [X] tracktag
*** DONE Ensure unit tests pass
** DONE Add faster and more accurate audio type identifier
Instead of checking open files on a format-by-format basis
to determine its type via looping, it's more effecient
to check for all possible file types from the same stream simultaneously
via a sort of finite automata.
*** DONE Add file_type function
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio - without ID3v2 tag
- [X] M4AAudio
- [X] MP2Audio - without ID3v2 tag
- [X] MP3Audio - without ID3v2 tag
- [X] OggFlacAudio
- [X] ShortenAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
- [X] FlacAudio - with ID3v2 tag
- [X] MP2Audio - with ID3v2 tag
- [X] MP3Audio - with ID3v2 tag
*** DONE Update functions which use is_type method to use file_type function
- [X] trackverify
- [X] audiotools.open
*** DONE Remove is_type method from AudioFile classes
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] ShortenAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Update programming documentation
*** DONE Update unit tests
- [X] test_formats.py
** DONE Update utilities to handle broken track_name template fields
- [X] cd2track
- [X] dvda2track
- [X] track2track
- [X] trackrename
- [X] tracksplit
*** DONE Add unit tests for broken track_name template fields
** DONE Split off tracktag's functionality
*** DONE Move the image options into a specialized tool (covertag?)
Its interactive mode should use PyGTK/Tkinter
since it's helpful to see the images one is selecting to add/remove.
- [X] --remove-images
- [X] --front-cover
- [X] --back-cover
- [X] --leaflet
- [X] --media
- [X] --other-image
- [X] -T, --thumbnail
*** DONE Move CD options into a specialized tool
Something for tagging a group of tracks as if they're an entire CD
- [X] --cue
- [X] -l, --lookup
- [X] --musicbrainz-server
- [X] --musicbrainz-port
- [X] --no-musicbrainz
- [X] --freedb-server
- [X] --freedb-port
- [X] --no-freedb
** DONE Add interative mode to audiotools-config
This is one instance where seeing all the options "up-front"
is likely to make the process easier.
** DONE Add Python-based file decoders
These would be low-performance, Python-based PCMReader-style objects
demonstrating how the decoding process works in a relatively simple
manner through the use of the BitstreamReader objects.
They would also provide reference implementations.
*** DONE py_decoders/FlacDecoder
*** DONE py_decoders/SHNDecoder
*** DONE py_decoders/ALACDecoder
*** DONE py_decoders/WavPackDecoder
** DONE Update .convert() method to use fewer temporary files
.wav and .aiff containers with embedded chunks
currently route data through actual .wav/.aiff files
in order to pass those chunks to another format.
It would be better to avoid creating an intermediate
file whenever possible.
*** DONE Update wav containers to use new interface
WaveContainer.has_foreign_wav_chunks()
returns True if the instance has chunks to convert
WaveContainer.header_footer()
returns (header, footer) binary strings
WaveContainer.from_wave(header, pcmreader, footer)
returns new instance built from heaeder, PCM data and footer
Once interface is in place, .convert() can pass header/footer
and wrap progress monitor around pcmreader in order to avoid
temporary wav files.
**** DONE Update FlacAudio
- [X] has_foreign_wave_chunks()
- [X] wave_header_footer()
- [X] from_wave(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update OggFlacAudio
- [X] has_foreign_wave_chunks()
- [X] wave_header_footer()
- [X] from_wave(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update ShortenAudio
- [X] has_foreign_wave_chunks()
- [X] wave_header_footer()
- [X] from_wave(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update WavPackAudio
- [X] has_foreign_wave_chunks()
- [X] wave_header_footer()
- [X] from_wave(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update WaveAudio
- [X] has_foreign_wave_chunks()
- [X] wave_header_footer()
- [X] from_wave(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update programming documentation
**** DONE Update unit tests
*** DONE Update aiff containers to use new interface
AiffContainer.has_foreign_aiff_chunks()
returns True if the instance has chunks to convert
AiffContainer.header_footer()
returns (header, footer) binary strings
AiffContainer.from_aiff(header, pcmreader, footer)
returns new instance built from heaeder, PCM data and footer
Once interface is in place, .convert() can pass header/footer
and wrap progress monitor around pcmreader in order to avoid
temporary aiff files.
**** DONE Update AiffAudio
- [X] has_foreign_aiff_chunks()
- [X] aiff_header_footer()
- [X] from_aiff(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update FlacAudio
- [X] has_foreign_aiff_chunks()
- [X] aiff_header_footer()
- [X] from_aiff(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update OggFlacAudio
- [X] has_foreign_aiff_chunks()
- [X] aiff_header_footer()
- [X] from_aiff(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update ShortenAudio
- [X] has_foreign_aiff_chunks()
- [X] aiff_header_footer()
- [X] from_aiff(filename, header, pcmreader, footer, compression)
- [X] convert(target_page, target_class, compression, progress)
**** DONE Update programming documentation
**** DONE Update unit tests
** DONE Add pause()/resume() methods to low-level output players
This will hopefully make pausing more responsive
and work better than simply emptying the output buffer.
** DONE Ensure unicode command-line arguments are parsed properly
*** DONE cd2track
- [X] --format
- [X] --dir
*** DONE coverdump
- [X] filename arguments
- [X] --dir
- [X] --prefix
*** DONE covertag
- [X] filename arguments
- [X] --front-cover
- [X] --back-cover
- [X] --leaflet
- [X] --media
- [X] --other-image
*** DONE track2track
- [X] filename arguments
- [X] --dir
- [X] --format
- [X] --output
*** DONE trackcat
- [X] filename arguments
- [X] --output
- [X] --cue
*** DONE trackcmp
- [X] filename arguments
*** DONE trackinfo
- [X] filename arguments
*** DONE tracklength
- [X] filename arguments
*** DONE tracklint
- [X] filename arguments
- [X] --db
*** DONE trackrename
- [X] filename arguments
- [X] --format
*** DONE tracksplit
- [X] filename arguments
- [X] --cue
- [X] --dir
- [X] --format
*** DONE tracktag
- [X] filename arguments
- [X] --name
- [X] --artist
- [X] --album
- [X] --performer
- [X] --composer
- [X] --conductor
- [X] --catalog
- [X] --ISRC
- [X] --publisher
- [X] --media-type
- [X] --year
- [X] --date
- [X] --copyright
- [X] --comment
- [X] --comment-file
** DONE Add unit tests for Python-based decoders
Since Python-based codecs are so much slower
it's impossible to make these as comprehensive as the C-based tests.
So we'll only be able to test the basics using very small streams
against the output of the C-based decoders.
*** DONE FlacDecoder
*** DONE ALACDecoder
*** DONE WavPackDecoder
*** DONE SHNDecoder
** DONE Add unit tests for Python-based encoders
*** DONE encode_flac
*** DONE encode_mdat
*** DONE encode_wavpack
*** DONE encode_shn
** DONE Ensure Python files are PEP8-compliant
*** DONE executables
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE libraries
- [X] __init__.py
- [X] accuraterip.py
- [X] aiff.py
- [X] ape.py
- [X] au.py
- [X] cue.py
- [X] delta.py
- [X] dvda.py
- [X] flac.py
- [X] freedb.py
- [X] id3.py
- [X] id3v1.py
- [X] image.py
- [X] m4a.py
- [X] m4a_atoms.py
- [X] mp3.py
- [X] musicbrainz.py
- [X] ogg.py
- [X] opus.py
- [X] player.py
- [X] shn.py
- [X] text.py
- [X] toc.py
- [X] ui.py
- [X] vorbis.py
- [X] vorbiscomment.py
- [X] wav.py
- [X] wavpack.py
**** DONE py_decoders
- [X] __init__.py
- [X] alac.py
- [X] flac.py
- [X] shn.py
- [X] wavpack.py
**** DONE py_encoders
- [X] __init__.py
- [X] alac.py
- [X] flac.py
- [X] shn.py
- [X] wavpack.py
** DONE Have interactive modes clear screen after finishing
Some systems leave the Urwid-built screens half-cleared
before resuming regular output.
It's preferable to erase the whole thing in that case.
- [X] audiotools-config
- [X] cd2track
- [X] cdplay
- [X] dvda2track
- [X] track2track
- [X] trackcat
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
** DONE Have interactive modes detect termios.error at launch
This seems to be caused mostly by opening interactive modes
with arguments piped from xargs
- [X] audiotools-config
- [X] cd2track
- [X] cdplay
- [X] dvda2track
- [X] track2track
- [X] trackcat
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
** DONE Spellcheck programming documentation
- [X] audiotools.rst
- [X] audiotools_bitstream.rst
- [X] audiotools_cdio.rst
- [X] audiotools_cue.rst
- [X] audiotools_pcm.rst
- [X] audiotools_pcmconverter.rst
- [X] audiotools_player.rst
- [X] audiotools_replaygain.rst
- [X] audiotools_toc.rst
- [X] index.rst
- [X] metadata.rst
** DONE Spellcheck reference documentation
- [X] aiff.tex
- [X] alac.tex
- [X] ape.tex
- [X] apev2.tex
- [X] au.tex
- [X] basics.tex
- [X] dvda2.tex
- [X] flac.tex
- [X] freedb.tex
- [X] introduction.tex
- [X] license.tex
- [X] m4a.tex
- [X] mp3.tex
- [X] musepack.tex
- [X] musicbrainz.tex
- [X] musicbrainz_mmd.tex
- [X] ogg.tex
- [X] oggflac.tex
- [X] references.tex
- [X] replaygain.tex
- [X] shorten.tex
- [X] speex.tex
- [X] vorbis.tex
- [X] wav.tex
- [X] wavpack.tex
** DONE Spellcheck reference figures
** DONE Spellcheck manual pages
** DONE Split reference documentation into sections by file
That is, massive codecs should be split into individual
.tex files by decode/encode sections and then subdivided
further as necessary to keep them from getting too fragile/unweildy
*** DONE Shorten
- [X] decode
- [X] encode
*** DONE FLAC
**** DONE metadata
**** DONE decode
**** DONE encode
- [X] fixed
- [X] residual
- [X] lpc
*** DONE WavPack
**** DONE decode
- [X] terms
- [X] weights
- [X] samples
- [X] entropy
- [X] bitstream
- [X] decorrelation
**** DONE encode
- [X] correlation
- [X] terms
- [X] weights
- [X] samples
- [X] entropy
- [X] bitstream
*** DONE ALAC
**** DONE decode
**** DONE encode
- [X] atoms
- [X] lpc
- [X] residual
*** DONE Remove m4 requirement
This is massive overkill for what little we need it for,
which is generating audioformats-_.tex and _-codec.tex files
with header/footers included and paper size populated.
It's better to use Python for that trivial templating instead.
** DONE Tweak reference documentation layout
Try harder to get pseudocode, file diagram,
bit diagram and example on same pair of pages.
*** DONE Shorten
*** DONE FLAC
*** DONE WavPack
*** DONE ALAC
*** DONE DVD-A
** DONE Ensure documentation flows correctly
Pages should start/end properly at letter and A4 paper sizes.
- [X] letter
- [X] A4
** DONE Handle multi-channel .opus files properly
*** DONE Add unit tests
** DONE Add optional interactive modes to utilities
Now that Urwid is being used for editxmcd, it might be helpful
to add optional console-based interactive modes to the other tools.
This may improve ease-of-use (particularly discoverability
in the case of format and quality options) without sacrificing
scriptability or command-line power.
Just as the command-line options are kept as consistent as possible,
all interactive modes will also need a consistent interface.
*** DONE audiotools-config
*** DONE cd2track
*** DONE cdplay
**** DONE make player widget generic
*** DONE dvda2track
*** DONE track2track
*** DONE trackcat
*** DONE trackplay
**** DONE make player widget generic
*** DONE trackrename
*** DONE tracksplit
*** DONE tracktag
** DONE run codecs through valgrind
Try to ensure there's no hidden bugs in the low-level C code.
*** DONE decoders
Will need to assemble standalone decoders for this.
- [X] alac
- [X] flac
- [X] mlp
- [X] oggflac
- [X] shorten
- [X] wavpack
*** DONE encoders
- [X] alac
- [X] flac
- [X] shorten
- [X] wavpack
*** DONE Update standalone encoders to take command-line arguments
This would make them easier to memory test.
- [X] alac
- [X] flac
- [X] shorten
- [X] wavpack
** DONE Have cdplay play properly
** DONE Update version number to 2.19 final
* DONE Finish version 2.20
** DONE Remove track number/album number guessing heuristics
Don't try to guess number from filename.
If a track number is needed, build it from the order
in which the files are submitted on the command line.
*** DONE track_number()
*** DONE album_number()
** DONE Update track2track/tracktag to use better option filler widget
cd2track, dvda2track and tracksplit always work with one album
at a time, pretty much by definition.
track2track may handle multiple albums simultaneously
and currently makes mutiple calls to urwid to work.
A better approach is to have all the metadata lookups
performed first, multiple metadata edit screens,
and a single output options/preview screen.
** DONE Simplify PCMReaderWindow
Split this into a PCMReaderHead and PCMReaderDeHead pair.
The former handles the "pcm_frames" argument,
either truncating a PCMReader or appending silence as needed.
The latter handles the "initial_offset" argument,
either chopping off frames or prepending silence as needed.
** DONE Adjust BitstreamReader to better handle huge byte counts
These are typically done in error and shouldn't eat up
all the RAM in the world before failing.
*** DONE Update functions
- [X] br_substream_append_f
- [X] br_substream_append_e
- [X] BitstreamReader_read_bytes
- [X] BitstreamReader_substream_meth
- [X] BitstreamReader_substream_append
*** DONE Add unit tests
- [X] br_substream_append_f
- [X] br_substream_append_e
- [X] BitstreamReader_read_bytes
- [X] BitstreamReader_substream_meth
- [X] BitstreamReader_substream_append
*** DONE turn the current buf_append into buf_extend
*** DONE Replace buf_extend with buf_append
** DONE Have process-based decoders exit when data runs out
That is, have PCMReader's .read() call subprocess.wait()
when the framelists end rather than waiting for .close()
to be called (which typically isn't).
If the wait fails, have it raise an exception at that point.
*** DONE Update process-based formats
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OpusAudio
*** DONE Update documentation
*** DONE Ensure unit tests pass
** DONE Reduce stdint usage in bitstream library
Try to limit stdint variables to places
where it's necessary, like read_64 and read_bytes
*** DONE Convert state/context to state_t
**** DONE Update br_huffman_table
**** DONE Update BitstreamReader
**** DONE struct read_bits
**** DONE struct unread_bit
**** DONE struct read_unary
**** DONE struct read_limited_unary
*** DONE Update jump table structures
**** DONE read_bits
**** DONE unread_bit
**** DONE read_unary
**** DONE read_limited_unary
*** DONE Update br_huffman_table
**** DONE Update continue_ to int
*** DONE Update bs_buffer
**** DONE unsigned data_size
**** DONE unsigned window_start
**** DONE unsigned window_end
**** DONE buf_resize()
**** DONE buf_write()
**** DONE buf_read()
*** DONE Update br_mark
**** DONE unsigned substream
**** DONE unsigned external
*** DONE Update substream_append()
**** DONE br_substream_append_f
**** DONE br_substream_append_s
**** DONE br_substream_append_e
**** DONE br_substream_append_c
*** DONE Update bw_external_output
**** DONE buffer_size
**** DONE bw_open_external()
**** DONE ext_open_w()
** DONE Add bs_buffer-specific unit tests to bitstream.c
- [X] buf_resize
- [X] buf_write
- [X] buf_read
- [X] buf_copy
- [X] buf_extend
- [X] buf_reset
- [X] buf_getc
- [X] buf_putc
- [X] buf_getpos
- [X] buf_setpos
- [X] buf_set_rewindable
- [X] BUF_WINDOW_SIZE
- [X] BUF_WINDOW_START
- [X] BUF_WINDOW_END
** DONE Fix cuesheet handling
Ensure the cuesheet interface handles unusual cases more accurately
and build a proper base class for the .cue and .toc files
*** DONE Add new base classes
- [X] Sheet
- [X] SheetTrack
- [X] SheetIndex
*** DONE Update cue module
- [X] read_cuesheet
- [X] write_cuesheet
*** DONE Update toc module
- [X] read_tocfile
- [X] write_tocfile
*** DONE Update get_cuesheet methods
- [X] FlacAudio
- [X] TrueAudio
- [X] WavPackAudio
*** DONE Update set_cuesheet methods
- [X] FlacAudio
- [X] TrueAudio
- [X] WavPackAudio
*** DONE Update documentation
- [X] read_sheet
- [X] Sheet
- [X] SheetTrack
- [X] SheetIndex
*** DONE Update utilities using cuesheet interface
- [X] track2cd
- [X] trackcat
- [X] trackinfo
- [X] tracksplit
*** DONE Update unit tests
*** DONE Add unit test for FlacAudio.set_cuesheet()
Ensure the resulting Flac_CUESHEET block matches
the one generated by metaflac --import-cuesheet-from
** DONE Add optional total_pcm_frames argument to from_pcm()
Certain formats encode much easier if the total number of PCM frames
is known in advance. Adding a total_pcm_frames argument
allows encoders to make use of that info if it's available.
*** DONE Update formats with total_pcm_frames argument
**** DONE AudioFile
does nothing
**** DONE ALACAudio
Builds placeholder seektable which is then populated later
**** DONE AiffAudio
does nothing
**** DONE AuAudio
does nothing
**** DONE FlacAudio
Allocates enough space for populated seektable
on top of any leftover for VORBIS tags.
**** DONE M4AAudio
does nothing
**** DONE MP2Audio
does nothing
**** DONE MP3Audio
does nothing
**** DONE OggFlacAudio
does nothing
**** DONE OpusAudio
does nothing
**** DONE ShortenAudio
If total_pcm_frames argument is given to from_pcm(),
precalculate Wave header rather than use temporary file.
This shouldn't require updating the encode_shn function.
**** DONE TrueAudio
If total_pcm_frames argument is given to from_pcm(),
fill header and temporary seektable rather than use temporary file.
This shouldn't require updating the encode_tta function.
**** DONE VorbisAudio
does nothing
**** DONE WavPackAudio
If total_pcm_frames argument is given to from_pcm(),
fill blocks during encoding rather than re-fill them afterward.
This will require minor update to encode_wavpack function.
**** DONE WaveAudio
does nothing
*** DONE Update convert() methods to call from_pcm() with argument
But only if the input file is lossless.
**** DONE AudioFile
**** DONE ALACAudio
**** DONE AiffAudio
**** DONE AuAudio
**** DONE FlacAudio
**** DONE M4AAudio
**** DONE MP2Audio
**** DONE MP3Audio
**** DONE OggFlacAudio
**** DONE OpusAudio
**** DONE ShortenAudio
**** DONE TrueAudio
**** DONE VorbisAudio
**** DONE WavPackAudio
**** DONE WaveAudio
*** DONE Update utilities to make use of total_pcm_frames argument
**** DONE cd2track
**** DONE dvda2track
**** DONE trackcat
**** DONE tracksplit
*** DONE Document total_pcm_frames argument
*** DONE Unit test calling formats with total_pcm_frames and without
*** DONE Add unit tests with total_pcm_frames and without per encoder
- [X] ALACAudio.from_pcm()
- [X] FlacAudio.from_pcm()
- [X] ShnAudio.from_pcm()
- [X] TTAAudio.from_pcm()
- [X] WavPackAudio.from_pcm()
** DONE Make decoder streams seekable
PCMReader.seek(pcm_frames) -> new pcm frames position
could seek to the closest position in the stream to the given frames
without going over, and return the current position in PCM frames.
*** DONE Update decoders
**** DONE AiffAudio
**** DONE AuAudio
**** DONE WaveAudio
**** DONE decoders.ALACDecoder
**** DONE decoders.FlacDecoder
**** DONE decoders.TTADecoder
**** DONE decoders.WavPackDecoder
*** DONE Add unit tests
** DONE Swap array types for something easier to comprehend
array_i/array_f/array_u is more opaque than it should be
*** DONE array_i -> a_int
*** DONE array_i_new() -> a_int_new()
- [X] decoders/alac.h/.c
- [X] decoders/flac.h/.c
- [X] decoders/mlp.h/.c
- [X] decoders/oggflac.h/.c
- [X] decoders/shn.h/.c
- [X] decoders/tta.h/.c
- [X] decoders/wavpack.h/.c
- [X] encoders/alac.h/.c
- [X] encoders/flac.h/.c
- [X] encoders/shn.h/.c
- [X] encoders/tta.h/.c
- [X] encoders/wavpack.h/.c
- [X] pcmconverter.h/.c
*** DONE array_ia -> aa_int
*** DONE array_ia_new() -> aa_int_new()
- [X] decoders/alac.h/.c
- [X] decoders/aob.h/.c
- [X] decoders/flac.h/.c
- [X] decoders/mlp.h/.c
- [X] decoders/oggflac.h/.c
- [X] decoders/shn.h/.c
- [X] decoders/sine.h/.c
- [X] decoders/tta.h/.c
- [X] decoders/wavpack.h/.c
- [X] encoders/alac.h/.c
- [X] encoders/flac.h/.c
- [X] encoders/shn.h/.c
- [X] encoders/tta.h/.c
- [X] encoders/wavpack.h/.c
- [X] pcmconverter.h/.c
- [X] replaygain.h/.c
*** DONE array_li -> l_int
*** DONE array_li_new() -> l_int_new()
- [X] encoders/flac.h/.c
*** DONE array_lia -> al_int
*** DONE array_lia_new() -> al_int_new()
- [X] encoders/flac.h/.c
- [X] pcmconverter.h/.c
*** DONE array_u -> l_unsigned
*** DONE array_u_new -> l_unsigned_new()
- [X] decoders/alac.c
- [X] encoders/alac.c
*** DONE array_lf -> l_double
*** DONE array_lu -> l_unsigned
*** DONE array_lu_new() -> l_unsigned_new()
- [X] decoders/alac.h/.c
*** DONE array_lfa -> al_double
*** DONE array_lfa_new() -> al_double_new()
*** DONE array_iaa -> aaa_int
*** DONE array_iaa_new() -> aaa_int_new()
- [X] encoders/wavpack.h/.c
- [X] decoders/wavpach.h/.c
*** DONE array_f -> a_double
*** DONE array_f_new() -> a_double_new()
- [X] pcmconverter.h/.c
- [X] encoders/alac.h/.c
- [X] encoders/flac.h/.c
*** DONE array_fa -> aa_double
*** DONE array_fa_new() -> aa_double_new()
- [X] replaygain.h/.c
- [X] encoders/alac.h/.c
- [X] encoders/flac.h/.c
*** DONE array_faa -> aaa_double
*** DONE array_faa_new() -> aaa_double_new()
*** DONE array_o -> a_obj
*** DONE array_o_new() -> a_obj_new()
- [X] decoders/alac.h/.c
- [X] decoders/aob.h/.c
- [X] decoders/flac.h/.c
- [X] encoders/wavpack.h/.c
*** DONE array_i_to_FrameList -> a_int_to_FrameList
- [X] decoders/flac.c
- [X] decoders/oggflac.c
- [X] pcmconv.c
- [X] pcmconverter.c
*** DONE array_ia_to_FrameList -> aa_int_to_FrameList
- [X] decoders/alac.c
- [X] decoders/aob.c
- [X] decoders/shn.c
- [X] decoders/sine.c
- [X] decoders/tta.c
- [X] decoders/wavpack.c
- [X] pcmconv.c
- [X] pcmconverter.c
- [X] replaygain.c
** DONE Better document M4A atoms
For each atom, indicate parent in bit diagram,
tell what it's for, have a hex diagram example
and show what those parsed values are.
*** DONE ftyp
*** DONE moov
**** DONE mvhd
**** DONE trak
***** DONE tkhd
***** DONE mdia
****** DONE mdhd
****** DONE hdlr
****** DONE minf
******* DONE smhd
******* DONE dinf
******** DONE dref
******* DONE stbl
******** DONE stsd
******** DONE stts
******** DONE stsc
******** DONE stsz
******** DONE stco
**** DONE udta
***** DONE meta
*** DONE free
*** DONE mdat
*** DONE Add some tree diagrams to fill sections of whitespace
- [X] moov
- [X] trak
- [X] mdia
- [X] minf
- [X] stbl
** DONE Add volume control to trackplay/cdplay
*** DONE Add get_volume() method to low-level audio players
It should return the current set volume as a float.
- [X] PulseAudioOutput
- [X] OSSAudioOutput
- [X] CoreAudioOutput
- [X] NULLAudioOutput
*** DONE Add set_volume(volume) method to low-level audio players
It should take a volume setting float and adjust the output volume.
- [X] PulseAudioOutput
- [X] OSSAudioOutput
- [X] CoreAudioOutput
- [X] NULLAudioOutput
*** DONE Build volume setting, progress-bar style widget
*** DONE Ensure volume control updates when system volume is updated
*** DONE Add widget to player widget
** DONE Make audio output selectable in trackplay/cdplay
*** DONE Add available_outputs() function to audiotools.player module
should return list of available AudioOutput subclasses
*** DONE Add description() method to AudioOutput subclasses
Returns a human-readable Unicode string indicating
what the audio output device is.
- [X] PulseAudioOutput
- [X] OSSAudioOutput
- [X] CoreAudioOutput
- [X] NULLAudioOutput
*** DONE Ensure output switches correctly
Switches should be as seamless as possible and include
setting the output volume properly.
** DONE Add track2track format conversion options
Primarily for conversion between one lossless format to another.
- [X] --sample-rate
- [X] --channels
- [X] --bits-per-sample
*** DONE Add documentation to man page
*** DONE Add unit tests
** DONE Add internal True Audio codec
*** DONE Add Python-based True Audio decoder
*** DONE Add Python-based True Audio encoder
*** DONE Document True Audio decoding
*** DONE Document True Audio encoding
*** DONE Add C-based True Audio decoder
**** DONE modify it for standalone use
**** DONE ensure there's no memory errors or leaks
**** DONE Make decoder thread-friendly
*** DONE Add C-based True Audio encoder
**** DONE modify it for standalone use
**** DONE ensure there's no memory errors or leaks
**** DONE make encoder thread-friendly
*** DONE Add True Audio-specific unit tests
*** DONE Test encoder/decoder against reference
*** DONE Add True Audio detecter to file_type() function
*** DONE Add True Audio AudioFile class
*** DONE Ensure True Audio class passes all unit tests
** DONE Add AccurateRip support
This might make give cd2track a little added respectability
and post-rip tools could be built also to verify tracks/disc images.
*** DONE Add accuraterip Python support
**** DONE add DiscID to accuraterip module
**** DONE add perform_lookup to accuraterip module
**** DONE add accuraterip_lookup to __init__ module
**** DONE add AccurateRipReader to accuraterip module
This would be a PCMReader wrapper to be used
by cd2track to verify track checksum while it's being extracted.
**** DONE add AccurateRipTrackChecksum to accuraterip module
This would be a transfer_framelist_data target
to be used by trackverify to verify tracks
already extracted.
**** DONE Add programming docstrings
**** DONE Add programming documentation
*** DONE Add AccurateRip disc ID to cdinfo
*** DONE Add support to cd2track
This should be done by default as a wrapper around
the existing CDDA PCMReader objects.
*** DONE Add support to trackverify
Add a -R/--accuraterip option which foregoes the usual
calls to .verify(), performs an AccurateRip lookup
for all albums and indicates whether they match/don't match/aren't found
*** DONE Add protocol documentation
- [X] calculating the AccurateRip disc ID
- [X] fetching database entries from the server
- [X] parsing database entries from the server
- [X] calculating a track's CRC
- [X] checking the confidence level
* DONE Finish version 2.21
** DONE Bump minimum required Python version to 2.7
Python 2.7 is pretty common these days and offers useful
features that have been backported from 3.
** DONE Cleanup ProgressDisplay design
Replace row_id indicators with a ProgressDisplayRow object
which is created by ProgressDisplay and features
update() and delete() methods that update the main ProgressDisplay.
This removes the need to specify row_id values and the
main ProgressDisplay can assign empty slots as needed.
*** DONE Update documentation
** DONE Update temporary file management
Some of the metadata functions update via tempfile.TemporaryFile
then overwrite the original once the file's been completed.
This would be a bad idea in the edge case of a full disk.
So it may be preferable to write to a temp file alongside the original
and then rename over it. That way the original wouldn't be changed
until commit-time.
- [X] aiff.py
- [X] ape.py
- [X] flac.py
- [X] m4a.py
- [X] tta.py
- [X] wav.py
*** DONE Add unit tests
Ensure tracks retain permissions when metadata is updated.
** DONE Convert utilties from optparse to argparse
argparse seems a bit nicer and more user-friendly
since it generates usage lines automatically.
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Ensure all utilities have a working --version option
Now that it's no longer built-in, I'll need to add and check
the option by hand.
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Improve Ogg format metadata speeds
Reading/writing should be faster for all Ogg-based formats.
*** DONE Ogg FLAC
*** DONE Ogg Vorbis
*** DONE Opus
** DONE Adjust MetaData.clean() interface
Returns (MetaData, [fixes]) tuple
where MetaData is a new, fixed metadata object
and fixes is a list of Unicode strings.
*** DONE Fix MetaData objects
- [X] MetaData
- [X] APEv2
- [X] FlacMetaData
- [X] ID3v22Comment
- [X] ID3v23Comment
- [X] ID3v24Comment
- [X] ID3CommentPair
- [X] ID3v1Comment
- [X] M4A_META_Atom
- [X] VorbisComment
*** DONE Update documentation
*** DONE Update unit tests
** DONE Adjust AudioFile.clean() interface
Takes optional output_filename and returns list of fixes performed.
It would be nice not to need separate code paths
for dry runs, like with MetaData, but that may not be feasible.
*** DONE Fix AudioFile objects
- [X] AudioFile
- [X] AiffAudio
- [X] FlacAudio
- [X] WaveAudio
*** DONE Update tracklint
*** DONE Update documentation
*** DONE Update unit tests
** DONE Add lint for "double-wrapped" ID3v2 tags
Sometimes files are idiotically wrapped in multiple layers of ID3v2 tags
like nested Russian dolls. These are currently unrecognized because
audiotools assumes a valid track follows the tag instead of another tag.
*** DONE Support tracks nested arbitrarily deep in ID3v2 tags
In order to be fixable,
these files will need to be readable in the first place
**** DONE Update file_type function to skip ID3v2 tags recursively
It should still only find MP2/MP3/FLAC/TTA files how matter how
deeply nested, but should support arbitrarily deep nesting.
**** DONE Update FlacAudio
***** DONE Update FlacAudio to support nested tags
This is basically a matter of making the offset as large
as it takes to hold all the tags.
***** DONE Have FlacAudio.clean() remove all ID3v2 tags
***** DONE Update unit tests
**** DONE Update MP3Audio
***** DONE Update MP3Audio to support nested tags
***** DONE Have MP3Audio.clean() remove all ID3v2 tags except one
***** DONE Update unit tests
**** DONE Update MP2Audio
***** DONE Update MP2Audio to support nested tags
***** DONE Have MP2Audio.clean() remove all ID3v2 tags except one
***** DONE Update unit tests
**** DONE Update TrueAudio
***** DONE Update TrueAudio to support nested tags
***** DONE Have TrueAudio.clean() remove all ID3v2 tags except one
***** DONE Update unit tests
* DONE Finish version 2.22
** DONE Update ReplayGain interface
All ReplayGain should be lossless (if supported at all) and needs an interface
that's less dependant on external tools.
*** DONE Remove add_replay_gain() classmethod
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Add add_replay_gain() function
Takes an album's worth of audiofile objects and optional progress function
and if any of their classes support it (via the supports_replay_gain() classmethod)
calls calculate_replay_gain() on all of them and applies the result
using set_replay_gain()
*** DONE Remove can_add_replay_gain() classmethod
If supports_replay_gain() classmethod returns True,
set_replay_gain() will be able to do something useful.
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Remove lossless_replay_gain classmethod
All ReplayGain will be lossless
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Convert replay_gain() method to get_replay_gain()
Returns a ReplayGain object or None, as it does now.
Analagous to get_metadata()
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Add set_replay_gain() method
Takes a ReplayGain object or None and sets the file's values
by updating metadata, or deletes the values if None
Analagous to set_metadata()
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Add delete_replay_gain() method
Deletes any ReplayGain values, if any
Analagous to delete_metadata()
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Update utilities to use new ReplayGain interface
- [X] cd2track
- [X] dvda2track
- [X] track2track
- [X] trackinfo
- [X] trackplay
- [X] tracksplit
- [X] tracktag
*** DONE Update documentation
*** DONE Update unit tests
** DONE Catch interrupts more cleanly in utilities
When the user cancels a long-running job, utilities should clean the screen
as well as possible, delete any partial files and display a "cancelled" message
instead of delivering stack traces like they do now.
- [X] cd2track
- [X] cdplay
- [X] dvda2track
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] tracklength
- [X] trackplay
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Add AudioFile.seekable() method
This returns True if the format's PCMReader has a .seek() method
and that method supports some sort of fine-grained seeking
(i.e. not just return to the beginning of the file).
*** DONE Update audio formats
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Update documentation
*** DONE Update utilities
**** DONE tracksplit
If the file being split isn't seekable, decompress it to a temp file
so it can be processed across multiple jobs.
**** DONE trackcmp
If comparing multiple tracks against a non-seekable image,
decompress it to a temp file so it can be processed across multiple jobs.
*** DONE Update unit tests
** DONE Have AccurateRip detect offset tracks
If the tracks have been ripped accurately but are merely offset
by some small positive or negative number of samples,
this should be detected and indicated in the AccurateRip results screens.
*** DONE Update ChecksumV1
**** DONE Add keyword parameters with sensible defaults
**** DONE Add range option
This indicates the total range of the window size.
Defaults to 1, indicating only a single checksum to be generated.
**** DONE Change .checksum() method to .checksums()
Returns a list of all calculated checksums over the whole range.
*** DONE Add unit tests
Ensure ranged and non-ranged checksums are calculated properly
and update tests for new interface.
*** DONE Build audiotools.cdio.CDDAReader object
This functions like a PCMReader object over the entire CDDA device.
It should work transparently on physical CD devices as well as CD images
and be PCM-frame centric by doing all the CD sector conversions
behind-the-scenes.
**** DONE Add methods and attributes
***** DONE CDDAReader.sample_rate
***** DONE CDDAReader.channels
***** DONE CDDAReader.channel_mask
***** DONE CDDAReader.bits_per_sample
***** DONE CDDAReader.track_offsets
- [X] CD image
- [X] CD drive
Returns starting offset of each track, in PCM frames
***** DONE CDDAReader.track_lengths
- [X] CD image
- [X] CD drive
Returns length of each track, in PCM frames
***** DONE CDDAReader.first_sector
- [X] CD image
- [X] CD drive
Used for calculating various disc IDs
***** DONE CDDAReader.last_sector
- [X] CD image
- [X] CD drive
Used for calculating various disc IDs
***** DONE CDDAReader.is_image
- [X] CD drive
- [X] CD image
***** DONE CDDAReader.read(pcm_frames)
- [X] CD image
- [X] CD drive
***** DONE CDDAReader.seek(pcm_frames)
- [X] CD image
- [X] CD drive
***** DONE CDDAReader.set_speed(speed)
- [X] CD image
- [X] CD drive
***** DONE CDDAReader.log()
- [X] CD image
- [X] CD drive
***** DONE CDDAReader.reset_log()
***** DONE CDDAReader.close()
**** DONE Update documentation
**** DONE Update unit tests
**** DONE Detect nonexistent discs
CDDAReader should detect when a physical drive doesn't contain a disc
and raise an appropriate exception.
**** DONE Update utilities
***** DONE cd2track
***** DONE cdinfo
***** DONE cdplay
**** DONE Clean out old audiotools.CDDA object
Remove outdated interface, its documentation and unit tests.
*** DONE Update utilities
When verifying AccurateRip, make sure to populate the checksum
with the last few samples of the previous track (if any)
and the next few samples of the next track (if any)
in order to find the checksum's offset.
**** DONE trackverify
**** DONE cd2track
** DONE Simplify lookup services interface
The perform_lookup() functions should work on DiscID objects
and DiscID objects should be generated from
CDDAReaders, track lists or cuesheet/length combinations.
*** DONE FreeDB
- [X] Add from_tracks classmethod
- [X] Add from_sheet classmethod
- [X] Add unit tests
*** DONE MusicBrainz
- [X] Add from_tracks classmethod
- [X] Add from_sheet classmethod
- [X] Add unit tests
*** DONE AccurateRip
- [X] Add from_tracks classmethod
- [X] Add from_sheet classmethod
- [X] Add unit tests
** DONE Add documentation for lookup services
- [X] audiotools.freedb
- [X] audiotools.musicbrainz
- [X] audiotools.accuraterip
** DONE Convert TOC and CUE handling to proper grammars
*** DONE Convert audiotools.cue
*** DONE Convert audiotools.toc
** DONE Add AccurateRipV2 support
*** DONE Add ChecksumV2 object
**** DONE Add unit tests
*** DONE Update utilities
- [X] cd2track
- [X] trackverify
** DONE Update Sheet interface
Although cuesheets are mostly a repository of index points,
it would be useful to support a wider subset of options
when converting one form to another.
*** DONE Sheet
- [X] @classmethod converted(sheet) -> Sheet
builds Sheet object from Sheet-compatible object
- [X] __len__() -> total_tracks
- [X] __getitem__(track_index) -> SheetTrack
- [X] __eq__(sheet) -> boolean
- [X] track_numbers() -> [int]
- [X] track(track_number) -> SheetTrack
- [X] get_metadata() -> MetaData
MetaData contains catalog_number and CD-TEXT information
*** DONE SheetTrack
- [X] @classmethod converted(sheet_track) -> SheetTrack
builds SheetTrack object from SheetTrack-compatible object
- [X] __len__() -> total_indexes
- [X] __getitem__(index_index) -> SheetIndex
- [X] __eq__(sheet_track) -> boolean
- [X] indexes() -> [int]
- [X] index(index_number) -> SheetIndex
- [X] filename() -> string
- [X] number() -> track_number
- [X] get_metadata() -> MetaData
MetaData contains track_number, ISRC and CD-TEXT information
- [X] is_audio() -> boolean
- [X] pre_emphasis() -> boolean
- [X] copy_peritted() -> boolean
*** DONE SheetIndex
- [X] @classmethod converted(sheet_index) -> SheetIndex
- [X] __eq__(sheet_index) -> boolean
- [X] number() -> index_number
pre-gap is index_number 0
- [X] offset() -> Fraction
offset of index in seconds from start of stream
*** DONE Update audiotools.cue.Cuesheet
*** DONE Update audiotools.toc.TOCFile
*** DONE Update audiotools.flac.Flac_CUESHEET
*** DONE Ensure non-image cuesheets are handled properly
Given a non-image cuesheet and list of track lengths,
it may be possible to convert a non-image cuesheet
to an image cuesheet.
*** DONE Handle 1st track pre-gap correctly
Discs with a pre-gap before the 1st track
should have that gap removed when split
and re-added when concatenating them back together
based on the cuesheet contents.
- [X] update tracksplit
- [X] update trackcat
- [X] add unit tests
*** DONE Update utilities
- [X] trackcat
- [X] tracksplit
- [X] track2cd
- [X] trackinfo
*** DONE Update functions/methods which take cuesheets
- [X] sheet_metadata_lookup
- [X] accuraterip_sheet_lookup
*** DONE Update documentation
*** DONE Update unit tests
** DONE Converts AudioFile.seconds_length() method to Fraction
This should be more useful than the Decmial it was using before.
*** DONE Update method
*** DONE Update documentation
*** DONE Update utilities
- [X] track2cd
- [X] trackcat
- [X] trackinfo
- [X] tracklength
- [X] trackplay
- [X] tracksplit
* DONE Finish version 3.0
** DONE Make compatible with Python 2.7 and 3.X
Like Urwid and PLY, the same code should work on both versions.
*** DONE Update setup script
*** DONE Update C-based extensions
Use #ifdefs as needed to support both Python versions.
- [X] audiotools.pcm
- [X] audiotools.pcmconverter
- [X] audiotools.replaygain
- [X] audiotools.decoders
- [X] audiotools.encoders
- [X] audiotools.bitstream
- [X] audiotools._ogg
- [X] audiotools._accuraterip
- [X] audiotools.output
*** DONE Update Python modules
**** DONE audiotools
- [X] __init__
- [X] accuraterip
- [X] aiff
- [X] ape
- [X] au
- [X] dvda
- [X] flac
- [X] freedb
- [X] id3
- [X] id3v1
- [X] image
- [X] m4a_atoms
- [X] m4a
- [X] mp3
- [X] musicbrainz
- [X] ogg
- [X] opus
- [X] player
- [X] shn
- [X] text
- [X] tta
- [X] ui
- [X] vorbiscomment
- [X] vorbis
- [X] wavpack
- [X] wav
**** DONE audiotools.cue
- [X] __init__
- [X] tokrules
- [X] yaccrules
**** DONE audiotools.toc
- [X] __init__
- [X] tokrules
- [X] yaccrules
*** DONE Update utilities
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
*** DONE Update Python-based decoders
- [X] alac
- [X] flac
- [X] shn
- [X] tta
- [X] wavpack
*** DONE Update Python-based encoders
- [X] alac
- [X] flac
- [X] shn
- [X] tta
- [X] wavpack
*** DONE Update documentation
*** DONE Update unit tests
- [X] test
- [X] test_core
- [X] test_formats
- [X] test_metadata
- [X] test_streams
- [X] test_utils
**** TODO Update unit test utilities
- [ ] error.py
- [ ] test_cdrdao
- [ ] test_cdrecord
*** DONE Ensure unit tests pass
**** DONE Python 2.7
***** DONE Lib
- [X] core
- [X] cuesheet
- [X] cdio
- [X] freedb
- [X] image
- [X] musicbrainz
- [X] accuraterip
- [X] pcm
- [X] bitstream
- [X] replaygain
- [X] resample
- [X] tocfile
- [X] verify
- [X] ogg
***** DONE Format
- [X] audiofile
- [X] lossless
- [X] lossy
- [X] aiff
- [X] alac
- [X] au
- [X] dvda
- [X] flac
- [X] m4a
- [X] mp2
- [X] mp3
- [X] oggflac
- [X] opus
- [X] shorten
- [X] sines
- [X] tta
- [X] vorbis
- [X] wave
- [X] wavpack
***** DONE Metadata
- [X] metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] opus
- [X] m4a
- [X] tta
***** DONE Util
- [X] audiotools-config
- [X] cd2track
- [ ] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
**** DONE Python 3
***** DONE Lib
- [X] core
- [X] cuesheet
- [X] cdio
- [X] freedb
- [X] image
- [X] musicbrainz
- [X] accuraterip
- [X] pcm
- [X] bitstream
- [X] replaygain
- [X] resample
- [X] tocfile
- [X] verify
- [X] ogg
***** DONE Format
- [X] audiofile
- [X] lossless
- [X] lossy
- [X] aiff
- [X] alac
- [X] au
- [X] dvda
- [X] flac
- [X] m4a
- [X] mp2
- [X] mp3
- [X] oggflac
- [X] opus
- [X] shorten
- [X] sines
- [X] tta
- [X] vorbis
- [X] wave
- [X] wavpack
***** DONE Metadata
- [X] metadata
- [X] flac
- [X] wavpack
- [X] id3v1
- [X] id3v2
- [X] vorbis
- [X] opus
- [X] m4a
- [X] tta
***** DONE Util
- [X] audiotools-config
- [X] cd2track
- [X] cdinfo
- [X] cdplay
- [X] coverdump
- [X] covertag
- [X] coverview
- [X] dvda2track
- [X] dvdainfo
- [X] track2cd
- [X] track2track
- [X] trackcat
- [X] trackcmp
- [X] trackinfo
- [X] tracklength
- [X] tracklint
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
- [X] trackverify
** DONE Update interactive utilities
Ensure they run under Python 2 and 3
- [X] audiotools/ui.py
- [X] audiotools-config
- [X] cd2track
- [X] cdplay
- [X] dvda2track
- [X] track2track
- [X] trackcat
- [X] trackplay
- [X] trackrename
- [X] tracksplit
- [X] tracktag
** DONE Calculate ReplayGain at rip-time
For utilities that operated single-threaded,
calculate ReplayGain during operation rather
than put off until ripping is done.
*** DONE cd2track
*** DONE dvda2track
** DONE Re-add DVD-A support using libdvdaudio
Supporting DVD-A in an external library should provide a useful decoupling.
*** DONE Add audiotools.dvda module
This contains thin wrappers around libdvdaudio structures and functions.
**** DONE Add DVDA object
**** DONE Add Titleset object
**** DONE Add Title object
**** DONE Add Track object
**** DONE Add TrackReader object
**** DONE Add documentation
*** DONE Re-add dvda2track script
**** DONE Re-add dvda2track.1 man page
*** DONE Re-add dvdainfo script
**** DONE Re-add dvdainfo.1 man page
*** DONE Update setup script
Probe for libdvdaudio and add module and scripts if present,
analagous to libcdio.
* DONE Finish version 3.1
** DONE Make AudioFile.available() classmethod finer-grained
That is, formats can be readable but not writable, or taggable but
not readable or writeable. This will allow read-only support for
some obscure formats like .tak or .ape by porting implementations
from ffmpeg but without having to build encoders for them as well.
*** DONE Add AudioFile.supports_to_pcm()
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Add AudioFile.supports_from_pcm()
- [X] AudioFile
- [X] ALACAudio
- [X] AiffAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OpusAudio
- [X] ShortenAudio
- [X] TrueAudio
- [X] VorbisAudio
- [X] WavPackAudio
- [X] WaveAudio
*** DONE Add AudioFile.supports_metadata()
*** DONE Remove AudioFile.missing_components() ?
Leave this job to setup.py and audiotools-config, perhaps.
*** DONE Utilities
**** DONE audiotools-config
Needs to display format availability in a more fine-grained fashion.
**** DONE cd2track
- [X] output format must supports_from_pcm()
**** DONE track2cd
- [X] input format must supports_to_pcm()
**** DONE track2track
- [X] input format(s) must supports_to_pcm()
- [X] output format must supports_from_pcm()
**** DONE trackcat
- [X] input format(s) must supports_to_pcm()
- [X] output format must supports_from_pcm()
**** DONE trackcmp
- [X] input format(s) must supports_to_pcm()
**** DONE trackplay
- [X] input format(s) must supports_to_pcm()
**** DONE tracksplit
- [X] input file must supports_to_pcm()
- [X] output format must supports_from_pcm()
**** DONE trackverify
- [X] input format must supports_to_pcm()
*** DONE Update documentation
*** DONE Update unit tests
* DONE Add compilation field to metadata
This boolean field indicates the track is part of a compilation
and should round-trip correctly across all metadata types
that support it.
** DONE Replace MetaData.INTEGER_FIELDS with a FIELD_TYPE lookup
This allows a field to be either a Unicode string (like track_name)
integer field (like track_number) or a boolean (like compilation).
** DONE Add field to metadata classes
*** DONE Add compilation field to MetaData class
*** DONE Add compilation field to ID3v2 classes
- [X] ID3v2.2
- [X] ID3v2.3
- [X] ID3v2.4
- [X] ID3CommentPair
*** DONE Add compilation field to VorbisComment classes
- [X] VorbisComment
- [X] FlacMetaData
*** DONE Add compilation field to M4A metadata
*** DONE Add compilation field to APEv2 metadata
** DONE Update tracktag to support compilation field
- [X] add command-line options
- [X] add UI support
*** TODO Update man page
** DONE Update documentation
** DONE Update unit tests
- [X] format unit tests
- [X] tracktag unit tests
* TODO Add support for genre tag?
I'm not a big fan of the genre tag.
Unlike track number, album name, ISRC, etc. in which a value
can be reliably determined from the source material (e.g. back of the CD),
genre is akin to a "rating" tag. Its value varies from person to person
and this makes it less valuable for archival purposes.
In addition, the genre tag itself is implemented in incompatible ways.
APEv2 uses a chunk of text, ID3v1 uses an integer representing one
of many designated genre labels, ID3v2 uses a mix of genre byte
and/or text string, and so on.
That said, the genre field shows up in a lot of players.
So, some grudging support for it would probably be appreciated.
* TODO Replace magic numbers with named constants
There's still a few instances of magic numbers in use,
in the __flac__.py module, for instance.
* TODO Support disc metadata submission
If a disc is not found on FreeDB or MusicBrainz,
there should be some mechanism to submit user-defined data
to those services.
* TODO build track2cover utility
It would be helpful to have tools that could query
online cover databases and retrieve images for tagging purposes.
track2cover can replace coverdump, functioning like trac2xmcd
which allows it to pull from existing metadata or from online sources.
* TODO build trackverify utility
Much like flac(1)'s --verify option, this should check
a file for correctness and, if possible, verify its output
matches any internal hashes/checksums.
May work recursively to check a user's entire collection.
** DONE add a .verify() method to AudioFile classes
Returns True if the file is okay. Raises InvalidFile if not.
Include unit test.
- [X] AiffAudio
- [X] ALACAudio
- [X] AuAudio
- [X] FlacAudio
- [X] M4AAudio
- [X] MP2Audio
- [X] MP3Audio
- [X] OggFlacAudio
- [X] SpeexAudio
- [X] ShortenAudio
- [X] VorbisAudio
- [X] WaveAudio
- [X] WavPackAudio
** TODO add trackverify unit tests for all known verifiable problems
** DONE add trackverify man page
** DONE link trackverify man page to others
* TODO Add a -r/--no-results flag to trackcmp/trackverify
Listing only the final results and not the running list
** TODO Update man page
* TODO Add DVD-A support
** DONE Build AOB parser/extractor
*** DONE Optimize AOB extractor for better offset handling
The current version works, but is a little too naive
** TODO Build CPPM handler
*** DONE Create audiotools.prot module
*** TODO Create audiotools.prot.CPPMDecoder object
**** DONE Add CPPMDecoder.__init__() method
**** DONE Add CPPMDecoder.decode() method
**** TODO Ensure CPPMDecoder is cross-platform
** DONE Document AOB parser
** DONE Build raw PCM decoder
The PCM data doesn't appear to be stored raw,
so some additional calculation will likely be necessary
** TODO Build MLP decoder
*** DONE Create decoders.MLPDecoder class
**** DONE Add MLPDecoder.init() method
**** DONE Add MLPDecoder.sample_rate attribute
**** DONE Add MLPDecoder.channels attribute
**** DONE Add MLPDecoder.bits_per_sample attribute
**** DONE Add MLPDecoder.channel_mask attribute
**** DONE Add MLPDecoder.read() method
**** DONE Add MLPDecoder.analyze_frame() method
**** DONE Add MLPDecoder.close() method
*** DONE Perform MLP frame parsing
**** DONE Perform frame size parsing
**** DONE Perform major sync parsing
**** DONE Perform substream sizes parsing
**** DONE Perform substream datas parsing
***** DONE Perform block parsing
****** DONE Perform restart header parsing
****** DONE Perform decoding parameters parsing
******* DONE Perform parameter presence flags parsing
******* DONE Perform block size parsing
******* DONE Perform matrix parameters parsing
******* DONE Perform output shifts parsing
******* DONE Perform quant step sizes parsing
******* DONE Perform channel parameters parsing
******** DONE Perform FIR filter parameters parsing
******** DONE Perform IIR filter parameters parsing
******** DONE Perform Huffman offset parsing
******** DONE Perform Codebook parsing
******** DONE Perform Huffman least-significant bits parsing
****** DONE Perform block data parsing
***** DONE Perform block alignment
***** DONE Perform CRC parsing
*** TODO Perform MLP data decoding
**** DONE Handle FIR/IIR filtering
**** DONE Handle matrix reconstruction
***** DONE Build noise channels
**** DONE Handle quant_step_sizes
**** DONE Combine multiple substreams into single output frame
**** DONE Handle output shifts
**** TODO Handle checksums
***** TODO restart header lossless check
***** DONE end-of-frame parity
***** DONE end-of-frame checksum
**** DONE Build pcm.FrameList from PCM data arrays
***** DONE Reorder MLP channels to wave order
**** DONE Add bs_try for proper EOF aborts
**** DONE Add end-of-stream marker checking to read()
**** TODO Add end-of-stream marker checking to analyze_frame()
**** DONE Optimize to work faster
Perhaps with multiple blocks per call to read()
**** TODO Support 1 substream output
MLP decoding supports 1 or 2 substreams.
In some cases, substream 1 will contain the first 2 channels
while substream 2 will contain the rest,
which provides two different "mixes" depending on whether
one is decoding to 2 channels or not.
***** TODO Update dvda2track with 1 substream output option
This would allow the user to decide which "mix" is desired
during extraction.
*** DONE Perform sanity checks
** TODO Document MLP decoder
*** DONE major sync
*** DONE substream size
*** DONE substream data
*** DONE restart header
*** DONE decoding parameters
**** DONE parameter presence flags
**** DONE block size
**** DONE matrix parameters
**** DONE output shifts
**** DONE quant step sizes
*** DONE checksums
*** DONE block data
*** DONE channel filtering
*** DONE channel rematrixing
**** DONE noise channels
**** DONE rematrixing
*** DONE end of stream marker
*** TODO decoding XOR byte
** DONE Document PCM decoder
** DONE Link MLP decoder to AOB extractor
** DONE Link PCM decoder to AOB extractor
** TODO Build DVD-A postprocessor
** DONE Document Python interface
** DONE Build dvdainfo utility
*** DONE Add dvdainfo.1 man page
*** DONE Ensure -A with invalid dir generates error message
** DONE Build dvda2track utility
*** DONE Fix to work without -d
*** DONE Add --track-start / --track-total options
Since some especially long discs split tracks across titles,
it makes sense to have a way to specify the starting track number
and the total number of tracks.
**** DONE Add options to man page
*** DONE Add dvda2track.1 man page
*** DONE Ensure -A with invalid dir generates error message
** DONE Build dvda2xmcd utility
Querying FreeDB and MusicBrainz are possible,
but I expect most of the time they'll generate empty templates.
*** DONE Add dvda2xmcd.1 man page
*** DONE Ensure -A with invalid dir generates error message
* TODO Add cdplay utility
Should work similarly to trackplay,
taking track number(s) and playing them to OSS/PulseAudio
or whatever other audio output is available.
** DONE Add audiotools.player.CDPlayer class
*** DONE Add docstrings
*** DONE Add programming docs
** DONE Add audiotools.player.CDPlayerThread class
*** DONE Add docstrings
** DONE Add non-interactive mode to cdplay
** DONE Add interative mode to cdplay
Urwid-based display should have various standard features
- [X] display CD info
- [X] progress monitor
- [X] start
- [X] pause
- [X] next track
- [X] previous track
** DONE Silence CD query messages
** DONE Support command-line tracks
One might want to play only a subset of the whole CD
** DONE Add -V/--verbose option
** DONE Add --shuffle option
** DONE Add -x/--xmcd file support
** DONE Avoid spinning down CDs between tracks
This makes playback less seamless than I'd like
** TODO Improve stability
** DONE Add man page for cdplay.1
** TODO Add basic unit tests
- [ ] Check command-line arguments
* TODO Reorganize test suite
The current haphazard layout makes it too difficult to deterimine
if some feature has been fully unit tested.
Or, if a new feature is added, the logical place to put new tests
is not obvious.
** TODO Group tests for the audio formats
*** DONE AudioFile
- [X] test_init
- [X] test_is_type
- [X] test_bits_per_sample
- [X] test_metadata
- [X] test_length
- [X] test_track_number
- [X] test_album_number
- [X] test_track_name
- [X] test_replay_gain
*** DONE LosslessAudioFile
- [X] test_lossless
- [X] test_channels
- [X] test_channel_mask
- [X] test_sample_rate
- [X] test_pcm
- [X] test_convert
*** DONE LossyAudioFile
- [X] test_bits_per_sample
- [X] test_lossless
- [X] test_channels
- [X] test_channel_mask
- [X] test_sample_rate
- [X] test_pcm
- [X] test_convert
*** DONE ALACAudio
- [X] test_init
- [X] test_bits_per_sample
- [X] test_channel_mask
- [X] test_verify
- [X] test_streams
- [X] test_small_files
- [X] test_full_scale_deflection
- [X] test_sines
- [X] test_wasted_bps
- [X] test_blocksizes
- [X] test_noise
- [X] test_fractional
- [X] test_frame_header_variations
*** TODO AiffAudio
- [ ] test_init
- [X] test_channel_mask
- [X] test_verify
- [X] test_roundtrip_aiff_chunks
- [X] test_convert_aiff_chunks
*** TODO AuAudio
- [ ] test_init
- [X] test_verify
- [X] test_channel_mask
*** TODO FlacAudio
- [ ] test_init
- [ ] test_metadata2
- [X] test_verify
- [ ] test_cuesheet
- [X] test_roundtrip_aiff_chunks
- [X] test_convert_aiff_chunks
- [X] test_roundtrip_wave_chunks
- [X] test_convert_wave_chunks
- [X] test_streams
- [X] test_small_files
- [X] test_full_scale_deflection
- [X] test_sines
- [X] test_wasted_bps
- [X] test_blocksizes
- [X] test_frame_header_variations
- [X] test_option_variations
- [X] test_noise
- [X] test_fractional
*** TODO M4AAudio
- [ ] test_init
- [ ] test_verify
*** TODO MP2Audio
- [ ] test_init
- [X] test_length
- [ ] test_verify
*** TODO MP3Audio
- [ ] test_init
- [X] test_length
- [ ] test_verify
*** TODO OggFlacAudio
- [ ] test_init
- [X] test_verify
- [ ] test_cuesheet
*** TODO ShortenAudio
- [ ] test_init
- [X] test_bits_per_sample
- [X] test_verify
- [X] test_roundtrip_wave_chunks
- [X] test_convert_wave_chunks
- [X] test_streams
- [X] test_small_files
- [X] test_full_scale_deflection
- [X] test_sines
- [X] test_blocksizes
- [X] test_noise
*** TODO VorbisAudio
- [ ] test_init
- [X] test_channels
- [X] test_verify
*** TODO WavPackAudio
- [ ] test_init
- [X] test_verify
- [ ] test_cuesheet
- [X] test_roundtrip_wave_chunks
- [X] test_convert_wave_chunks
- [X] test_small_files
- [X] test_full_scale_deflection
- [X] test_wasted_bps
- [X] test_blocksizes
- [X] test_silence
- [X] test_noise
- [X] test_fractional
- [X] test_multichannel
- [X] test_sines
- [X] test_option_variations
*** TODO WaveAudio
- [ ] test_init
- [X] test_verify
- [X] test_roundtrip_wave_chunks
- [X] test_convert_wave_chunks
** DONE Group tests for the metadata formats
*** DONE ApeTag
*** DONE FLAC
*** DONE ID3v1
*** DONE ID3v2.2
*** DONE ID3v2.3
*** DONE ID3v2.4
*** DONE IDCommentPair
*** DONE M4A
*** DONE VorbisComment
*** DONE Ensure that merge() works properly
It has to handle all supported text fields
*and* must handle images if supported.
** TODO Group tests for the core libraries
*** TODO audiotools.__init__
**** TODO AlbumMetaData
**** DONE BufferedPCMReader
**** DONE CDDA
**** DONE ChannelMask
**** DONE Image
**** DONE LimitedPCMReader
**** TODO Messenger
**** DONE PCMCat
**** DONE PCMConverter
**** DONE PCMReaderWindow
**** TODO ReorderedPCMReader
**** DONE ReplayGain
**** DONE applicable_replay_gain
**** DONE at_a_time
**** DONE build_timestamp
**** DONE calculate_replay_gain
**** DONE filename_to_type
**** DONE group_tracks
**** TODO make_dirs
**** DONE open
**** DONE open_directory
**** DONE open_files
**** DONE parse_timestamp
**** DONE pcm_frame_cmp
**** DONE pcm_split
**** DONE read_sheet
**** DONE str_width
**** DONE transfer_framelist_data
**** DONE XMCD
**** DONE MusicBrainzReleaseXML
*** DONE audiotools.pcm
**** DONE FloatFrameList
**** DONE FrameList
**** DONE from_channels
**** DONE from_float_Frames
**** DONE from_float_channels
**** DONE from_frames
**** DONE from_list
*** DONE audiotools.player
**** DONE Player
**** DONE CDPlayer
*** DONE audiotools.replaygain
**** DONE ReplayGain
**** DONE ReplayGainReader
*** DONE audiotools.decoders
**** DONE BitstreamReader
*** DONE audiotools.encoders
**** DONE BitstreamWriter
*** TODO audiotools.verify
**** TODO mpeg
**** TODO ogg
** TODO Group tests for the individual tools
*** TODO audiotools-config
**** TODO test_options
**** TODO test_errors
*** DONE cd2track
**** DONE test_options
**** DONE test_errors
*** DONE cd2xmcd
**** DONE test_options
**** DONE test_errors
*** TODO cdinfo
**** TODO test_options
**** TODO test_errors
*** TODO cdplay
**** TODO test_options
**** TODO test_errors
*** DONE coverdump
**** DONE test_options
**** DONE test_errors
*** DONE dvdainfo
**** DONE test_errors
*** DONE dvda2track
**** DONE test_errors
*** DONE dvda2xmcd
**** DONE test_errors
*** DONE track2track
**** DONE test_options
**** DONE test_errors
*** DONE track2xmcd
**** DONE test_options
**** DONE test_errors
*** DONE trackcat
**** DONE test_options
*** DONE trackcmp
**** DONE test_options
*** TODO trackinfo
**** TODO test_options
**** TODO test_errors
*** DONE tracklength
*** DONE tracklint
*** TODO trackplay
**** TODO test_options
**** TODO test_errors
*** DONE trackrename
**** DONE test_options
**** DONE test_errors
*** DONE tracksplit
**** DONE test_options
**** DONE test_errors
*** TODO tracktag
**** DONE test_options
**** TODO test_errors
*** TODO trackverify
**** TODO test_options
**** TODO test_errors
** DONE Split tests into multiple files
* TODO Handle write errors more gracefully
Just as the BitstreamReader uses an exception mechanism to detect
and handle read errors, the BitstreamWriter should use a similar
mechanism to detect write errors and bubble-up a Python exception.
The problem is that invalid writes are difficult to unit test.
With a reader, one can simply truncate a valid file.
It's harder to constrict a writer to only have X number of bytes
available so that any errors can be checked.
** TODO Add try/etry support to BitstreamWriter
** DONE Update BitstreamWriter methods to raise exceptions
** TODO Update Python-based BitstreamWriter to catch C exceptions
** TODO Update encoders to catch C exceptions and raise Python exceptions
** TODO Unit test write errors
* TODO Verify metadata against reference implementations
Where feasible, try to ensure our metadata
matches what's read/written by known reference implementations.
** TODO FlacAudio
against metaflac
** TODO M4AAudio/ALACAudio
against taglib?
** TODO MP3Audio/MP2Audio
Against taglib, perhaps? Venerable id3lib doesn't work with UCS-2.
** TODO VorbisAudio
against vorbis-tools
** TODO WavPackAudio
against tablib?
* TODO Add lyrics metadata support
Supporting storing lyrics text in the audio files themselves
would be quite useful.
** TODO Add .lyrics field to MetaData
Analagous to the lengthy .comment field, most likely.
** TODO Add unit testing for .lyrics field
** TODO Find automated source for lyrics
Analagous to CDDB.
This will be challenging since online sources for lyrics are rare.
Unfortunately, expecting everyone to transcribe lyrics for songs
is unrealistic - even moreso than filling in song names
or scanning in covers by hand.
If it's too much work, there's little point in having it.
** TODO Add tool support for lyrics
** TODO Add unit testing to tools
* TODO Convert format reference to HTML
Not only would it be more accessible,
but I could better integrate examples and give it basic interactivity.
All of the diagrams and formulas must be kept as vector art
so that they'll remain crisp when scaled.
Unfortunately, Chrome doesn't do MathML and IE doesn't do SVG
which makes it non-viable right now.
* TODO Add a dvdaplay utility
** TODO Unify trackplay/cdplay/dvdaplay widgets into audiotools.ui
** TODO Unify non-Urwid player into audiotools.ui
** TODO Add man page
* TODO Make internal functions static
Encoders and decoders come with lots of helper functions.
These should be defined statically whenever possible
to avoid colliding with one another.
As a side effect, these function names can now be shortened.
(not applicable to FLAC and Ogg FLAC, which share a lot of functions)
** TODO decoders
- [X] src/decoders/alac.c
- [ ] src/decoders/aobpcm.c
- [ ] src/decoders/mlp.c
- [ ] src/decoders/ogg.c
- [ ] src/decoders/shn.c
- [ ] src/decoders/sine.c
- [ ] src/decoders/vorbis.c
- [X] src/decoders/wavpack.c
** TODO encoders
- [X] src/encoders/alac.c
- [ ] src/encoders/flac.c
- [ ] src/encoders/shn.c
- [X] src/encoders/wavpack.c
* TODO handle AIFF offset/block size in SSND chunk
* TODO Assimilate external codecs
More of a long-term plan than anything else.
It would be best to have as few external program
dependencies as possible
** TODO Add internal Monkey's Audio codec
This needs to be assimilated with a native decoder/encoder.
I've seen these out in the wild, but only rarely.
*** TODO Add Python-based Monkey's Audio decoder
*** TODO Document Monkey's Audio decoding
*** TODO Add C-based Monkey's Audio decoder
*** TODO Add Python-based Monkey's Audio encoder
*** TODO Document Monkey's Audio encoding
*** TODO Add C-based Monkey's Audio encoder
*** TODO Add Monkey's Audio-specific unit tests
*** TODO Test encoder/decoder against reference
*** TODO Restore AudioFile-compatible Python interface
** DONE Add context manager support
Having file-like objects work with "with" context managers
should hopefully make file handle management a bit simpler.
*** DONE BitstreamReader
Call .close() on internal stream,
eat any exception (like the "file" object does) and return a False value
**** DONE Add documentation
**** DONE Add unit tests
*** DONE BitstreamWriters
If no exception, call .flush() on internal stream and eat any exception.
Then call .close() on internal stream and eat any exception also.
Returns a False value.
**** DONE Add documentation
**** DONE Add unit tests
*** DONE PCMReaders
Call .close() and eat any exception (like the "file" object does).
- [X] aiff/AIFFReader
- [X] au/AuReader
- [X] audiotools/BufferedPCMReader
- [X] audiotools/CounterPCMReader
- [X] audiotools/LimitedPCMReader
- [X] audiotools/PCMCat
- [X] audiotools/PCMReader
- [X] audiotools/PCMReaderDeHead
- [X] audiotools/PCMReaderError
- [X] audiotools/PCMReaderHead
- [X] audiotools/PCMReaderProgress
- [X] audiotools/ReorderedPCMReader
- [X] decoders/ALACDecoder
- [X] decoders/DVDA_Title
- [X] decoders/FlacDecoder
- [X] decoders/MP3Decoder
- [X] decoders/OggFlacDecoder
- [X] decoders/OpusDecoder
- [X] decoders/SHNDecoder
- [X] decoders/SameSample
- [X] decoders/Sine_Mono
- [X] decoders/Sine_Simple
- [X] decoders/Sine_Stereo
- [X] decoders/TTADecoder
- [X] decoders/VorbisDecoder
- [X] decoders/WavPackDecoder
- [X] player/ThreadedPCMReader
- [X] py_decoders/ALACDecoder
- [X] py_decoders/FlacDecoder
- [X] py_decoders/SHNDecoder
- [X] py_decoders/TTADecoder
- [X] py_decoders/WavPackDecoder
- [X] test/EXACT_RANDOM_PCM_Reader
- [X] test/Join_Reader
- [X] test/MD5_Reader
- [X] test/RANDOM_PCM_Reader
- [X] test/Variable_Reader
- [X] test_formats/CLOSE_PCM_Reader
- [X] test_formats/ERROR_PCM_Reader
- [X] test_streams/FrameListReader
- [X] test_streams/MD5Reader
- [X] test_streams/Raw
- [X] test_streams/Simple_Sine
- [X] test_streams/WastedBPS16
- [X] wav/WaveReader
**** DONE Add documentation
**** DONE Add unit tests
* TODO Finish version 3.2
** TODO Add better metadata merge strategies
These could be used by trackcat and others to combine MetaData objects
in a useful way.
*** TODO Add metadata1.intersection(metadata2) -> metadata3 method
metadata3 contains fields that are in both metadata1 and metadata2
and contain the same values
if both metadata objects are the same type, returns metadata in that type
and optimize the merge to handle low-level metadata fields
otherwise returns a generic MetaData object
**** DONE Update metadata implementations
- [X] MetaData
- [X] ApeTag
- [X] FlacMetaData
- [X] OggFlacMetaData
- [X] ID3v22Comment
- [X] ID3v23Comment
- [X] ID3v24Comment
- [X] ID3CommentPair
- [X] ID3v1Comment
- [X] M4A_META_Atom
- [X] VorbisComment
**** DONE Add unit tests
These should check that foreign fields are merged correctly,
if applicable.
- [X] MetaData
- [X] ApeTag
- [X] FlacMetaData
- [X] ID3v22Comment
- [X] ID3v23Comment
- [X] ID3v24Comment
- [X] ID3v1Comment
- [X] M4A_META_Atom
- [X] VorbisComment
**** DONE Update documentation
*** TODO Update trackcat to use .intersection() method
**** TODO Add unit tests
** TODO Handle pre-gaps that contain audio data
*** DONE Update cd2track
If pre-gap is present, check it for data.
If data is present, dump data to a "track 0" file
with as much metadata as possible.
If data is not present, skip it.
**** DONE Add unit tests
*** TODO Update track2cd
If pre-gap is present, check for a "track 0" file of the same length.
If track is present, prepend is to stream before writing to disc.
If track is not present, prepend empty data to disc.
**** TODO Add unit tests
*** DONE Update tracksplit
If pre-gap is present, check it for data.
If data is present, dump data to a "track 0" file
with as much metadata as possible.
If data is not present, skip it.
**** DONE Add unit tests
*** DONE Update trackcat
If pre-gap is present, check for a "track 0" file of the same length.
If track is present, prepend is to stream before writing to image.
If track is not present, prepend empty data to image.
**** DONE Add unit tests
** TODO Support MBID tags
These are basically direct MusicBrainz links rather than using
calculated disc IDs to perform lookups.
*** TODO Update MetaData formats to perform MBID lookups, if possible
- [ ] ApeTag
- [ ] FlacMetaData
- [ ] ID3CommentPair
- [ ] ID3v1Comment
- [ ] ID3v22Comment
- [ ] ID3v23Comment
- [ ] ID3v24Comment
- [ ] M4A
- [ ] VorbisComment
**** TODO Add unit tests
*** TODO Update musicbrainz module to handle MBID lookup
Given an ID, returns a list of MetaData objects
**** TODO Add unit tests
*** TODO Update utilities to support MBID lookup
Basically anything that takes tracks and performs a lookup may benefit.
- [ ] tracksplit
- [ ] trackcat
- [ ] track2track
- [ ] tracktag
**** TODO Add unit tests
** TODO Add pre-emphasis support
*** TODO Add de-emphasis filter to pcmconverters
**** TODO Add unit test
*** TODO Add pre-emphasis filter to pcmconverters
**** TODO Add unit test
*** TODO Update cd2track
If disc contains pre-emphasis, remove it during extraction
**** TODO Add unit test
*** TODO Update tracksplit
If CD image contains pre-emphasis, remove it during extraction
**** TODO Add unit test
*** TODO Update track2cd
If cuesheet is given and indicates pre-emphasis,
re-add it when creating disc image for writing
**** TODO Add unit test
*** TODO Update trackcat
If cuesheet is given an indicates pre-emphasis,
re-add it when concatenating files to image
**** TODO Add unit test
** TODO Add CTDB support
Need to figure out how the cuetools client interface actually works.
Then attempt to use it wherever AccurateRip is used, if possible.
** TODO Improve test coverage
- [X] set_metadata(None) to all formats
*** TODO Check repr on everything
Verifying the contents isn't important;
just make sure calling repr() doesn't throw an exception.
*** TODO audiotools/__init__
- [X] output_text
- [X] output_list
- [X] output_table
- [ ] threaded_transfer_framelist_data
- [ ] pcm_cmp
- [ ] pcm_frame_cmp
- [ ] resampled_frame_count
- [ ] read_sheet (IOError)
- [X] iter_first
- [X] iter_last
- [X] most_numerous (len(item_list) == 0)
- [X] most_numerous (all_differ)
- [ ] cddareader_metadata_lookup
- [ ] track_metadata_lookup
- [ ] sheet_metadata_lookup
- [ ] accuraterip_lookup (len(sorted_tracks) == 0)
**** TODO MetaData
- [ ] __delattr__
- [ ] empty_fields
- [ ] __unicode__
- [ ] delete_image
- [ ] clean
**** TODO AudioFile
- [ ] rich compare operators
**** DONE Sheet
- [X] converted
- [X] __eq__
- [X] track_numbers
- [X] track (KeyError)
- [X] pre_gap
- [X] track_offset
- [X] track_length
**** DONE SheetTrack
- [X] converted
- [X] indexes
- [X] index (KeyError)
- [X] __eq__
**** DONE SheetIndex
- [X] converted
- [X] __eq__
**** TODO PCMReaderHead
- [ ] check for negative pcm_frames
**** TODO PCMReaderDeHead
- [ ] truncation longer than entire stream
- [ ] read_closed
**** DONE ExecProgressQueue
*** DONE audiotools/accuraterip
- [X] match_offset
*** TODO audiotools/aiff
**** TODO AiffAudio
- [ ] verify
- [ ] clean (with metadata)
*** TODO audiotools/ape
**** TODO ApeTag
- [ ] get
- [ ] index
**** DONE ApeTaggedAudio
- [X] set_metadata(None)
- [X] set_metadata with cuesheet
- [X] delete_metadata with ReplayGain
- [X] delete_metadata with cuesheet
*** TODO audiotools/cue
- [ ] read_cuesheet_string (with ValueError)
**** DONE Track
- [X] filename
- [X] pre_emphasis
- [X] copy_permitted
**** TODO audiotools/cue/tokrules
- [ ] with illegal character
**** TODO audiotools/cue/yaccrules
- [X] with flags
- [ ] with syntax error
*** TODO audiotools/flac
**** DONE FlacMetaData
- [X] converted(None)
- [X] clean (multiple STREAMINFO)
- [X] clean (multiple VORBIS_COMMENT)
- [X] clean (multiple SEEKTABLE)
- [X] clean (multiple CUESHEET)
- [X] raw_info()
check with all metadata blocks
**** DONE Flac_VORBISCOMMENT
- [X] converted(Flac_VORBISCOMMENT)
should return newly created object
**** TODO Flac_Cuesheet
- [ ] track_length
- [ ] get_metadata with catalog
- [ ] converted with padding
**** TODO Flac_Cuesheet_track
- [ ] filename
**** TODO Flac_PICTURE
- [ ] setattr(type, ???)
- [ ] type_string
**** TODO FlacAudio
- [X] set_metadata(None)
- [ ] set_metadata with channel mask in old comment
- [X] get_cuesheet() -> None
- [ ] from_pcm with UnsupportedChannelMask
- [ ] has_foreign_wave_chunks() -> False
- [ ] wave_header_footer() without chunks
- [ ] has_foreign_aiff_chunks() -> False
- [ ] aiff_header_footer() without chunks
- [ ] convert() to WaveContainer
- [ ] convert() to AiffContainer
- [ ] delete_replay_gain() without VORBIS_COMMENT
- [ ] clean on < 128 byte file
**** DONE FLAC_Data_Chunk
is this still in use?
**** DONE FLAC_SSND_Chunk
is this still in use?
**** DONE OggFlacMetaData
- [X] converted(None)
**** TODO OggFlacAudio
- [ ] from_pcm with UnsupportedChannelMask
*** TODO audiotools/freedb
- [ ] xmcd_metadata without album artist
- [ ] xmcd_metadata without track artist
*** TODO audiotools/id3
- [ ] read_id3v2_comment (invalid header)
- [ ] read_id3v2_comment (unsupported version)
- [ ] skip_id3v2_comment (unsupported version)
- [ ] skip_id3v2_comment (IOError)
- [ ] total_id3v2_comments (unsupported version)
- [ ] total_id3v2_comments (IOError)
**** TODO ID3v22Comment
- [X] raw_info
- [ ] parse
- [ ] build
- [ ] size
- [ ] clean
**** TODO ID3v22_T__Frame
- [ ] number() -> 0, no total
- [ ] number() -> not numerical type
- [ ] total() -> not numerical type
**** TODO ID3v22_TXX_Frame
**** TODO ID3v22_W__Frame
**** TODO ID3v22_WXX_Frame
**** TODO ID3v22_COM_Frame
- [ ] clean
**** TODO ID3v22_PIC_Frame
- [ ] invalid image from data
- [ ] type_string
- [ ] getattr -> AttributeError
- [ ] setattr(type, ???)
- [ ] setattr(desription, ???)
- [ ] clean
**** TODO ID3v22Comment
- [ ] copy
- [ ] parse (invalid header)
- [ ] parse (invalid major version)
- [ ] parse (invalid minor version)
- [ ] parse (TXX, WXX, W??)
- [ ] delitem
- [ ] items
- [ ] getattr -> AttributeError
- [ ] delattr(track/alum_number) unslashed
- [ ] delattr unsupported field
- [X] converted(None)
**** TODO ID3v23_TXXX_Frame
**** TODO ID3v23_WXXX_Frame
**** TODO ID3v23_APIC_Frame
- [ ] __init__ invalid image
- [ ] getattr -> AttributeError
- [ ] setattr(pic_type)
- [ ] setattr(description)
- [ ] setattr(mime_type)
- [ ] clean
**** TODO ID3v23Comment
- [ ] parse invalid ID3 header
- [ ] invalid major version
- [ ] invalid minor version
- [ ] parse (WXXX, W???)
**** TODO ID3v24_TXXX_Frame
- [ ] __unicode__
- [ ] parse
**** TODO ID3v24_APIC_Frame
- [ ] setattr(type)
- [ ] setattr(description)
- [ ] setattr(mime_type)
- [ ] clean
**** TODO ID3v24_WXXX_Frame
- [ ] parse
**** TODO ID3v24_COMM_Frame
- [ ] clean
**** TODO ID3v24Comment
- [ ] parse (invalid ID3 header)
- [ ] parse (invalid major version)
- [ ] parse (invalid minor version)
- [ ] parse (TXXX, WXXX, W???)
**** TODO ID3CommentPair
- [ ] init id3v1 is not None
- [X] converted(None)
- [ ] convert(ID3v2Comment)
- [X] raw_info
- [ ] images (id3v2 is None)
- [ ] clean
*** TODO audiotools/id3v1
**** TODO ID3v1Comment
- [ ] getattr -> AttributeError
- [ ] setattr(non field)
- [ ] delattr(non field)
- [X] converted(None)
- [ ] images
***** TODO parse
- [ ] track_name length != 30
- [ ] artist_name length != 30
- [ ] album_name length != 30
- [ ] year length != 4
- [ ] comment length != 28
- [ ] track_number length != 1
- [ ] genre length != 1
*** TODO audiotools/image
- [ ] rename classes without __s
- [ ] image_metrics -> InvalidImage
**** TODO __JPEG__
- [ ] parse -> IOError
**** TODO __PNG__
- [ ] parse -> InvalidPNG
- [ ] parse -> IOError
- [ ] parse -> grayscale
- [ ] parse -> invalid PLTE
- [ ] parse -> grayscale + alpha
**** TODO __BMP__
- [ ] parse -> IOError
- [ ] parse -> InvalidBMP
**** TODO __GIF__
- [ ] parse -> IOError
- [ ] parse -> InvalidGIF
**** TODO __TIFF__
- [ ] parse big-endian TIFF
- [ ] parse invalid magic number
*** TODO audiotools/m4a
- [ ] get_m4a_atom -> KeyError
- [ ] get_m4a_atom_offset -> KeyError
- [ ] get_m4a_atom_offset -> IOError/KeyError
- [ ] has_m4a_atom (if (length - 8) <= 0)
- [ ] has_m4a_atom -> IOError
**** TODO M4ATaggedAduio
- [ ] get_metadata -> KeyError if no meta
- [ ] update_metadata (generate moov)
- [ ] update_metadata (generate udta)
- [ ] update_metadata (generate meta)
- [X] set_metadata(None)
*** TODO audiotools/m4a_atoms
**** TODO M4A_Tree_Atom
- [ ] has_child -> False
- [ ] remove_child
- [ ] child_offset -> KeyError
**** TODO M4A_META_Atom
- [ ] getattr -> AttributeError
- [ ] setattr -> replace_data_atom
- [ ] delattr -> AttributeError
- [X] converted(None)
*** TODO audiotools/mp3
**** TODO MP3Audio
- [X] set_metadata(None)
- [ ] update_metadata (id3v2 not None, id3v1 is None)
- [ ] update_metadata (id3v2 None, id3v1 not None)
- [ ] update_metadata (id3v2 None, id3v1 None)
- [ ] clean (output_filename None, metadata None)
- [ ] clean (output_filename not None, metadata None)
**** TODO MP2Audio
- [ ] from_pcm (nonstandard sample rate)
*** TODO audiotools/opus
**** DONE OpusAudio
- [X] init (invalid Ogg magic number)
- [X] init (invalid Ogg version)
- [X] init (invalid Opus type)
- [X] init (invalid Opus version)
- [X] init (invalid Opus channels)
- [X] get_replay_gain
- [X] set_replay_gain
- [X] delete_replay_gain
*** TODO audiotools/shn
**** TODO ShortenAudio
- [ ] __init__ -> IOError
- [ ] has_foreign_wave_chunks -> True
- [ ] has_foreign_wave_chunks -> odd-sized wave chunks
- [ ] has_foreign_wave_chunks -> no foreign chunks found
- [ ] has_foreign_aiff_chunks -> True
- [ ] has_foreign_aiff_chunks -> odd-sized aiff chunks
- [ ] has_foreign_aiff_chunks -> no foreign chunks found
- [ ] from_pcm using external function
- [ ] from_pcm (len(footer) == 0)
- [ ] convert to wave container
- [ ] convert to aiff container
*** TODO audiotools/toc
- [ ] read_tocfile -> IOError
- [ ] read_tocfile_string -> SheetException
- [ ] write_tocfile
**** TODO TOCFile
- [ ] get_metadata (catalog not None, cd_text not None)
**** TODO TOCTrack
- [ ] get_metadata (isrc not None, cd_text not None)
- [X] filename
- [X] pre_emphasis
- [X] copy_permitted (not False)
**** TODO audiotools/toc/tokrules
- [ ] illegal character
**** TODO audiotools/toc/yaccrules
- [ ] syntax error
*** TODO audiotools/tta
**** TODO TrueAudio
- [ ] init -> invalid signature
- [ ] init -> invalid format
- [ ] from_pcm -> IOError to EncodingError
- [ ] from_pcm -> frame count mismatch
- [X] set_metadata(None)
- [X] cuesheet in old metadata
- [X] cuesheet in new metadata
- [ ] get_cuesheet -> CueException
- [X] set_cuesheet(None)
- [ ] clean when metadata is None
*** TODO audiotools/vorbis
**** TODO VorbisAudio
- [X] init -> invalid Ogg magic number
- [X] init -> invalid Ogg version
- [X] init -> invalid Vorbis type
- [X] init -> invalid Vorbis header
- [X] init -> invalid Vorbis version
- [X] init -> invalid Vorbis framing bit
**** TODO VorbisChannelMask
- [ ] channels
*** TODO audiotools/vorbiscomment
**** TODO VorbisComment
- [ ] values
- [ ] __contains__
- [ ] getattr(non-MetaData attrib)
- [ ] delattr(non-MetaData attrib)
- [X] converted(None)
- [ ] converted(FlacMetaData without VORBISCOMMENT)
- [ ] clean(track_total/album_total with leading 0s)
*** TODO audiotools/wav
- [X] wave_header -> total size too large
**** TODO RIFF_Chunk
- [ ] handle odd sized chunks
**** TODO WaveReader
- [ ] init -> file too small
- [ ] init -> invalid RIFF
- [ ] init -> invalid WAVE
- [ ] init -> chunk header too small
- [ ] init -> invalid chunk ID
- [ ] init -> data chunk before fmt chunk
- [ ] init -> no audio chunks
- [ ] init -> no data chunk
- [ ] read -> data chunk too small
**** TODO WaveAudio
- [X] from_pcm -> total_pcm_frames too large
- [X] from_pcm -> total_pcm_frames mismatch
- [ ] track_name(format=None)
- [ ] verify -> not enough data chunk
- [ ] clean -> non audio chunk
*** TODO audiotools/wavpack
**** TODO WavPackAudio
- [ ] blocks -> blocks_iter -> non wvpk block header
- [ ] __read_info__ -> non wvpk block ID
- [ ] __read_info__ -> nonstandard sample rate
- [ ] __read_info__ -> no channel info sub block
- [X] from_pcm -> total_pcm_frames mismatch
- [ ] fmt_chunk
- [ ] get_cuesheet -> CueException
- [X] set_cuesheet(None)
*** TODO audiotools/py_decoders/flac
**** TODO FlacDecoder
- [ ] init -> invalid FLAC file
- [ ] read -> MD5 checksum mismatch
- [ ] read -> invalid channel assignment
- [ ] read -> CRC16 mismatch
- [ ] read_frame_header -> invalid sync code
- [ ] read_frame_header -> invalid sample rate
- [ ] read_frame_header -> invalid bits-per-sample
- [ ] read_frame_header -> CRC8 mismatch
- [ ] read_subframe_header -> invalid subframe type
- [ ] read_fixed_subframe -> invalid order
- [ ] read_residual_partition(coding 0) -> escape code
- [ ] read_residual_partition(coding 1) -> escape code
- [ ] close
*** TODO audiotools/py_decoders/shn
**** TODO SHNDecoder
- [ ] init -> unsupported file type
- [ ] init -> non-audio RIFF chunks
- [ ] init -> AIFF chunks
- [ ] read_header -> invalid magic number
- [ ] read_header -> unsupported version
- [ ] read -> QLPC options
*** TODO audiotools/py_decoders/tta
**** TODO TTADecoder
- [ ] init -> CRC mismatch in header
- [ ] init -> CRC mismatch in seektable
- [ ] init -> CRC mismatch in frame
- [ ] close
*** TODO audiotools/py_decoders/wavpack
**** TODO WavPackDecoder
- [ ] init -> nonstandard sample rate
- [ ] read -> MD5 mismatch at end of stream
- [ ] read -> IOError/ValueError
- [ ] close
**** TODO Block_Header
- [ ] invalid block ID
**** TODO Sub_Block
- [ ] total_size large
**** TODO read_block
- [ ] weights before terms
- [ ] samples before terms
- [ ] invalid samples byte count
- [ ] bitstream before entropy vars
- [ ] decorrelation weights not found
- [ ] decorrelation samples not found
- [ ] bitstream not found
- [ ] CRC mismatch
**** TODO read_decorrelation_terms
- [ ] invalid passes count
- [ ] invalid term
**** TODO read_decorrelation_weights
- [ ] invalid weight count
**** TODO read_decorrelation_samples
- [ ] sub_block_size < 8, two channels
- [ ] sub_block_size < 8, one channel
- [ ] invalid term
*** TODO audiotools/py_encoders/alac
- [ ] encode_frame -> residual overflow
- [ ] tukey_window -> n > window2
- [ ] encode_residuals -> residual overflow
*** TODO audiotools/py_encoders/flac
- [ ] write_utf8 (value > 127)
- [ ] tukey_window (n > window2)
- [ ] compute_lpc_coefficients (estimate_best_order)
- [ ] estimate_best_order
*** TODO audiotools/py_encoders/shn
**** TODO encode_shn
- [X] all zeroes
- [ ] write footer
*** TODO audiotools/py_encoders/wavpack
**** TODO encode_wavpack
- [ ] write wave footer
**** TODO write_block
- [ ] all samples are 0
** TODO Cleanup chunk-based interface (again)
There needs to be a single-pass approach to encoding chunked files
that doesn't involve pulling out the chunk data ahead of time.
Perhaps a simple .to_wave(), .from_wave() approach
which returns a whole .wav file as a file stream
would be easiest.
** TODO Support building cue sheets from discs
Find some way of grabbing the index points from a disc
so cuesheets can be populated.
** TODO Cleanup AAC support
Although the fdk-aac library doesn't have a compatible license,
there must be *some* way to support AAC without the nasty
hacks in place now.
** TODO Improve utility test coverage
*** TODO Add some basic tests to ensure they still works
- [ ] cdinfo
- [ ] cdplay
- [ ] trackplay
- [ ] trackverify