1# -*- Mode: Org -*- 2* Previous Issues 3** DONE Fix WAVE/MP3 formats to support MP3 audio in a WAVE container 4 Instead of WaveAudio generating a nasty "compression not supported" error, 5 its is_type() classmethod should return False. 6 And, MP3Audio's is_type() classmethod should check for MP3 compressed 7 RIFF WAVE containers. 8 This isn't likely to mess up decoding, but may confuse ID3 tagging. 9** DONE Allow file template to be specified on the command line 10 When making new files with track2track, cd2track, etc. 11** DONE Update the website with the latest documentation 12** DONE Allow a unified %(album_track_number)s file template field 13 If there's no album number, it's simply 2 digits of track number. 14 Otherwise, it's a combination of the two fields. 15 For example, album_number = 2 and track_number = 13 results in 16 "213" for a value. 17** DONE Update trackcat to take a cuesheet argument when outputting FLACs 18 Thus, one can perform: 19 trackcat --cuesheet=file.cue file1.wav file2.wav file3.wav -t flac -o cd.flac 20 which will embed "file.cue" into "cd.flac" using metaflac. 21 Though no other format I'm aware of supports this kind of cuesheet handling, 22 being able to easily build solid disc images of a single FLAC file 23 is much of the reason for trackcat/tracksplit. 24** DONE Don't remove undone tracklint entries from its undo DB 25 Since its checksum will change anyway and no longer match, 26 explicitly removing the entry is no longer necessary 27** DONE Support FLAC padding 28 If changes to FLAC metadata are small enough, write over the 29 padding (if present) rather than rewrite the whole file - like metaflac. 30 This approach should speed up tagging considerably. 31** DONE Fix image support in ID3v2 32 Very large images can take a very long time to load. 33** DONE Fix programs to key on album number and track number 34 Certain programs, such as trackcmp, work on tracks across two directories 35 and key on track number to determine which to compare to which. 36 These need to be updated to use both track number and album number. 37** DONE Adjust wave conversions to use album number, if present 38 For example, converting track_number 15 and album_number 2 to WAVE 39 should make a file "track215.cdda.wav" which then properly converts 40 back to track_number 15 and album_number 2 if read. 41** DONE Improve XMCD handling 42 Support for XMCD files often breaks down if one or more tracks 43 are missing. 44 In some cases, there's no fix to be had (track2xmcd) 45 but in most instances it should be made to work correctly. 46** DONE Perform type inference wherever possible 47 Anything with a single output file (trackcat and record2track) 48 should be able to infer its output type from the track suffix, if possible. 49** DONE Add "comment" field support to all metadata types 50 Don't forget to add unit tests for comment field. 51*** TODO Sort "comment" fields correctly across all metadata types 52*** TODO Add --comment support to tracktag 53** DONE Fix ID3v2 image support to handle Unicode descriptions 54 The current implementation falls down on UTF-16 input, 55 but I should have a solution from the COMM frame handler. 56** DONE Limit ID3v2.2/2.3 to UCS-2 encoding 57 The current implementation treats UCS-2 the same as UTF-16. 58 This needs to be fixed so that really high unicode characters 59 (above U+FFFF) are replaced with something within spec. 60** DONE Unify ID3v2 frame handling 61 In the beginning, there were text frames and Everything Else. 62 Text frames were unicode strings, 63 and Everything Else was a binary string of whatever. 64 Now that ID3 is cluttered with APIC frames and COMM frames that need 65 special treatment, ID3v2 needs an overhaul to more resemble FlacMetaData. 66*** DONE Ensure unknown frames are displayed correctly 67 Anything that's not text, images or comments should get some sort 68 of proper display instead of a Python object string. 69** DONE Add app testing to the unit test suite 70 Though not everything is unit-testable 71 (such as the CD handling programs or anything X11) 72 a lot of the batch programs are to some degree: 73- [X] coverdump 74- [X] track2track 75- [X] trackcat 76- [X] trackcmp 77- [X] tracklength 78- [X] tracklint 79- [X] trackrename 80- [X] tracksplit 81- [X] tracktag 82** DONE Add verbosity levels to programs 83 Every batch program should support a -V --verbose flag 84 with options for "silence","normal" (the default) and "debug". 85 Silence shuts off everything but error messages. 86 Normal is standard output behavior. 87 Debug for additional debugging output. 88- [X] cd2track 89- [X] cd2xmcd 90- [X] coverdump 91- [X] record2track 92- [X] track2cd (this will need to forward verbosity to cdrecord) 93- [X] track2track 94- [X] track2xmcd 95- [X] trackcmp 96- [X] trackrename 97- [X] tracksplit 98- [X] tracktag 99- [X] tracklint 100** DONE Add compression percentage display to trackinfo 101 Though not massively useful, it'd be neat to see just how 102 compressed audio tracks are, as a percentage of their original size. 103** DONE Add support for W??? frames to ID3v2 104 The various W??? frames are really just URLs and don't need to 105 be displayed as hex-encoded blobs. 106** DONE Add CUE/TOC support to track2cd 107 It should be possible to burn a selection of tracks, or a disc image, 108 from a cuesheet with all its indexes/ISRC/catalog data intact 109 by passing --cue to track2cd. 110** DONE Unify CUE/TOC support 111 Cuesheets and cdrdao TOC files are largely interchangeable. 112 They both feature a listing of track offsets and, optionally, 113 CD-TEXT data, ISRCs and so on. 114 These formats should be unified such that any program will 115 handle them both automatically. 116- [X] tracksplit 117- [X] trackcat 118- [X] tracktag 119*** DONE Update docs to mention CUE/TOC interchangeability 120- [X] tracksplit 121- [X] trackcat 122- [X] tracktag 123*** DONE Support cuesheet from FlacMetaData directly 124 Since we're parsing CUE/TOC files anyway, this data can be used 125 to build FLAC CUESHEET blocks directly instead of punting 126 this task to metaflac. 127*** DONE Add unit tests for TOC/CUE files, as well as embedded FLAC cuesheets 128** DONE Update copyright text for 2009 129** DONE Preserve metadata when using trackcat 130 Any fields shared by all tracks should be merged into metadata 131 for the newly combined track. 132** DONE Don't route data though WAVE files unless necessary 133 Currently, track2track routes through WAVE if both ends happen to 134 support foreign RIFF chunks, whether the files have such chunks or not. 135 This behavior needs to be modified such that only source files 136 which actually have foreign chunks, and a target format that supports them, 137 results in a pass through RIFF WAVE. 138** DONE Convert editxmcd to PyGTK 139 Although the dialog(1)-based version works in terminals and is curses-based, 140 it's extremely hokey, error-prone and doesn't support any cut & paste. 141 This needs to be reimplemented in PyGTK (since coverview already uses it) 142 and made into a stable app someone would want to use. 143*** DONE Update XMCD support 144 The current handling of XMCD files treats them only as very primative 145 AlbumMetaData implementations. This must be updated into something 146 round-trippable if editxmcd is to be modernized. 147**** DONE Add XMCD unit tests 148**** DONE Update XMCD API documentation 149** DONE Require Python 2.5 150 Since Python 2.4 is in bugfix-only mode and barely supported, 151 it's best to move the minimum version to Python 2.5 or better 152 (which has already been superceded by Python 2.6). 153 This reduces the amount of Python versions to test on 154 and allows the use of more modern Python features which 155 makes the code less clunky. 156*** TODO Update documentation to mention Python 2.5 requirement. 157** DONE Expand WavPack's APEv2 tag coverage 158 WavPack's official specification defines APEv2 tags such as 159 "Cuesheet" and "Cover Art" which the APEv2 standard does not. 160 It would be helpful to make WavPack's APEv2 tags a superset of regular APEv2. 161*** DONE Add image support to WavePackAPEv2 162*** DONE Add cuesheet support to WavePackAPEv2 163** DONE Build unified cuesheet interface 164 Once both FLAC and WavPack support embedded cuesheets, 165 there will need to be a unified interface to support them. 166 I expect this will be a simple pair of get_cuesheet/set_cuesheet 167 methods, probably attached to the AudioFiles themselves 168 rather than to MetaData objects. 169*** DONE Alter FLAC-specific cuesheet documentation to be more general 170*** DONE Ensure cuesheets are transferred properly when transcoding 171*** DONE Update trackcat to use the interface 172*** DONE Update tracksplit to use the interface 173*** DONE Update track2cd to use the interface 174*** DONE Document cuesheet interface 175*** DONE Add unit tests for embedded cuesheets across all formats 176*** DONE Add cuesheet import option to tracktag 177 This can also use the --cue flag, 178 for consistency with other image-handling programs like tracksplit. 179 If given with a single, album-length track, --cue will import a cuesheet. 180 If given with multiple tracks or a single track that's too short, 181 --cue will function like --xmcd and act as a metadata source. 182*** DONE Update track2xmcd to support getting an XMCD file from CD image 183** DONE Convert to Muspack SV8 184 Now that Musepack SV8 is finalized, it should be the new default. 185 The old SV7 command-line tools aren't well supported and don't 186 seem to work outside of x86 platforms. 187 SV7 streams are, in theory, backwards compatible so switching 188 shouldn't be a problem. 189** DONE Update coverview to look more standard 190 It's currently a haphazard assortment of widgets 191 rather than anything like a proper GTK app. 192 It should be tweaked to look better. 193** DONE Improve transcoding robustness 194 Just about all of the to_pcm() and from_pcm() methods expect 195 that their subprocess calls will work as expected. 196 Though rare in practice, these need to be checked in case 197 the child processes fail for any reason. 198*** DONE Check for invalid input/output files/permissions errors 199 If an output file can't be read/written to for some reason 200 (invalid permissions, etc.) generate a proper error message 201 instead of throwing ugly IOExceptions or confusing errors. 202- [X] cd2track 203- [X] cd2xmcd 204- [X] coverdump 205- [X] editxmcd 206- [X] record2track 207- [X] track2cd 208- [X] track2track 209- [X] track2xmcd 210- [X] trackcat 211- [X] trackcmp 212- [X] trackinfo 213- [X] tracklength 214- [X] tracklint 215- [X] trackplay 216- [X] trackrename 217- [X] tracksplit 218- [X] tracktag 219** DONE Make text output consistent 220 Currently, command-line programs generate output using a 221 selection of scattered print statements - often accompanied by 222 if blocks when verbosity is indicated - and haphazardly 223 filtered through unicode. 224 This should be replaced by a unified message system similar 225 to Python's built-in logging module which can abstract away 226 these difficulties. 227*** DONE Convert tty output to gettext-based strings 228 This will not only make output messages more consistent across the tools, 229 but will also allow for foreign language translations in the future. 230- [X] cd2track 231- [X] cd2xmcd 232- [X] coverdump 233- [X] record2track 234- [X] track2cd 235- [X] track2track 236- [X] track2xmcd 237- [X] trackcat 238- [X] trackcmp 239- [X] trackinfo 240- [X] tracklength 241- [X] tracklint 242- [X] trackplay 243- [X] trackrename 244- [X] tracksplit 245- [X] tracktag 246**** DONE Convert output from audiotools module to gettext-based strings 247- [X] __aiff__.py 248- [X] __ape__.py 249- [X] __au__.py 250- [X] cue.py 251- [X] __flac__.py 252- [X] __freedb__.py 253- [X] __id3__.py 254- [X] __id3v1__.py 255- [X] __image__.py 256- [X] __init__.py 257- [X] __m4a__.py 258- [X] __mp3__.py 259- [X] __musepack__.py 260- [X] __speex__.py 261- [X] toc.py 262- [X] __vorbiscomment__.py 263- [X] __vorbis__.py 264- [X] __wavpack__.py 265- [X] __wav__.py 266*** DONE Add unit tests for tty output 267 All programs which generate output should be unit tested 268 so that all code paths are assured of printing the messages they're 269 supposed to print, at the streams they're supposed to print on, 270 and in the proper encoding settings. 271- [X] coverdump 272- [X] track2track 273- [X] track2xmcd 274- [X] trackcat 275- [X] trackcmp 276- [X] trackinfo 277- [X] tracklength 278- [X] tracklint 279- [X] trackrename 280- [X] tracksplit 281- [X] tracktag 282*** DONE Convert --help output to gettext-based strings 283*** DONE Convert GUI programs to gettext-based strings 284- [X] coverview 285- [X] editxmcd 286*** DONE Convert "Usage" output to gettext-based strings 287** DONE Update tracksplit's man page 288 It now supports more of track2track's options 289** DONE Support total tracks/total albums metadata fields 290*** DONE Add support for fields in the metadata tags 291- [X] Add support in Vorbis Comments 292- [X] Add support in ID3v2 293- [X] Add support in M4A 294- [X] Add support in APEv2 295*** DONE Add support in utilities 296- [X] Add support in tracktag 297- [X] Add support in cd2track 298- [X] Add support in tracksplit 299- [X] Add support in trackcat 300*** DONE Add unit tests 301*** DONE Add fields to --format output 302*** DONE Update man pages with fields information 303** DONE Integrate better MetaData merging 304 There's a few areas in which MetaData from multiple sources must 305 be merged in an intelligent manner, 306 such as where tracksplit takes a source track an XMCD file. 307 Now that a preliminary MetaData.merge() classmethod is in place, 308 this process must be integrated consistently. 309- [X] track2track 310- [X] trackrename 311- [X] tracksplit 312- [X] tracktag 313*** DONE Add unit tests for MetaData merging process 314- [X] track2track 315- [X] trackrename 316- [X] tracksplit 317- [X] tracktag 318** DONE Improve M4A metadata handling 319*** DONE Make M4A metadata updating less destructive 320 Like FLAC, not all fields need to be wiped out when overwriting 321 old metadata with new. 322*** DONE Add more M4A-specific unit tests 323** DONE Add more system information to audiotools-config 324 All BIN-referenced binaries should be accounted for. 325 Thumbnailing status and requirements should be shown. 326** DONE Add cdinfo utility 327 Analagous to trackinfo, but for an inserted CD. 328 This would be a better location for cd2xmcd's "-i" option. 329*** DONE Add cdinfo man page 330*** DONE Link cdinfo man page to other utility man pages 331** DONE Add manual page for audiotools.cfg 332 It'll be easier to check what the options are from a man page 333 rather than having to check the website or PDF doc. 334** DONE Convert vorbiscomment dependency to Python 335 This would remove the last app-based MetaData-setting utility 336 and may pave the way for adding cover art to Ogg Vorbis 337 (assuming I can find the standard for a secondary stream of image data) 338** DONE Add metadata deletion capability 339 It would be helpful to have the low-level capability of deleting 340 either part of a MetaData tag or the entire tag altogether. 341 For example, deleting the "track_name" field would delete 342 a Vorbis comment's "TITLE" field. 343 Or, deleting the MetaData from MP3 would remove all the ID3v2/ID3v1 tags. 344*** DONE Add delattr to ID3v1 345** DONE Integrate pyconstruct as a submodule 346** DONE Add undo capability to editxmcd 347** DONE Add --cue option to track2xmcd 348 One should be able to pull metadata from CD images 349 without having to embed the cuesheet. 350*** DONE Add unit tests for track2xmcd's --cue option 351*** DONE Update man page 352** DONE Group --help output more intelligently 353 For tools with a large number of options (such as track2track or tracktag) 354 the --help output is particularly jumbled. 355 Use more of optparse's features to make this output clearer. 356- [X] cd2track 357- [X] cd2xmcd 358- [X] track2track 359- [X] track2xmcd 360- [X] tracksplit 361- [X] tracktag 362** DONE Check for FLAC metadata chunk overflow 363 Although APEv2 and ID3 tags support very large objects (hundreds of MB), 364 FLAC metadata chunks have a maxmimum of about 16MB per chunk, 365 which may be hit accidentally. 366** DONE Fix or replace Python's built-in aifc module 367 The current implementation suffers from bugs. 368*** DONE Document AIFF better 369** DONE Add MusicBrainz support 370 It would be helpful to have external metadata support beyond FreeDB, 371 since FreeDB is very primitive. 372*** DONE Ensure that MusicBrainz is interchangeable with FreeDB/XMCD 373**** DONE Unify track2xmcd/track2mb, cd2xmcd/cd2mb 374 Based on preliminary testing, MusicBrainz's output is better than FreeDB's 375 but its album coverage is not as broad. 376 In addition, nobody wants to run their albums through two separate tools 377 in order to extract metadata for tagging. The best solution is 378 for tools to try both and output the one that's most complete. 379**** DONE Extend editxmcd to MusicBrainz XML 380 Although editxmcd was originally designed specifically for XMCD files 381 and MusicBrainz's XML format differs radically, no one should have to 382 know whether an album metadata file is one or the other. 383 Therefore, editxmcd should be extended with additional fields 384 to handle XML backend data if necessary. 385**** DONE Handle multiple Release entries with single Disc ID 386**** DONE Allow MusicBrainz XML output for new editxmcd files 387 FreeDB output should also be an option, however. 388*** DONE Add MusicBrainz protocol/format documentation 389*** DONE Add MusicBrainz-specific unit tests 390- [X] track2track 391- [X] track2xmcd 392- [X] trackrename 393- [X] tracksplit 394- [X] tracktag 395*** DONE Update --help text to indicate MusicBrainz compatibility 396- [X] cd2xmcd 397- [X] editxmcd 398- [X] track2track 399- [X] track2xmcd 400- [X] trackrename 401- [X] tracksplit 402- [X] tracktag 403*** DONE Update man pages to indiciate MusicBrainz compatibility 404- [X] cd2xmcd 405- [X] editxmcd 406- [X] track2track 407- [X] track2xmcd 408- [X] trackrename 409- [X] tracksplit 410- [X] tracktag 411*** DONE Update documentation with MusicBrainz config file fields 412*** DONE Ensure missing XML fields are handled correctly 413 The MusicBrainz XML spec allows most fields to be missing altogether 414 (such as <title>). editxmcd should add these fields in the proper place 415 if necessary. 416**** DONE Add unit tests for improperly reordered XML fields 417** DONE Ensure .glade files are found 418 Not all systems place Python data files in the same locations. 419** DONE Convert to_pcm()/from_pcm() to FrameList-based I/O 420 Passing specifically-sized blobs of binary data between conversion 421 routines worked well when those routines are little more than 422 subprocess black-boxes. However, this approach works less well 423 whenever actual sample values are required, or when processing is needed. 424 In those cases, going from integers to strings, converting the strings 425 back to integers for processing, then bouncing them into strings once 426 again becomes needless work. 427 A more sensible approach is to keep all data as FrameList-compatible 428 objects (stored as C-based lists of int32s behind-the-scenes) 429 and convert that data to/from strings only at the beginning and end 430 of processing. 431*** DONE Build C-based audiotools.pcm.FrameList object 432 This needs to closely match audiotools.FrameList's functionality 433 and combine all the PCM conversion features from audiotools.pcmreader 434**** DONE Integrate audiotools.pcm.FrameList with i_array structures 435**** DONE Make audiotools.pcm.FrameList into a standalone object 436 So standalone test codecs can use them, such as "flacenc" 437**** DONE Unit test audiotools.pcm.FrameList 438*** DONE Convert FLAC encoder/decoder to use FrameList objects 439 - [X] flacenc 440 - [X] audiotools.decoders.FlacDecoder 441 - [X] audiotools.encoders.encode_flac 442*** DONE Convert to_pcm()/from_pcm() routines to use FrameList objects 443 - [X] AAC 444 - [X] AIFF 445 - [X] Sun AU 446 - [X] FLAC 447 - [X] M4A 448 - [X] MP2 449 - [X] MP3 450 - [X] Ogg FLAC 451 - [X] Ogg Speex 452 - [X] WAVE 453 - [X] WavPack 454*** DONE Convert CDTrackReader/OffsetCDTrackReader to use FrameList objects 455*** DONE Convert PCMConverter to use FrameList objects 456*** DONE Convert ReplayGainReader to use FrameList objects 457*** DONE Ensure integrated FrameList passes all unit tests 458*** DONE Remove deprecated audiotools.FrameList object 459*** DONE Remove deprecated pcmstream.PCMStreamReader object 460*** DONE Convert pcmstream module to resample module 461*** DONE Avoid importing audiotools.pcm so often 462 Other C libraries often import audiotools.pcm via Python callbacks 463 This library importing should be cached when possible. 464 - [X] cdiomodule 465 - [X] pcmreader 466 - [X] replaygain 467 - [X] resample 468*** DONE Check for memory leaks 469*** DONE Add FrameList and FloatFrameList programming documentation 470*** DONE Remove .copy() method 471 Since FrameLists are now immutable, there's no need for it 472*** DONE Make pcm objects self-documenting 473 For example, their methods and functions should give useful info 474 when checked with "help()" 475** DONE Add native ReplayGain handling routines 476*** DONE Add native ReplayGain handling to FlacAudio/OggFlacAudio 477*** DONE Ensure add_replay_gain()'s exceptions are caught 478 Errors during calculation may raise ValueError, 479 which must be caught anywhere the function is called 480*** DONE Add ReplayGain unit tests 481*** DONE Ensure ReplayGain works properly on 8bps and 24bps output 482*** DONE Ensure ReplayGain is applied consistently 483 Although cd2track and tracksplit are guaranteed 484 to generate only one album at a time, track2track and tracktag are not. 485 If multiple albums are applied gain at once, 486 add_replay_gain must be called on an album-by-album basis 487 rather than on the entire set. 488*** DONE Double-check ReplayGainReader 489 Ensure its output is consistent with other implementations. 490** DONE Fix multi-channel audio handling 491 It's important that channel mapping information be preserved 492 when transcoding between sources with 3+ channels. 493 This likely means another flag for PCMReader so that 494 from_pcm() can build a file with the proper channel mask set. 495 However, it may also be necessary to build some sort of 496 channel reordering mechanism in the event that formats differ 497 on how channels are to be ordered in the file. 498*** Channel Counts and Ordering 499| Format | Maximum Channels | Ordering | 500|------------+------------------+------------------------| 501| AAC | 48 | stereo-only (via faac) | 502| AIFF | 2^16 | predefined | 503| Sun AU | 2^32 | mostly undefined | 504| FLAC | 8 | as WAVE | 505| M4A | 48 | as WAVE? | 506| MP2 | 2 | stereo-only | 507| MP3 | 2 | stereo-only | 508| Musepack | 2 | stereo-only | 509| Ogg FLAC | 8 | as WAVE | 510| Ogg Vorbis | 255 | predefined | 511| Ogg Speex | 2^32 | stereo-only | 512| RIFF WAVE | 2^16 | predefined | 513| WavPack | 16 | as WAVE | 514|------------+------------------+------------------------| 515*** DONE Fix AudioFile definitions to support channel_mask() 516 - [X] AACAudio 517 - [X] AiffAudio 518 - [X] AuAudio 519 - [X] FlacAudio 520 - [X] M4AAudio 521 - [X] MP2Audio 522 - [X] MP3Audio 523 - [X] OggFlacAudio 524 - [X] VorbisAudio 525 - [X] SpeexAudio 526 - [X] WaveAudio 527 - [X] WavPackAudio 528*** DONE Fix to_pcm() methods to support channel_mask 529 - [X] AACAudio 530 - [X] AiffAudio 531 - [X] AuAudio 532 - [X] FlacAudio 533 - [X] M4AAudio 534 - [X] MP2Audio 535 - [X] MP3Audio 536 - [X] OggFlacAudio 537 - [X] VorbisAudio 538 - [X] SpeexAudio 539 - [X] WaveAudio 540 - [X] WavPackAudio 541*** DONE Fix from_pcm() classmethods to support channel_mask 542 - [X] AACAudio 543 - [X] AiffAudio 544 - [X] AuAudio 545 - [X] FlacAudio 546 - [X] M4AAudio 547 - [X] MP2Audio 548 - [X] MP3Audio 549 - [X] OggFlacAudio 550 - [X] VorbisAudio 551 - [X] SpeexAudio 552 - [X] WaveAudio 553 - [X] WavPackAudio 554*** DONE Fix alternate PCMReaders to support channel_mask 555 - [X] BufferedPCMReader 556 - [X] PCMConverter 557 - [X] ReplayGainReader 558 - [X] CDTrackReader 559 - [X] OffsetCDTrackReader 560 - [X] PCMCat 561*** DONE Handle undefined channel masks in a sane way 562**** DONE Fix to_pcm() methods to output undefined ChannelMasks 563 If a format has not defined channel assignments for a given 564 channel count, its to_pcm() method should return undefined ChannelMasks. 565 - [X] AACAudio 566 - [X] AiffAudio 567 - [X] AuAudio 568 - [X] FlacAudio 569 - [X] M4AAudio 570 - [X] MP2Audio 571 - [X] MP3Audio 572 - [X] OggFlacAudio 573 - [X] VorbisAudio 574 - [X] SpeexAudio 575 - [X] WaveAudio 576 - [X] WavPackAudio 577**** DONE Fix from_pcm() classmethods to accept undefined ChannelMasks 578 So long as the number of channels is acceptable, 579 audio formats are free to place undefined ChannelMasks 580 in whatever arrangement they'd like. 581 - [X] AACAudio 582 - [X] AiffAudio 583 - [X] AuAudio 584 - [X] FlacAudio 585 - [X] M4AAudio 586 - [X] MP2Audio 587 - [X] MP3Audio 588 - [X] OggFlacAudio 589 - [X] VorbisAudio 590 - [X] SpeexAudio 591 - [X] WaveAudio 592 - [X] WavPackAudio 593*** DONE Unit test multichannel encoding and channel_mask handling 594**** DONE Ensure all AudioFile types have a working channel_mask() method 595 Even 2 channel audio should yield something valid. 596**** DONE Ensure all to_pcm() methods yield a matching channel_mask attribute 597**** DONE Ensure channel_mask is preserved between from_pcm(to_pcm()) calls 598**** DONE Ensure channel_mask is preserved between to_wave()/from_wave() calls 599**** DONE Ensure channels are actually stored in the proper order 600 This is less of an issue for .wav, .flac, .oga or .wv 601 which already store channels in RIFF WAVE order 602 and more of an issue for Ogg Vorbis and other formats that do not. 603**** DONE Ensure UnsupportedChannelMask is raised when necessary 604 This includes calls to from_pcm() and from_wave() 605*** DONE Ensure PCMReader.channel_mask is always an integer 606** DONE Fix the unit test error messages 607** DONE Make the programming documentation web-capable 608 It should render consistently with the regular Python reference docs 609 and be placed both in the source tree and on the website 610 for better accessability. 611*** DONE Document audiotools 612 - [X] AudioFile 613 - [X] BufferedPCMReader 614 - [X] ChannelMask 615 - [X] ExecQueue 616 - [X] Image 617 - [X] MetaData 618 - [X] PCMConverter 619 - [X] PCMReader 620 - [X] PCMCat 621 - [X] ReorderedPCMReader 622 - [X] ReplayGain 623 - [X] ReplayGainReader 624 - [X] Messenger 625 - [X] AlbumMetaData 626 - [X] CDTrackLog 627 - [X] CDDA 628 - [X] CDTrackReader 629 - [X] calculate_replay_gain 630 - [X] filename_to_type 631 - [X] find_glade_file 632 - [X] group_tracks 633 - [X] open 634 - [X] open_directory 635 - [X] open_files 636 - [X] pcm_cmp 637 - [X] pcm_split 638 - [X] read_metadata_file 639 - [X] read_sheet 640 - [X] stripped_pcm_cmp 641 - [X] transfer_data 642 - [X] transfer_framelist_data 643 - [X] BIN 644 - [X] TYPE_MAP 645 - [X] VERSION 646 - [X] AVAILABLE_TYPES 647*** DONE Document audiotools.pcm 648 - [X] FloatFrameList 649 - [X] FrameList 650 - [X] from_channels 651 - [X] from_float_channels 652 - [X] from_float_frames 653 - [X] from_frames 654 - [X] from_list 655*** DONE Document audiotools.resample 656 - [X] Resampler 657*** DONE Document audiotools.replaygain 658 - [X] ReplayGain 659*** DONE Document audiotools.cdio 660 - [X] CDDA 661 - [X] set_read_callback 662*** DONE Document audiotools.cue 663 - [X] Cuesheet 664 - [X] read_cuesheet 665 - [X] CueException 666*** DONE Document audiotools.toc 667 - [X] TOCFile 668 - [X] read_tocfile 669 - [X] TOCException 670** DONE Make reference documentation render consistently 671*** DONE Ensure documents render in letter and A4 size 672*** DONE Add Creative Commons licensing to source code and doc itself 673*** DONE Add internal PDF linkage 674 The file should have working bookmarks 675 and internal links so one can click directly to a chapter 676*** DONE Add new introduction 677*** DONE Basics 678**** DONE Hexadecimal 679**** DONE Endianness 680**** DONE Signed values 681 How to decode/encode signed integers should be properly explained 682**** DONE Character Encodings 683**** DONE PCM 684*** DONE .wav 685**** DONE the RIFF WAVE stream 686**** DONE the fmt chunk 687**** DONE the WAVEFORMATEXTENSIBLE fmt chunk 688**** DONE the data chunk 689**** DONE channel mapping 690*** DONE .aiff 691**** DONE the AIFF stream 692**** DONE the COMM chunk 693***** TODO 80 bit IEEE standard 754 floating point 694**** DONE the SSND chunk 695*** DONE .au 696**** DONE the AU stream 697**** DONE the AU header 698*** DONE .flac 699**** DONE the FLAC file stream 700**** DONE FLAC metadata 701***** DONE the PADDING metadata block 702***** DONE the APPLICATION metadata block 703***** DONE the SEEKTABLE metadata block 704***** DONE the VORBIS_COMMENT metadata block 705***** DONE the PICTURE metadata block 706***** DONE the CUESHEET metadata block 707**** DONE FLAC decoding 708***** DONE the CONSTANT subframe 709***** DONE the VERBATIM subframe 710***** DONE the FIXED subframe 711***** DONE the LPC subframe 712***** DONE the Residual 713****** DONE Rice Encoding 714***** DONE Channels 715***** DONE Wasted bits per sample 716**** DONE FLAC encoding 717***** DONE Metadata header 718***** DONE the STREAMINFO metadata block 719***** DONE Frame header 720***** DONE Channel assignment 721***** DONE Subframe header 722***** DONE the CONSTANT subframe 723***** DONE the VERBATIM subframe 724***** DONE the FIXED subframe 725***** DONE the LPC subframe 726****** DONE Windowing 727****** DONE Computing autocorrelation 728****** DONE LP coefficient calculation 729****** DONE Best order estimation 730****** DONE Best order exhaustive search 731****** DONE Quantizing coefficients 732****** DONE Calculation Residual 733***** DONE the Residual 734****** DONE Residual Values 735**** DONE the Checksums 736***** TODO CRC-8 737***** TODO CRC-16 738*** DONE .ape 739**** DONE the Monkey's Audio stream 740**** DONE the APE Descriptor 741**** DONE the APE Header 742**** DONE the APEv2 tag 743**** DONE the APEv2 tag header/footer 744**** DONE the APEv2 flags 745*** DONE .wv 746**** DONE the WavPack file stream 747**** DONE a WavPack block header 748**** DONE a WavPack sub-block header 749*** DONE .mp3 750**** DONE the MP3 file stream 751**** DONE an MPEG frame header 752***** DONE the Xing header 753**** DONE the ID3v1 tag 754***** DONE ID3v1 755***** DONE ID3v1.1 756**** DONE the ID3v2 tag 757***** DONE the ID3v2 stream 758***** DONE ID3v2.2 759****** DONE the ID3v2.2 Header 760****** DONE an ID3v2.2 Frame 761****** DONE ID3v2.2 Frame IDs 762****** DONE the PIC Frame 763***** DONE ID3v2.3 764****** DONE the ID3v2.3 Header 765****** DONE an ID3v2.3 Frame 766****** DONE ID3v2.3 Frame IDs 767****** DONE the APIC Frame 768***** DONE ID3v2.4 769****** DONE the ID3v2.4 Header 770****** DONE an ID3v2.4 Frame 771****** DONE ID3v2.4 Frame IDs 772****** DONE the APIC Frame 773*** DONE .ogg 774**** DONE the Ogg file stream 775**** DONE an Ogg Page 776**** DONE Ogg packets 777**** DONE the Identification packet 778**** DONE the Comment packet 779**** DONE Channel assignment 780*** DONE .spx 781**** DONE the Header packet 782**** DONE the Comment packet 783*** DONE .oga 784**** DONE the Ogg FLAC file stream 785**** DONE the STREAMINFO metadata packet 786**** DONE the Metadata packets 787*** DONE .m4a 788**** DONE the QuickTime file stream 789**** DONE a QuickTime atom 790**** DONE Container atoms 791**** DONE M4A atoms 792***** DONE the ftyp atom 793***** DONE the mvhd atom 794***** DONE the tkhd atom 795***** DONE the mdhd atom 796***** DONE the hdlr atom 797***** DONE the smhd atom 798***** DONE the dref atom 799***** DONE the stsd atom 800***** DONE the mp4a atom 801***** DONE the stts atom 802***** DONE the stsc atom 803***** DONE the stsz atom 804***** DONE the stco atom 805***** DONE the meta atom 806****** DONE the trkn sub-atom 807****** DONE the disk sub-atom 808*** DONE .mpc 809**** DONE Musepack SV7 810***** DONE the Musepack SV7 file stream 811***** DONE the Musepack SV7 header 812**** DONE Musepack SV8 813***** DONE the Musepack SV8 file stream 814***** DONE Nut-encoded values 815***** DONE the SH packet 816***** DONE the SE packet 817***** DONE the RG packet 818***** DONE the EI packet 819*** DONE FreeDB 820**** DONE Native Protocol 821***** DONE the Disc ID 822***** DONE Initial Greeting 823***** DONE Client-Server Handshake 824***** DONE Set Protocol Level 825***** DONE Query Database 826***** DONE Read XMCD Data 827***** DONE Close Connection 828**** DONE Web Protocol 829**** DONE XMCD 830*** DONE MusicBrainz 831**** DONE Searching Releases 832***** DONE The Disc ID 833***** DONE Server Query 834***** DONE Release XML 835**** DONE MusieBrainz XML 836*** DONE ReplayGain 837**** DONE Applying ReplayGain 838**** DONE Calculating ReplayGain 839***** DONE the Equal Loudness Filter 840 This should be re-documented to be closer to the actual implementation 841****** TODO the Yule Filter 842****** TODO the Buffer Filter 843****** TODO a Filtering Example 844***** DONE RMS Energy Blocks 845***** DONE Statistical Processing and Calibration 846*** DONE References 847*** DONE Remove old troff reference documentation 848*** DONE Add title and author to PDF documentation 849** DONE Ensure make(1) from doc/ directory builds both doc trees 850** DONE Seperate unreadable files from unknown files 851 Files we're unable to read should be handled differently 852 from files we're unable to understand. 853*** DONE Update audiotools.open() to raise IOErrors 854*** DONE Update audiotools.open_files() to handle IOErrors 855*** DONE Update audiotools.open_directory() to handle IOErrors 856*** DONE Update internal calls to open()/open_files() to handle IOErrors 857 - [X] __flac__.py 858 - [X] __m4a__.py 859 - [X] __mp3__.py 860 - [X] __vorbis__.py 861 - [X] __wavpack__.py 862 - [X] __wav__.py 863*** DONE Update tools which use open()/open_files() to handle IOErrors 864 - [X] coverdump 865 - [X] editxmcd 866 - [X] track2cd 867 - [X] track2track 868 - [X] track2xmcd 869 - [X] trackcat 870 - [X] trackcmp 871 - [X] trackinfo 872 - [X] tracklength 873 - [X] tracklint 874 - [X] trackplay 875 - [X] trackrename 876 - [X] tracksplit 877 - [X] tracktag 878*** DONE Add unit tests to demonstrate new behavior 879*** DONE Update programming documentation with new behavior 880** DONE Ensure embedded cuesheets aren't clobbered by adding more metadata 881** DONE Adjust %(album_track_number)s to accomodate more than 9 albums 882 For example, track 2 of 7, album 5 of 11 in format 883 "%(album_track_number)s - %(track_name)s.%(suffix)s should be: 884 "0502 - name.suffix" 885** DONE editxmcd's "New" command should work with embedded cuesheets 886 Selecting a single disc image with embedded cuesheets should 887 fill in the proper XMCD/MusicBrainz fields 888** DONE Ensure add_replay_gain used on hi-def tracks doesn't raise errors 889** DONE Add Shorten support 890 I don't expect people have a lot of shn files lying around 891 and nobody should be using it for new data 892 (though I'll add a rudimentary encoder for completeness' sake) 893 but it's interesting to document for historical reasons. 894*** DONE Build complete decoder 895 - [X] DIFF0 896 - [X] DIFF1 897 - [X] DIFF2 898 - [X] DIFF3 899 - [X] QUIT 900 - [X] BLOCKSIZE 901 - [X] BITSHIFT 902 - [X] QLPC 903 - [X] ZERO 904 - [X] VERBATIM 905 I'll likely limit support to Shorten version2/3 906 since generating older versions will be a challenge 907 and this format is obscure enough as it is. 908*** DONE Build partial encoder 909 - [X] DIFF0 910 - [X] DIFF1 911 - [X] DIFF2 912 - [X] QUIT 913 - [X] BLOCKSIZE 914 - [X] ZERO 915 - [X] VERBATIM 916**** DONE Convert partial encoder for standalone use 917 To ensure there aren't any memory leaks 918*** DONE Add ShortenAudio type to audiotools Python core 919*** DONE Add Shorten-specific unit tests 920*** DONE Document Shorten 921 - [X] Shorten data types 922 - [X] the Shorten file stream 923 - [X] the decoding process 924 - [X] the encoding process 925** DONE trackcmp should give exact PCM frame/byte of first mismatch 926*** DONE update unit tests to cover new behavior 927 - [X] test_trackcmp 928 - [X] test_trackcmp1 929 - [X] test_trackcmp2 930 - [X] test_trackcmp3 931 - [X] test_trackcmp4 932*** DONE update manual page to cover new behavior 933** DONE Add analyzers for built-in decoders 934 Analagous to flac(1)'s --analyze option, 935 this will be an .analyze_frame() method that returns a Python dict 936 of ints/lists/dicts containing frame data on each pass, 937 or None at the stream's end. 938 This will provide both an easier way to visualize the file's internals, 939 and also a debugging aid. 940*** DONE FlacDecoder 941*** DONE SHNDecoder 942*** DONE ALACDecoder 943** DONE Add more examples 944 A lot of handy new features aren't documented with examples and walkthroughs. 945 Examples to add include: 946- [X] a full multi-CD example, detailing the use of --album-number 947- [X] an image embedding walkthrough 948- [X] a CD image creation, splitting, burning example involving TOC/CUE files 949- [X] an XMCD walkthrough with fetching, editing and tagging 950** DONE Update documentation to cover concrete MetaData classes 951 - [X] ApeTag 952 - [X] FlacMetaData 953 - [X] ID3v1Comment 954 - [X] ID3v22Comment 955 - [X] ID3v23Comment 956 - [X] ID3v24Comment 957 - [X] ID3CommentPair 958 - [X] M4AMetaData 959 - [X] VorbisComment 960** DONE Ensure man pages install correctly on Mac OS X 961** DONE add a %(basename)s --format attribute 962 For example, given the path: "/foo/bar/01 - track name.mp3" 963 the %(basename)s attribute would be: "01 - track name" 964 allowing one to ignore its internal metadata entirely 965 and use original names. 966*** DONE Update AudioFile.track_name to support attribute 967*** DONE Update tools that call AudioFile.track_name 968 - [X] cd2track 969 - [X] track2track 970 - [X] trackrename 971 - [X] tracksplit 972*** DONE Update man pages for tools that call AudioFile.track_name 973 - [X] track2track.1 974 - [X] trackrename.1 975 - [X] audiotools.cfg.5 976*** DONE Add unit test support for new attribute 977*** DONE Add documentation for new field to programming reference 978*** DONE Add documentation for format strings to programming reference 979** DONE Update AudioFile.track_name classmethod 980 the previous behavior was a kludge cobbled together over time 981 Its new call method is: track_name(file_path, metadata, format) 982 so that track_number and album_number can be pulled from file_path 983 directly instead of passed in from outside. 984*** DONE Update tools to support new calling method 985 - [X] track2track 986 - [X] cd2track 987 - [X] trackrename 988 - [X] tracksplit 989*** DONE Update programming documentation 990*** DONE Add unit tests 991*** DONE Update old unit tests with new behavior 992*** DONE unit test suffix field 993** DONE Update Python code to support PEP 8 994 Following accepted Python style should make the code more 995 accessible and maintainable in the long run. 996 It's also a good opportunity to clean up and simplify code 997 without changing the actual API interface. 998*** DONE Update core modules 999**** DONE __aiff__.py 1000***** DONE adjust syntax 1001***** DONE add docstrings 1002 - [X] IEEE_Extended 1003 - [X] AiffException 1004 - [X] AiffAudio 1005 - [X] AiffAudio.bits_per_sample 1006 - [X] AiffAudio.channels 1007 - [X] AiffAudio.channel_mask 1008 - [X] AiffAudio.lossless 1009 - [X] AiffAudio.total_frames 1010 - [X] AiffAudio.sample_rate 1011 - [X] AiffAudio.is_type 1012 - [X] AiffAudio.chunks 1013 - [X] AiffAudio.comm_chunk 1014 - [X] AiffAudio.chunk_files 1015 - [X] AiffAudio.get_metadata 1016 - [X] AiffAudio.set_metadata 1017 - [X] AiffAudio.delete_metadata 1018 - [X] AiffAudio.to_pcm 1019 - [X] AiffAudio.from_pcm 1020 - [X] AIFFChannelMask 1021 - [X] AIFFChannelMask.channels 1022**** DONE __ape__.py 1023***** DONE adjust syntax 1024***** DONE add docstrings 1025 - [X] ApeTagItem 1026 - [X] ApeTagItem.build 1027 - [X] ApeTagItem.binary 1028 - [X] ApeTagItem.external 1029 - [X] ApeTagItem.string 1030 - [X] ApeTag 1031 - [X] ApeTag.converted 1032 - [X] ApeTag.merge 1033 - [X] ApeTag.supports_images 1034 - [X] ApeTag.add_image 1035 - [X] ApeTag.delete_image 1036 - [X] ApeTag.images 1037 - [X] ApeTag.read 1038 - [X] ApeTag.build 1039 - [X] ApeTaggedAudio 1040 - [X] ApeTaggedAudio.get_metadata 1041 - [X] ApeTaggedAudio.set_metadata 1042 - [X] ApeTaggedAudio.delete_metadata 1043 - [X] ApeAudio 1044 - [X] ApeAudio.is_type 1045 - [X] ApeAudio.lossless 1046 - [X] ApeAudio.supports_foreign_riff_chunks 1047 - [X] ApeAudio.has_foreign_riff_chunks 1048 - [X] ApeAudio.bits_per_sample 1049 - [X] ApeAudio.channels 1050 - [X] ApeAudio.total_frames 1051 - [X] ApeAudio.sample_rate 1052 - [X] ApeAudio.to_wave 1053 - [X] ApeAudio.from_wave 1054**** DONE __au__.py 1055***** DONE adjust syntax 1056***** DONE add docstrings 1057 - [X] AuAudio 1058 - [X] AuAudio.is_type 1059 - [X] AuAudio.lossless 1060 - [X] AuAudio.bits_per_sample 1061 - [X] AuAudio.channels 1062 - [X] AuAudio.channel_mask 1063 - [X] AuAudio.sample_rate 1064 - [X] AuAudio.total_frames 1065 - [X] AuAudio.to_pcm 1066 - [X] AuAudio.from_pcm 1067 - [X] AuAudio.track_name 1068**** DONE __flac__.py 1069***** DONE adjust syntax 1070***** DONE add docstrings 1071 - [ ] FlacException 1072 - [X] FlacMetaDataBlockTooLarge 1073 - [X] FlacMetaDataBlock 1074 - [X] FlacMetaDataBlock.build_block 1075 - [X] FlacMetaData 1076 - [X] FlacMetaData.converted 1077 - [X] FlacMetaData.merge 1078 - [X] FlacMetaData.add_image 1079 - [X] FlacMetaData.delete_image 1080 - [X] FlacMetaData.images 1081 - [X] FlacMetaData.metadata_blocks 1082 - [X] FlacMetaData.build 1083 - [X] FlacMetaData.supports_images 1084 - [X] FlacVorbisComment 1085 - [X] FlacVorbisComment.build_block 1086 - [X] FlacVorbisComment.converted 1087 - [X] FlacPictureComment 1088 - [X] FlacPictureComment.converted 1089 - [X] FlacPictureComment.type_string 1090 - [X] FlacPictureComment.build 1091 - [X] FlacPictureComment.build_block 1092 - [X] FlacCueSheet 1093 - [X] FlacCueSheet.build_block 1094 - [X] FlacCueSheet.converted 1095 - [X] FlacCueSheet.catalog 1096 - [X] FlacCueSheet.ISRCs 1097 - [X] FlacCueSheet.indexes 1098 - [X] FlacCueSheet.pcm_lengths 1099 - [X] FlacAudio 1100 - [X] FlacAudio.is_type 1101 - [X] FlacAudio.channel_mask 1102 - [X] FlacAudio.lossless 1103 - [X] FlacAudio.supports_foreign_riff_chunks 1104 - [X] FlacAudio.get_metadata 1105 - [X] FlacAudio.set_metadata 1106 - [X] FlacAudio.metadata_length 1107 - [X] FlacAudio.delete_metadata 1108 - [X] FlacAudio.set_cuesheet 1109 - [X] FlacAudio.get_cuesheet 1110 - [X] FlacAudio.to_pcm 1111 - [X] FlacAudio.from_pcm 1112 - [X] FlacAudio.has_foreign_riff_chunks 1113 - [X] FlacAudio.riff_wave_chunks 1114 - [X] FlacAudio.to_wave 1115 - [X] FlacAudio.from_wave 1116 - [X] FlacAudio.bits_per_sample 1117 - [X] FlacAudio.channels 1118 - [X] FlacAudio.total_frames 1119 - [X] FlacAudio.sample_rate 1120 - [X] FlacAudio.add_replay_gain 1121 - [X] FlacAudio.can_add_replay_gain 1122 - [X] FlacAudio.lossless_replay_gain 1123 - [X] FlacAudio.replay_gain 1124 - [X] FlacAudio.sub_pcm_tracks 1125 - [X] OggFlacAudio 1126 - [X] OggFlacAudio.is_type 1127 - [X] OggFlacAudio.get_metadata 1128 - [X] OggFlacAudio.set_metadata 1129 - [X] OggFlacAudio.metadata_length 1130 - [X] OggFlacAudio.to_pcm 1131 - [X] OggFlacAudio.from_pcm 1132 - [X] OggFlacAudio.sub_pcm_tracks 1133 - [X] OggFlacAudio.supports_foreign_riff_chunks 1134**** DONE __freedb__.py 1135***** DONE adjust syntax 1136***** DONE add docstrings 1137 - [X] XMCDException 1138 - [X] XMCD 1139 - [X] XMCD.key_digits 1140 - [X] XMCD.build 1141 - [X] XMCD.read 1142 - [X] XMCD.read_data 1143 - [X] XMCD.from_files 1144 - [X] XMCD.from_cuesheet 1145 - [X] XMCD.metadata 1146 - [X] DiscID 1147 - [X] DiscID.from_cdda 1148 - [X] DiscID.add 1149 - [X] DiscID.offsets 1150 - [X] DiscID.length 1151 - [X] DiscID.idsuffix 1152 - [X] DiscID.freedb_id 1153 - [X] DiscID.toxmcd 1154 - [X] FreeDBException 1155 - [X] FreeDB 1156 - [X] FreeDB.connect 1157 - [X] FreeDB.close 1158 - [X] FreeDB.write 1159 - [X] FreeDB.read 1160 - [X] FreeDB.query 1161 - [X] FreeDB.read_data 1162 - [X] FreeDBWeb 1163 - [X] FreeDBWeb.connect 1164 - [X] FreeDBWeb.close 1165 - [X] FreeDBWeb.write 1166 - [X] FreeDBWeb.read 1167 - [X] FreeDBWeb.query 1168 - [X] FreeDBWeb.read_data 1169 - [X] get_xmcd 1170**** DONE __id3__.py 1171***** DONE adjust syntax 1172***** DONE add docstrings 1173 - [X] UCS2Codec 1174 - [X] UCS2Codec.fix_char 1175 - [X] UCS2Codec.encode 1176 - [X] UCS2Codec.decode 1177 - [X] UnsupportedID3v2Version 1178 - [X] Syncsafe32 1179 - [X] UBInt24 1180 - [X] WidecharCStringAdapter 1181 - [X] UCS2CString 1182 - [X] UTF16CString 1183 - [X] UTF16BECString 1184 - [X] ID3v22Frame 1185 - [X] ID3v22Frame.build 1186 - [X] ID3v22Frame.parse 1187 - [X] ID3v22TextFrame 1188 - [X] ID3v22TextFrame.total 1189 - [X] ID3v22TextFrame.from_unicode 1190 - [X] ID3v22TextFrame.build 1191 - [X] ID3v22ComFrame 1192 - [X] ID3v22ComFrame.from_unicode 1193 - [X] ID3v22ComFrame.build 1194 - [X] ID3v22PicFrame 1195 - [X] ID3v22PicFrame.type_string 1196 - [X] ID3v22PicFrame.build 1197 - [X] ID3v22PicFrame.converted 1198 - [X] ID3v22Comment 1199 - [X] ID3v22Comment.add_image 1200 - [X] ID3v22Comment.delete_image 1201 - [X] ID3v22Comment.images 1202 - [X] ID3v22Comment.parse 1203 - [X] ID3v22Comment.converted 1204 - [X] ID3v22Comment.merge 1205 - [X] ID3v22Comment.build 1206 - [X] ID3v22Comment.skip 1207 - [X] ID3v22Comment.read_id3v2_comment 1208 - [X] ID3v23Frame 1209 - [X] ID3v23Frame.build 1210 - [X] ID3v23Frame.parse 1211 - [X] ID3v23TextFrame 1212 - [X] ID3v23TextFrame.total 1213 - [X] ID3v23TextFrame.from_unicode 1214 - [X] ID3v23TextFrame.build 1215 - [X] ID3v23PicFrame 1216 - [X] ID3v23PicFrame.build 1217 - [X] ID3v23PicFrame.converted 1218 - [X] ID3v23ComFrame 1219 - [X] ID3v23ComFrame.from_unicode 1220 - [X] ID3v23ComFrame.build 1221 - [X] ID3v23Comment 1222 - [X] ID3v23Comment.add_image 1223 - [X] ID3v23Comment.delete_image 1224 - [X] ID3v23Comment.images 1225 - [X] ID3v23Comment.build 1226 - [X] ID3v24Frame 1227 - [X] ID3v24Frame.build 1228 - [X] ID3v24Frame.parse 1229 - [X] ID3v24TextFrame 1230 - [X] ID3v24TextFrame.total 1231 - [X] ID3v24TextFrame.from_unicode 1232 - [X] ID3v24TextFrame.build 1233 - [X] ID3v24PicFrame 1234 - [X] ID3v24PicFrame.build 1235 - [X] ID3v24PicFrame.converted 1236 - [X] ID3v24ComFrame 1237 - [X] ID3v24ComFrame.from_unicode 1238 - [X] ID3v24ComFrame.build 1239 - [X] ID3v24Comment 1240 - [X] ID3v24Comment.build 1241 - [X] ID3CommentPair 1242 - [X] ID3CommentPair.converted 1243 - [X] ID3CommentPair.merge 1244 - [X] ID3CommentPair.images 1245 - [X] ID3CommentPair.add_image 1246 - [X] ID3CommentPair.delete_image 1247 - [X] ID3CommentPair.supports_images 1248**** DONE __id3v1__.py 1249***** DONE adjust syntax 1250***** DONE add docstrings 1251 - [X] ID3v1Comment 1252 - [X] ID3v1Comment.read_id3v1_comment 1253 - [X] ID3v1Comment.build_id3v1 1254 - [X] ID3v1Comment.supports_images 1255 - [X] ID3v1Comment.converted 1256 - [X] ID3v1Comment.build_tag 1257 - [X] ID3v1Comment.images 1258**** DONE __image__.py 1259***** DONE adjust syntax 1260***** DONE add docstrings 1261 - [X] image_metrics 1262 - [X] ImageMetrics 1263 - [X] InvalidImage 1264 - [X] InvalidJPEG 1265 - [X] InvalidPNG 1266 - [X] InvalidBMP 1267 - [X] InvalidGIF 1268 - [X] InvalidTIFF 1269 - [X] can_thumbnail 1270 - [X] thumbnail_formats 1271 - [X] thumbnail_image 1272**** DONE __init__.py 1273***** DONE adjust syntax 1274***** DONE add docstrings 1275 - [X] __init__.py 1276 - [X] RawConfigParser 1277 - [X] RawConfigParser.get_default 1278 - [X] RawConfigParser.getint_default 1279 - [X] find_glade_file 1280 - [X] OptionParser 1281 - [X] Messenger 1282 - [X] str_width 1283 - [X] VerboseMessenger 1284 - [X] VerboseMessenger.output 1285 - [X] VerboseMessenger.partial_output 1286 - [X] VerboseMessenger.new_row 1287 - [X] VerboseMessenger.blank_row 1288 - [X] VerboseMessenger.divider_row 1289 - [X] VerboseMessenger.output_column 1290 - [X] VerboseMessenger.output_rows 1291 - [X] VerboseMessenger.info 1292 - [X] VerboseMessenger.partial_info 1293 - [X] VerboseMessenger.error 1294 - [X] VerboseMessenger.warning 1295 - [X] VerboseMessenger.usage 1296 - [X] VerboseMessenger.filename 1297 - [X] VerboseMessenger.ansi 1298 - [X] VerboseMessenger.ansi_err 1299 - [X] SilentMessenger 1300 - [X] SilentMessenger.output 1301 - [X] SilentMessenger.partial_output 1302 - [X] SilentMessenger.warning 1303 - [X] SilentMessenger.info 1304 - [X] SilentMessenger.partial_info 1305 - [X] UnsupportedFile 1306 - [X] InvalidFile 1307 - [X] InvalidFormat 1308 - [X] EncodingError 1309 - [X] UnsupportedChannelMask 1310 - [X] UnsupportedChannelCount 1311 - [X] DecodingError 1312 - [X] open 1313 - [X] open_files 1314 - [X] open_directory 1315 - [X] UnknownAudioType 1316 - [X] AmbiguousAudioType 1317 - [X] filename_to_type 1318 - [X] ChannelMask 1319 - [X] ChannelMask.defined 1320 - [X] ChannelMask.undefined 1321 - [X] ChannelMask.channels 1322 - [X] ChannelMask.index 1323 - [X] ChannelMask.from_fields 1324 - [X] ChannelMask.from_channels 1325 - [X] PCMReader 1326 - [X] PCMReader.read 1327 - [X] PCMReader.close 1328 - [X] PCMReaderError 1329 - [X] PCMReaderError.read 1330 - [X] PCMReaderError.close 1331 - [X] ReorderedPCMReader 1332 - [X] ReorderedPCMReader.read 1333 - [X] ReorderedPCMReader.close 1334 - [X] transfer_data 1335 - [X] transfer_framelist_data 1336 - [X] threaded_transfer_framelist_data 1337 - [X] pcm_cmp 1338 - [X] stripped_pcm_cmp 1339 - [X] pcm_frame_cmp 1340 - [X] PCMCat 1341 - [X] PCMCat.read 1342 - [X] PCMCat.close 1343 - [X] BufferedPCMReader 1344 - [X] BufferedPCMReader.close 1345 - [X] BufferedPCMReader.read 1346 - [X] pcm_split 1347 - [X] PCMConverter 1348 - [X] PCMConverter.read 1349 - [X] PCMConverter.close 1350 - [X] applicable_replay_gain 1351 - [X] calculate_replay_gain 1352 - [X] InterruptableReader 1353 - [X] InterruptableReader.stop 1354 - [X] InterruptableReader.send_data 1355 - [X] InterruptableReader.read 1356 - [X] ignore_sigint 1357 - [X] make_dirs 1358 - [X] MetaData 1359 - [X] MetaData.converted 1360 - [X] MetaData.supports_images 1361 - [X] MetaData.images 1362 - [X] MetaData.front_covers 1363 - [X] MetaData.back_covers 1364 - [X] MetaData.leaflet_pages 1365 - [X] MetaData.media_images 1366 - [X] MetaData.other_images 1367 - [X] MetaData.add_image 1368 - [X] MetaData.delete_image 1369 - [X] MetaData.merge 1370 - [X] AlbumMetaData 1371 - [X] AlbumMetaData.metadata 1372 - [X] MetaDataFileException 1373 - [X] Image 1374 - [X] Image.suffix 1375 - [X] Image.type_string 1376 - [X] Image.new 1377 - [X] Image.thumbnail 1378 - [X] ReplayGain 1379 - [X] UnsupportedTracknameField 1380 - [X] AudioFile 1381 - [X] AudioFile.is_type 1382 - [X] AudioFile.bits_per_sample 1383 - [X] AudioFile.channels 1384 - [X] AudioFile.channel_mask 1385 - [X] AudioFile.lossless 1386 - [X] AudioFile.set_metadata 1387 - [X] AudioFile.get_metadata 1388 - [X] AudioFile.delete_metadata 1389 - [X] AudioFile.total_frames 1390 - [X] AudioFile.cd_frames 1391 - [X] AudioFile.sample_rate 1392 - [X] AudioFile.to_pcm 1393 - [X] AudioFile.from_pcm 1394 - [X] AudioFile.to_wave 1395 - [X] AudioFile.from_wave 1396 - [X] AudioFile.supports_foreign_riff_chunks 1397 - [X] AudioFile.has_foreign_riff_chunks 1398 - [X] AudioFile.track_number 1399 - [X] AudioFile.album_number 1400 - [X] AudioFile.track_name 1401 - [X] AudioFile.add_replay_gain 1402 - [X] AudioFile.can_add_replay_gain 1403 - [X] AudioFile.lossless_replay_gain 1404 - [X] AudioFile.replay_gain 1405 - [X] AudioFile.set_cuesheet 1406 - [X] AudioFile.get_cuesheet 1407 - [X] AudioFile.has_binaries 1408 - [X] DummyAudioFile 1409 - [X] DummyAudioFile.get_metadata 1410 - [X] DummyAudioFile.cd_frames 1411 - [X] DummyAudioFile.track_number 1412 - [X] DummyAudioFile.sample_rate 1413 - [X] DummyAudioFile.total_frames 1414 - [X] SheetException 1415 - [X] read_sheet 1416 - [X] parse_timestamp 1417 - [X] build_timestamp 1418 - [X] sheet_to_unicode 1419 - [X] at_a_time 1420 - [X] CDDA 1421 - [X] RawCDDA 1422 - [X] RawCDDA.length 1423 - [X] RawCDDA.close 1424 - [X] RawCDDA.first_sector 1425 - [X] RawCDDA.last_sector 1426 - [X] OffsetCDDA 1427 - [X] OffsetCDDA.close 1428 - [X] CDTrackLog 1429 - [X] CDTrackReader 1430 - [X] CDTrackReader.offset 1431 - [X] CDTrackReader.length 1432 - [X] CDTrackReader.log 1433 - [X] CDTrackReader.read 1434 - [X] CDTrackReader.close 1435 - [X] OffsetCDTrackReader 1436 - [X] OffsetCDTrackReader.offset 1437 - [X] OffsetCDTrackReader.length 1438 - [X] OffsetCDTrackReader.log 1439 - [X] OffsetCDTrackReader.read 1440 - [X] OffsetCDTrackReader.close 1441 - [X] read_metadata_file 1442 - [X] ExecQueue 1443 - [X] ExecQueue.execute 1444 - [X] ExecQueue.run 1445 - [X] BitstreamReader 1446 - [X] BitstreamReader.byte_align 1447 - [X] BitstreamReader.read 1448 - [X] BitstreamReader.unread 1449 - [X] BitstreamReader.read_signed 1450 - [X] BitstreamReader.unary 1451 - [X] BitstreamReader.tell 1452 - [X] BitstreamReader.close 1453 - [X] BitstreamWriter 1454 - [X] BitstreamWriter.byte_align 1455 - [X] BitstreamWriter.write 1456 - [X] BitstreamWriter.write_signed 1457 - [X] BitstreamWriter.unary 1458 - [X] BitstreamWriter.tell 1459 - [X] BitstreamWriter.close 1460**** DONE __m4a_atoms__.py 1461***** DONE adjust syntax 1462***** DONE add docstrings 1463 - [X] VersionLength 1464 - [X] AtomAdapter 1465 - [X] Atom 1466 - [X] AtomListAdapter 1467 - [X] AtomContainer 1468 - [X] AtomWrapper 1469**** DONE __m4a__.py 1470***** DONE adjust syntax 1471***** DONE add docstrings 1472 - [X] M4AAudio_faac 1473 - [X] M4AAudio_faac.channel_mask 1474 - [X] M4AAudio_faac.is_type 1475 - [X] M4AAudio_faac.lossless 1476 - [X] M4AAudio_faac.channels 1477 - [X] M4AAudio_faac.bits_per_sample 1478 - [X] M4AAudio_faac.sample_rate 1479 - [X] M4AAudio_faac.cd_frames 1480 - [X] M4AAudio_faac.total_frames 1481 - [X] M4AAudio_faac.get_metadata 1482 - [X] M4AAudio_faac.set_metadata 1483 - [X] M4AAudio_faac.delete_metadata 1484 - [X] M4AAudio_faac.to_pcm 1485 - [X] M4AAudio_faac.from_pcm 1486 - [X] M4AAudio_faac.can_add_replay_gain 1487 - [X] M4AAudio_faac.lossless_replay_gain 1488 - [X] M4AAudio_faac.add_replay_gain 1489 - [X] M4AAudio_nero 1490 - [X] M4AAudio_nero.to_pcm 1491 - [X] M4AAudio_nero.from_pcm 1492 - [X] M4AAudio_nero.to_wave 1493 - [X] M4AAudio_nero.from_wave 1494 - [X] ILST_Atom 1495 - [X] M4AMetaData 1496 - [X] M4AMetaData.binary_atom 1497 - [X] M4AMetaData.text_atom 1498 - [X] M4AMetaData.trkn_atom 1499 - [X] M4AMetaData.disk_atom 1500 - [X] M4AMetaData.covr_atom 1501 - [X] M4AMetaData.images 1502 - [X] M4AMetaData.add_image 1503 - [X] M4AMetaData.delete_image 1504 - [X] M4AMetaData.converted 1505 - [X] M4AMetaData.merge 1506 - [X] M4AMetaData.to_atom 1507 - [X] M4AMetaData.supports_images 1508 - [X] M4ACovr 1509 - [X] M4ACovr.converted 1510 - [X] ALACAudio 1511 - [X] ALACAudio.is_type 1512 - [X] ALACAudio.total_frames 1513 - [X] ALACAudio.channel_mask 1514 - [X] ALACAudio.cd_frames 1515 - [X] ALACAudio.lossless 1516 - [X] ALACAudio.to_pcm 1517 - [X] ALACAudio.from_pcm 1518 - [X] ALACAudio.to_wave 1519 - [X] ALACAudio.from_wave 1520 - [X] ADTSException 1521 - [X] AACAudio 1522 - [X] AACAudio.is_type 1523 - [X] AACAudio.bits_per_sample 1524 - [X] AACAudio.channels 1525 - [X] AACAudio.lossless 1526 - [X] AACAudio.total_frames 1527 - [X] AACAudio.sample_rate 1528 - [X] AACAudio.to_pcm 1529 - [X] AACAudio.from_pcm 1530 - [X] AACAudio.aac_frames 1531 - [X] AACAudio.aac_frame_count 1532**** DONE __mp3__.py 1533***** DONE adjust syntax 1534***** DONE add docstrings 1535 - [X] MP3Exception 1536 - [X] MP3Audio 1537 - [X] MP3Audio.is_type 1538 - [X] MP3Audio.lossless 1539 - [X] MP3Audio.to_pcm 1540 - [X] MP3Audio.from_pcm 1541 - [X] MP3Audio.bits_per_sample 1542 - [X] MP3Audio.channels 1543 - [X] MP3Audio.sample_rate 1544 - [X] MP3Audio.get_metadata 1545 - [X] MP3Audio.set_metadata 1546 - [X] MP3Audio.delete_metadata 1547 - [X] MP3Audio.cd_frames 1548 - [X] MP3Audio.total_frames 1549 - [X] MP3Audio.can_add_replay_gain 1550 - [X] MP3Audio.lossless_replay_gain 1551 - [X] MP3Audio.add_replay_gain 1552 - [X] MP2Audio 1553 - [X] MP2Audio.is_type 1554 - [X] MP2Audio.from_pcm 1555**** DONE __musepack__.py 1556***** DONE adjust syntax 1557***** DONE add docstrings 1558 - [X] NutValue 1559 - [X] Musepack8StreamReader 1560 - [X] Musepack8StreamReader.packets 1561 - [X] MusepackAudio 1562 - [X] MusepackAudio.from_pcm 1563 - [X] MusepackAudio.is_type 1564 - [X] MusepackAudio.sample_rate 1565 - [X] MusepackAudio.total_frames 1566 - [X] MusepackAudio.channels 1567 - [X] MusepackAudio.bits_per_sample 1568 - [X] MusepackAudio.lossless 1569**** DONE __musicbrainz__.py 1570***** DONE adjust syntax 1571***** DONE add docstrings 1572 - [X] get_xml_nodes 1573 - [X] get_xml_text_node 1574 - [X] reorder_xml_children 1575 - [X] MBDiscID 1576 - [X] MBDiscID.from_cdda 1577 - [X] MBDiscID.offsets 1578 - [X] MusicBrainz 1579 - [X] MusicBrainz.connect 1580 - [X] MusicBrainz.close 1581 - [X] MusicBrainz.read_data 1582 - [X] MBXMLException 1583 - [X] MusicBrainzReleaseXML 1584 - [X] MusicBrainzReleaseXML.read 1585 - [X] MusicBrainzReleaseXML.read_data 1586 - [X] MusicBrainzReleaseXML.metadata 1587 - [X] MusicBrainzReleaseXML.from_files 1588 - [X] MusicBrainzReleaseXML.from_cuesheet 1589 - [X] MusicBrainzReleaseXML.build 1590 - [X] get_mbxml 1591**** DONE __shn__.py 1592***** DONE adjust syntax 1593***** DONE add docstrings 1594 - [X] ShortenAudio 1595 - [X] ShortenAudio.is_type 1596 - [X] ShortenAudio.bits_per_sample 1597 - [X] ShortenAudio.channels 1598 - [X] ShortenAudio.channel_mask 1599 - [X] ShortenAudio.lossless 1600 - [X] ShortenAudio.total_frames 1601 - [X] ShortenAudio.sample_rate 1602 - [X] ShortenAudio.to_pcm 1603 - [X] ShortenAudio.from_pcm 1604 - [X] ShortenAudio.to_wave 1605 - [X] ShortenAudio.from_wave 1606 - [X] ShortenAudio.supports_foreign_riff_chunks 1607 - [X] ShortenAudio.has_foreign_riff_chunks 1608**** DONE __speex__.py 1609***** DONE adjust syntax 1610***** DONE add docstrings 1611 - [X] UnframedVorbisComment 1612 - [X] SpeexAudio 1613 - [X] SpeexAudio.is_type 1614 - [X] SpeexAudio.to_pcm 1615 - [X] SpeexAudio.from_pcm 1616 - [X] SpeexAudio.set_metadata 1617 - [X] SpeexAudio.can_add_replay_gain 1618**** DONE __vorbiscomment__.py 1619***** DONE adjust syntax 1620***** DONE add docstrings 1621 - [X] VorbisComment 1622 - [X] VorbisComment.supports_images 1623 - [X] VorbisComment.images 1624 - [X] VorbisComment.converted 1625 - [X] VorbisComment.merge 1626 - [X] VorbisComment.build 1627**** DONE __vorbis__.py 1628***** DONE adjust syntax 1629***** DONE add docstrings 1630 - [X] OggStreamReader 1631 - [X] OggStreamReader.close 1632 - [X] OggStreamReader.packets 1633 - [X] OggStreamReader.pages 1634 - [X] OggStreamReader.pages_to_packets 1635 - [X] OggStreamReader.calculate_ogg_checksum 1636 - [X] OggStreamWriter 1637 - [X] OggStreamWriter.close 1638 - [X] OggStreamWriter.write_page 1639 - [X] OggStreamWriter.build_pages 1640 - [X] VorbisAudio 1641 - [X] VorbisAudio.is_type 1642 - [X] VorbisAudio.lossless 1643 - [X] VorbisAudio.bits_per_sample 1644 - [X] VorbisAudio.channels 1645 - [X] VorbisAudio.channel_mask 1646 - [X] VorbisAudio.total_frames 1647 - [X] VorbisAudio.sample_rate 1648 - [X] VorbisAudio.to_pcm 1649 - [X] VorbisAudio.from_pcm 1650 - [X] VorbisAudio.set_metadata 1651 - [X] VorbisAudio.get_metadata 1652 - [X] VorbisAudio.delete_metadata 1653 - [X] VorbisAudio.add_replay_gain 1654 - [X] VorbisAudio.can_add_replay_gain 1655 - [X] VorbisAudio.lossless_replay_gain 1656 - [X] VorbisAudio.replay_gain 1657 - [X] VorbisChannelMask 1658 - [X] VorbisChannelMask.channels 1659**** DONE __wavpack__.py 1660***** DONE adjust syntax 1661***** DONE add docstrings 1662 - [X] SymlinkPCMReader 1663 - [X] SymlinkPCMReader.read 1664 - [X] SymlinkPCMReader.close 1665 - [X] SymlinkPCMReader.new 1666 - [X] WavePackAPEv2 1667 - [X] WavePackAPEv2.converted 1668 - [X] WavPackAudio 1669 - [X] WavPackAudio.is_type 1670 - [X] WavPackAudio.lossless 1671 - [X] WavPackAudio.supports_foreign_riff_chunks 1672 - [X] WavPackAudio.channel_mask 1673 - [X] WavPackAudio.get_metadata 1674 - [X] WavPackAudio.has_foreign_riff_chunks 1675 - [X] WavPackAudio.frames 1676 - [X] WavPackAudio.sub_frames 1677 - [X] WavPackAudio.bits_per_sample 1678 - [X] WavPackAudio.channels 1679 - [X] WavPackAudio.total_frames 1680 - [X] WavPackAudio.sample_rate 1681 - [X] WavPackAudio.from_pcm 1682 - [X] WavPackAudio.to_wave 1683 - [X] WavPackAudio.to_pcm 1684 - [X] WavPackAudio.from_wave 1685 - [X] WavPackAudio.add_replay_gain 1686 - [X] WavPackAudio.can_add_replay_gain 1687 - [X] WavPackAudio.replay_gain 1688 - [X] WavPackAudio.get_cuesheet 1689 - [X] WavPackAudio.set_cuesheet 1690**** DONE __wav__.py 1691***** DONE adjust syntax 1692***** DONE add docstrings 1693 - [X] WaveReader 1694 - [X] WaveReader.read 1695 - [X] WaveReader.close 1696 - [X] TempWaveReader 1697 - [X] TempWaveReader.close 1698 - [X] WavException 1699 - [X] WaveAudio 1700 - [X] WaveAudio.is_type 1701 - [X] WaveAudio.lossless 1702 - [X] WaveAudio.supports_foreign_riff_chunks 1703 - [X] WaveAudio.has_foreign_riff_chunks 1704 - [X] WaveAudio.channel_mask 1705 - [X] WaveAudio.to_pcm 1706 - [X] WaveAudio.from_pcm 1707 - [X] WaveAudio.to_wave 1708 - [X] WaveAudio.from_wave 1709 - [X] WaveAudio.total_frames 1710 - [X] WaveAudio.sample_rate 1711 - [X] WaveAudio.channels 1712 - [X] WaveAudio.bits_per_sample 1713 - [X] WaveAudio.can_add_replay_gain 1714 - [X] WaveAudio.lossless_replay_gain 1715 - [X] WaveAudio.add_replay_gain 1716 - [X] WaveAudio.track_name 1717 - [X] WaveAudio.fmt_chunk_to_channel_mask 1718 - [X] WaveAudio.chunk_ids 1719 - [X] WaveAudio.chunks 1720 - [X] WaveAudio.wave_from_chunks 1721 - [X] WaveAudio.pcm_split 1722**** DONE cue.py 1723***** DONE adjust syntax 1724***** DONE add docstrings 1725 - [X] cue.py 1726 - [X] CueException 1727 - [X] tokens 1728 - [X] get_value 1729 - [X] parse 1730 - [X] Cuesheet 1731 - [X] Cuesheet.catalog 1732 - [X] Cuesheet.single_file_type 1733 - [X] Cuesheet.indexes 1734 - [X] Cuesheet.pcm_lengths 1735 - [X] Cuesheet.ISRCs 1736 - [X] Cuesheet.file 1737 - [X] Track 1738 - [X] Track.ISRC 1739 - [X] read_cuesheet 1740**** DONE toc.py 1741***** DONE adjust syntax 1742***** DONE add docstrings 1743 - [X] toc.py 1744 - [X] TOCException 1745 - [X] parse 1746 - [X] TOCFile 1747 - [X] TOCFile.catalog 1748 - [X] TOCFile.indexes 1749 - [X] TOCFile.pcm_lengths 1750 - [X] TOCFile.ISRCs 1751 - [X] TOCFile.file 1752 - [X] Track 1753 - [X] Track.ISRC 1754 - [X] read_tocfile 1755*** DONE Update utilities 1756 - [X] audiotools-config 1757 - [X] cd2track 1758 - [X] cd2xmcd 1759 - [X] cdinfo 1760 - [X] coverdump 1761 - [X] coverview 1762 - [X] editxmcd 1763 - [X] record2track 1764 - [X] track2cd 1765 - [X] track2track 1766 - [X] track2xmcd 1767 - [X] trackcat 1768 - [X] trackcmp 1769 - [X] trackinfo 1770 - [X] tracklength 1771 - [X] tracklint 1772 - [X] trackplay 1773 - [X] trackrename 1774 - [X] tracksplit 1775 - [X] tracktag 1776*** DONE Update tests 1777 - [X] test.py 1778 - [X] test_streams.py 1779** DONE Update C code to support PEP 7 1780 - [X] array.c 1781 - [X] array.h 1782 - [X] bitstream_r.c 1783 - [X] bitstream_r.h 1784 - [X] bitstream_w.c 1785 - [X] bitstream_w.h 1786 - [X] cdiomodule.c 1787 - [X] decoders.c 1788 - [X] decoders.h 1789 - [X] encoders.c 1790 - [X] encoders.h 1791 - [X] md5.c 1792 - [X] md5.h 1793 - [X] pcm.c 1794 - [X] pcm.h 1795 - [X] pcmreader.c 1796 - [X] pcmreader.h 1797 - [X] replaygain.c 1798 - [X] replaygain.h 1799 - [X] resample.c 1800 - [X] resample.h 1801 - [X] decoders/alaac.c 1802 - [X] decoders/alac.h 1803 - [X] decoders/flac.c 1804 - [X] decoders/flac_crc.c 1805 - [X] decoders/flac_crc.h 1806 - [X] decoders/flac.h 1807 - [X] decoders/shn.c 1808 - [X] decoders/shn.h 1809 - [X] encoders/alac.c 1810 - [X] encoders/alac.h 1811 - [X] encoders/alac_lpc.c 1812 - [X] encoders/alac_lpc.h 1813 - [X] encoders/flac.c 1814 - [X] encoders/flac.h 1815 - [X] encoders/flac_lpc.c 1816 - [X] encoders/flac_lpc.h 1817 - [X] encoders/shn.c 1818 - [X] encoders/shn.h 1819** DONE Add ALAC support 1820*** DONE Build ALAC decoder 1821**** DONE Add audiotools.decoders.AlacDecoder object 1822**** DONE Add frame header parsing 1823**** DONE Add subframe header parsing 1824**** DONE Add wasted-bits block parsing 1825**** DONE Add residual decoding 1826**** DONE Ensure frame footer is checked 1827**** DONE Decode subframes 1828**** DONE Perform channel decorrelation 1829 - [X] leftweight zero 1830 - [X] leftweight nonzero 1831**** DONE Handle wasted-bits samples 1832**** DONE Return pcm.FrameList objects on calls to read() 1833**** DONE Ensure PCMReader-compatible fields are present 1834 - [X] sample_rate 1835 - [X] channels 1836 - [X] channel_mask 1837 - [X] bits_per_sample 1838**** DONE Ensure 16/24 bps streams work correctly 1839 - [X] 16bps 1840 - [X] 24bps 1841**** DONE Ensure 1/2 channel streams work correctly 1842 - [X] 1 channel 1843 - [X] 2 channels 1844**** DONE Ensure different sample rates work correctly 1845 - [X] 44100Hz 1846 - [X] 48000Hz 1847 - [X] 96000Hz 1848 - [X] 192000Hz 1849 (need to figure out what other sample rates ALAC supports) 1850**** DONE Update source to more closely match documentation 1851**** DONE Optimize for speed 1852*** DONE Build ALAC encoder 1853**** DONE Add audiotools.encoders.encode_alac function 1854**** DONE Ensure verbatim ALAC file is written correctly 1855**** DONE Determine ALAC stream tunables 1856***** wasted bits for 24bps streams 1857***** interlacing shift 1858***** interlacing leftweight 1859***** prediction quantitization 1860***** coefficients 1861**** DONE extract wasted bits for 24bps streams 1862**** DONE correlate stereo samples 1863**** DONE determine coefficients/quantitization 1864**** DONE calculate residual values 1865**** DONE write residuals based on initial history/history multiplier/etc. 1866**** DONE handle random noise with uncompressed frames 1867**** DONE handle atypical sample rates properly 1868**** DONE Update source to more closely match documentation 1869**** DONE make interlacing shift and interlacing leftweight range options 1870**** DONE optimize for speed 1871*** DONE Add ALACAudio type to audiotools Python core 1872*** DONE Enable TestAlacAudio core tests 1873*** DONE Add ALAC-specific unit tests 1874**** DONE test_streams 1875**** DONE test_small_files 1876**** DONE test_full_scale_deflection 1877**** DONE test_sines 1878 eliminate DeprecationWarning at construct/core.py:541 1879 which seems to be caused by 96000Hz input 1880**** DONE test_wasted_bps 1881**** DONE test_blocksizes 1882**** DONE test_frame_header_variations 1883**** DONE test_noise 1884**** DONE test_fractional 1885*** DONE Document ALAC 1886**** DONE the ALAC file stream 1887**** DONE ALAC decoding 1888***** DONE Frame header 1889***** DONE Subframe header 1890***** DONE Residual decoding 1891***** DONE Residual decoding example 1892***** DONE Subframe decoding 1893 Simplify this to make it easier to understand 1894***** DONE Subframe decoding example 1895***** DONE Channel decorrelation 1896***** DONE Channel decorrelation example 1897***** DONE Wasted bits 1898***** DONE Wasted bits example 1899**** DONE ALAC encoding 1900***** DONE Figure out compliant atom contents 1901 - [X] ftyp 1902 - [X] moov->mvhd 1903 - [X] moov->trak->tkhd 1904 - [X] moov->trak->mdia->mdhd 1905 - [X] moov->trak->mdia->hdlr 1906 - [X] moov->trak->mdia->minf->smhd 1907 - [X] moov->trak->mdia->dinf->dref 1908 - [X] moov->trak->mdia->stbl->stsd->alac 1909 - [X] moov->trak->mdia->stbl->stts 1910 - [X] moov->trak->mdia->stbl->stsc 1911 - [X] moov->trak->mdia->stbl->stsz 1912 - [X] moov->trak->mdia->stbl->stco 1913 - [X] moov->udta->meta 1914 - [X] free 1915***** DONE Add forward references in "alac" atom description 1916***** DONE figure out if "meta" has required "----" sub-atoms 1917***** DONE extracting wasted bits for 24bps streams 1918***** DONE correlating stereo samples 1919***** DONE determining coefficients/quantitization 1920****** DONE Windowing 1921****** DONE Computing autocorrelation 1922****** DONE LP coefficient calculation 1923****** DONE Best order estimation 1924****** DONE Quantizing coefficients 1925***** DONE calculating residual values 1926 Simplify this to make it easier to understand 1927***** DONE writing residuals based on initial history/history multiplier/etc. 1928***** DONE Fix bitstream figs to be monospace font for binary digits 1929**** DONE verify A4 layout is correct 1930*** DONE Update M4A metadata routines to exploit "free" atoms 1931 As with FLAC, rewriting the entire file should be avoided 1932*** DONE Fix InvalidImage exceptions when reading test ALACs 1933*** DONE Ensure UnsupportedChannels exception is handled by user-level tools 1934*** DONE Ensure new ALACs work in iTunes 1935*** DONE Ensure new ALACs work on iPods 1936*** DONE Have M4A files group properly on iTunes/iPods 1937** DONE Remove xdelta requirement 1938 It's doesn't compile well on some platforms and is only used by tracklint 1939*** DONE Build trivial binary delta routine 1940 Since most metadata formats make use of padding, 1941 we can use a simple XOR over their contents to generate 1942 a bidirectional patch that's optimized for tracklint's behavior. 1943 Since the bulk of such a patch should be NULLs, 1944 we can compress it with zlib/bz2 and achieve 1945 excellent compression. 1946** DONE Tweak documentation 1947*** DONE Update indexes to account for warm-up samples 1948 The i index on the left and right hand sides must match. 1949 - [X] FLAC FIXED decoding 1950 - [X] FLAC LPC decoding 1951 - [X] FLAC FIXED encoding 1952 - [X] FLAC LPC encoding 1953*** DONE Rewrite the FLAC channel assignment section 1954 Reference the side channel extra bit and add examples. 1955*** DONE Add FLAC channel assignment encoding documentation 1956 Show its channel calculations and include an example. 1957** DONE indicate ReplayGain capabilities/binaries 1958 audiotools-config(1) should show what ReplayGain binaries are present 1959 and all audio classes that support it 1960** DONE update trackcmp to share trackverify's output interface 1961** DONE Add unary jump tables with a max value 1962 Since both Apple Lossless *and* WavPack have unary reading 1963 with a maximum upper limit of read bits, it makes sense 1964 to build a proper jump table for it. 1965 The size of our state limits the maximum to 8 bits, 1966 so larger maximums will be supported at a read_limited_unary() level. 1967 1968 The trouble is, we need to differentiate between normal exits 1969 (we've hit the stop bit) and exits that hit the maximum value. 1970 So, the jump table itself must have a different syntax 1971 (probably an extra bit for "maximum value reached") 1972 and read_limited_unary() will likely return -1 in that event. 1973** DONE Add little-endian bitstream readers 1974*** DONE integrate read functions into Bitstream struct 1975*** DONE add bitstream.py jump tables for little-endian reading 1976 - [X] read_bits_table_le.h 1977 - [X] read_unary_table_le.h 1978 - [X] read_limited_unary_table_le.h 1979 - [X] unread_bit_table_le.h 1980*** DONE add little-endian Bitstream functions 1981 - [X] bs_read_bits_le 1982 - [X] bs_read_bits64_le 1983 - [X] bs_unread_bit_le 1984 - [X] bs_read_unary_le 1985 - [X] bs_read_limited_unary_le 1986*** DONE have bs_open() attach the proper endian functions 1987*** DONE update Python BitstreamReader for little-endian operation 1988 This should function similar to the C one, 1989 with alignment specified at init-time. 1990 Or, perhaps replace Python reader with C-based one altogether. 1991*** DONE add some basic Bitstream reader unit testing 1992*** DONE allow endianness swapping 1993** DONE Add little-endian bitstream writers 1994*** DONE add bitstream.py jump tables for little-endian writing 1995 - [X] write_bits_table_le.h 1996 - [X] write_unary_table_le.h 1997*** DONE Add little-endian Bitstream functions 1998 - [X] write_bits_actual_le 1999 - [X] write_signed_bits_actual_le 2000 - [X] write_bits64_actual_le 2001 - [X] write_unary_actual_le 2002 - [X] byte_align_w_actual_le 2003*** DONE have bs_open() attach the proper endian functions 2004*** DONE update Python BitstreamWriter for little-endian operation 2005 Convert to a C type, similar to BitstreamReader 2006*** DONE add some basic Bitstream writer unit testing 2007*** DONE allow endianness swapping 2008** DONE integrate new endianness routines into existing routines 2009*** DONE Convert Ogg verifier to proper little-endian operation 2010*** DONE Swap endianness for proper FLAC VORBISCOMMENT writing 2011*** DONE have bs_set_endianness create instruction in recorder-mode 2012 So that if we're recording an endianness shift, 2013 it gets set properly when "played back" to an actual writer. 2014 In fact, it may be a good idea to attach the set_endianness() 2015 function to the bitstream writer itself. 2016** DONE Build proper AlbumMetaDataFile class 2017 This is a superclass of FreeDB's XMCD and MusicBrainz's XML 2018 which wraps metadata containers into a consistent interface 2019 for use by editxmcd and command-line utilities. 2020*** DONE Convert XMCD to AlbumMetaDataFile subclass 2021*** DONE Add unit tests for XMCD 2022*** DONE Convert MusicBrainzReleaseXML to AlbumMetaDataFile subclass 2023*** DONE Add unit tests for MusicBrainzReleaseXML 2024*** DONE Update utilities to use new interface 2025 - [X] tracksplit 2026 - [X] track2track 2027 - [X] track2xmcd 2028 - [X] trackrename 2029 - [X] tracktag 2030 - [ ] editxmcd 2031 - [X] cd2track 2032 - [X] cd2xmcd 2033*** DONE Update old unit tests to new interface 2034*** DONE Fix get_track to return blank artist name if not present 2035 Don't pull from the class artist name; 2036 have track_metadata() figure that out as appropriate instead. 2037**** DONE Fix unit tests for proper behavior 2038*** DONE Document AlbumMetaDataFile 2039** DONE Update ALAC to handle multichannel audio 2040 What David Hammerton's reverse-engineered decoder described as 2041 a 3-bit frame footer isn't; it's actually a "stop" delimiter 2042 analagous to WavPack's block header stop bit. 2043 If it's not 0x7, keep reading frames and combine them 2044 channel-wise into a single multichannel chunk of output. 2045 2046 iTunes and iPods still won't be able to handle such files, 2047 but XLD should be able to. 2048*** DONE Update ALACDecoder's analyze_frame() method for multichannel 2049*** DONE Update ALACDecoder's read() method for multichannel 2050*** DONE Update encode_alac function for multichannel 2051*** DONE Unit test multichannel ALAC encoding and decoding 2052*** DONE Update decoding documentation describing multichannel handling 2053*** DONE Update encoding documentation describing multichannel handling 2054** DONE Add higher sampling rate support to ReplayGain module 2055 Extract the higher rates from wvgain.c 2056 - [X] 8000Hz 2057 - [X] 11025Hz 2058 - [X] 12000Hz 2059 - [X] 16000Hz 2060 - [X] 18900Hz 2061 - [X] 22050Hz 2062 - [X] 24000Hz 2063 - [X] 32000Hz 2064 - [X] 37800Hz 2065 - [X] 44100Hz 2066 - [X] 48000Hz 2067 - [X] 56000Hz 2068 - [X] 64000Hz 2069 - [X] 88200Hz 2070 - [X] 96000Hz 2071 - [X] 112000Hz 2072 - [X] 128000Hz 2073 - [X] 144000Hz 2074 - [X] 176400Hz 2075 - [X] 192000Hz 2076*** DONE Unit test sample rates 2077** DONE Allow audio type defaults to be selectable 2078*** DONE Update tools to pull -t from config file 2079 - [X] cd2track 2080 - [X] record2track 2081 - [X] track2track 2082 - [X] trackcat 2083 - [X] tracksplit 2084*** DONE Update tools to pull -q from config file 2085 - [X] cd2track 2086 - [X] record2track 2087 - [X] track2track 2088 - [X] trackcat 2089 - [X] tracksplit 2090*** DONE Update audio formats to pull default quality from config file (if any) 2091 for all calls to from_pcm() and from_wave() 2092 - [X] aac 2093 - [X] flac 2094 - [X] m4a (Nero) 2095 - [X] m4a (faac) 2096 - [X] mp2 2097 - [X] mp3 2098 - [X] oga 2099 - [X] ogg 2100 - [X] spx 2101 - [X] wv 2102*** DONE Update audiotools-config to display default type 2103*** DONE Update audiotools-config to display default qualities 2104*** DONE Update audiotools-config to select default type 2105*** DONE Update audiotools-config to select default quality for a type 2106*** DONE Document new configuration options in man pages 2107 - [X] audiotools-config 2108 - [X] cd2track 2109 - [X] record2track 2110 - [X] track2track 2111 - [X] trackcat 2112 - [X] tracksplit 2113 - [X] audiotools.cfg 2114** DONE Allow default verbosity to be selectable 2115*** DONE Update audiotools-config to display default verbosity 2116*** DONE Update audiotools-config to select default verbosity 2117*** DONE Update tools to use default verbosity 2118 - [X] cd2track 2119 - [X] cd2xmcd 2120 - [X] coverdump 2121 - [X] record2track 2122 - [X] track2cd 2123 - [X] track2track 2124 - [X] track2xmcd 2125 - [X] trackcmp 2126 - [X] tracklint 2127 - [X] trackrename 2128 - [X] tracksplit 2129 - [X] tracktag 2130 - [X] trackverify 2131*** DONE Document new configuration option in man pages 2132 - [X] audiotools-config 2133 - [X] audiotools.cfg 2134** DONE Shift common decoder/encoder routines to a common/ directory 2135 - [X] flac_crc.h 2136 - [X] flac_crc.c 2137 - [X] misc.h 2138 - [X] misc.c 2139 - [X] md5.h 2140 - [X] md5.c 2141** DONE Get coverview and editxmcd working on Mac OS X 2142*** DONE editxmcd 2143**** DONE Update man page 2144*** DONE Update coverview for dual PyGTK/Tkinter operation 2145 It's a simple enough app that it should be able to conditionally do both, 2146 especially since audiotools does most of the heavy lifting. 2147 This allows it to look like a proper app under X11 2148 and work at all everywhere else. 2149 2150 It should look and function approximately the same on both. 2151**** DONE Remove glade requirement 2152 I'm sick of glade, and coverview should be small enough 2153 that it's not a problem to lay it out internally. 2154**** DONE Update coverview for PyGTK 2155**** DONE Update coverview for Tkinter 2156***** DONE Fixup error messages, if possible 2157**** DONE Add --gtk/--tkinter switches for conditional launch 2158 For testing purposes 2159**** DONE Cleanup conditional classes/helper functions 2160**** DONE Check for init-time errors 2161 Both in loading audiofiles and in import problems 2162 such as Mac OS's 32-bit problem 2163**** DONE Update man page 2164** DONE More graceful handling of broken files 2165 A lot of the track handlers assume that once the start of the file is good, 2166 the rest of it is following the spec. This is not always the case. 2167*** DONE All audio formats need to implement the error specification 2168 This means that: 2169 classmethod.is_type() must never error 2170 __init__() must raise InvalidFile if the filename's contents are invalid 2171 to_pcm() must return PCMReaderError if the decoder can't be built 2172 classmethod.from_pcm() must raise EncodingError if it can't encode file 2173 to_wave() must raise EncodingError if a wave can't be written 2174 classmethod.from_wave() must raise EncodingError if it can't encode file 2175 a failed to_wave() mustn't leave half-encoded .wav files behind 2176 a failed from_wave() mustn't leave half-encoded .wav files behind 2177 a failed from_pcm() mustn't leave a partially encoded file behind 2178 PCMReaders may raise IOError and ValueError on read() 2179 PCMReaders may raise DecodingError on close() 2180**** DONE AACAudio 2181 - [X] is_type() doesn't error 2182 - [X] __init__() raises InvalidFile 2183 - [X] to_pcm() returns PCMReaderError on decoder error 2184 - [X] from_pcm() raises EncodingError on encoder error 2185 - [X] from_wave() raises EncodingError on encoder error 2186 - [X] failed from_wave() deletes partial file 2187 - [X] failed from_pcm() deletes partial file 2188 - [X] PCMReader raises IOError/ValueError on read() if necessary 2189 - [X] PCMReader raises DecodingError on close() if necessary 2190**** DONE AiffAudio 2191 - [X] is_type() doesn't error 2192 - [X] __init__() raises InvalidFile 2193 - [X] to_pcm() returns PCMReaderError on decoder error 2194 - [X] from_pcm() raises EncodingError on encoder error 2195 - [X] to_wave() raises EncodingError on decoder error 2196 - [X] from_wave() raises EncodingError on encoder error 2197 - [X] failed to_wave() deletes partial file 2198 - [X] failed from_wave() deletes partial file 2199 - [X] failed from_pcm() deletes partial file 2200 - [X] PCMReader raises IOError/ValueError on read() if necessary 2201 - [X] PCMReader raises DecodingError on close() if necessary 2202**** DONE ALACAudio 2203 - [X] is_type() doesn't error 2204 - [X] __init__() raises InvalidFile 2205 - [X] to_pcm() returns PCMReaderError on decoder error 2206 - [X] from_pcm() raises EncodingError on encoder error 2207 - [X] to_wave() raises EncodingError on decoder error 2208 - [X] from_wave() raises EncodingError on encoder error 2209 - [X] failed to_wave() deletes partial file 2210 - [X] failed from_wave() deletes partial file 2211 - [X] failed from_pcm() deletes partial file 2212 - [X] PCMReader raises IOError/ValueError on read() if necessary 2213 - [X] PCMReader raises DecodingError on close() if necessary 2214**** DONE AuAudio 2215 - [X] is_type() doesn't error 2216 - [X] __init__() raises InvalidFile 2217 - [X] to_pcm() returns PCMReaderError on decoder error 2218 - [X] from_pcm() raises EncodingError on encoder error 2219 - [X] to_wave() raises EncodingError on decoder error 2220 - [X] from_wave() raises EncodingError on encoder error 2221 - [X] failed to_wave() deletes partial file 2222 - [X] failed from_wave() deletes partial file 2223 - [X] failed from_pcm() deletes partial file 2224 - [X] PCMReader raises IOError/ValueError on read() if necessary 2225 - [X] PCMReader raises DecodingError on close() if necessary 2226**** DONE FlacAudio 2227 - [X] is_type() doesn't error 2228 - [X] __init__() raises InvalidFile 2229 - [X] to_pcm() returns PCMReaderError on decoder error 2230 - [X] from_pcm() raises EncodingError on encoder error 2231 - [X] to_wave() raises EncodingError on decoder error 2232 - [X] from_wave() raises EncodingError on encoder error 2233 - [X] failed to_wave() deletes partial file 2234 - [X] failed from_wave() deletes partial file 2235 - [X] failed from_pcm() deletes partial file 2236 - [X] PCMReader raises IOError/ValueError on read() if necessary 2237 - [X] PCMReader raises DecodingError on close() if necessary 2238**** DONE M4AAudio_faac 2239 - [X] is_type() doesn't error 2240 - [X] __init__() raises InvalidFile 2241 - [X] from_pcm() raises EncodingError on encoder error 2242 - [X] from_wave() raises EncodingError on encoder error 2243 - [X] failed from_wave() deletes partial file 2244 - [X] failed from_pcm() deletes partial file 2245**** DONE M4AAudio_nero 2246 - [X] is_type() doesn't error 2247 - [X] __init__() raises InvalidFile 2248 - [X] to_pcm() returns PCMReaderError on decoder error 2249 - [X] from_pcm() raises EncodingError on encoder error 2250 - [X] to_wave() raises EncodingError on decoder error 2251 - [X] from_wave() raises EncodingError on encoder error 2252 - [X] failed to_wave() deletes partial file 2253 - [X] failed from_wave() deletes partial file 2254 - [X] failed from_pcm() deletes partial file 2255 - [X] PCMReader raises IOError/ValueError on read() if necessary 2256 - [X] PCMReader raises DecodingError on close() if necessary 2257**** DONE MP2Audio 2258 - [X] is_type() doesn't error 2259 - [X] __init__() raises InvalidFile 2260 - [X] to_pcm() returns PCMReaderError on decoder error 2261 - [X] from_pcm() raises EncodingError on encoder error 2262 - [X] to_wave() raises EncodingError on decoder error 2263 - [X] from_wave() raises EncodingError on encoder error 2264 - [X] failed to_wave() deletes partial file 2265 - [X] failed from_wave() deletes partial file 2266 - [X] failed from_pcm() deletes partial file 2267 - [X] PCMReader raises IOError/ValueError on read() if necessary 2268 - [X] PCMReader raises DecodingError on close() if necessary 2269**** DONE MP3Audio 2270 - [X] is_type() doesn't error 2271 - [X] __init__() raises InvalidFile 2272 - [X] to_pcm() returns PCMReaderError on decoder error 2273 - [X] from_pcm() raises EncodingError on encoder error 2274 - [X] to_wave() raises EncodingError on decoder error 2275 - [X] from_wave() raises EncodingError on encoder error 2276 - [X] failed to_wave() deletes partial file 2277 - [X] failed from_wave() deletes partial file 2278 - [X] failed from_pcm() deletes partial file 2279 - [X] PCMReader raises IOError/ValueError on read() if necessary 2280 - [X] PCMReader raises DecodingError on close() if necessary 2281**** DONE OggFlacAudio 2282 - [X] is_type() doesn't error 2283 - [X] __init__() raises InvalidFile 2284 - [X] to_pcm() returns PCMReaderError on decoder error 2285 - [X] from_pcm() raises EncodingError on encoder error 2286 - [X] to_wave() raises EncodingError on decoder error 2287 - [X] from_wave() raises EncodingError on encoder error 2288 - [X] failed to_wave() deletes partial file 2289 - [X] failed from_wave() deletes partial file 2290 - [X] failed from_pcm() deletes partial file 2291 - [X] PCMReader raises IOError/ValueError on read() if necessary 2292 - [X] PCMReader raises DecodingError on close() if necessary 2293**** DONE ShortenAudio 2294 - [X] is_type() doesn't error 2295 - [X] __init__() raises InvalidFile 2296 - [X] to_pcm() returns PCMReaderError on decoder error 2297 - [X] from_pcm() raises EncodingError on encoder error 2298 - [X] to_wave() raises EncodingError on decoder error 2299 - [X] from_wave() raises EncodingError on encoder error 2300 - [X] failed to_wave() deletes partial file 2301 - [X] failed from_wave() deletes partial file 2302 - [X] failed from_pcm() deletes partial file 2303 - [X] PCMReader raises IOError/ValueError on read() if necessary 2304 - [X] PCMReader raises DecodingError on close() if necessary 2305**** DONE SpeexAudio 2306 - [X] is_type() doesn't error 2307 - [X] __init__() raises InvalidFile 2308 - [X] from_pcm() raises EncodingError on encoder error 2309 - [X] failed from_wave() deletes partial file 2310 - [X] failed from_pcm() deletes partial file 2311**** DONE VorbisAudio 2312 - [X] is_type() doesn't error 2313 - [X] __init__() raises InvalidFile 2314 - [X] to_pcm() returns PCMReaderError on decoder error 2315 - [X] from_pcm() raises EncodingError on encoder error 2316 - [X] to_wave() raises EncodingError on decoder error 2317 - [X] from_wave() raises EncodingError on encoder error 2318 - [X] failed to_wave() deletes partial file 2319 - [X] failed from_wave() deletes partial file 2320 - [X] failed from_pcm() deletes partial file 2321 - [X] PCMReader raises IOError/ValueError on read() if necessary 2322 - [X] PCMReader raises DecodingError on close() if necessary 2323**** DONE WaveAudio 2324 - [X] is_type() doesn't error 2325 - [X] __init__() raises InvalidFile 2326 - [X] to_pcm() returns PCMReaderError on decoder error 2327 - [X] from_pcm() raises EncodingError on encoder error 2328 - [X] to_wave() raises EncodingError on decoder error 2329 - [X] from_wave() raises EncodingError on encoder error 2330 - [X] failed to_wave() deletes partial file 2331 - [X] failed from_wave() deletes partial file 2332 - [X] failed from_pcm() deletes partial file 2333 - [X] PCMReader raises IOError/ValueError on read() if necessary 2334 - [X] PCMReader raises DecodingError on close() if necessary 2335**** DONE WavPackAudio 2336 - [X] is_type() doesn't error 2337 - [X] __init__() raises InvalidFile 2338 - [X] to_pcm() returns PCMReaderError on decoder error 2339 - [X] from_pcm() raises EncodingError on encoder error 2340 - [X] to_wave() raises EncodingError on decoder error 2341 - [X] from_wave() raises EncodingError on encoder error 2342 - [X] failed to_wave() deletes partial file 2343 - [X] failed from_wave() deletes partial file 2344 - [X] failed from_pcm() deletes partial file 2345 - [X] PCMReader raises IOError/ValueError on read() if necessary 2346 - [X] PCMReader raises DecodingError on close() if necessary 2347*** DONE Check for invalid files at the tool level 2348 If an invalid file is encountered, display a proper 2349 user-readable error message explaining what's wrong 2350 with the file. 2351**** DONE track2cd 2352**** DONE track2track 2353**** DONE trackcat 2354**** DONE trackcmp 2355**** DONE trackplay 2356**** DONE tracksplit 2357*** DONE Document ValueError/IOError behavior 2358 Both in docstrings and in the rst documentation. 2359** DONE Add a convert() method to AudioFile subclasses 2360 Something like: 2361 2362 audiofile.convert(target_path, 2363 target_class, 2364 quality=None) 2365 2366 so one could perform a call like: 2367 2368 audiotools.open("infile.flac").convert("outfile.mp3", audiotools.MP3Audio) 2369 2370 Which would perform the proper to_pcm()/from_pcm()/to_wave()/from_wave() 2371 calls as necessary and could be overloaded to handle specific 2372 conversion processes, like AIFF->Shorten with a different set of 2373 IFF chunks. 2374*** DONE Deprecate wave-specific methods from base AudioFile class 2375 These methods might still be present, but only on classes that 2376 have specific need of them. 2377 - [X] to_wave() 2378 - [X] from_wave() 2379 - [X] supports_foreign_riff_chunks() 2380 - [X] has_foreign_riff_chunks() 2381*** DONE Convert classes to proper WaveContainer/AiffContainer subclasses 2382 - [X] FlacAudio 2383 - [X] OggFlacAudio (should *not* be a WaveContainer/AiffContainer subclass) 2384 - [X] WaveAudio 2385 - [X] AiffAudio 2386 - [X] WavPackAudio 2387 - [X] ShortenAudio 2388*** DONE Update old tests to reflect removed methods 2389*** DONE Update audio formats with convert() short-circuiting as needed 2390*** DONE Add unit tests for convert() methods 2391**** DONE Add unit tests which convert() every type to every other type 2392**** DONE Add unit tests to ensure foreign chunks are converted 2393*** DONE Update track2track to exploit convert() method 2394*** DONE Update documentation 2395**** DONE Add convert() documentation 2396**** DONE Remove wave-specific documentation 2397** DONE Update trackverify for multiprocess support 2398 I'll need some interprocess communication (probably pipes and select) 2399 to return the results from child processes for totals calculation. 2400*** DONE Update man page 2401*** DONE Document ExecQueue2 2402** DONE Update trackcmp for multiprocess support 2403*** DONE Update man page 2404*** DONE Update unit tests to account for -j flag 2405** DONE Update encoders for thread nonblocking 2406*** DONE encode_alac 2407*** DONE encode_flac 2408*** DONE encode_shn 2409*** DONE encode_wavpack 2410** DONE get trackplay working on Mac OS X 2411 There must be some way to pipe PCM data to its audio system 2412 without the need for additional libraries. 2413** DONE Remove -v option to mv(1) for file renaming 2414 This can be emulated in software. 2415** DONE Update audiotools.CDDA class 2416*** DONE Support reading offsets 2417 Without the horrible hack of reading the whole disc at once 2418*** DONE Document audiotools.CDDA class 2419*** DONE Document PCMReaderWindow class 2420** DONE Add support for System->cdrom_offset 2421 This will automatically apply offset samples when reading CDs 2422 so that rips will have the appropate amount of null samples. 2423*** DONE Add offset support when ripping 2424 Automatically apply the configfile's cdrom_offset value to tracks 2425 during reading. 2426*** DONE Add offset support when burning? 2427 cd2track and track2cd should round-trip properly 2428 If cd2track applies a sample offset when reading, does track2cd 2429 need to apply that same offset when writing? 2430 One would presume a drive's read offset and write offset are the same, 2431 but that may not be correct. 2432** DONE Add support for more lame encoding options 2433 Although the numerical presets are recommended, 2434 one should also be able to use the --preset values 2435 - [X] medium 2436 - [X] standard 2437 - [X] extreme 2438 - [X] insane 2439** DONE Remove wavegain for applying ReplayGain to .wav files 2440 This should be done internally instead. 2441** DONE Add more verbosity to --quality settings 2442 For formats with varying quality, the "-q help" option 2443 should indicate what those settings represent. 2444 - [X] FlacAudio 2445 - [X] M4AAudio_Nero 2446 - [X] MP2Audio 2447 - [X] MP3Audio 2448 - [X] OggFlacAudio 2449 - [X] SpeexAudio 2450 - [X] VorbisAudio 2451 - [X] WavPackAudio 2452*** DONE Update tools to indicate quality settings 2453 - [X] audiotools-config 2454 - [X] cd2track 2455 - [X] dvda2track 2456 - [X] record2track 2457 - [X] track2track 2458 - [X] trackcat 2459 - [X] tracksplit 2460** DONE Have coverdump build leading directories as needed 2461** DONE Add -T / --thumbnail option to tracktag 2462*** DONE Add option to tracktag man page 2463** DONE Convert ReplayGainReader to C 2464 The Python implementation simply uses too many CPU cycles, 2465 which can cause trackplay to stutter on hi-def files. 2466*** DONE Add audiotools.replaygain.ReplayGainReader object 2467**** DONE Add sample_rate attribute 2468**** DONE Add channels attribute 2469**** DONE Add channel_mask attribute 2470**** DONE Add bits_per_sample attribute 2471**** DONE Add read() method 2472**** DONE Add close() method 2473*** DONE Convert references to audiotools.ReplayGainReader 2474*** DONE Update documentation 2475** DONE Have the *2xmcd utilities delete .xmcd files if cancelled 2476 - [X] cd2xmcd 2477 - [X] dvda2xmcd 2478 - [X] track2xmcd 2479*** DONE Fix the *2xmcd utilities to use the proper mode on output files 2480** DONE Add software-based routines for bitstream reading/writing 2481 These should be optional, at least, for the bitstream writer especially. 2482 But if fast enough, they could replace the jump tables entirely. 2483*** DONE bitstream_w.h 2484 - [X] write_bits_actual_be 2485 - [X] write_bits_actual_le 2486 - [X] write_unary_actual_be 2487 - [X] write_unary_actual_le 2488** DONE Add individual tag item removal option to tracktag 2489 - [X] --remove-name 2490 - [X] --remove-artist 2491 - [X] --remove-performer 2492 - [X] --remove-composer 2493 - [X] --remove-conductor 2494 - [X] --remove-album 2495 - [X] --remove-catalog 2496 - [X] --remove-number 2497 - [X] --remove-track-total 2498 - [X] --remove-album-number 2499 - [X] --remove-album-total 2500 - [X] --remove-ISRC 2501 - [X] --remove-media-type 2502 - [X] --remove-year 2503 - [X] --remove-date 2504 - [X] --remove-copyright 2505 - [X] --remove-comment 2506*** DONE Unit test tag item addition/removal 2507*** DONE Update man page with new options 2508** DONE Add progess indicator to various utilities 2509 This will likely require an ExecQueue update which can 2510 receive progress output from multiple subprocesses 2511 so that the total progress can be generated. 2512 - [X] track2track 2513 - [X] cd2track 2514 - [X] dvda2track 2515 - [X] tracksplit 2516 - [X] trackcat 2517 - [X] trackcmp 2518 - [X] trackverify 2519 - [X] tracktag (for ReplayGain) 2520*** DONE Update AudioFile.convert() with a progress callback option 2521*** DONE Update AudioFile.add_replay_gain() with a progress callback option 2522 - [X] AudioFile 2523 - [X] FlacAudio 2524 - [X] M4AAudio 2525 - [X] MP3Audio 2526 - [X] VorbisAudio 2527 - [X] WavPackAudio 2528 - [X] WaveAudio 2529*** DONE Update programming documentation with progress callback option 2530*** DONE Update AudioFile.verify() with a progress callback option 2531 - [X] AACAudio 2532 - [X] ALACAudio 2533 - [X] AiffAudio 2534 - [X] AuAudio 2535 - [X] FlacAudio 2536 - [X] M4AAudio 2537 - [X] MP2Audio 2538 - [X] MP3Audio 2539 - [X] OggFlacAudio 2540 - [X] ShortenAudio 2541 - [X] SpeexAudio 2542 - [X] VorbisAudio 2543 - [X] WavPackAudio 2544 - [X] WaveAudio 2545*** DONE Add documentation for progress indicators and infrastructure 2546** DONE Add tool list and documentation to website 2547 I should probably find a way to either format the man pages 2548 to HTML directly (though groff's html output has been unfortunate 2549 in the past) or find an intermediate format that generates 2550 both man pages and web pages. 2551 - [X] audiotools-config 2552 - [X] audiotools.cfg 2553 - [X] cd2xmcd 2554 - [X] cdinfo 2555 - [X] cdplay 2556 - [X] cd2track 2557 - [X] coverdump 2558 - [X] coverview 2559 - [X] dvda2track 2560 - [X] dvda2xmcd 2561 - [X] dvdainfo 2562 - [X] editxmcd 2563 - [X] track2cd 2564 - [X] track2track 2565 - [X] track2xmcd 2566 - [X] trackcat 2567 - [X] trackcmp 2568 - [X] trackinfo 2569 - [X] tracklength 2570 - [X] tracklint 2571 - [X] trackplay 2572 - [X] trackrename 2573 - [X] tracksplit 2574 - [X] tracktag 2575 - [X] trackverify 2576*** DONE Build reStructuredText output 2577** DONE Add options for ID3v2/ID3v1 tagging 2578 Perhaps add config file options and corresponding audiotools-config options. 2579*** DONE Make ID3v2 version selectable 2580 Either ID3v2.2/ID3v2.3/ID3v2.4/none 2581*** DONE Make ID3v1 version selectable 2582 ID3v1.0/ID3v1.1/none 2583*** DONE Make ID3v2 track number formatting adjustable 2584 Allow leading 0s, since the spec doesn't forbid them. 2585*** DONE Display current ID3 info in audiotools-config 2586*** DONE Add ID3v2.2 option to audiotools-config 2587*** DONE Add ID3v1 option to audiotools-config 2588*** DONE Add ID3 number padding to audiotools-config 2589*** DONE Document new audiotools-config options in man page 2590*** DONE Document new audiotools config options on website 2591** DONE Add C-based FLAC encoder 2592*** DONE Use VERBATIM subframes when necessary 2593*** DONE Add significant initial padding blocks 2594 This will save a lot of time during retagging after FLAC creation 2595*** DONE Add a variety of unit tests 2596 - [X] test_stream.sh 2597 - [X] test_flac.sh 2598*** DONE Convert i_array size and data types to typedefs 2599*** DONE Convert f_array size and data types to typedefs 2600*** DONE Add more comprehensive encoding documentation 2601*** DONE Add a variety of assert() statements 2602 As with unit tests, these ensure everything is working during testing 2603 without a performance penalty at runtime. 2604*** DONE Handle foreign RIFF chunks 2605*** DONE Ensure FLACs work on a variety of other decoders 2606 Although decoding properly on the reference decoder *should* guarantee 2607 the file works everywhere, the only way to be certain is to test it. 2608*** DONE Ensure encoder raises the proper exceptions 2609*** DONE Support Rice2 partitions? 2610 The reference encoder uses these for more efficient handling of 24-bit audio 2611 but I'm not sure they're strictly necessary for my more basic encoder. 2612*** DONE Support wasted-bits-per-sample? 2613 I don't think I've ever seen these used on actual audio data 2614 that isn't artificial and hasn't been processed specifically for its use. 2615 As with Rice2, it's something that may get added later. 2616*** DONE Handle multi-channel PCM data correctly 2617 Anything higher than 2 channels needs to set a channel mask 2618 and the vorbis comment to the proper value. 2619 I expect this will be a long-term project 2620 coinciding with re-engineering the to_pcm()/from_pcm() methods. 2621*** DONE Remove external MD5 dependency 2622*** DONE Generate SEEKTABLE blocks 2623** DONE Add UTF-8 to FLAC documentation 2624*** DONE Explain how to decode a UTF-8 value 2625*** DONE Explain how to encode a UTF-8 value 2626** DONE Add C-based FLAC decoder 2627*** DONE Add a variety of unit tests 2628*** DONE Handle Rice escape codes 2629 Not sure how to test these, but they should be handled properly. 2630*** DONE Ensure decoder raises the proper exceptions 2631*** DONE Handle empty MD5 sums correctly 2632 If the MD5SUM is 00000000000000000000000000000000 2633 it's never a mismatch and should not trigger an error. 2634**** DONE Update tracklint to populate an empty MD5 sum 2635**** DONE Add unit tests 2636***** DONE Ensure an empty MD5 doesn't trigger an error at read time 2637***** DONE Ensure an empty MD5 doesn't trigger an error at verify time 2638***** DONE Ensure tracklint populates an empty MD5 correctly 2639** DONE Add substream support to bitstream reader 2640 Its function is to allow one to pull pieces out of a larger bitstream 2641 and process them separately. 2642 For example, while parsing an Ogg stream's pages with one bitstream, 2643 the extracted Vorbis packets could be processed with smaller substreams - 2644 including substreams that span one or more pages. 2645 It's also potentially helpful for MP3, Ogg FLAC, DVD-A and any other format 2646 with nontrivial wrappers that need to be parsed seperately 2647 from the main bitstream. 2648*** DONE Implement substream reader methods 2649**** DONE bs_read_bits_s_be 2650**** DONE bs_read_bits_s_le 2651**** DONE bs_read_signed_bits_s_be 2652**** DONE bs_read_signed_bits_s_le 2653**** DONE bs_read_bits64_s_be 2654**** DONE bs_read_bits64_s_le 2655**** DONE bs_skip_bits_s_be 2656**** DONE bs_skip_bits_s_le 2657**** DONE bs_read_unary_s_be 2658**** DONE bs_read_unary_s_le 2659**** DONE bs_read_limited_unary_s_be 2660**** DONE bs_read_limited_unary_s_le 2661**** DONE bs_set_endianness_s_be 2662**** DONE bs_set_endianness_s_le 2663**** DONE bs_read_huffman_code_s 2664**** DONE bs_mark_s 2665**** DONE bs_rewind_s 2666**** DONE bs_unmark_s 2667**** DONE bs_close_stream_s 2668**** DONE bs_substream_new 2669**** DONE bs_substream_f_be 2670**** DONE bs_substream_f_le 2671**** DONE bs_substream_p_be 2672**** DONE bs_substream_p_le 2673**** DONE bs_substream_s_be 2674**** DONE bs_substream_s_le 2675**** DONE bs_substream_append_f 2676**** DONE bs_substream_append_p 2677**** DONE bs_substream_append_s 2678*** DONE Add substream and substream_append to stream initializers 2679**** DONE bs_open 2680 - [X] substream 2681 - [X] substream_append 2682**** DONE bs_open_python 2683 - [X] substream 2684 - [X] substream_append 2685*** DONE Update current endianness setters with substream method 2686**** DONE bs_set_endianness_f_be 2687**** DONE bs_set_endianness_f_le 2688**** DONE bs_set_endianness_p_be 2689**** DONE bs_set_endianness_p_le 2690*** DONE Add garbage collection to substream 2691 It should be possible to create a substream, process it partway, 2692 then append more data to it without causing any overflow problems. 2693 That is, data at the beginning of the buffer will be recycled 2694 at append time if it hasn't been marked for rewinding back to. 2695*** DONE Add Python interface to substream 2696**** DONE audiotools.decoders.BitstreamReader.substream 2697**** DONE audiotools.decoders.BitstreamReader.substream_append 2698*** TODO Add unit tests to substream 2699** DONE Check objects for invalid init calls 2700 If an init fails, the subsequent dealloc call shouldn't segfault Python. 2701*** DONE audiotools.bitstream 2702 - [X] BitstreamAccumulator 2703 - [X] BitstreamReader 2704 - [X] BitstreamRecorder 2705 - [X] BitstreamWriter 2706*** DONE audiotools.cdio 2707 - [X] CDDA 2708 - [X] CDImage 2709*** DONE audiotools.decoders 2710 - [X] ALACDecoder 2711 - [X] AOBPCMDecoder 2712 - [X] FlacDecoder 2713 - [X] MLPDecoder 2714 - [X] OggFlacDecoder 2715 - [X] SHNDecoder 2716 - [X] Sine_Mono 2717 - [X] Sine_Simple 2718 - [X] Sine_Stereo 2719 - [X] WavPackDecoder 2720*** DONE audiotools.pcm 2721 - [X] FrameList 2722 - [X] FloatFrameList 2723*** DONE audiotools.resample 2724 - [X] Resampler 2725** DONE Update BitstreamWriter to work on Python objects 2726 That is, anything with a .write() and .close() method, 2727 similar to how BitstreamReader operates. 2728** DONE Calculate multi-album ReplayGain concurrently 2729 For instance, if one is calculating --replay-gain for four seperate 2730 albums and -j 4 is indicated, calculate each album's gain across 2731 its own core using the existing ProgressQueue facilities. 2732*** DONE track2track 2733*** DONE tracktag 2734**** DONE update man page with -j option 2735** DONE Adjust FlacMetaData to store blocks internally in order 2736 That is, they should output in the same order that they are stored on disk. 2737*** DONE Add size() method to FLAC blocks 2738 This returns the size of the block data, not including its 32-bit header 2739 - [X] Flac_STREAMINFO 2740 - [X] Flac_VORBISCOMMENT 2741 - [X] Flac_PICTURE 2742 - [X] Flac_APPLICATION 2743 - [X] Flac_SEEKTABLE 2744 - [X] Flac_CUESHEET 2745 - [X] Flac_PADDING 2746*** DONE FlacMetaData 2747 - [X] __init__ 2748 - [X] __setattr__ 2749 - [X] __getattr__ 2750 - [X] __delattr__ 2751 - [X] converted 2752 - [X] merge 2753 - [X] add_image 2754 - [X] delete_image 2755 - [X] images 2756 - [X] clean 2757 - [X] __repr__ 2758 - [X] parse 2759 - [X] raw_info 2760 - [X] blocks 2761 - [X] build 2762*** DONE FlacAudio 2763 - [X] channel_mask 2764 - [X] get_metadata 2765 - [X] update_metadata 2766 - [X] set_metadata 2767 - [X] set_cuesheet 2768 - [X] get_cuesheet 2769 - [X] has_foreign_riff_chunks 2770 - [X] riff_wave_chunks 2771 - [X] from_wave 2772 - [X] has_foreign_aiff_chunks 2773 - [X] from_aiff 2774 - [X] aiff_chunks 2775 - [X] add_replay_gain 2776 - [X] replay_gain 2777 - [X] clean 2778*** DONE OggFlacMetaData 2779 - [X] converted 2780 - [X] __repr__ 2781 - [X] parse 2782 - [X] build 2783*** DONE OggFlacAudio 2784 - [X] channel_mask 2785 - [X] update_metadata 2786 - [X] replay_gain 2787** DONE Have tracklint add channel mask info to hi-def FLAC files 2788 If omitted. Fix cases in which the tag is missing 2789 from the VORBISCOMMENT block, or the VORBISCOMMENT block 2790 is absent altogether. 2791*** DONE Add unit test 2792*** DONE Add fix to man page 2793** DONE Update FLAC/Vorbis to support TOTALTRACKS field for track_total 2794 This seems to be catching on as a standard. 2795 The best solution may be to implement a set of "fallback" fields 2796 such that a single metadata field may use a number of 2797 different Vorbis comment names and the first match is used. 2798*** DONE Preserve TOTALTRACKS when updating track_total 2799*** DONE Add unit tests to ensure TOTALTRACKS works 2800** DONE Don't port ReplayGain tags with AudioFile.set_metadata() 2801 That is, if we perform: 2802 2803 >>> track1 = audiotools.open("file1") 2804 >>> track2 = audiotools.open("file2") 2805 >>> track1.set_metadata(track2.get_metadata()) 2806 >>> track1.replay_gain() != track2.replay_gain() 2807 True 2808 2809 For all audio formats that store ReplayGain as embedded tags 2810*** DONE Update formats 2811 - [X] FlacAudio 2812 - [X] OggFlacAudio 2813 - [X] VorbisAudio 2814 - [X] WavPackAudio 2815*** DONE Add unit tests 2816 - [X] FlacAudio 2817 - [X] OggFlacAudio 2818 - [X] VorbisAudio 2819 - [X] WavPackAudio 2820** DONE Have MetaData.converted() always return a new object 2821 The following should hold for all metadata objects: 2822 2823 >>> a = MetaData(track_name=u"Foo") 2824 >>> b = MetaData.converted(a) 2825 >>> b.track_name = u"Bar" 2826 >>> a.track_name != b.track_name 2827 True 2828*** DONE Update MetaData classes 2829**** DONE ApeTag 2830**** DONE FlacMetaData 2831**** DONE ID3CommentPair 2832**** DONE ID3v1Comment 2833**** DONE ID3v22Comment 2834 - [X] ID3v22_Frame 2835 - [X] ID3v22_TXX_Frame 2836 - [X] ID3v22_COM_Frame 2837 - [X] ID3v22_PIC_Frame 2838**** DONE ID3v23Comment 2839 - [X] ID3v23_Frame 2840 - [X] ID3v23_TXXX_Frame 2841 - [X] ID3v23_COMM_Frame 2842 - [X] ID3v23_APIC_Frame 2843**** DONE ID3v24Comment 2844 - [X] ID3v24_Frame 2845 - [X] ID3v24_TXXX_Frame 2846 - [X] ID3v24_COMM_Frame 2847 - [X] ID3v24_APIC_Frame 2848**** DONE M4A_META_Atom 2849 - [X] M4A_Tree_Atom 2850 - [X] M4A_Leaf_Atom 2851 - [X] M4A_META_Atom 2852 - [X] M4A_FREE_Atom 2853 - [X] M4A_HDLR_Atom 2854 - [X] M4A_ILST_Leaf_Atom 2855 - [X] M4A_ILST_COVR_Data_Atom 2856 - [X] M4A_ILST_DISK_Data_Atom 2857 - [X] M4A_ILST_TRKN_Data_Atom 2858 - [ ] M4A_ILST_Unicode_Data_Atom 2859**** DONE MetaData 2860**** DONE OggFlacMetaData 2861**** DONE VorbisComment 2862*** DONE Update documentation for converted()'s behavior 2863*** DONE Add unit tests to all MetaData classes 2864 - [X] ApeTag 2865 - [X] FlacMetaData 2866 - [X] ID3CommentPair 2867 - [X] ID3v1Comment 2868 - [X] ID3v22Comment 2869 - [X] ID3v23Comment 2870 - [X] ID3v24Comment 2871 - [X] M4A_META_Atom 2872 - [X] MetaData 2873 - [X] OggFlacMetaData 2874 - [X] VorbisComment 2875** DONE Add better ID3v2 documentation 2876 Do a full explanation for frames one will find in nature. 2877 Don't be too concerned about obscure frames no one ever uses. 2878 | Frame | ID3v2.2 | ID3v2.3 | ID3v2.4 | 2879 |-----------------------------+---------+---------+---------| 2880 | all text | T__ | T___ | T___ | 2881 | all web | W__ | W___ | W___ | 2882 | picture | PIC | APIC | APIC | 2883 | comment | COM | COMM | COMM | 2884 | general encapsulated object | GEO | GEOB | GEOB | 2885 | unsynchronized lyrics | ULT | USLT | USLT | 2886*** DONE ID3v2.2 2887 - [X] COM 2888 - [X] GEO 2889 - [X] PIC 2890 - [X] TAL 2891 - [X] TBP 2892 - [X] TCM 2893 - [X] TCO 2894 - [X] TCR 2895 - [X] TDA 2896 - [X] TDY 2897 - [X] TEN 2898 - [X] TFT 2899 - [X] TIM 2900 - [X] TKE 2901 - [X] TLA 2902 - [X] TLE 2903 - [X] TMT 2904 - [X] TOA 2905 - [X] TOF 2906 - [X] TOL 2907 - [X] TOR 2908 - [X] TOT 2909 - [X] TP1 2910 - [X] TP2 2911 - [X] TP3 2912 - [X] TP4 2913 - [X] TPA 2914 - [X] TPB 2915 - [X] TRC 2916 - [X] TRD 2917 - [X] TRK 2918 - [X] TSI 2919 - [X] TSS 2920 - [X] TT1 2921 - [X] TT2 2922 - [X] TT3 2923 - [X] TXT 2924 - [X] TXX 2925 - [X] TYE 2926 - [X] ULT 2927 - [X] WAF 2928 - [X] WAR 2929 - [X] WAS 2930 - [X] WCM 2931 - [X] WCP 2932 - [X] WPB 2933 - [X] WXX 2934*** DONE ID3v2.3 2935 - [X] APIC 2936 - [X] COMM 2937 - [X] GEOB 2938 - [X] TALB 2939 - [X] TBPM 2940 - [X] TCOM 2941 - [X] TCON 2942 - [X] TCOP 2943 - [X] TDAT 2944 - [X] TDLY 2945 - [X] TENC 2946 - [X] TEXT 2947 - [X] TFLT 2948 - [X] TIME 2949 - [X] TIT1 2950 - [X] TIT2 2951 - [X] TIT3 2952 - [X] TKEY 2953 - [X] TLAN 2954 - [X] TLEN 2955 - [X] TMED 2956 - [X] TOAL 2957 - [X] TOFN 2958 - [X] TOLY 2959 - [X] TOPE 2960 - [X] TORY 2961 - [X] TOWN 2962 - [X] TPE1 2963 - [X] TPE2 2964 - [X] TPE3 2965 - [X] TPE4 2966 - [X] TPOS 2967 - [X] TPUB 2968 - [X] TRCK 2969 - [X] TRDA 2970 - [X] TRSN 2971 - [X] TRSO 2972 - [X] TSIZ 2973 - [X] TSRC 2974 - [X] TSSE 2975 - [X] TXXX 2976 - [X] TYER 2977 - [X] USLT 2978 - [X] WCOM 2979 - [X] WCOP 2980 - [X] WOAF 2981 - [X] WOAR 2982 - [X] WOAS 2983 - [X] WORS 2984 - [X] WPAY 2985 - [X] WPUB 2986 - [X] WXXX 2987*** DONE ID3v2.4 2988 - [X] APIC 2989 - [X] COMM 2990 - [X] GEOB 2991 - [X] TALB 2992 - [X] TBPM 2993 - [X] TCOM 2994 - [X] TCON 2995 - [X] TCOP 2996 - [X] TDEN 2997 - [X] TDLY 2998 - [X] TDOR 2999 - [X] TDRC 3000 - [X] TDRL 3001 - [X] TDTG 3002 - [X] TENC 3003 - [X] TEXT 3004 - [X] TFLT 3005 - [X] TIPL 3006 - [X] TIT1 3007 - [X] TIT2 3008 - [X] TIT3 3009 - [X] TKEY 3010 - [X] TLAN 3011 - [X] TLEN 3012 - [X] TMCL 3013 - [X] TMED 3014 - [X] TMOO 3015 - [X] TOAL 3016 - [X] TOFN 3017 - [X] TOLY 3018 - [X] TOPE 3019 - [X] TOWN 3020 - [X] TPE1 3021 - [X] TPE2 3022 - [X] TPE3 3023 - [X] TPE4 3024 - [X] TPOS 3025 - [X] TPRO 3026 - [X] TPUB 3027 - [X] TRCK 3028 - [X] TRSN 3029 - [X] TRSO 3030 - [X] TSOA 3031 - [X] TSOP 3032 - [X] TSOT 3033 - [X] TSRC 3034 - [X] TSSE 3035 - [X] TSST 3036 - [X] TXXX 3037 - [X] USLT 3038 - [X] WCOM 3039 - [X] WCOP 3040 - [X] WOAF 3041 - [X] WOAR 3042 - [X] WOAS 3043 - [X] WORS 3044 - [X] WPAY 3045 - [X] WPUB 3046 - [X] WXXX 3047** DONE Adjust ID3v2 to store frames internally in order 3048 That is, they should output in the same order that they are stored on disk. 3049*** DONE Rebuild and simplify the ID3v2 frame handling 3050 Create a simple "frame protocol" which the frames can implement 3051 and the ID3v2 formats can use so that they parse/build consistently. 3052**** DONE is_latin_1 3053**** DONE UCS2Codec 3054**** DONE decode_syncsafe32 3055**** DONE encode_syncsafe32 3056**** DONE __padded_number_pair__ 3057**** DONE __unpadded_number_pair__ 3058**** DONE __number_pair__ 3059**** DONE decode_ascii_c_string 3060**** DONE encode_ascii_c_string 3061**** DONE read_id3v2_comment() 3062 convert to standalone function 3063**** DONE skip_id3v2_comment() 3064 convert to standalone function 3065**** DONE ID3v22Comment 3066 - [X] __repr__ 3067 - [X] parse 3068 - [X] build 3069 - [X] size 3070 - [X] __len__ 3071 - [X] __getitem__ 3072 - [X] __setitem__ 3073 - [X] __delitem__ 3074 - [X] keys 3075 - [X] values 3076 - [X] items 3077 - [X] __getattr__ 3078 - [X] __setattr__ 3079 - [X] __delattr__ 3080 - [X] raw_info 3081 - [X] add_image 3082 - [X] delete_image 3083 - [X] images 3084 - [X] converted 3085 - [X] clean 3086***** DONE ID3v22_Frame 3087 - [X] __init__ 3088 - [X] __repr__ 3089 - [X] __eq__ 3090 - [X] parse 3091 - [X] build 3092 - [X] size 3093 - [X] converted 3094 - [X] clean 3095 - [X] raw_info 3096***** DONE ID3v22_TXX_Frame 3097 - [X] __init__ 3098 - [X] __repr__ 3099 - [X] __eq__ 3100 - [X] __unicode__ 3101 - [X] parse 3102 - [X] build 3103 - [X] size 3104 - [X] converted 3105 - [X] number 3106 - [X] total 3107 - [X] raw_info 3108 - [X] clean 3109***** DONE ID3v22_PIC_Frame 3110 - [X] __init__ 3111 - [X] __repr__ 3112 - [X] __eq__ 3113 - [X] __getattr__ 3114 - [X] __setattr__ 3115 - [X] parse 3116 - [X] build 3117 - [X] size 3118 - [X] converted 3119 - [X] raw_info 3120 - [X] clean 3121***** DONE ID3v22_COM_Frame 3122 - [X] __init__ 3123 - [X] __repr__ 3124 - [X] __eq__ 3125 - [X] __unicode__ 3126 - [X] parse 3127 - [X] build 3128 - [X] size 3129 - [X] converted 3130 - [X] raw_info 3131 - [X] clean 3132**** DONE ID3v23Comment 3133 - [X] __repr__ 3134 - [X] parse 3135 - [X] build 3136 - [X] size 3137 - [X] __len__ 3138 - [X] __getitem__ 3139 - [X] __setitem__ 3140 - [X] __delitem__ 3141 - [X] keys 3142 - [X] values 3143 - [X] items 3144 - [X] __setattr__ 3145 - [X] __getattr__ 3146 - [X] __delattr__ 3147 - [X] raw_info 3148 - [X] add_image 3149 - [X] delete_image 3150 - [X] images 3151 - [X] converted 3152 - [X] clean 3153***** DONE ID3v23_Frame 3154 - [X] __init__ 3155 - [X] __repr__ 3156 - [X] __eq__ 3157 - [X] raw_info 3158 - [X] parse 3159 - [X] build 3160 - [X] size 3161 - [X] converted 3162 - [X] clean 3163***** DONE ID3v23_TXXX_Frame 3164 - [X] __init__ 3165 - [X] __repr__ 3166 - [X] __eq__ 3167 - [X] __unicode__ 3168 - [X] raw_info 3169 - [X] parse 3170 - [X] build 3171 - [X] size 3172 - [X] converted 3173 - [X] clean 3174 - [X] number 3175 - [X] total 3176***** DONE ID3v23_APIC_Frame 3177 - [X] __init__ 3178 - [X] __repr__ 3179 - [X] __eq__ 3180 - [X] __getattr__ 3181 - [X] __setattr__ 3182 - [X] raw_info 3183 - [X] parse 3184 - [X] build 3185 - [X] size 3186 - [X] converted 3187 - [X] clean 3188***** DONE ID3v23_COMM_Frame 3189 - [X] __init__ 3190 - [X] __repr__ 3191 - [X] __eq__ 3192 - [X] __unicode__ 3193 - [X] raw_info 3194 - [X] parse 3195 - [X] build 3196 - [X] size 3197 - [X] converted 3198 - [X] clean 3199**** DONE ID3v24Comment 3200 - [X] __repr__ 3201 - [X] parse 3202 - [X] build 3203 - [X] size 3204 - [X] __len__ 3205 - [X] __getitem__ 3206 - [X] __setitem__ 3207 - [X] __delitem__ 3208 - [X] keys 3209 - [X] values 3210 - [X] items 3211 - [X] __setattr__ 3212 - [X] __getattr__ 3213 - [X] __delattr__ 3214 - [X] raw_info 3215 - [X] add_image 3216 - [X] delete_image 3217 - [X] images 3218 - [X] converted 3219 - [X] clean 3220***** DONE ID3v24_Frame 3221 - [X] __init__ 3222 - [X] __repr__ 3223 - [X] __eq__ 3224 - [X] raw_info 3225 - [X] parse 3226 - [X] build 3227 - [X] size 3228 - [X] converted 3229 - [X] clean 3230***** DONE ID3v24_TXXX_Frame 3231 - [X] __init__ 3232 - [X] __repr__ 3233 - [X] __eq__ 3234 - [X] __unicode__ 3235 - [X] raw_info 3236 - [X] parse 3237 - [X] build 3238 - [X] size 3239 - [X] converted 3240 - [X] clean 3241 - [X] number 3242 - [X] total 3243***** DONE ID3v24_APIC_Frame 3244 - [X] __init__ 3245 - [X] __repr__ 3246 - [X] __eq__ 3247 - [X] __getattr__ 3248 - [X] __setattr__ 3249 - [X] raw_info 3250 - [X] parse 3251 - [X] build 3252 - [X] size 3253 - [X] converted 3254 - [X] clean 3255***** DONE ID3v24_COMM_Frame 3256 - [X] __init__ 3257 - [X] __repr__ 3258 - [X] __eq__ 3259 - [X] __unicode__ 3260 - [X] raw_info 3261 - [X] parse 3262 - [X] build 3263 - [X] size 3264 - [X] converted 3265 - [X] clean 3266*** DONE Ensure they pass unit tests 3267*** DONE Ensure UCS-2 C strings are handled correctly 3268 For UCS-2/UTF-16 encoding, the string should end on 2 NULL bytes 3269 - [X] ID3v22_COM_Frame 3270 - [X] ID3v22_PIC_Frame 3271 - [X] ID3v23_COMM_Frame 3272 - [X] ID3v23_APIC_Frame 3273 - [X] ID3v24_COMM_Frame 3274 - [X] ID3v24_APIC_Frame 3275*** DONE Handle user-defined text frames properly 3276 - [X] ID3v22_TXX_Frame 3277 - [X] ID3v23_TXXX_Frame 3278 - [X] ID3v24_TXXX_Frame 3279*** DONE Handle web link frames properly 3280 - [X] ID3v22_W__Frame 3281 - [X] ID3v23_W___Frame 3282 - [X] ID3v24_W___Frame 3283*** DONE Handle user-defined web link frames properly 3284 - [X] ID3v22_WXX_Frame 3285 - [X] ID3v23_WXXX_Frame 3286 - [X] ID3v24_WXXX_Frame 3287*** DONE Handle text frames with embedded NULLs 3288 According to the spec, anything after the first decoded NULL 3289 should be ignored and not displayed. 3290 - [X] ID3v22_T__Frame 3291 - [X] ID3v22_TXX_Frame 3292 - [X] ID3v23_T___Frame 3293 - [X] ID3v23_TXXX_Frame 3294 - [X] ID3v24_T___Frame 3295 - [X] ID3v24_TXXX_Frame 3296*** DONE Update tests to always check required/prohibited leading zeroes 3297 - [X] ID3v22Comment 3298 - [X] ID3v23Comment 3299 - [X] ID3v24Comment 3300** DONE Eliminate the MetaData.merge() method 3301 The idea of this method is to provide some sort of precedence 3302 which combining metadata from two sources. 3303 For example, in track2track, we want provided XMCD metadata 3304 to override metadata inside the track itself. 3305 The .merge() method takes a raw MetaData object from XMCD 3306 and merges it with non-blank fields from the original file 3307 which means the XMCD metadata is the "base" of sorts. 3308 3309 A cleaner approach would be to take the raw MetaData object from XMCD, 3310 get a list of its non-empty fields and call __setattr__ on 3311 the track's metadata to update those fields. 3312 3313 MetaData with the highest priority would call __setattr__ last. 3314*** DONE Remove method from MetaData and subclasses 3315 - [X] ApeTag 3316 - [X] FlacMetaData 3317 - [X] ID3v22Comment 3318 - [X] ID3v23Comment 3319 - [X] ID3v24Comment 3320 - [X] ID3CommentPair 3321 - [X] M4A_META_Atom 3322 - [X] MetaData 3323 - [X] VorbisComment 3324*** DONE Remove method from tools 3325 - [X] track2track 3326 - [X] trackrename 3327 - [X] tracksplit 3328 - [X] tracktag 3329*** DONE Remove method from documentation 3330*** DONE Remove method from tests 3331** DONE Have trackinfo display metadata fields by default 3332 Instead of displaying the low-level info, 3333 show fields like "track name", "album name", etc. 3334 unless a -R/--raw flag is indicated. 3335*** DONE Replace MetaData.comment_pairs() with MetaData.raw_info() 3336 This should be even lower level than it is now, and unsorted. 3337 - [X] ApeTag 3338 - [X] FlacMetaData 3339 - [X] ID3CommentPair 3340 - [X] ID3v1Comment 3341 - [X] ID3v22Comment 3342 - [X] ID3v23Comment 3343 - [X] ID3v24Comment 3344 - [X] M4A_META_Atom 3345 - [X] OggFlacMetaData 3346 - [X] VorbisComment 3347**** DONE Document MetaData.raw_info() method 3348*** DONE Convert MetaData.__unicode__() to display fields by name 3349 This should always use the higher level implementation 3350 and sort fields by name. 3351*** DONE Update trackinfo to use MetaData's unicode output by default 3352*** DONE Add -L/--low-level option to trackinfo 3353*** DONE Add -L/--low-level option to trackinfo.1 3354*** DONE Add consistent embedded cuesheet display 3355*** DONE Update unit tests 3356** DONE Make metadata fully round-trippable 3357 For instance, the following should hold: 3358 3359 >>> track_data1 = open(track.filename).read() 3360 >>> track.update_metadata(track.get_metadata()) 3361 >>> track_data2 = open(track.filename).read() 3362 >>> track_data1 == track_data2 3363 True 3364 3365 This requires metadata to not jumble fields around until required. 3366** DONE Don't populate empty track_name, ISRC values during tracksplit 3367** DONE Fix ALAC channel assignment 3368 Since the channel assignment is detailed in the specs, 3369 add proper support for them. 3370*** DONE Update ALACAudio.channel_mask() method 3371*** DONE Update ALACAudio.from_pcm() method 3372 Like FLAC, it should reject unsupported channel masks. 3373*** DONE Update py_decoders.ALACDecoder's .channel_mask attribute 3374*** DONE Update py_decoders.ALACDecoder's .read() method 3375 Convert ALAC channel order to Wave channel order internally 3376 rather than punt that task to a reordering wrapper. 3377*** DONE Update py_encoders.encode_mdat 3378 Convert Wave channel order to ALAC channel order internally 3379 rather than punt that task to a reordering wrapper. 3380*** DONE Update decoders.ALACDecoder's .channel_mask attribute 3381*** DONE Update decoders.ALACDecoder's .read() method 3382 Convert ALAC channel order to Wave channel order internally 3383 rather than punt that task to a reordering wrapper. 3384*** DONE Update encoders.encode_alac 3385 Convert Wave channel order to ALAC channel order internally 3386 rather than punt that task to a reordering wrapper. 3387*** DONE Add unit tests to ensure channel variants encode/decode correctly 3388 - [X] 1 channel 3389 - [X] 2 channels 3390 - [X] 3 channels 3391 - [X] 4 channels 3392 - [X] 5 channels 3393 - [X] 6 channels 3394 - [X] 7 channels 3395 - [X] 8 channels 3396**** DONE Add unit tests to ensure invalid channel counts aren't encoded 3397**** DONE Add unit tests to ensure invalid channel masks aren't encoded 3398** DONE Add Python-based file encoders 3399 Like the Python-based decoders, 3400 these provide simple reference implementations 3401 one can easily pull apart to see how the encoders work. 3402*** DONE py_encoders/encode_flac 3403*** DONE py_encoders/encode_shn 3404*** DONE py_encoders/encode_alac 3405*** DONE py_encoders/encode_wavpack 3406** DONE Cleanup Shorten for better accuracy 3407*** DONE Handle 8-bit files correctly 3408 waves are unsigned, aiffs are signed, Sun AU is ? 3409 - [X] update py_decoders.SHNDecoder 3410 - [X] update decoders.SHNDecoder 3411 - [X] update py_encoders.encode_shn 3412 - [X] update encoders.encode_shn 3413 - [X] update __shn__.py 3414 - [X] update documentation 3415*** DONE Handle multichannel Shn/AIFF files correctly 3416**** DONE Ensure multichannel files converted from AIFF work 3417 Their channels should be kept in whatever order AIFF happens to use 3418 rather than have them remapped to wave order. 3419**** DONE Ensure multichannel Shn/AIFF to PCM works 3420 Output channels should be rearranged to PCMReader order. 3421*** DONE Improve thread friendliness in decoder/encoder 3422 - [X] decoders/shn.c 3423 - [X] encoders/shn.h 3424** DONE Overhaul array.h 3425 Just as the bitstream module benefits from having a good design, 3426 the array module would also be better served by having 3427 a more elegant API. 3428 3429 The main goal is to have less function variants and 3430 data allocation/deallocation routines to remember. 3431 Something like: 3432 3433 array = new_int_array(); 3434 array->append(array, value); 3435 array->del(array); 3436 3437 which always functions the same whether we're dealing with ints or 3438 floats or other arrays, yet is still type-checked at compile-time. 3439*** DONE Better unify FrameList <-> array_ia routines 3440*** DONE Remove old src/decoders/pcm.h src/decoders/pcm.c module 3441 Use the unified pcmconv.h module instead 3442 - [X] mlp.c 3443 - [X] shn.c 3444 - [X] sine.c 3445*** DONE Replace old array.h with new one in all source files 3446 - [X] decoders/mlp.h 3447 - [X] decoders/shn.h 3448 - [X] decoders/sine.h 3449 - [X] decoders/wavpack.h 3450 - [X] encoders/alac.h 3451 - [X] encoders/shn.h 3452 - [X] encoders/wavpack.h 3453*** DONE Remove old array.h 3454*** DONE Replace array2.h with array.h in all source files 3455** DONE Make second pass through updated documentation 3456*** DONE Update introduction 3457**** DONE re-explain endianness 3458**** DONE explain pseudocode with actual code examples 3459*** DONE Convert writes to a systax consistent with reads 3460 var <- read 10 unsigned bits 3461 var -> write 10 unsigned bits 3462 - [X] alac.tex 3463 - [X] flac.tex 3464 - [X] shorten.tex 3465 - [X] wavpack.tex 3466*** DONE Convert for loops to a consistent assignment syntax 3467 for i <- 0 to x do 3468 <code block> 3469 - [X] alac.tex 3470 - [X] dvda2.tex 3471 - [X] flac.tex 3472 - [X] shorten.tex 3473 - [X] wavpack.tex 3474*** DONE Double-check codecs for consistency 3475 - [X] alac.tex 3476 - [X] dvda2.tex 3477 - [X] flac.tex 3478 - [X] shorten.tex 3479 - [X] wavpack.tex 3480*** DONE Add hyperref linking 3481 If one's browsing the PDF, 3482 one should be able to click on operations directly 3483 and go to a specific part of the doc. 3484 - [X] alac.tex 3485 - [X] dvda2.tex 3486 - [X] flac.tex 3487 - [X] shorten.tex 3488 - [X] wavpack.tex 3489** DONE Tweak track labeling interactive mode for better usability 3490 make return key move to the next line 3491** DONE Combine and simplify DVD-A decoding and documentation 3492 The current routine bounces back and forth between Python and C 3493 several times in order to generate output, overcomplicating the design. 3494 I'd prefer to have a simpler, low-level, random-access reader hooked directly 3495 to the DVDATrack object - analagous to audiotools.cdda.CDDA. 3496** DONE Overhaul decoding/encoding documentation 3497 It needs to be cleaned up so one can better follow the entire 3498 decoding process, as well as the entire encoding process. 3499 Use a mix of pseudocode, bit diagrams, bit parsing diagrams 3500 and examples so that it can be followed with as little effort as possible. 3501*** DONE FLAC 3502**** DONE decoding 3503**** DONE encoding 3504*** DONE ALAC 3505**** DONE decoding 3506**** DONE encoding 3507*** DONE WavPack 3508**** DONE decoding 3509**** DONE encoding 3510*** DONE Shorten 3511**** DONE decoding 3512**** DONE encoding 3513*** DONE DVD-A 3514**** DONE decoding 3515* DONE Finish version 2.18 3516** DONE Ensure audiotools works on FreeBSD 3517 the unprotection module, in particular, needs additional testing 3518** DONE Ensure excessive zero residuals don't overflow output buffers 3519 Certain formats provide "escape code" blocks of zeroes. 3520 Ensure these routines don't generate more zeroes than are allowed 3521 (either accidentally or deliberately). 3522*** DONE ALACDecoder 3523*** DONE WavPackDecoder 3524** DONE Cleaup documentation layout 3525 Add subdirectories for format figures. 3526** DONE Spellcheck reference docs 3527 - [X] introduction.tex 3528 - [X] basics.tex 3529 - [X] wav.tex 3530 - [X] aiff.tex 3531 - [X] au.tex 3532 - [X] shorten.tex 3533 - [X] flac.tex 3534 - [X] wavpack.tex 3535 - [X] ape.tex 3536 - [X] mp3.tex 3537 - [X] m4a.tex 3538 - [X] alac.tex 3539 - [X] vorbis.tex 3540 - [X] oggflac.tex 3541 - [X] speex.tex 3542 - [X] musepack.tex 3543 - [X] dvda2.tex 3544 - [X] freedb.tex 3545 - [X] musicbrainz.tex 3546 - [X] replaygain.tex 3547** DONE Make ReplayGain a configurable option 3548 Even tag-based ReplayGain should be something 3549 users can turn on or off globally via audiotools-config 3550*** DONE add audiotools-config option 3551**** DONE document in audiotools-config man page 3552*** DONE update tools to use option 3553 - [X] cdtrack 3554 - [X] dvda2track 3555 - [X] track2track 3556 - [X] tracksplit 3557** DONE Add progress to track2cd audio file conversion 3558 - [X] CD quality, embedded cuesheet 3559 - [X] non-CD quality, embedded cuesheet 3560 - [X] CD quality, external cuesheet 3561 - [X] non-CD quality, external cuesheet 3562 - [X] CD quality, multiple files 3563 - [X] non-CD quality, multiple files 3564** DONE Improve .wav performance 3565 don't read entire data chunk by default 3566** DONE Integrate MusicBrainz/FreeDB lookup with cd2track/dvda2track 3567 The two step extraction process is a relic from when I'd do 3568 batch lookups via modem. 3569 Combining metadata querying with extraction lets me perform more 3570 powerful lookups than are possible by using XMCD/XML file intermediaries. 3571 3572 However, CD lookups may be still be wrong. 3573 Therefore, it's essential to have a simple, interactive 3574 track metadata editor so that this data is very easy to populate. 3575*** DONE Add multi-track interactive editing mode to tracktag 3576**** DONE Update man page 3577*** DONE Build unified metadata selection widget for interactive modes 3578 This is something that can be run while a disc is being extracted 3579 or a track is being split which will drop the user back 3580 into a progress indicator once completed and then 3581 tag/rename the resulting tracks. 3582*** DONE Add MusicBrainz/FreeDB lookup options to audiotools-config 3583 It should be possible to decide whether to query either or both 3584 as a config option. 3585*** DONE Query MusicBrainz for album_number/album_total info 3586 Given a particular disc ID, there must be some way to pull 3587 the disc's album_number/album_total off MusicBrainz's servers 3588 if it's one of a series of discs. 3589*** DONE Add pre-extraction metadata lookup to tracksplit 3590**** DONE Update man page 3591*** DONE Add pre-extraction metadata lookup to cd2track 3592**** DONE Update man page with new options 3593*** DONE Add pre-extraction metadata lookup to dvda2track 3594**** DONE Update man page with new options 3595*** DONE Update cdinfo to use new ID calculation routines 3596 Ensure they handle the FreeDB test disc properly. 3597*** DONE Add pre-play metadata lookup to cdplay 3598**** DONE Update man page 3599*** DONE Add album-number/album-total options to tracksplit 3600 Allow these values to be populated at split-time 3601 if none can be found in metadata services 3602**** DONE Update man page 3603*** DONE Update album-number/album-total options in cd2track 3604*** DONE Remove xmcd-specific options 3605 Automatic CD lookup should be folded into utilites as needed. 3606 - [X] cd2track 3607 - [X] cdplay 3608 - [X] dvda2track 3609 - [X] track2track 3610 - [X] trackrename 3611 - [X] tracksplit 3612 - [X] tracktag 3613*** DONE Remove xmcd-specific tools 3614 - [X] cd2xmcd 3615 - [X] dvda2xmcd 3616 - [X] editxmcd 3617 - [X] track2xmcd 3618*** DONE Update unit tests 3619 - [X] cd2track 3620 - [X] dvda2track 3621 - [X] tracksplit 3622*** DONE Deprecate xmcd-specific modules 3623 Since metadata lookup handles files internally, 3624 there's no need for metadata file handling classes/functions 3625 at the Python level. 3626**** DONE Update documentation to indicate deprecation 3627** DONE Adjust album_number/track_number heuristics 3628 these should be last-resort fields that apply 3629 *only* if a track has no metadata of any kind 3630** DONE Don't port cuesheets with AudioFile.set_metadata() 3631 This is mostly for WavPack since it embeds cuesheet data 3632 in the APEv2 tag. 3633 - [X] FlacAudio 3634 - [X] OggFlacAudio 3635 - [X] WavPackAudio 3636** DONE Ensure overly-long files are handled correctly 3637 That is, anything larger than a .wav can typically handle 3638*** DONE wave should fail with error 3639*** DONE aiff should fail with error 3640*** DONE au should fail with error 3641*** DONE flac should work 3642*** DONE ogg flac should work 3643*** DONE wavpack should work 3644*** DONE alac should work 3645*** DONE shorten shouldn't begin 3646 requires verbatim wave or aiff chunks 3647 which can't be created because 3648 the amount of PCM data is too large 3649** DONE Fix FLAC embedded cuesheets 3650** DONE Ensure files are PEP8-compliant 3651*** DONE check user-level scripts 3652 - [X] audiotools-config 3653 - [X] cd2track 3654 - [X] cdinfo 3655 - [X] cdplay 3656 - [X] coverdump 3657 - [X] coverview 3658 - [X] dvda2track 3659 - [X] dvdainfo 3660 - [X] record2track 3661 - [X] track2cd 3662 - [X] track2track 3663 - [X] trackcat 3664 - [X] trackcmp 3665 - [X] trackinfo 3666 - [X] tracklength 3667 - [X] tracklint 3668 - [X] trackplay 3669 - [X] trackrename 3670 - [X] tracksplit 3671 - [X] tracktag 3672 - [X] trackverify 3673 - [X] setup.py 3674*** DONE check audiotools module 3675 - [X] __aiff__.py 3676 - [X] __ape__.py 3677 - [X] __au__.py 3678 - [X] __dvda__.py 3679 - [X] __flac__.py 3680 - [X] __freedb__.py 3681 - [X] __id3__.py 3682 - [X] __id3v1__.py 3683 - [X] __image__.py 3684 - [X] __init__.py 3685 - [X] __m4a__.py 3686 - [X] __m4a_atoms__.py 3687 - [X] __mp3__.py 3688 - [X] __musepack__.py 3689 - [X] __musicbrainz__.py 3690 - [X] __ogg__.py 3691 - [X] __shn__.py 3692 - [X] __vorbis__.py 3693 - [X] __vorbiscomment__.py 3694 - [X] __wav__.py 3695 - [X] __wavpack__.py 3696 - [X] cue.py 3697 - [X] delta.py 3698 - [X] freedb.py 3699 - [X] musicbrainz.py 3700 - [X] player.py 3701 - [X] toc.py 3702 - [X] ui.py 3703*** DONE check audiotools.py_decoders module 3704 - [X] __init__.py 3705 - [X] alac.py 3706 - [X] flac.py 3707 - [X] shn.py 3708 - [X] wavpack.py 3709*** DONE check audiotools.py_encoders module 3710 - [X] __init__.py 3711 - [X] alac.py 3712 - [X] flac.py 3713 - [X] shn.py 3714 - [X] wavpack.py 3715*** DONE check test 3716 - [X] test.py 3717 - [X] test_core.py 3718 - [X] test_formats.py 3719 - [X] test_metadata.py 3720 - [X] test_streams.py 3721 - [X] test_utils.py 3722** DONE Double-check reference docs one last time 3723*** DONE Ensure pages break correctly in letter mode 3724*** DONE Ensure pages break correctly in A4 mode 3725** DONE Fix FLAC seektable generation 3726 Ensure new seektables are aligned properly. 3727*** DONE Ensure proper seektable written on from_pcm 3728*** DONE Add .offsets() method to FlacDecoder 3729 Instead of decoding the file, this walks through it 3730 and returns a list of absolute file offsets of all frames. 3731*** DONE Add method to generate Flac_SEEKTABLE from offset list 3732*** DONE Add tracklint check/fix for mis-aligned seektables 3733*** DONE Add unit tests for seektable errors 3734 - [X] empty seekpoints 3735 - [X] mis-ordered seekpoints 3736 - [X] bad seekpoint destinations 3737** DONE Shift lint to the AudioFile and MetaData subclasses 3738 Instead of having tracklint have to perform lots of built-in tests, 3739 it would be better to have clean() functions added to the classes 3740 themselves. 3741 For MetaData, it could return a new object with fixed fields. 3742 For AudioFile, it could function like convert() and build a new file 3743 with fixes applied. 3744*** DONE Add clean() method to MetaData and subclasses 3745**** DONE MetaData 3746**** DONE ApeTag 3747**** DONE WavPackAPEv2 3748**** DONE FlacMetaData 3749**** DONE ID3v22Comment 3750**** DONE ID3v23Comment 3751**** DONE ID3v24Comment 3752**** DONE ID3v1Comment 3753**** DONE ID3CommentPair 3754**** DONE M4AMetaData 3755**** DONE VorbisComment 3756***** DONE FlacVorbisComment 3757***** DONE UnframedVorbisComment 3758*** DONE Add clean() method to AudioFile and subclasses 3759 I expect a lot of these will do nothing in the short term. 3760**** DONE AudioFile 3761**** DONE AiffAudio 3762 - [X] Reorder streams in which the COMM chunk doesn't come before data 3763 - [X] remove duplicate COMM chunks 3764 - [X] remove duplicate SSND chunks 3765***** DONE add unit test for verify() 3766 - [X] multiple COMM chunks found 3767 - [X] multiple SSND chunks found 3768 - [X] SSND chunk before COMM chunk 3769***** DONE add unit test for clean() 3770 - [X] multiple COMM chunks found 3771 - [X] multiple SSND chunks found 3772 - [X] SSND chunk before COMM chunk 3773**** DONE FlacAudio 3774**** DONE WaveAudio 3775 - [X] reorder streams in which the fmt chunk doesn't come before data 3776 - [X] remove duplicate fmt chunks 3777 - [X] remove duplicate data chunks 3778***** DONE add unit test for verify() 3779 - [X] multiple fmt chunks found 3780 - [X] multiple data chunks found 3781 - [X] data chunk before fmt chunk 3782***** DONE add unit test for clean() 3783 - [X] multiple fmt chunks found 3784 - [X] multiple data chunks found 3785 - [X] data chunk before fmt chunk 3786*** DONE Document MetaData clean() method 3787*** DONE Document AudioFile clean() method 3788*** DONE Add more comprehensive unit tests for clean() methods 3789*** DONE Convert tracklint to use clean() methods 3790** DONE Ensure individual unit tests pass 3791*** DONE Lib 3792 - [X] core 3793 - [X] cuesheet 3794 - [X] freedb 3795 - [X] image 3796 - [X] musicbrainz 3797 - [X] pcm 3798 - [X] bitstream 3799 - [X] replaygain 3800 - [X] resample 3801 - [X] tocfile 3802 - [X] verify 3803 - [X] player 3804*** DONE Format 3805 - [X] audiofile 3806 - [X] lossless 3807 - [X] lossy 3808 - [X] aiff 3809 - [X] alac 3810 - [X] au 3811 - [X] dvda 3812 - [X] flac 3813 - [X] m4a 3814 - [X] mp2 3815 - [X] mp3 3816 - [X] oggflac 3817 - [X] shorten 3818 - [X] sines 3819 - [X] vorbis 3820 - [X] wave 3821 - [X] wavpack 3822*** DONE Metadata 3823 - [X] metadata 3824 - [X] flac 3825 - [X] wavpack 3826 - [X] id3v1 3827 - [X] id3v2 3828 - [X] vorbis 3829 - [X] m4a 3830*** DONE Util 3831 - [X] audiotools_config 3832 - [X] cd2track 3833 - [X] cdinfo 3834 - [X] cdplay 3835 - [X] coverdump 3836 - [X] coverview 3837 - [X] dvda2track 3838 - [X] dvdainfo 3839 - [X] record2track 3840 - [X] track2cd 3841 - [X] track2track 3842 - [X] trackcat 3843 - [X] trackcmp 3844 - [X] trackinfo 3845 - [X] tracklength 3846 - [X] tracklint 3847 - [X] trackplay 3848 - [X] trackrename 3849 - [X] tracksplit 3850 - [X] tracktag 3851 - [X] trackverify 3852** DONE Ensure complete unit test passes 3853 this includes some compound tests 3854 which may not be covered by individual tests 3855** DONE Cleanup bitstream module 3856 This is at the heart of a lot of things so it should be properly cleaned up. 3857*** DONE Merge bitstream_r and bitstream_w source files 3858*** DONE Make BitstreamReader and BitstreamWriter more symmetric 3859*** DONE Add placeholders to BitstreamWriter 3860 These allow one to put temporary values in the stream 3861 which can be automatically filled-in later on. 3862**** DONE Add write_placeholder method to BitstreamWriter 3863**** DONE Add fill_placeholder method to BitstreamWriter 3864**** DONE Add write_64_placeholder method to BitstreamWriter 3865**** DONE Add fill_64_placeholder method to BitstreamWriter 3866**** DONE Implement bw_write_placeholder_f 3867**** DONE Implement bw_write_64_placeholder_f 3868**** DONE Implement bw_fill_placeholder_f 3869**** DONE Implement bw_fill_64_placeholder_f 3870**** DONE Implement bw_write_placeholder_r 3871**** DONE Implement bw_write_64_placeholder_r 3872**** DONE Implement bw_fill_placeholder_r 3873**** DONE Implement bw_fill_64_placeholder_r 3874**** DONE Implement bw_write_placeholder_a 3875 Should manage the placeholder stack, but only keep track of bits sent 3876**** DONE Implement bw_write_64_placeholder_a 3877 Should manage the placeholder stack, but only keep track of bits sent 3878**** DONE Implement bw_fill_placeholder_a 3879 Should manage the placeholder stack, but not do anything else 3880**** DONE Implement bw_fill_64_placeholder_a 3881 Should manage the placeholder stack, but not do anything else 3882**** DONE Store filled placeholders in a stack for reuse 3883**** DONE Clean out allocated placeholders as close() time 3884***** DONE Trigger warnings if not all placeholders are used at close() 3885*** DONE Add C-based unit tests 3886 This should be something I can compile into a standalone file 3887 and run with no external dependencies. 3888 The idea is to build something valgrind-able to ensure 3889 there's no memory errors. 3890**** DONE BitstreamReader 3891***** DONE big-endian 3892 - [X] read 3893 - [X] read_signed 3894 - [X] read_64 3895 - [X] skip 3896 - [X] skip_bytes 3897 - [X] unread 3898 - [X] read_unary 3899 - [X] read_limited_unary 3900 - [X] read_huffman_code 3901 - [X] byte_align 3902 - [X] read_bytes 3903 - [X] set_endianness 3904 - [X] mark 3905 - [X] unmark 3906 - [X] rewind 3907***** DONE little-endian 3908 - [X] read 3909 - [X] read_signed 3910 - [X] read_64 3911 - [X] skip 3912 - [X] skip_bytes 3913 - [X] unread 3914 - [X] read_unary 3915 - [X] read_limited_unary 3916 - [X] read_huffman_code 3917 - [X] byte_align 3918 - [X] read_bytes 3919 - [X] set_endianness 3920 - [X] mark 3921 - [X] unmark 3922 - [X] rewind 3923***** DONE br_try/etry 3924 - [X] read 3925 - [X] read_signed 3926 - [X] read_64 3927 - [X] skip 3928 - [X] skip_bytes 3929 - [X] read_unary 3930 - [X] read_limited_unary 3931 - [X] read_huffman_code 3932 - [X] read_bytes 3933 - [X] substream_append 3934***** DONE Callbacks 3935 - [X] read 3936 - [X] read_signed 3937 - [X] read_64 3938 - [X] skip 3939 - [X] skip_bytes 3940 - [X] read_unary 3941 - [X] read_limited_unary 3942 - [X] read_huffman_code 3943 - [X] read_bytes 3944**** DONE Substream BitstreamReader 3945**** DONE BitstreamWriter 3946***** DONE big-endian 3947***** DONE little-endian 3948***** DONE callbacks 3949**** DONE BitstreamRecorder 3950**** DONE BitstreamAccumulator 3951*** DONE Shift BitstreamReader/BitstreamWriters to audiotools.bitstream 3952*** DONE Add documentation for audiotools.bitstream 3953**** DONE BitstreamReader 3954 - [X] add_callback 3955 - [X] byte_align 3956 - [X] call_callbacks 3957 - [X] close 3958 - [X] limited_unary 3959 - [X] mark 3960 - [X] parse 3961 - [X] pop_callback 3962 - [X] read 3963 - [X] read64 3964 - [X] read_bytes 3965 - [X] read_huffman_code 3966 - [X] read_signed 3967 - [X] read_signed64 3968 - [X] rewind 3969 - [X] set_endianness 3970 - [X] skip 3971 - [X] skip_bytes 3972 - [X] substream 3973 - [X] substream_append 3974 - [X] unary 3975 - [X] unmark 3976 - [X] unread 3977**** DONE BitstreamWriter 3978 - [X] add_callback 3979 - [X] build 3980 - [X] byte_align 3981 - [X] call_callbacks 3982 - [X] close 3983 - [X] flush 3984 - [X] pop_callback 3985 - [X] set_endianness 3986 - [X] unary 3987 - [X] write 3988 - [X] write64 3989 - [X] write_bytes 3990 - [X] write_signed 3991 - [X] write_signed64 3992**** DONE BitstreamRecorder 3993 - [X] add_callback 3994 - [X] bits 3995 - [X] build 3996 - [X] byte_align 3997 - [X] bytes 3998 - [X] call_callbacks 3999 - [X] close 4000 - [X] copy 4001 - [X] data 4002 - [X] flush 4003 - [X] pop_callback 4004 - [X] reset 4005 - [X] set_endianness 4006 - [X] split 4007 - [X] swap 4008 - [X] unary 4009 - [X] write 4010 - [X] write64 4011 - [X] write_bytes 4012 - [X] write_signed 4013 - [X] write_signed64 4014**** DONE BitstreamAccumulator 4015 - [X] bits 4016 - [X] build 4017 - [X] byte_align 4018 - [X] bytes 4019 - [X] close 4020 - [X] reset 4021 - [X] set_endianness 4022 - [X] unary 4023 - [X] write 4024 - [X] write64 4025 - [X] write_bytes 4026 - [X] write_signed 4027 - [X] write_signed64 4028**** DONE HuffmanTree 4029**** DONE Substream 4030**** DONE format_size 4031*** DONE Handle bitstream closing more consistently 4032 The basic handle cycle is: 4033 4034 h = open_handle(substream); /*allocates space for handle*/ 4035 h->method(h); /*performs reads/writes on handle*/ 4036 ... 4037 h->close(h); /*closes substream and deallocates handle*/ 4038 4039 But we also need two additional methods 4040 for working with the handle and its substream seperately. 4041 4042 | method | substream | handle | 4043 |-------------------+----------------+-------------| 4044 | close() | flushed/closed | deallocated | 4045 | close_substream() | flushed/closed | nothing | 4046 | free() | nothing | deallocated | 4047 |-------------------+----------------+-------------| 4048 4049 This is especially important for the Python wrappers 4050 in which closing and dealloacting will come from different routines. 4051**** DONE Add functions to bitstream core 4052***** DONE BitstreamReader 4053 - [X] br_close_substream_f 4054 - [X] br_close_substream_s 4055 - [X] br_close_substream_p 4056 - [X] br_close_methods 4057 - [X] br_free_f 4058 - [X] br_free_s 4059 - [X] br_free_p 4060 - [X] br_close 4061 - [X] br_read_bits_c 4062 - [X] br_read_bits64_c 4063 - [X] br_skip_bits_c 4064 - [X] br_unread_c 4065 - [X] br_read_unary_c 4066 - [X] br_read_limited_unary_c 4067 - [X] br_read_huffman_code_c 4068 - [X] br_read_bytes_c 4069 - [X] br_set_endianness_c 4070 - [X] br_close_substream_c 4071 - [X] br_mark_c 4072 - [X] br_rewind_c 4073 - [X] br_unmark_c 4074 - [X] br_substream_append_c 4075***** DONE BitstreamWriter 4076 - [X] bw_close_substream_f 4077 - [X] bw_close_substream_r 4078 - [X] bw_close_substream_p 4079 - [X] bw_close_substream_a 4080 - [X] bw_close_methods 4081 - [X] bw_free_f_a 4082 - [X] bw_free_r 4083 - [X] bw_free_p 4084 - [X] bw_close 4085 - [X] bw_write_bits_c 4086 - [X] bw_write_bits64_c 4087 - [X] bw_write_bytes_c 4088 - [X] bw_write_signed_bits_c 4089 - [X] bw_write_signed_bits64_c 4090 - [X] bw_write_unary_c 4091 - [X] bw_set_endianness_c 4092 - [X] bw_close_substream_c 4093 - [X] bw_byte_align_c 4094***** DONE Ensure bw_rec_split detects closed stream(s) properly 4095 Call bw_abort if one attempts to split from or to a closed stream. 4096***** DONE Ensure bw_dump_bytes detects closed stream properly 4097 Call bw_abort if one attempts to dump bytes to a closed stream. 4098***** DONE Ensure bw_rec_copy detects closed stream properly 4099 Call bw_abort if one attempts to copy records to a closed stream. 4100**** DONE Update mod_bitstream.c to use new hooks properly 4101***** DONE Add bw_try/bw_etry wrappers around write methods 4102 - [X] BitstreamWriter_write 4103 - [X] BitstreamWriter_write_signed 4104 - [X] BitstreamWriter_write64 4105 - [X] BitstreamWriter_write_signed64 4106 - [X] BitstreamWriter_unary 4107 - [X] BitstreamWriter_byte_align 4108 - [X] BitstreamWriter_write_bytes 4109 - [X] BitstreamWriter_flush 4110 - [X] BitstreamRecorder_write 4111 - [X] BitstreamRecorder_write_signed 4112 - [X] BitstreamRecorder_write64 4113 - [X] BitstreamRecorder_write_signed64 4114 - [X] BitstreamRecorder_unary 4115 - [X] BitstreamRecorder_byte_align 4116 - [X] BitstreamRecorder_write_bytes 4117 - [X] BitstreamRecorder_copy 4118 - [X] BitstreamRecorder_split 4119 - [X] bitstream_build 4120 - [X] BitstreamAccumulator_write 4121 - [X] BitstreamAccumulator_write_signed 4122 - [X] BitstreamAccumulator_write64 4123 - [X] BitstreamAccumulator_write_signed64 4124 - [X] BitstreamAccumulator_unary 4125 - [X] BitstreamAccumulator_byte_align 4126 - [X] BitstreamAccumulator_write_bytes 4127***** DONE Ensure close() method calls bs->close_substream() 4128 - [X] BitstreamWriter 4129 - [X] BitstreamRecorder 4130 - [X] BitstreamAccumulator 4131***** DONE Ensure dealloc method calls bs->free() 4132 - [X] BitstreamWriter 4133 - [X] BitstreamRecorder 4134 - [X] BitstreamAccumulator 4135***** DONE Don't fclose() file objects from underneath Python file objects 4136 Although we may convert a Python file object to a FILE struct, 4137 we must not fclose that struct out from underneath its parent. 4138****** DONE BitstreamReader_close 4139 - [X] call .close() method on Python file object 4140 - [X] set read methods to raise errors 4141 - [X] return result of .close() method 4142****** DONE BitstreamWriter_close 4143 - [X] flush pending output 4144 - [X] call .close() method on Python file object 4145 - [X] set write methods to raise errors 4146 - [X] return result of .close() method 4147****** DONE BitstreamRecorder_close 4148****** DONE BitstreamAccumulator_close 4149**** DONE Double-check existing C modules for proper free/close usage 4150 - [X] bitstream.c 4151 - [X] decoders/alac.c 4152 - [X] decoders/flac.c 4153 - [X] decoders/mlp.c 4154 - [X] decoders/ogg.c 4155 - [X] decoders/shn.c 4156 - [X] decoders/wavpack.c 4157 - [X] encoders/alac.c 4158 - [X] encoders/flac.c 4159 - [X] encoders/flac_lpc.c 4160 - [X] encoders/shn.c 4161 - [X] encoders/wavpack.c 4162 - [X] mod_bitstream.c 4163 - [X] verify/mpeg.c 4164 - [X] verify/ogg.c 4165*** DONE Ensure that reading/writing closed streams always fails 4166 Once a stream's been closed, 4167 the bitstream should set I/O functions to error generators 4168 and further closes should do nothing. 4169**** DONE Add unit test to bitstream.c 4170**** DONE Add unit test to Python side 4171** DONE Add update_metadata() method to AudioFile 4172 Consider how AudioFile.set_metadata() handles six different cases: 4173 4174 Case 1: adjusting a file's own textual metadata (tracktag) 4175 >>> m = flac1.get_metadata() 4176 >>> m.track_name = u"Fixed Name" 4177 >>> flac1.set_metadata(m) 4178 4179 Case 2: transferring metadata from the same audio type (track2track) 4180 >>> flac1.set_metadata(flac2.get_metadata()) 4181 4182 Case 3: transferring metadata from a different audio type (track2track) 4183 >>> flac1.set_metadata(mp3.get_metadata()) 4184 4185 Case 4: adjusting a file's own low-level metadata (tracklint) 4186 >>> m = flac1.get_metadata() 4187 >>> m.streaminfo.md5sum = fixed_md5sum 4188 >>> flac1.set_metadata(m) 4189 4190 Case 5: building new metadata from scratch (cd2track) 4191 >>> flac1 = FlacAudio.from_pcm(pcm_reader) 4192 >>> flac1.set_metadata(MetaData(track_name=u"New Name", ...)) 4193 4194 Case 6: transferring adjusted metadata from the same audio type 4195 >>> m = flac2.get_metadata() 4196 >>> m.track_name = u"Adjusted Name" 4197 >>> flac1.set_metadata(m) 4198 4199 What happens to stuff like the STREAMINFO block 4200 which contains track length, md5sum, etc. 4201 and is part of FLAC's metadata? 4202 4203 If set_metadata() works naively and doesn't override any values, 4204 case 2 breaks since flac1 suddenly has flac2's track length. 4205 4206 If set_metadata() overrides new metadata with stuff from the current file, 4207 case 4 breaks since the fixed_md5sum gets overridden. 4208 4209 Counting on set_metadata() being smart enough to know what you mean 4210 is a losing proposition for FLAC, M4A and other metadata formats 4211 with embedded non-textual (side) metadata. 4212 4213 One solution is to add a low-level AudioFile.update_metadata() method 4214 which takes only the AudioFile's required metadata type 4215 and leaves side data as-is. So case 1 becomes: 4216 4217 >>> m = flac1.get_metadata() 4218 >>> m.track_name = u"Fixed Name" 4219 >>> flac1.update_metadata(m) 4220 4221 and case 4 becomes: 4222 4223 >>> m = flac1.get_metadata() 4224 >>> m.streaminfo.md5sum = fixed_md5sum 4225 >>> flac1.update_metadata(m) 4226 4227 while the other cases remain unchanged. 4228*** DONE Add update_metadata() method to AudioFile and subclasses 4229 for formats which take metadata at all 4230 - [X] ALACAudio 4231 - [X] AiffAudio 4232 - [X] AudioFile 4233 - [X] FlacAudio 4234 - [X] M4AAudio 4235 - [X] MP2Audio 4236 - [X] MP3Audio 4237 - [X] OggFlacAudio 4238 - [X] VorbisAudio 4239 - [X] WavPackAudio 4240*** DONE Update clean() method to use update_metadata() 4241 for formats which implement clean() at all 4242 - [X] ALACAudio 4243 - [X] AiffAudio 4244 - [X] FlacAudio 4245 - [X] M4AAudio 4246 - [X] MP2Audio 4247 - [X] MP3Audio 4248 - [X] OggFlacAudio 4249 - [X] VorbisAudio 4250 - [X] WavPackAudio 4251*** DONE Add update_metadata() to tracktag 4252 when not using -r/--replace option 4253*** DONE Document new set_metadata() behavior 4254*** DONE Document update_metadata() method 4255*** DONE Add unit tests for update_metadata() 4256 - [X] ALACAudio 4257 - [X] AiffAudio 4258 - [X] FlacAudio 4259 - [X] M4AAudio 4260 - [X] MP2Audio 4261 - [X] MP3Audio 4262 - [X] OggFlacAudio 4263 - [X] VorbisAudio 4264 - [X] WavPackAudio 4265** DONE Ensure Python API docs are updated if necessary 4266 - [X] audiotools.rst 4267 - [X] audiotools_bitstream.rst 4268 - [X] audiotools_cdio.rst 4269 - [X] audiotools_cue.rst 4270 - [X] audiotools_pcm.rst 4271 - [X] audiotools_player.rst 4272 - [X] audiotools_replaygain.rst 4273 - [X] audiotools_resample.rst 4274 - [X] audiotools_toc.rst 4275 - [X] index.rst 4276 - [X] metadata.rst 4277** DONE Spellcheck Python API docs 4278 - [X] audiotools.rst 4279 - [X] audiotools_bitstream.rst 4280 - [X] audiotools_cdio.rst 4281 - [X] audiotools_cue.rst 4282 - [X] audiotools_pcm.rst 4283 - [X] audiotools_player.rst 4284 - [X] audiotools_replaygain.rst 4285 - [X] audiotools_resample.rst 4286 - [X] audiotools_toc.rst 4287 - [X] index.rst 4288 - [X] metadata.rst 4289** DONE Eliminate all compiler warnings 4290 - [X] check Ubuntu 4291 - [X] check Fedora 4292 - [X] check Mac OS X 4293** DONE Reduce load from progress updating routines 4294 Send fewer progress updates from child to parent 4295 when performing progress-based tasks. 4296 4297 This is harder than it sounds. 4298 4299 In an ideal world, I'd have the parent poll its children 4300 on a regular basis and update the progress bars 4301 and/or start more children. 4302 4303 In practice, this doesn't work with subprocesses and shared memory 4304 because shared memory accumulators don't free themselves correctly 4305 when working with more than one child process. 4306 4307 It works even less well with threading because subprocess.Popen 4308 isn't thread-safe and will certainly deadlock if called often enough. 4309 4310 So although the current system is clunky and inefficient 4311 at least it works. 4312** DONE Ensure all Python modules have up-to-date docstrings 4313 - [X] __aiff__.py 4314 - [X] __ape__.py 4315 - [X] __au__.py 4316 - [X] __dvda__.py 4317 - [X] __flac__.py 4318 - [X] __id3__.py 4319 - [X] __id3v1__.py 4320 - [X] __image__.py 4321 - [X] __init__.py 4322 - [X] __m4a__.py 4323 - [X] __m4a_atoms__.py 4324 - [X] __mp3__.py 4325 - [X] __ogg__.py 4326 - [X] __shn__.py 4327 - [X] __vorbis__.py 4328 - [X] __vorbiscomment__.py 4329 - [X] __wav__.py 4330 - [X] __wavpack__.py 4331 - [X] cue.py 4332 - [X] delta.py 4333 - [X] freedb.py 4334 - [X] musicbrainz.py 4335 - [X] player.py 4336 - [X] toc.py 4337 - [X] ui.py 4338** DONE Ensure MANIFEST.in is complete 4339** DONE Update apptest.sh 4340 It's not much of a test, but it's good to keep it around 4341 as a last-resort check of things people normally run. 4342** DONE Run final batch of unit tests on different platforms 4343 - [X] check Ubuntu 4344 - [X] check Fedora 4345 - [X] check Mac OS X 4346* DONE Finish version 2.19 4347** DONE Update PCMReader.read() to take a PCM frame count instead of bytes 4348 Taking a byte count as an argument is a relic from the days 4349 when most conversion happened through external programs. 4350 It's time to update this function to work on PCM frames instead 4351 which is much more natural fit and makes many calculations much easier. 4352*** DONE Update __init__.py 4353 - [X] PCMReader.read 4354 - [X] PCMReaderError.read 4355 - [X] PCMReaderProgress.read 4356 - [X] ReorderedPCMReader.read 4357 - [X] transfer_framelist_data 4358 - [X] threaded_transfer_framelist_data 4359 - [X] pcm_cmp 4360 - [X] pcm_frame_cmp 4361 - [X] PCMCat.read 4362 - [X] __buffer__.__init__ 4363 - [X] __buffer__.__len__ 4364 - [X] BufferedPCMReader.read 4365 - [X] BufferedPCMReader.__fill__ 4366 - [X] LimitedPCMReader.read 4367 - [X] pcm_split 4368 - [X] PCMConverter.read 4369 - [X] ReplayGainReader.read 4370 - [X] calculate_replay_gain 4371 - [X] AudioFile.verify 4372 - [X] PCMReaderWindow.read 4373 - [X] CDTrackReader.read 4374 - [X] CDTrackReaderAccurateRipCRC.read 4375*** DONE Update __aiff__.py 4376 - [X] AiffReader.read 4377 - [X] AiffAudio.from_pcm 4378*** DONE Update __au__.py 4379 - [X] AuReader.read 4380 - [X] AuReader.from_pcm 4381*** DONE Update __flac__.py 4382 - [X] FlacAudio.__eq__ 4383 - [X] FLAC_Data_Chunk.write 4384 - [X] FLAC_SSND_Chunk.write 4385*** DONE Update __shn__.py 4386 - [X] ShortenAudio.to_wave 4387 - [X] ShortenAudio.to_aiff 4388*** DONE Update __wav__.py 4389 - [X] WaveReader.read 4390 - [X] WaveAudio.from_pcm 4391 - [X] WaveAudio.add_replay_gain 4392*** DONE Update __wavpack__.py 4393 - [X] WavPackAudio.to_wave 4394*** DONE Update py_decoders/alac.py 4395 - [X] ALACDecoder.read 4396*** DONE Update py_decoders/flac.py 4397 - [X] FlacDecoder.read 4398*** DONE Update py_decoders/shn.py 4399 - [X] SHNDecoder.read 4400*** DONE Update py_decoders/wavpack.py 4401 - [X] WavPackDecoder.read 4402*** DONE Update py_encoders/alac.py 4403 - [X] encode_mdat 4404*** DONE Update py_encoders/flac.py 4405 - [X] encode_flac 4406*** DONE Update py_encoders/shn.py 4407 - [X] encode_shn 4408*** DONE Update py_encoders/wavpack.py 4409 - [X] encode_wavpack 4410*** DONE Update src/pcmconv.c 4411 - [X] pcmreader_read 4412 - [X] pcmreader_read (alt version) 4413*** DONE Update src/replaygain.c 4414 - [X] ReplayGainReader_read 4415*** DONE Update src/decoders/sine.c 4416 - [X] Sine_Mono_read 4417 - [X] Sine_Stereo_read 4418 - [X] Sine_Simple_read 4419*** DONE Update test/test.py 4420 - [X] BLANK_PCM_Reader 4421 - [X] RANDOM_PCM_Reader 4422 - [X] EXACT_BLANK_PCM_Reader 4423 - [X] EXACT_SILENCE_PCM_Reader 4424 - [X] EXACT_RANDOM_PCM_Reader 4425 - [X] MD5_Reader 4426 - [X] Variable_Reader 4427 - [X] Join_Reader 4428 - [X] MiniFrameReader 4429*** DONE Update test/test_core.py 4430 - [X] BufferedPCMReader.test_pcm 4431 - [X] LimitedPCMReader.test_read 4432 - [X] PCMReaderWindow.__test_reader__ 4433 - [X] PCM_Reader_Multiplexer.read 4434 - [X] TestMultiChannel.__test_assignment__ 4435*** DONE Update test/test_formats.py 4436 - [X] ERROR_PCM_Reader.read 4437 - [X] ALACFileTest.__test_reader__ 4438 - [X] ALACFileTest.__test_reader_nonalac__ 4439 - [X] ALACFileTest.test_streams 4440 - [X] FlacFileTest.test_streams 4441 - [X] FlacFileTest.__test_reader__ 4442 - [X] ShortenFileTest.test_streams 4443 - [X] ShortenFileTest.__test_reader__ 4444 - [X] WavPackFileTest.__test_reader__ 4445*** DONE Update test/test_streams.py 4446 - [X] FrameListReader.read 4447 - [X] MD5Reader.read 4448 - [X] Sine8_Mono.read 4449 - [X] Sine8_Stereo.read 4450 - [X] Simple_Sine.read 4451 - [X] WastedBPS16.read 4452*** DONE Ensure all unit tests pass 4453**** DONE [Lib] 4454 - [X] core 4455 - [X] cuesheet 4456 - [X] freedb 4457 - [X] image 4458 - [X] musicbrainz 4459 - [X] pcm 4460 - [X] bitstream 4461 - [X] replaygain 4462 - [X] resample 4463 - [X] tocfile 4464 - [X] verify 4465 - [X] player 4466**** DONE [Format] 4467 - [X] audiofile 4468 - [X] lossless 4469 - [X] lossy 4470 - [X] aiff 4471 - [X] alac 4472 - [X] au 4473 - [X] dvda 4474 - [X] flac 4475 - [X] m4a 4476 - [X] mp2 4477 - [X] mp3 4478 - [X] oggflac 4479 - [X] shorten 4480 - [X] sines 4481 - [X] vorbis 4482 - [X] wave 4483 - [X] wavpack 4484**** DONE [Metadata] 4485 - [X] metadata 4486 - [X] flac 4487 - [X] wavpack 4488 - [X] id3v1 4489 - [X] id3v2 4490 - [X] vorbis 4491 - [X] m4a 4492**** DONE [Util] 4493 - [X] audiotools_config 4494 - [X] cd2track 4495 - [X] cdinfo 4496 - [X] cdplay 4497 - [X] coverdump 4498 - [X] coverview 4499 - [X] dvda2track 4500 - [X] dvdainfo 4501 - [X] track2cd 4502 - [X] track2track 4503 - [X] trackcat 4504 - [X] trackcmp 4505 - [X] trackinfo 4506 - [X] tracklength 4507 - [X] tracklint 4508 - [X] trackplay 4509 - [X] trackrename 4510 - [X] tracksplit 4511 - [X] tracktag 4512 - [X] trackverify 4513*** DONE Update reference documentation 4514** DONE Remove the big pile of imports from various modules 4515 Only import the stuff we need, when we need it. 4516*** DONE __init__.py 4517*** DONE accuraterip.py 4518*** DONE aiff.py 4519*** DONE ape.py 4520*** DONE au.py 4521*** DONE dvda.py 4522*** DONE flac.py 4523*** DONE id3.py 4524*** DONE id3v1.py 4525*** DONE image.py 4526*** DONE m4a.py 4527*** DONE m4a_atoms.py 4528*** DONE mp3.py 4529*** DONE ogg.py 4530*** DONE shn.py 4531*** DONE vorbis.py 4532*** DONE vorbiscomment.py 4533*** DONE wav.py 4534*** DONE wavpack.py 4535*** DONE cue.py 4536*** DONE delta.py 4537*** DONE freedb.py 4538*** DONE musicbrainz.py 4539*** DONE player.py 4540*** DONE toc.py 4541*** DONE ui.py 4542*** DONE ensure unit tests pass 4543**** DONE [Lib] 4544 - [X] core 4545 - [X] cuesheet 4546 - [X] freedb 4547 - [X] image 4548 - [X] musicbrainz 4549 - [X] pcm 4550 - [X] bitstream 4551 - [X] replaygain 4552 - [X] resample 4553 - [X] tocfile 4554 - [X] verify 4555 - [X] player 4556**** DONE [Format] 4557 - [X] audiofile 4558 - [X] lossless 4559 - [X] lossy 4560 - [X] aiff 4561 - [X] alac 4562 - [X] au 4563 - [X] dvda 4564 - [X] flac 4565 - [X] m4a 4566 - [X] mp2 4567 - [X] mp3 4568 - [X] oggflac 4569 - [X] shorten 4570 - [X] sines 4571 - [X] vorbis 4572 - [X] wave 4573 - [X] wavpack 4574**** DONE [Metadata] 4575 - [X] metadata 4576 - [X] flac 4577 - [X] wavpack 4578 - [X] id3v1 4579 - [X] id3v2 4580 - [X] vorbis 4581 - [X] m4a 4582**** DONE [Util] 4583 - [X] audiotools_config 4584 - [X] cd2track 4585 - [X] cdinfo 4586 - [X] cdplay 4587 - [X] coverdump 4588 - [X] coverview 4589 - [X] dvda2track 4590 - [X] dvdainfo 4591 - [X] track2cd 4592 - [X] track2track 4593 - [X] trackcat 4594 - [X] trackcmp 4595 - [X] trackinfo 4596 - [X] tracklength 4597 - [X] tracklint 4598 - [X] trackplay 4599 - [X] trackrename 4600 - [X] tracksplit 4601 - [X] tracktag 4602 - [X] trackverify 4603** DONE Integrate Filename object into utilities 4604 This object should replace the Messenger.filename classmethod. 4605 It automatically performs filename -> unicode conversion 4606 and, when files are on disk, compares for equality by device/inode. 4607*** DONE Update utilities 4608**** DONE audiotools-config 4609**** DONE cd2track 4610**** DONE coverdump 4611**** DONE coverview 4612**** DONE dvda2track 4613**** DONE dvdainfo 4614**** DONE track2cd 4615**** DONE track2track 4616**** DONE trackcat 4617**** DONE trackcmp 4618**** DONE trackinfo 4619**** DONE tracklint 4620**** DONE trackrename 4621**** DONE tracksplit 4622**** DONE tracktag 4623**** DONE trackverify 4624*** DONE Add documentation for Filename 4625*** DONE Add unit tests for Filename 4626*** DONE Remove Messenger.filename classmethod 4627**** DONE remove mention in documentation 4628*** DONE Ensure all unit tests pass 4629** DONE Sanity check tool inputs/outputs 4630*** DONE Ensure input files are included only once 4631 - [X] track2cd - generate warning 4632 - [X] track2track - generate error 4633 - [X] trackcat - generate warning 4634 - [X] trackcmp - short-circuit same file comparison 4635 - [X] tracklength - generate warning 4636 - [X] tracklint - generate error 4637 - [X] trackrename - generate error 4638 - [X] tracktag - generate error 4639 - [X] trackverify - skip duplicates 4640**** DONE Unit test new behavior 4641 - [X] track2cd 4642 - [X] track2track 4643 - [X] trackcat 4644 - [X] trackcmp 4645 - [X] tracklint 4646 - [X] trackrename 4647 - [X] tracktag 4648 - [X] trackverify 4649*** DONE Ensure input file(s) are different from output file(s) 4650 Overwriting files is okay by default (in the Unix tradition) 4651 but input and output as same file is not and should generate error. 4652 - [X] coverdump 4653 - [X] track2track 4654 - [X] trackcat 4655 - [X] tracksplit 4656**** DONE Unit test new behavior 4657 - [X] coverdump 4658 - [X] track2track 4659 - [X] trackcat 4660 - [X] tracksplit 4661*** DONE Ensure same file isn't written twice by the same utility 4662 This would typically be the result of a misused "--format" argument. 4663 - [X] cd2track 4664 - [X] dvda2track 4665 - [X] track2track 4666 - [X] trackrename 4667 - [X] tracksplit 4668**** DONE unit test new behavior 4669 - [X] cd2track 4670 - [X] track2track 4671 - [X] trackrename 4672 - [X] tracksplit 4673** DONE Ensure progress display doesn't overload terminal with rows 4674 As more cores become commonplace, it's important not to 4675 overload the screen with too many progress rows 4676 in case the number of simultaneous jobs 4677 exceeds the number of terminal rows. 4678** DONE Improve metadata tagging widget 4679 I'm not convinced the current opened/closed bottom window 4680 is the ideal design for editing extended album/track metadata. 4681 Something more similar to a spreadsheet would be ideal 4682 but that's complicated by the serious lack of space 4683 in terminal windows. 4684** DONE Fix ReplayGain to work on files with different sample rates 4685 This should handle a wider array of cases than it does now. 4686*** DONE Update can_add_replay_gain classmethod 4687 It should take a list of tracks and return True 4688 if ReplayGain can be added to them, False if not 4689 which takes the place of applicable_replay_gain 4690 - [X] AudioFile.can_add_replay_gain 4691 - [X] FlacAudio.can_add_replay_gain 4692 - [X] M4AAudio_faac.can_add_replay_gain 4693 - [X] MP3Audio.can_add_replay_gain 4694 - [X] VorbisAudio.can_add_replay_gain 4695 - [X] WaveAudio.can_add_replay_gain 4696 - [X] WavPackAudio.can_add_replay_gain 4697**** DONE update reference documentation 4698**** DONE update unit tests 4699 - [X] test_formats.py AudioFileTest.test_replay_gain 4700 - [X] test_utils.py track2track.test_options 4701 - [X] test_utils.py tracktag.test_options 4702*** DONE Add supports_replay_gain() classmethod 4703 Returns True if the class supports ReplayGain of any kind. 4704 - [X] AudioFile 4705 - [X] FlacAudio 4706 - [X] M4AAudio 4707 - [X] MP2Audio 4708 - [X] MP3Audio 4709 - [X] OggFlacAudio 4710 - [X] VorbisAudio 4711 - [X] WavPackAudio 4712 - [X] WaveAudio 4713**** DONE Add documentation 4714*** DONE Remove audiotools.applicable_replay_gain function 4715 this functionality is shifted to can_add_replay_gain 4716**** DONE remove from utilities 4717 - [X] dvda2track 4718 - [X] track2track 4719 - [X] tracksplit 4720**** DONE update reference documentation 4721**** DONE update unit tests 4722*** DONE Update calculate_replay_gain function 4723**** DONE tracks with unsupported sample rates should be resampled 4724 according to the nearest supported sample rate available 4725**** DONE tracks with different sample rates should be resampled 4726 according to the most common sample rate available 4727**** DONE tracks with more than two channels should be culled 4728 remove any channels above the first two during calculation 4729**** DONE update unit tests 4730 - [X] test_core.py TestReplayGain.test_basics 4731*** DONE Update add_replay_gain classmethods as needed 4732 - [X] AudioFile.add_replay_gain 4733 - [X] FlacAudio.add_replay_gain 4734 - [X] M4AAudio_faac.add_replay_gain 4735 - [X] MP3Audio.add_replay_gain 4736 - [X] VorbisAudio.add_replay_gain 4737 - [X] WaveAudio.add_replay_gain 4738 - [X] WavPackAudio.add_replay_gain 4739*** DONE Update utilities to use new ReplayGain application procedure 4740 Given a list of tracks for a given album, 4741 if all are the same format and can_add_replay_gain returns True, 4742 queue a call to add_replay_gain on those tracks. 4743**** DONE audiotools-config 4744**** DONE cd2track 4745**** DONE dvda2track 4746**** DONE track2track 4747**** DONE tracksplit 4748**** DONE tracktag 4749** DONE Display X/Y progress during operations 4750 When a track is finished transcoding, for instance, output: 4751 [ 2 / 15 ] input.wav -> output.mp3 4752 or something similar. 4753*** DONE Update utilities 4754 - [X] cd2track 4755 - [X] dvda2track 4756 - [X] track2track 4757 - [X] trackcmp 4758 - [X] trackrename 4759 - [X] tracksplit 4760 - [X] tracktag 4761 - [X] trackverify 4762*** DONE Update unit tests 4763 - [X] cd2track 4764 - [X] dvda2track 4765 - [X] track2track 4766 - [X] trackcmp 4767 - [X] trackrename 4768 - [X] tracksplit 4769 - [X] tracktag 4770 - [X] trackverify 4771** DONE Update metadata documentation with examples 4772*** DONE FLAC 4773*** DONE MP3 4774 - [X] ID3v1/ID3v1.1 4775 - [X] ID3v2.2 4776 - [X] ID3v2.3 4777 - [X] ID3v2.4 4778*** DONE APEv2 4779*** DONE M4A 4780** DONE Remove Construct module 4781 Convert all usage of Construct to BitstreamReader/BitstreamWriter. 4782 Since this is unlikely to be updated for Python 3, 4783 removing it should smooth that inevitable transition. 4784*** DONE __accuraterip__.py 4785*** DONE __aiff__.py 4786 - [X] chunks 4787 - [X] get_metadata 4788 - [X] set_metadata 4789 - [X] delete_metadata 4790 - [X] to_pcm 4791 - [X] from_pcm 4792 - [X] pcm_split 4793 - [X] aiff_from_chunks 4794**** DONE AiffReader 4795 - [X] __init__ 4796 - [X] read 4797*** DONE __ape__.py 4798*** DONE __au__.py 4799*** DONE cue.py 4800*** DONE __dvda__.py 4801**** DONE DVDAudio 4802 - [X] __titlesets__ 4803 - [X] __titles__ 4804**** DONE DVDATitle 4805 - [X] __parse_info__ 4806*** DONE __flac__.py 4807*** DONE __freedb__.py 4808*** DONE __id3__.py 4809*** DONE __id3v1__.py 4810*** DONE __image__.py 4811 - [X] __JPEG__ 4812 - [X] __PNG__ 4813 - [X] __GIF__ 4814 - [X] __BMP__ 4815 - [X] __TIFF__ 4816**** DONE check these against PIL's output 4817**** DONE check against truncated images 4818*** DONE __init__.py 4819*** DONE __m4a__.py 4820**** DONE M4ATaggedAudio 4821 - [X] get_metadata 4822 - [X] set_metadata 4823 - [X] delete_metadata 4824**** DONE M4A_META_Atom 4825 - [X] __init__ 4826 - [X] __repr__ 4827 - [X] parse 4828 - [X] __getattr__ 4829 - [X] __setattr__ 4830 - [X] __delattr__ 4831 - [X] images 4832 - [X] add_image 4833 - [X] delete_image 4834 - [X] converted 4835 - [X] __comment_name__ 4836 - [X] supports_images 4837 - [X] __by_pair__ 4838 - [X] __comment_pairs__ 4839 - [X] clean 4840**** DONE M4AAudio_faac 4841 - [X] __init__ 4842 - [X] is_type 4843**** DONE ALACAudio 4844 - [X] __init__ 4845 - [X] is_type 4846 - [X] to_pcm 4847 - [X] from_pcm 4848 - [X] __ftyp_atom__ 4849 - [X] __moov_atom__ 4850 - [X] __free_atom__ 4851*** DONE __m4a_atoms__.py 4852 Re-implement atom parsing/building without Construct 4853**** DONE ftyp 4854**** DONE moov 4855***** DONE mvhd 4856***** DONE trak 4857****** DONE tkhd 4858****** DONE mdia 4859******* DONE mdhd 4860******* DONE hdlr 4861******* DONE minf 4862******** DONE smhd 4863******** DONE dinf 4864********* DONE dref 4865******** DONE stbl 4866********* DONE stsd 4867********** DONE alac 4868********* DONE stts 4869********* DONE stsc 4870********* DONE stsz 4871********* DONE stco 4872***** DONE udta 4873****** DONE meta 4874**** DONE free 4875**** DONE Rename __m4a_atoms2__.py to __m4a_atoms__.py 4876*** DONE __mp3__.py 4877**** DONE MP3 4878 - [X] __init__ 4879 - [X] is_type 4880 - [X] __find_next_mp3_frame__ 4881 - [X] __find_mp3_start__ 4882 - [X] __find_last_mp3_frame__ 4883 - [X] verify 4884**** DONE MP2 4885 - [X] is_type 4886*** DONE __musepack__.py 4887*** DONE __musicbrainz__.py 4888*** DONE __ogg__.py 4889*** DONE player.py 4890*** DONE __shn__.py 4891*** DONE toc.py 4892*** DONE __vorbis__.py 4893**** DONE VorbisAudio 4894 - [X] __read_metadata__ 4895 - [X] total_frames 4896 - [X] get_metadata 4897 - [X] set_metadata 4898**** DONE Remove cruft 4899 - [X] OggStreamReader 4900 - [X] OggStreamWriter 4901*** DONE __vorbiscomment__.py 4902*** DONE __wav__.py 4903*** DONE __wavpack__.py 4904*** DONE test/test_core.py 4905**** DONE TestFrameList 4906 - [X] test_8bit_roundtrip 4907 - [X] test_16bit_roundtrip 4908 - [X] test_24bit_roundtrip 4909*** DONE test/test_formats.py 4910**** DONE ALACFileTest 4911 - [X] test_blocksizes 4912**** DONE FlacFileTest 4913 - [X] test_blocksizes 4914**** DONE ShortenFileTest 4915 - [X] test_blocksizes 4916**** DONE WavpackFileTest 4917 - [X] test_blocksizes 4918** DONE Replace gettext with string constants 4919 Transforming _(u"some text") to SOME_TEXT 4920 where SOME_TEXT is a predefined unicode string 4921 in an audiotools sub-module. 4922 This makes text more consistent *and* easier to modify. 4923*** DONE Update utilities 4924 - [X] audiotools-config 4925 - [X] cd2track 4926 - [X] cdinfo 4927 - [X] cdplay 4928 - [X] coverdump 4929 - [X] coverview 4930 - [X] dvda2track 4931 - [X] dvdainfo 4932 - [X] track2cd 4933 - [X] track2track 4934 - [X] trackcat 4935 - [X] trackcmp 4936 - [X] trackinfo 4937 - [X] tracklength 4938 - [X] tracklint 4939 - [X] trackplay 4940 - [X] trackrename 4941 - [X] tracksplit 4942 - [X] tracktag 4943 - [X] trackverify 4944*** DONE Update modules 4945 - [X] __init__.py 4946 - [X] aiff.py 4947 - [X] ape.py 4948 - [X] au.py 4949 - [X] cue.py 4950 - [X] dvda.py 4951 - [X] flac.py 4952 - [X] image.py 4953 - [X] m4a.py 4954 - [X] m4a_atoms.py 4955 - [X] mp3.py 4956 - [X] ogg.py 4957 - [X] toc.py 4958 - [X] ui.py 4959 - [X] vorbis.py 4960 - [X] vorbiscomment.py 4961 - [X] wav.py 4962 - [X] wavpack.py 4963*** DONE Remove gettext 4964 - [X] audiotools-config 4965 - [X] cd2track 4966 - [X] cdinfo 4967 - [X] cdplay 4968 - [X] coverdump 4969 - [X] coverview 4970 - [X] dvda2track 4971 - [X] dvdainfo 4972 - [X] track2cd 4973 - [X] track2track 4974 - [X] trackcat 4975 - [X] trackcmp 4976 - [X] trackinfo 4977 - [X] tracklength 4978 - [X] tracklint 4979 - [X] trackplay 4980 - [X] trackrename 4981 - [X] tracksplit 4982 - [X] tracktag 4983 - [X] trackverify 4984 - [X] audiotools/__init__.py 4985 - [X] audiotools/aiff.py 4986 - [X] audiotools/ape.py 4987 - [X] audiotools/au.py 4988 - [X] audiotools/cue.py 4989 - [X] audiotools/flac.py 4990 - [X] audiotools/id3.py 4991 - [X] audiotools/image.py 4992 - [X] audiotools/m4a.py 4993 - [X] audiotools/mp3.py 4994 - [X] audiotools/toc.py 4995 - [X] audiotools/vorbis.py 4996 - [X] audiotools/wav.py 4997 - [X] audiotools/wavpack.py 4998*** DONE Update unit tests 4999 - [X] test_formats.py 5000 - [X] test_metadata.py 5001 - [X] test_utils.py 5002*** DONE Reduce big import chunks 5003 Convert "from audiotools.text import (CONSTANT, ...)" 5004 to "import audiotools.text as t" and "t.CONSTANT" 5005 to avoid having huge import blocks at the start of utilities. 5006 - [X] audiotools-config 5007 - [X] cd2track 5008 - [X] cdinfo 5009 - [X] cdplay 5010 - [X] coverdump 5011 - [X] coverview 5012 - [X] dvda2track 5013 - [X] dvdainfo 5014 - [X] track2cd 5015 - [X] track2track 5016 - [X] trackcat 5017 - [X] trackcmp 5018 - [X] trackinfo 5019 - [X] tracklength 5020 - [X] tracklint 5021 - [X] trackplay 5022 - [X] trackrename 5023 - [X] tracksplit 5024 - [X] tracktag 5025 - [X] trackverify 5026*** DONE Ensure unit tests pass 5027** DONE Update C-based ReplayGainReader 5028 Use a lot of the new C-based facilities to make it simpler. 5029** DONE Fix --number=0 argument to tracktag 5030 I'd like to make track_number=0 a valid value 5031 and have track_number=None indicate a missing field. 5032 The problem is maintaining consistency between 5033 metadata formats that store track numbers as text (like ID3v2) 5034 and those that store track numbers as integers (like M4A). 5035 - [X] MetaData 5036 - [X] ApeTag 5037 - [X] FlacMetaData 5038 - [X] ID3CommentPair 5039 - [X] ID3v1Comment 5040 - [X] ID3v22Comment 5041 - [X] ID3v23Comment 5042 - [X] ID3v24Comment 5043 - [X] M4A_META_Atom 5044 - [X] VorbisComment 5045*** DONE Update utilities 5046*** DONE Update documentation 5047*** DONE Update unit tests 5048**** DONE Add getitem/setitem/getattr/setattr/delattr tests to metadata 5049 - [X] flac 5050 - [X] wavpack 5051 - [X] id3v1 5052 - [X] id3v2 5053 - [X] vorbis 5054 - [X] m4a 5055** DONE Remove Python Imaging Library requirement 5056 This is only used for thumbnailing 5057 and for TKinter-based image display. 5058 Since a Python3 version doesn't seem to be pending, 5059 it would be better to remove the requirement. 5060*** DONE Remove thumbnail functions from audiotools.image 5061 - [X] can_thumbnail 5062 - [X] thumbnail_formats 5063 - [X] thumbnail_image 5064*** DONE Remove thumbnail method from audiotools.Image 5065*** DONE Remove thumbnail config options 5066 - [X] audiotools.THUMBNAIL_FORMAT 5067 - [X] audiotools.THUMBNAIL_SIZE 5068*** DONE Update utilities 5069 - [X] audiotools-config 5070 - [X] track2track 5071 - [X] tracktag 5072*** DONE Update utility man pages 5073 - [X] audiotools-config 5074 - [X] track2track 5075 - [X] tracktag 5076*** DONE Update programming documentation 5077*** DONE Update unit tests 5078** DONE Update cuesheet interface to handle non-CD sheets 5079 Though rare, non-CD audio is sometimes combined 5080 with cuesheets and should be handled properly 5081 in those instances. 5082*** DONE Add sample_rate field to cuesheet pcm_lengths() method 5083 - [X] Cuesheet.pcm_lengths 5084 - [X] Flac_CUESHEET.pcm_lengths 5085 - [X] TOCFile.pcm_lengths 5086**** DONE Update documentation 5087**** DONE Update unit tests 5088*** DONE Remove sheet_to_unicode function 5089*** DONE Update utilities to use sample_rate field with pcm_lengths 5090 - [X] trackinfo 5091 - [X] tracksplit 5092 - [X] tracktag 5093*** DONE Ensure unit tests pass 5094** DONE Add faster and more accurate audio type identifier 5095 Instead of checking open files on a format-by-format basis 5096 to determine its type via looping, it's more effecient 5097 to check for all possible file types from the same stream simultaneously 5098 via a sort of finite automata. 5099*** DONE Add file_type function 5100 - [X] ALACAudio 5101 - [X] AiffAudio 5102 - [X] AuAudio 5103 - [X] FlacAudio - without ID3v2 tag 5104 - [X] M4AAudio 5105 - [X] MP2Audio - without ID3v2 tag 5106 - [X] MP3Audio - without ID3v2 tag 5107 - [X] OggFlacAudio 5108 - [X] ShortenAudio 5109 - [X] VorbisAudio 5110 - [X] WavPackAudio 5111 - [X] WaveAudio 5112 - [X] FlacAudio - with ID3v2 tag 5113 - [X] MP2Audio - with ID3v2 tag 5114 - [X] MP3Audio - with ID3v2 tag 5115*** DONE Update functions which use is_type method to use file_type function 5116 - [X] trackverify 5117 - [X] audiotools.open 5118*** DONE Remove is_type method from AudioFile classes 5119 - [X] ALACAudio 5120 - [X] AiffAudio 5121 - [X] AuAudio 5122 - [X] FlacAudio 5123 - [X] M4AAudio 5124 - [X] MP2Audio 5125 - [X] MP3Audio 5126 - [X] OggFlacAudio 5127 - [X] ShortenAudio 5128 - [X] VorbisAudio 5129 - [X] WavPackAudio 5130 - [X] WaveAudio 5131*** DONE Update programming documentation 5132*** DONE Update unit tests 5133 - [X] test_formats.py 5134** DONE Update utilities to handle broken track_name template fields 5135 - [X] cd2track 5136 - [X] dvda2track 5137 - [X] track2track 5138 - [X] trackrename 5139 - [X] tracksplit 5140*** DONE Add unit tests for broken track_name template fields 5141** DONE Split off tracktag's functionality 5142*** DONE Move the image options into a specialized tool (covertag?) 5143 Its interactive mode should use PyGTK/Tkinter 5144 since it's helpful to see the images one is selecting to add/remove. 5145 - [X] --remove-images 5146 - [X] --front-cover 5147 - [X] --back-cover 5148 - [X] --leaflet 5149 - [X] --media 5150 - [X] --other-image 5151 - [X] -T, --thumbnail 5152*** DONE Move CD options into a specialized tool 5153 Something for tagging a group of tracks as if they're an entire CD 5154 - [X] --cue 5155 - [X] -l, --lookup 5156 - [X] --musicbrainz-server 5157 - [X] --musicbrainz-port 5158 - [X] --no-musicbrainz 5159 - [X] --freedb-server 5160 - [X] --freedb-port 5161 - [X] --no-freedb 5162** DONE Add interative mode to audiotools-config 5163 This is one instance where seeing all the options "up-front" 5164 is likely to make the process easier. 5165** DONE Add Python-based file decoders 5166 These would be low-performance, Python-based PCMReader-style objects 5167 demonstrating how the decoding process works in a relatively simple 5168 manner through the use of the BitstreamReader objects. 5169 They would also provide reference implementations. 5170*** DONE py_decoders/FlacDecoder 5171*** DONE py_decoders/SHNDecoder 5172*** DONE py_decoders/ALACDecoder 5173*** DONE py_decoders/WavPackDecoder 5174** DONE Update .convert() method to use fewer temporary files 5175 .wav and .aiff containers with embedded chunks 5176 currently route data through actual .wav/.aiff files 5177 in order to pass those chunks to another format. 5178 It would be better to avoid creating an intermediate 5179 file whenever possible. 5180*** DONE Update wav containers to use new interface 5181 WaveContainer.has_foreign_wav_chunks() 5182 returns True if the instance has chunks to convert 5183 WaveContainer.header_footer() 5184 returns (header, footer) binary strings 5185 WaveContainer.from_wave(header, pcmreader, footer) 5186 returns new instance built from heaeder, PCM data and footer 5187 5188 Once interface is in place, .convert() can pass header/footer 5189 and wrap progress monitor around pcmreader in order to avoid 5190 temporary wav files. 5191**** DONE Update FlacAudio 5192 - [X] has_foreign_wave_chunks() 5193 - [X] wave_header_footer() 5194 - [X] from_wave(filename, header, pcmreader, footer, compression) 5195 - [X] convert(target_page, target_class, compression, progress) 5196**** DONE Update OggFlacAudio 5197 - [X] has_foreign_wave_chunks() 5198 - [X] wave_header_footer() 5199 - [X] from_wave(filename, header, pcmreader, footer, compression) 5200 - [X] convert(target_page, target_class, compression, progress) 5201**** DONE Update ShortenAudio 5202 - [X] has_foreign_wave_chunks() 5203 - [X] wave_header_footer() 5204 - [X] from_wave(filename, header, pcmreader, footer, compression) 5205 - [X] convert(target_page, target_class, compression, progress) 5206**** DONE Update WavPackAudio 5207 - [X] has_foreign_wave_chunks() 5208 - [X] wave_header_footer() 5209 - [X] from_wave(filename, header, pcmreader, footer, compression) 5210 - [X] convert(target_page, target_class, compression, progress) 5211**** DONE Update WaveAudio 5212 - [X] has_foreign_wave_chunks() 5213 - [X] wave_header_footer() 5214 - [X] from_wave(filename, header, pcmreader, footer, compression) 5215 - [X] convert(target_page, target_class, compression, progress) 5216**** DONE Update programming documentation 5217**** DONE Update unit tests 5218*** DONE Update aiff containers to use new interface 5219 AiffContainer.has_foreign_aiff_chunks() 5220 returns True if the instance has chunks to convert 5221 5222 AiffContainer.header_footer() 5223 returns (header, footer) binary strings 5224 5225 AiffContainer.from_aiff(header, pcmreader, footer) 5226 returns new instance built from heaeder, PCM data and footer 5227 5228 Once interface is in place, .convert() can pass header/footer 5229 and wrap progress monitor around pcmreader in order to avoid 5230 temporary aiff files. 5231**** DONE Update AiffAudio 5232 - [X] has_foreign_aiff_chunks() 5233 - [X] aiff_header_footer() 5234 - [X] from_aiff(filename, header, pcmreader, footer, compression) 5235 - [X] convert(target_page, target_class, compression, progress) 5236**** DONE Update FlacAudio 5237 - [X] has_foreign_aiff_chunks() 5238 - [X] aiff_header_footer() 5239 - [X] from_aiff(filename, header, pcmreader, footer, compression) 5240 - [X] convert(target_page, target_class, compression, progress) 5241**** DONE Update OggFlacAudio 5242 - [X] has_foreign_aiff_chunks() 5243 - [X] aiff_header_footer() 5244 - [X] from_aiff(filename, header, pcmreader, footer, compression) 5245 - [X] convert(target_page, target_class, compression, progress) 5246**** DONE Update ShortenAudio 5247 - [X] has_foreign_aiff_chunks() 5248 - [X] aiff_header_footer() 5249 - [X] from_aiff(filename, header, pcmreader, footer, compression) 5250 - [X] convert(target_page, target_class, compression, progress) 5251**** DONE Update programming documentation 5252**** DONE Update unit tests 5253** DONE Add pause()/resume() methods to low-level output players 5254 This will hopefully make pausing more responsive 5255 and work better than simply emptying the output buffer. 5256** DONE Ensure unicode command-line arguments are parsed properly 5257*** DONE cd2track 5258 - [X] --format 5259 - [X] --dir 5260*** DONE coverdump 5261 - [X] filename arguments 5262 - [X] --dir 5263 - [X] --prefix 5264*** DONE covertag 5265 - [X] filename arguments 5266 - [X] --front-cover 5267 - [X] --back-cover 5268 - [X] --leaflet 5269 - [X] --media 5270 - [X] --other-image 5271*** DONE track2track 5272 - [X] filename arguments 5273 - [X] --dir 5274 - [X] --format 5275 - [X] --output 5276*** DONE trackcat 5277 - [X] filename arguments 5278 - [X] --output 5279 - [X] --cue 5280*** DONE trackcmp 5281 - [X] filename arguments 5282*** DONE trackinfo 5283 - [X] filename arguments 5284*** DONE tracklength 5285 - [X] filename arguments 5286*** DONE tracklint 5287 - [X] filename arguments 5288 - [X] --db 5289*** DONE trackrename 5290 - [X] filename arguments 5291 - [X] --format 5292*** DONE tracksplit 5293 - [X] filename arguments 5294 - [X] --cue 5295 - [X] --dir 5296 - [X] --format 5297*** DONE tracktag 5298 - [X] filename arguments 5299 - [X] --name 5300 - [X] --artist 5301 - [X] --album 5302 - [X] --performer 5303 - [X] --composer 5304 - [X] --conductor 5305 - [X] --catalog 5306 - [X] --ISRC 5307 - [X] --publisher 5308 - [X] --media-type 5309 - [X] --year 5310 - [X] --date 5311 - [X] --copyright 5312 - [X] --comment 5313 - [X] --comment-file 5314** DONE Add unit tests for Python-based decoders 5315 Since Python-based codecs are so much slower 5316 it's impossible to make these as comprehensive as the C-based tests. 5317 So we'll only be able to test the basics using very small streams 5318 against the output of the C-based decoders. 5319*** DONE FlacDecoder 5320*** DONE ALACDecoder 5321*** DONE WavPackDecoder 5322*** DONE SHNDecoder 5323** DONE Add unit tests for Python-based encoders 5324*** DONE encode_flac 5325*** DONE encode_mdat 5326*** DONE encode_wavpack 5327*** DONE encode_shn 5328** DONE Ensure Python files are PEP8-compliant 5329*** DONE executables 5330 - [X] audiotools-config 5331 - [X] cd2track 5332 - [X] cdinfo 5333 - [X] cdplay 5334 - [X] coverdump 5335 - [X] covertag 5336 - [X] coverview 5337 - [X] dvda2track 5338 - [X] dvdainfo 5339 - [X] track2cd 5340 - [X] track2track 5341 - [X] trackcat 5342 - [X] trackcmp 5343 - [X] trackinfo 5344 - [X] tracklength 5345 - [X] tracklint 5346 - [X] trackplay 5347 - [X] trackrename 5348 - [X] tracksplit 5349 - [X] tracktag 5350 - [X] trackverify 5351*** DONE libraries 5352 - [X] __init__.py 5353 - [X] accuraterip.py 5354 - [X] aiff.py 5355 - [X] ape.py 5356 - [X] au.py 5357 - [X] cue.py 5358 - [X] delta.py 5359 - [X] dvda.py 5360 - [X] flac.py 5361 - [X] freedb.py 5362 - [X] id3.py 5363 - [X] id3v1.py 5364 - [X] image.py 5365 - [X] m4a.py 5366 - [X] m4a_atoms.py 5367 - [X] mp3.py 5368 - [X] musicbrainz.py 5369 - [X] ogg.py 5370 - [X] opus.py 5371 - [X] player.py 5372 - [X] shn.py 5373 - [X] text.py 5374 - [X] toc.py 5375 - [X] ui.py 5376 - [X] vorbis.py 5377 - [X] vorbiscomment.py 5378 - [X] wav.py 5379 - [X] wavpack.py 5380**** DONE py_decoders 5381 - [X] __init__.py 5382 - [X] alac.py 5383 - [X] flac.py 5384 - [X] shn.py 5385 - [X] wavpack.py 5386**** DONE py_encoders 5387 - [X] __init__.py 5388 - [X] alac.py 5389 - [X] flac.py 5390 - [X] shn.py 5391 - [X] wavpack.py 5392** DONE Have interactive modes clear screen after finishing 5393 Some systems leave the Urwid-built screens half-cleared 5394 before resuming regular output. 5395 It's preferable to erase the whole thing in that case. 5396 - [X] audiotools-config 5397 - [X] cd2track 5398 - [X] cdplay 5399 - [X] dvda2track 5400 - [X] track2track 5401 - [X] trackcat 5402 - [X] trackplay 5403 - [X] trackrename 5404 - [X] tracksplit 5405 - [X] tracktag 5406** DONE Have interactive modes detect termios.error at launch 5407 This seems to be caused mostly by opening interactive modes 5408 with arguments piped from xargs 5409 - [X] audiotools-config 5410 - [X] cd2track 5411 - [X] cdplay 5412 - [X] dvda2track 5413 - [X] track2track 5414 - [X] trackcat 5415 - [X] trackplay 5416 - [X] trackrename 5417 - [X] tracksplit 5418 - [X] tracktag 5419** DONE Spellcheck programming documentation 5420 - [X] audiotools.rst 5421 - [X] audiotools_bitstream.rst 5422 - [X] audiotools_cdio.rst 5423 - [X] audiotools_cue.rst 5424 - [X] audiotools_pcm.rst 5425 - [X] audiotools_pcmconverter.rst 5426 - [X] audiotools_player.rst 5427 - [X] audiotools_replaygain.rst 5428 - [X] audiotools_toc.rst 5429 - [X] index.rst 5430 - [X] metadata.rst 5431** DONE Spellcheck reference documentation 5432 - [X] aiff.tex 5433 - [X] alac.tex 5434 - [X] ape.tex 5435 - [X] apev2.tex 5436 - [X] au.tex 5437 - [X] basics.tex 5438 - [X] dvda2.tex 5439 - [X] flac.tex 5440 - [X] freedb.tex 5441 - [X] introduction.tex 5442 - [X] license.tex 5443 - [X] m4a.tex 5444 - [X] mp3.tex 5445 - [X] musepack.tex 5446 - [X] musicbrainz.tex 5447 - [X] musicbrainz_mmd.tex 5448 - [X] ogg.tex 5449 - [X] oggflac.tex 5450 - [X] references.tex 5451 - [X] replaygain.tex 5452 - [X] shorten.tex 5453 - [X] speex.tex 5454 - [X] vorbis.tex 5455 - [X] wav.tex 5456 - [X] wavpack.tex 5457** DONE Spellcheck reference figures 5458** DONE Spellcheck manual pages 5459** DONE Split reference documentation into sections by file 5460 That is, massive codecs should be split into individual 5461 .tex files by decode/encode sections and then subdivided 5462 further as necessary to keep them from getting too fragile/unweildy 5463*** DONE Shorten 5464 - [X] decode 5465 - [X] encode 5466*** DONE FLAC 5467**** DONE metadata 5468**** DONE decode 5469**** DONE encode 5470 - [X] fixed 5471 - [X] residual 5472 - [X] lpc 5473*** DONE WavPack 5474**** DONE decode 5475 - [X] terms 5476 - [X] weights 5477 - [X] samples 5478 - [X] entropy 5479 - [X] bitstream 5480 - [X] decorrelation 5481**** DONE encode 5482 - [X] correlation 5483 - [X] terms 5484 - [X] weights 5485 - [X] samples 5486 - [X] entropy 5487 - [X] bitstream 5488*** DONE ALAC 5489**** DONE decode 5490**** DONE encode 5491 - [X] atoms 5492 - [X] lpc 5493 - [X] residual 5494*** DONE Remove m4 requirement 5495 This is massive overkill for what little we need it for, 5496 which is generating audioformats-_.tex and _-codec.tex files 5497 with header/footers included and paper size populated. 5498 5499 It's better to use Python for that trivial templating instead. 5500** DONE Tweak reference documentation layout 5501 Try harder to get pseudocode, file diagram, 5502 bit diagram and example on same pair of pages. 5503*** DONE Shorten 5504*** DONE FLAC 5505*** DONE WavPack 5506*** DONE ALAC 5507*** DONE DVD-A 5508** DONE Ensure documentation flows correctly 5509 Pages should start/end properly at letter and A4 paper sizes. 5510 - [X] letter 5511 - [X] A4 5512** DONE Handle multi-channel .opus files properly 5513*** DONE Add unit tests 5514** DONE Add optional interactive modes to utilities 5515 Now that Urwid is being used for editxmcd, it might be helpful 5516 to add optional console-based interactive modes to the other tools. 5517 This may improve ease-of-use (particularly discoverability 5518 in the case of format and quality options) without sacrificing 5519 scriptability or command-line power. 5520 5521 Just as the command-line options are kept as consistent as possible, 5522 all interactive modes will also need a consistent interface. 5523*** DONE audiotools-config 5524*** DONE cd2track 5525*** DONE cdplay 5526**** DONE make player widget generic 5527*** DONE dvda2track 5528*** DONE track2track 5529*** DONE trackcat 5530*** DONE trackplay 5531**** DONE make player widget generic 5532*** DONE trackrename 5533*** DONE tracksplit 5534*** DONE tracktag 5535** DONE run codecs through valgrind 5536 Try to ensure there's no hidden bugs in the low-level C code. 5537*** DONE decoders 5538 Will need to assemble standalone decoders for this. 5539 - [X] alac 5540 - [X] flac 5541 - [X] mlp 5542 - [X] oggflac 5543 - [X] shorten 5544 - [X] wavpack 5545*** DONE encoders 5546 - [X] alac 5547 - [X] flac 5548 - [X] shorten 5549 - [X] wavpack 5550*** DONE Update standalone encoders to take command-line arguments 5551 This would make them easier to memory test. 5552 - [X] alac 5553 - [X] flac 5554 - [X] shorten 5555 - [X] wavpack 5556** DONE Have cdplay play properly 5557** DONE Update version number to 2.19 final 5558* DONE Finish version 2.20 5559** DONE Remove track number/album number guessing heuristics 5560 Don't try to guess number from filename. 5561 If a track number is needed, build it from the order 5562 in which the files are submitted on the command line. 5563*** DONE track_number() 5564*** DONE album_number() 5565** DONE Update track2track/tracktag to use better option filler widget 5566 cd2track, dvda2track and tracksplit always work with one album 5567 at a time, pretty much by definition. 5568 track2track may handle multiple albums simultaneously 5569 and currently makes mutiple calls to urwid to work. 5570 A better approach is to have all the metadata lookups 5571 performed first, multiple metadata edit screens, 5572 and a single output options/preview screen. 5573** DONE Simplify PCMReaderWindow 5574 Split this into a PCMReaderHead and PCMReaderDeHead pair. 5575 5576 The former handles the "pcm_frames" argument, 5577 either truncating a PCMReader or appending silence as needed. 5578 5579 The latter handles the "initial_offset" argument, 5580 either chopping off frames or prepending silence as needed. 5581** DONE Adjust BitstreamReader to better handle huge byte counts 5582 These are typically done in error and shouldn't eat up 5583 all the RAM in the world before failing. 5584*** DONE Update functions 5585 - [X] br_substream_append_f 5586 - [X] br_substream_append_e 5587 - [X] BitstreamReader_read_bytes 5588 - [X] BitstreamReader_substream_meth 5589 - [X] BitstreamReader_substream_append 5590*** DONE Add unit tests 5591 - [X] br_substream_append_f 5592 - [X] br_substream_append_e 5593 - [X] BitstreamReader_read_bytes 5594 - [X] BitstreamReader_substream_meth 5595 - [X] BitstreamReader_substream_append 5596*** DONE turn the current buf_append into buf_extend 5597*** DONE Replace buf_extend with buf_append 5598** DONE Have process-based decoders exit when data runs out 5599 That is, have PCMReader's .read() call subprocess.wait() 5600 when the framelists end rather than waiting for .close() 5601 to be called (which typically isn't). 5602 If the wait fails, have it raise an exception at that point. 5603*** DONE Update process-based formats 5604 - [X] M4AAudio 5605 - [X] MP2Audio 5606 - [X] MP3Audio 5607 - [X] OpusAudio 5608*** DONE Update documentation 5609*** DONE Ensure unit tests pass 5610** DONE Reduce stdint usage in bitstream library 5611 Try to limit stdint variables to places 5612 where it's necessary, like read_64 and read_bytes 5613*** DONE Convert state/context to state_t 5614**** DONE Update br_huffman_table 5615**** DONE Update BitstreamReader 5616**** DONE struct read_bits 5617**** DONE struct unread_bit 5618**** DONE struct read_unary 5619**** DONE struct read_limited_unary 5620*** DONE Update jump table structures 5621**** DONE read_bits 5622**** DONE unread_bit 5623**** DONE read_unary 5624**** DONE read_limited_unary 5625*** DONE Update br_huffman_table 5626**** DONE Update continue_ to int 5627*** DONE Update bs_buffer 5628**** DONE unsigned data_size 5629**** DONE unsigned window_start 5630**** DONE unsigned window_end 5631**** DONE buf_resize() 5632**** DONE buf_write() 5633**** DONE buf_read() 5634*** DONE Update br_mark 5635**** DONE unsigned substream 5636**** DONE unsigned external 5637*** DONE Update substream_append() 5638**** DONE br_substream_append_f 5639**** DONE br_substream_append_s 5640**** DONE br_substream_append_e 5641**** DONE br_substream_append_c 5642*** DONE Update bw_external_output 5643**** DONE buffer_size 5644**** DONE bw_open_external() 5645**** DONE ext_open_w() 5646** DONE Add bs_buffer-specific unit tests to bitstream.c 5647 - [X] buf_resize 5648 - [X] buf_write 5649 - [X] buf_read 5650 - [X] buf_copy 5651 - [X] buf_extend 5652 - [X] buf_reset 5653 - [X] buf_getc 5654 - [X] buf_putc 5655 - [X] buf_getpos 5656 - [X] buf_setpos 5657 - [X] buf_set_rewindable 5658 - [X] BUF_WINDOW_SIZE 5659 - [X] BUF_WINDOW_START 5660 - [X] BUF_WINDOW_END 5661** DONE Fix cuesheet handling 5662 Ensure the cuesheet interface handles unusual cases more accurately 5663 and build a proper base class for the .cue and .toc files 5664*** DONE Add new base classes 5665 - [X] Sheet 5666 - [X] SheetTrack 5667 - [X] SheetIndex 5668*** DONE Update cue module 5669 - [X] read_cuesheet 5670 - [X] write_cuesheet 5671*** DONE Update toc module 5672 - [X] read_tocfile 5673 - [X] write_tocfile 5674*** DONE Update get_cuesheet methods 5675 - [X] FlacAudio 5676 - [X] TrueAudio 5677 - [X] WavPackAudio 5678*** DONE Update set_cuesheet methods 5679 - [X] FlacAudio 5680 - [X] TrueAudio 5681 - [X] WavPackAudio 5682*** DONE Update documentation 5683 - [X] read_sheet 5684 - [X] Sheet 5685 - [X] SheetTrack 5686 - [X] SheetIndex 5687*** DONE Update utilities using cuesheet interface 5688 - [X] track2cd 5689 - [X] trackcat 5690 - [X] trackinfo 5691 - [X] tracksplit 5692*** DONE Update unit tests 5693*** DONE Add unit test for FlacAudio.set_cuesheet() 5694 Ensure the resulting Flac_CUESHEET block matches 5695 the one generated by metaflac --import-cuesheet-from 5696** DONE Add optional total_pcm_frames argument to from_pcm() 5697 Certain formats encode much easier if the total number of PCM frames 5698 is known in advance. Adding a total_pcm_frames argument 5699 allows encoders to make use of that info if it's available. 5700*** DONE Update formats with total_pcm_frames argument 5701**** DONE AudioFile 5702 does nothing 5703**** DONE ALACAudio 5704 Builds placeholder seektable which is then populated later 5705**** DONE AiffAudio 5706 does nothing 5707**** DONE AuAudio 5708 does nothing 5709**** DONE FlacAudio 5710 Allocates enough space for populated seektable 5711 on top of any leftover for VORBIS tags. 5712**** DONE M4AAudio 5713 does nothing 5714**** DONE MP2Audio 5715 does nothing 5716**** DONE MP3Audio 5717 does nothing 5718**** DONE OggFlacAudio 5719 does nothing 5720**** DONE OpusAudio 5721 does nothing 5722**** DONE ShortenAudio 5723 If total_pcm_frames argument is given to from_pcm(), 5724 precalculate Wave header rather than use temporary file. 5725 This shouldn't require updating the encode_shn function. 5726**** DONE TrueAudio 5727 If total_pcm_frames argument is given to from_pcm(), 5728 fill header and temporary seektable rather than use temporary file. 5729 This shouldn't require updating the encode_tta function. 5730**** DONE VorbisAudio 5731 does nothing 5732**** DONE WavPackAudio 5733 If total_pcm_frames argument is given to from_pcm(), 5734 fill blocks during encoding rather than re-fill them afterward. 5735 This will require minor update to encode_wavpack function. 5736**** DONE WaveAudio 5737 does nothing 5738*** DONE Update convert() methods to call from_pcm() with argument 5739 But only if the input file is lossless. 5740**** DONE AudioFile 5741**** DONE ALACAudio 5742**** DONE AiffAudio 5743**** DONE AuAudio 5744**** DONE FlacAudio 5745**** DONE M4AAudio 5746**** DONE MP2Audio 5747**** DONE MP3Audio 5748**** DONE OggFlacAudio 5749**** DONE OpusAudio 5750**** DONE ShortenAudio 5751**** DONE TrueAudio 5752**** DONE VorbisAudio 5753**** DONE WavPackAudio 5754**** DONE WaveAudio 5755*** DONE Update utilities to make use of total_pcm_frames argument 5756**** DONE cd2track 5757**** DONE dvda2track 5758**** DONE trackcat 5759**** DONE tracksplit 5760*** DONE Document total_pcm_frames argument 5761*** DONE Unit test calling formats with total_pcm_frames and without 5762*** DONE Add unit tests with total_pcm_frames and without per encoder 5763 - [X] ALACAudio.from_pcm() 5764 - [X] FlacAudio.from_pcm() 5765 - [X] ShnAudio.from_pcm() 5766 - [X] TTAAudio.from_pcm() 5767 - [X] WavPackAudio.from_pcm() 5768** DONE Make decoder streams seekable 5769 PCMReader.seek(pcm_frames) -> new pcm frames position 5770 could seek to the closest position in the stream to the given frames 5771 without going over, and return the current position in PCM frames. 5772*** DONE Update decoders 5773**** DONE AiffAudio 5774**** DONE AuAudio 5775**** DONE WaveAudio 5776**** DONE decoders.ALACDecoder 5777**** DONE decoders.FlacDecoder 5778**** DONE decoders.TTADecoder 5779**** DONE decoders.WavPackDecoder 5780*** DONE Add unit tests 5781** DONE Swap array types for something easier to comprehend 5782 array_i/array_f/array_u is more opaque than it should be 5783*** DONE array_i -> a_int 5784*** DONE array_i_new() -> a_int_new() 5785 - [X] decoders/alac.h/.c 5786 - [X] decoders/flac.h/.c 5787 - [X] decoders/mlp.h/.c 5788 - [X] decoders/oggflac.h/.c 5789 - [X] decoders/shn.h/.c 5790 - [X] decoders/tta.h/.c 5791 - [X] decoders/wavpack.h/.c 5792 - [X] encoders/alac.h/.c 5793 - [X] encoders/flac.h/.c 5794 - [X] encoders/shn.h/.c 5795 - [X] encoders/tta.h/.c 5796 - [X] encoders/wavpack.h/.c 5797 - [X] pcmconverter.h/.c 5798*** DONE array_ia -> aa_int 5799*** DONE array_ia_new() -> aa_int_new() 5800 - [X] decoders/alac.h/.c 5801 - [X] decoders/aob.h/.c 5802 - [X] decoders/flac.h/.c 5803 - [X] decoders/mlp.h/.c 5804 - [X] decoders/oggflac.h/.c 5805 - [X] decoders/shn.h/.c 5806 - [X] decoders/sine.h/.c 5807 - [X] decoders/tta.h/.c 5808 - [X] decoders/wavpack.h/.c 5809 - [X] encoders/alac.h/.c 5810 - [X] encoders/flac.h/.c 5811 - [X] encoders/shn.h/.c 5812 - [X] encoders/tta.h/.c 5813 - [X] encoders/wavpack.h/.c 5814 - [X] pcmconverter.h/.c 5815 - [X] replaygain.h/.c 5816*** DONE array_li -> l_int 5817*** DONE array_li_new() -> l_int_new() 5818 - [X] encoders/flac.h/.c 5819*** DONE array_lia -> al_int 5820*** DONE array_lia_new() -> al_int_new() 5821 - [X] encoders/flac.h/.c 5822 - [X] pcmconverter.h/.c 5823*** DONE array_u -> l_unsigned 5824*** DONE array_u_new -> l_unsigned_new() 5825 - [X] decoders/alac.c 5826 - [X] encoders/alac.c 5827*** DONE array_lf -> l_double 5828*** DONE array_lu -> l_unsigned 5829*** DONE array_lu_new() -> l_unsigned_new() 5830 - [X] decoders/alac.h/.c 5831*** DONE array_lfa -> al_double 5832*** DONE array_lfa_new() -> al_double_new() 5833*** DONE array_iaa -> aaa_int 5834*** DONE array_iaa_new() -> aaa_int_new() 5835 - [X] encoders/wavpack.h/.c 5836 - [X] decoders/wavpach.h/.c 5837*** DONE array_f -> a_double 5838*** DONE array_f_new() -> a_double_new() 5839 - [X] pcmconverter.h/.c 5840 - [X] encoders/alac.h/.c 5841 - [X] encoders/flac.h/.c 5842*** DONE array_fa -> aa_double 5843*** DONE array_fa_new() -> aa_double_new() 5844 - [X] replaygain.h/.c 5845 - [X] encoders/alac.h/.c 5846 - [X] encoders/flac.h/.c 5847*** DONE array_faa -> aaa_double 5848*** DONE array_faa_new() -> aaa_double_new() 5849*** DONE array_o -> a_obj 5850*** DONE array_o_new() -> a_obj_new() 5851 - [X] decoders/alac.h/.c 5852 - [X] decoders/aob.h/.c 5853 - [X] decoders/flac.h/.c 5854 - [X] encoders/wavpack.h/.c 5855*** DONE array_i_to_FrameList -> a_int_to_FrameList 5856 - [X] decoders/flac.c 5857 - [X] decoders/oggflac.c 5858 - [X] pcmconv.c 5859 - [X] pcmconverter.c 5860*** DONE array_ia_to_FrameList -> aa_int_to_FrameList 5861 - [X] decoders/alac.c 5862 - [X] decoders/aob.c 5863 - [X] decoders/shn.c 5864 - [X] decoders/sine.c 5865 - [X] decoders/tta.c 5866 - [X] decoders/wavpack.c 5867 - [X] pcmconv.c 5868 - [X] pcmconverter.c 5869 - [X] replaygain.c 5870** DONE Better document M4A atoms 5871 For each atom, indicate parent in bit diagram, 5872 tell what it's for, have a hex diagram example 5873 and show what those parsed values are. 5874*** DONE ftyp 5875*** DONE moov 5876**** DONE mvhd 5877**** DONE trak 5878***** DONE tkhd 5879***** DONE mdia 5880****** DONE mdhd 5881****** DONE hdlr 5882****** DONE minf 5883******* DONE smhd 5884******* DONE dinf 5885******** DONE dref 5886******* DONE stbl 5887******** DONE stsd 5888******** DONE stts 5889******** DONE stsc 5890******** DONE stsz 5891******** DONE stco 5892**** DONE udta 5893***** DONE meta 5894*** DONE free 5895*** DONE mdat 5896*** DONE Add some tree diagrams to fill sections of whitespace 5897 - [X] moov 5898 - [X] trak 5899 - [X] mdia 5900 - [X] minf 5901 - [X] stbl 5902** DONE Add volume control to trackplay/cdplay 5903*** DONE Add get_volume() method to low-level audio players 5904 It should return the current set volume as a float. 5905 - [X] PulseAudioOutput 5906 - [X] OSSAudioOutput 5907 - [X] CoreAudioOutput 5908 - [X] NULLAudioOutput 5909*** DONE Add set_volume(volume) method to low-level audio players 5910 It should take a volume setting float and adjust the output volume. 5911 - [X] PulseAudioOutput 5912 - [X] OSSAudioOutput 5913 - [X] CoreAudioOutput 5914 - [X] NULLAudioOutput 5915*** DONE Build volume setting, progress-bar style widget 5916*** DONE Ensure volume control updates when system volume is updated 5917*** DONE Add widget to player widget 5918** DONE Make audio output selectable in trackplay/cdplay 5919*** DONE Add available_outputs() function to audiotools.player module 5920 should return list of available AudioOutput subclasses 5921*** DONE Add description() method to AudioOutput subclasses 5922 Returns a human-readable Unicode string indicating 5923 what the audio output device is. 5924 - [X] PulseAudioOutput 5925 - [X] OSSAudioOutput 5926 - [X] CoreAudioOutput 5927 - [X] NULLAudioOutput 5928*** DONE Ensure output switches correctly 5929 Switches should be as seamless as possible and include 5930 setting the output volume properly. 5931** DONE Add track2track format conversion options 5932 Primarily for conversion between one lossless format to another. 5933 - [X] --sample-rate 5934 - [X] --channels 5935 - [X] --bits-per-sample 5936*** DONE Add documentation to man page 5937*** DONE Add unit tests 5938** DONE Add internal True Audio codec 5939*** DONE Add Python-based True Audio decoder 5940*** DONE Add Python-based True Audio encoder 5941*** DONE Document True Audio decoding 5942*** DONE Document True Audio encoding 5943*** DONE Add C-based True Audio decoder 5944**** DONE modify it for standalone use 5945**** DONE ensure there's no memory errors or leaks 5946**** DONE Make decoder thread-friendly 5947*** DONE Add C-based True Audio encoder 5948**** DONE modify it for standalone use 5949**** DONE ensure there's no memory errors or leaks 5950**** DONE make encoder thread-friendly 5951*** DONE Add True Audio-specific unit tests 5952*** DONE Test encoder/decoder against reference 5953*** DONE Add True Audio detecter to file_type() function 5954*** DONE Add True Audio AudioFile class 5955*** DONE Ensure True Audio class passes all unit tests 5956** DONE Add AccurateRip support 5957 This might make give cd2track a little added respectability 5958 and post-rip tools could be built also to verify tracks/disc images. 5959*** DONE Add accuraterip Python support 5960**** DONE add DiscID to accuraterip module 5961**** DONE add perform_lookup to accuraterip module 5962**** DONE add accuraterip_lookup to __init__ module 5963**** DONE add AccurateRipReader to accuraterip module 5964 This would be a PCMReader wrapper to be used 5965 by cd2track to verify track checksum while it's being extracted. 5966**** DONE add AccurateRipTrackChecksum to accuraterip module 5967 This would be a transfer_framelist_data target 5968 to be used by trackverify to verify tracks 5969 already extracted. 5970**** DONE Add programming docstrings 5971**** DONE Add programming documentation 5972*** DONE Add AccurateRip disc ID to cdinfo 5973*** DONE Add support to cd2track 5974 This should be done by default as a wrapper around 5975 the existing CDDA PCMReader objects. 5976*** DONE Add support to trackverify 5977 Add a -R/--accuraterip option which foregoes the usual 5978 calls to .verify(), performs an AccurateRip lookup 5979 for all albums and indicates whether they match/don't match/aren't found 5980*** DONE Add protocol documentation 5981 - [X] calculating the AccurateRip disc ID 5982 - [X] fetching database entries from the server 5983 - [X] parsing database entries from the server 5984 - [X] calculating a track's CRC 5985 - [X] checking the confidence level 5986* DONE Finish version 2.21 5987** DONE Bump minimum required Python version to 2.7 5988 Python 2.7 is pretty common these days and offers useful 5989 features that have been backported from 3. 5990** DONE Cleanup ProgressDisplay design 5991 Replace row_id indicators with a ProgressDisplayRow object 5992 which is created by ProgressDisplay and features 5993 update() and delete() methods that update the main ProgressDisplay. 5994 5995 This removes the need to specify row_id values and the 5996 main ProgressDisplay can assign empty slots as needed. 5997*** DONE Update documentation 5998** DONE Update temporary file management 5999 Some of the metadata functions update via tempfile.TemporaryFile 6000 then overwrite the original once the file's been completed. 6001 6002 This would be a bad idea in the edge case of a full disk. 6003 6004 So it may be preferable to write to a temp file alongside the original 6005 and then rename over it. That way the original wouldn't be changed 6006 until commit-time. 6007 - [X] aiff.py 6008 - [X] ape.py 6009 - [X] flac.py 6010 - [X] m4a.py 6011 - [X] tta.py 6012 - [X] wav.py 6013*** DONE Add unit tests 6014 Ensure tracks retain permissions when metadata is updated. 6015** DONE Convert utilties from optparse to argparse 6016 argparse seems a bit nicer and more user-friendly 6017 since it generates usage lines automatically. 6018 - [X] audiotools-config 6019 - [X] cd2track 6020 - [X] cdinfo 6021 - [X] cdplay 6022 - [X] coverdump 6023 - [X] covertag 6024 - [X] coverview 6025 - [X] dvda2track 6026 - [X] dvdainfo 6027 - [X] track2cd 6028 - [X] track2track 6029 - [X] trackcat 6030 - [X] trackcmp 6031 - [X] trackinfo 6032 - [X] tracklength 6033 - [X] tracklint 6034 - [X] trackplay 6035 - [X] trackrename 6036 - [X] tracksplit 6037 - [X] tracktag 6038 - [X] trackverify 6039*** DONE Ensure all utilities have a working --version option 6040 Now that it's no longer built-in, I'll need to add and check 6041 the option by hand. 6042 - [X] audiotools-config 6043 - [X] cd2track 6044 - [X] cdinfo 6045 - [X] cdplay 6046 - [X] coverdump 6047 - [X] covertag 6048 - [X] coverview 6049 - [X] dvda2track 6050 - [X] dvdainfo 6051 - [X] track2cd 6052 - [X] track2track 6053 - [X] trackcat 6054 - [X] trackcmp 6055 - [X] trackinfo 6056 - [X] tracklength 6057 - [X] tracklint 6058 - [X] trackplay 6059 - [X] trackrename 6060 - [X] tracksplit 6061 - [X] tracktag 6062 - [X] trackverify 6063** DONE Improve Ogg format metadata speeds 6064 Reading/writing should be faster for all Ogg-based formats. 6065*** DONE Ogg FLAC 6066*** DONE Ogg Vorbis 6067*** DONE Opus 6068** DONE Adjust MetaData.clean() interface 6069 Returns (MetaData, [fixes]) tuple 6070 where MetaData is a new, fixed metadata object 6071 and fixes is a list of Unicode strings. 6072*** DONE Fix MetaData objects 6073 - [X] MetaData 6074 - [X] APEv2 6075 - [X] FlacMetaData 6076 - [X] ID3v22Comment 6077 - [X] ID3v23Comment 6078 - [X] ID3v24Comment 6079 - [X] ID3CommentPair 6080 - [X] ID3v1Comment 6081 - [X] M4A_META_Atom 6082 - [X] VorbisComment 6083*** DONE Update documentation 6084*** DONE Update unit tests 6085** DONE Adjust AudioFile.clean() interface 6086 Takes optional output_filename and returns list of fixes performed. 6087 It would be nice not to need separate code paths 6088 for dry runs, like with MetaData, but that may not be feasible. 6089*** DONE Fix AudioFile objects 6090 - [X] AudioFile 6091 - [X] AiffAudio 6092 - [X] FlacAudio 6093 - [X] WaveAudio 6094*** DONE Update tracklint 6095*** DONE Update documentation 6096*** DONE Update unit tests 6097** DONE Add lint for "double-wrapped" ID3v2 tags 6098 Sometimes files are idiotically wrapped in multiple layers of ID3v2 tags 6099 like nested Russian dolls. These are currently unrecognized because 6100 audiotools assumes a valid track follows the tag instead of another tag. 6101*** DONE Support tracks nested arbitrarily deep in ID3v2 tags 6102 In order to be fixable, 6103 these files will need to be readable in the first place 6104**** DONE Update file_type function to skip ID3v2 tags recursively 6105 It should still only find MP2/MP3/FLAC/TTA files how matter how 6106 deeply nested, but should support arbitrarily deep nesting. 6107**** DONE Update FlacAudio 6108***** DONE Update FlacAudio to support nested tags 6109 This is basically a matter of making the offset as large 6110 as it takes to hold all the tags. 6111***** DONE Have FlacAudio.clean() remove all ID3v2 tags 6112***** DONE Update unit tests 6113**** DONE Update MP3Audio 6114***** DONE Update MP3Audio to support nested tags 6115***** DONE Have MP3Audio.clean() remove all ID3v2 tags except one 6116***** DONE Update unit tests 6117**** DONE Update MP2Audio 6118***** DONE Update MP2Audio to support nested tags 6119***** DONE Have MP2Audio.clean() remove all ID3v2 tags except one 6120***** DONE Update unit tests 6121**** DONE Update TrueAudio 6122***** DONE Update TrueAudio to support nested tags 6123***** DONE Have TrueAudio.clean() remove all ID3v2 tags except one 6124***** DONE Update unit tests 6125* DONE Finish version 2.22 6126** DONE Update ReplayGain interface 6127 All ReplayGain should be lossless (if supported at all) and needs an interface 6128 that's less dependant on external tools. 6129*** DONE Remove add_replay_gain() classmethod 6130 - [X] AudioFile 6131 - [X] ALACAudio 6132 - [X] AiffAudio 6133 - [X] AuAudio 6134 - [X] FlacAudio 6135 - [X] M4AAudio 6136 - [X] MP2Audio 6137 - [X] MP3Audio 6138 - [X] OggFlacAudio 6139 - [X] OpusAudio 6140 - [X] ShortenAudio 6141 - [X] TrueAudio 6142 - [X] VorbisAudio 6143 - [X] WavPackAudio 6144 - [X] WaveAudio 6145*** DONE Add add_replay_gain() function 6146 Takes an album's worth of audiofile objects and optional progress function 6147 and if any of their classes support it (via the supports_replay_gain() classmethod) 6148 calls calculate_replay_gain() on all of them and applies the result 6149 using set_replay_gain() 6150*** DONE Remove can_add_replay_gain() classmethod 6151 If supports_replay_gain() classmethod returns True, 6152 set_replay_gain() will be able to do something useful. 6153 - [X] AudioFile 6154 - [X] ALACAudio 6155 - [X] AiffAudio 6156 - [X] AuAudio 6157 - [X] FlacAudio 6158 - [X] M4AAudio 6159 - [X] MP2Audio 6160 - [X] MP3Audio 6161 - [X] OggFlacAudio 6162 - [X] OpusAudio 6163 - [X] ShortenAudio 6164 - [X] TrueAudio 6165 - [X] VorbisAudio 6166 - [X] WavPackAudio 6167 - [X] WaveAudio 6168*** DONE Remove lossless_replay_gain classmethod 6169 All ReplayGain will be lossless 6170 - [X] AudioFile 6171 - [X] ALACAudio 6172 - [X] AiffAudio 6173 - [X] AuAudio 6174 - [X] FlacAudio 6175 - [X] M4AAudio 6176 - [X] MP2Audio 6177 - [X] MP3Audio 6178 - [X] OggFlacAudio 6179 - [X] OpusAudio 6180 - [X] ShortenAudio 6181 - [X] TrueAudio 6182 - [X] VorbisAudio 6183 - [X] WavPackAudio 6184 - [X] WaveAudio 6185*** DONE Convert replay_gain() method to get_replay_gain() 6186 Returns a ReplayGain object or None, as it does now. 6187 Analagous to get_metadata() 6188 - [X] AudioFile 6189 - [X] ALACAudio 6190 - [X] AiffAudio 6191 - [X] AuAudio 6192 - [X] FlacAudio 6193 - [X] M4AAudio 6194 - [X] MP2Audio 6195 - [X] MP3Audio 6196 - [X] OggFlacAudio 6197 - [X] OpusAudio 6198 - [X] ShortenAudio 6199 - [X] TrueAudio 6200 - [X] VorbisAudio 6201 - [X] WavPackAudio 6202 - [X] WaveAudio 6203*** DONE Add set_replay_gain() method 6204 Takes a ReplayGain object or None and sets the file's values 6205 by updating metadata, or deletes the values if None 6206 Analagous to set_metadata() 6207 - [X] AudioFile 6208 - [X] ALACAudio 6209 - [X] AiffAudio 6210 - [X] AuAudio 6211 - [X] FlacAudio 6212 - [X] M4AAudio 6213 - [X] MP2Audio 6214 - [X] MP3Audio 6215 - [X] OggFlacAudio 6216 - [X] OpusAudio 6217 - [X] ShortenAudio 6218 - [X] TrueAudio 6219 - [X] VorbisAudio 6220 - [X] WavPackAudio 6221 - [X] WaveAudio 6222*** DONE Add delete_replay_gain() method 6223 Deletes any ReplayGain values, if any 6224 Analagous to delete_metadata() 6225 - [X] AudioFile 6226 - [X] ALACAudio 6227 - [X] AiffAudio 6228 - [X] AuAudio 6229 - [X] FlacAudio 6230 - [X] M4AAudio 6231 - [X] MP2Audio 6232 - [X] MP3Audio 6233 - [X] OggFlacAudio 6234 - [X] OpusAudio 6235 - [X] ShortenAudio 6236 - [X] TrueAudio 6237 - [X] VorbisAudio 6238 - [X] WavPackAudio 6239 - [X] WaveAudio 6240*** DONE Update utilities to use new ReplayGain interface 6241 - [X] cd2track 6242 - [X] dvda2track 6243 - [X] track2track 6244 - [X] trackinfo 6245 - [X] trackplay 6246 - [X] tracksplit 6247 - [X] tracktag 6248*** DONE Update documentation 6249*** DONE Update unit tests 6250** DONE Catch interrupts more cleanly in utilities 6251 When the user cancels a long-running job, utilities should clean the screen 6252 as well as possible, delete any partial files and display a "cancelled" message 6253 instead of delivering stack traces like they do now. 6254 - [X] cd2track 6255 - [X] cdplay 6256 - [X] dvda2track 6257 - [X] track2cd 6258 - [X] track2track 6259 - [X] trackcat 6260 - [X] trackcmp 6261 - [X] tracklength 6262 - [X] trackplay 6263 - [X] tracksplit 6264 - [X] tracktag 6265 - [X] trackverify 6266** DONE Add AudioFile.seekable() method 6267 This returns True if the format's PCMReader has a .seek() method 6268 and that method supports some sort of fine-grained seeking 6269 (i.e. not just return to the beginning of the file). 6270*** DONE Update audio formats 6271 - [X] AudioFile 6272 - [X] ALACAudio 6273 - [X] AiffAudio 6274 - [X] AuAudio 6275 - [X] FlacAudio 6276 - [X] M4AAudio 6277 - [X] MP2Audio 6278 - [X] MP3Audio 6279 - [X] OggFlacAudio 6280 - [X] OpusAudio 6281 - [X] ShortenAudio 6282 - [X] TrueAudio 6283 - [X] VorbisAudio 6284 - [X] WavPackAudio 6285 - [X] WaveAudio 6286*** DONE Update documentation 6287*** DONE Update utilities 6288**** DONE tracksplit 6289 If the file being split isn't seekable, decompress it to a temp file 6290 so it can be processed across multiple jobs. 6291**** DONE trackcmp 6292 If comparing multiple tracks against a non-seekable image, 6293 decompress it to a temp file so it can be processed across multiple jobs. 6294*** DONE Update unit tests 6295** DONE Have AccurateRip detect offset tracks 6296 If the tracks have been ripped accurately but are merely offset 6297 by some small positive or negative number of samples, 6298 this should be detected and indicated in the AccurateRip results screens. 6299*** DONE Update ChecksumV1 6300**** DONE Add keyword parameters with sensible defaults 6301**** DONE Add range option 6302 This indicates the total range of the window size. 6303 Defaults to 1, indicating only a single checksum to be generated. 6304**** DONE Change .checksum() method to .checksums() 6305 Returns a list of all calculated checksums over the whole range. 6306*** DONE Add unit tests 6307 Ensure ranged and non-ranged checksums are calculated properly 6308 and update tests for new interface. 6309*** DONE Build audiotools.cdio.CDDAReader object 6310 This functions like a PCMReader object over the entire CDDA device. 6311 It should work transparently on physical CD devices as well as CD images 6312 and be PCM-frame centric by doing all the CD sector conversions 6313 behind-the-scenes. 6314**** DONE Add methods and attributes 6315***** DONE CDDAReader.sample_rate 6316***** DONE CDDAReader.channels 6317***** DONE CDDAReader.channel_mask 6318***** DONE CDDAReader.bits_per_sample 6319***** DONE CDDAReader.track_offsets 6320 - [X] CD image 6321 - [X] CD drive 6322 Returns starting offset of each track, in PCM frames 6323***** DONE CDDAReader.track_lengths 6324 - [X] CD image 6325 - [X] CD drive 6326 Returns length of each track, in PCM frames 6327***** DONE CDDAReader.first_sector 6328 - [X] CD image 6329 - [X] CD drive 6330 Used for calculating various disc IDs 6331***** DONE CDDAReader.last_sector 6332 - [X] CD image 6333 - [X] CD drive 6334 Used for calculating various disc IDs 6335***** DONE CDDAReader.is_image 6336 - [X] CD drive 6337 - [X] CD image 6338***** DONE CDDAReader.read(pcm_frames) 6339 - [X] CD image 6340 - [X] CD drive 6341***** DONE CDDAReader.seek(pcm_frames) 6342 - [X] CD image 6343 - [X] CD drive 6344***** DONE CDDAReader.set_speed(speed) 6345 - [X] CD image 6346 - [X] CD drive 6347***** DONE CDDAReader.log() 6348 - [X] CD image 6349 - [X] CD drive 6350***** DONE CDDAReader.reset_log() 6351***** DONE CDDAReader.close() 6352**** DONE Update documentation 6353**** DONE Update unit tests 6354**** DONE Detect nonexistent discs 6355 CDDAReader should detect when a physical drive doesn't contain a disc 6356 and raise an appropriate exception. 6357**** DONE Update utilities 6358***** DONE cd2track 6359***** DONE cdinfo 6360***** DONE cdplay 6361**** DONE Clean out old audiotools.CDDA object 6362 Remove outdated interface, its documentation and unit tests. 6363*** DONE Update utilities 6364 When verifying AccurateRip, make sure to populate the checksum 6365 with the last few samples of the previous track (if any) 6366 and the next few samples of the next track (if any) 6367 in order to find the checksum's offset. 6368**** DONE trackverify 6369**** DONE cd2track 6370** DONE Simplify lookup services interface 6371 The perform_lookup() functions should work on DiscID objects 6372 and DiscID objects should be generated from 6373 CDDAReaders, track lists or cuesheet/length combinations. 6374*** DONE FreeDB 6375 - [X] Add from_tracks classmethod 6376 - [X] Add from_sheet classmethod 6377 - [X] Add unit tests 6378*** DONE MusicBrainz 6379 - [X] Add from_tracks classmethod 6380 - [X] Add from_sheet classmethod 6381 - [X] Add unit tests 6382*** DONE AccurateRip 6383 - [X] Add from_tracks classmethod 6384 - [X] Add from_sheet classmethod 6385 - [X] Add unit tests 6386** DONE Add documentation for lookup services 6387 - [X] audiotools.freedb 6388 - [X] audiotools.musicbrainz 6389 - [X] audiotools.accuraterip 6390** DONE Convert TOC and CUE handling to proper grammars 6391*** DONE Convert audiotools.cue 6392*** DONE Convert audiotools.toc 6393** DONE Add AccurateRipV2 support 6394*** DONE Add ChecksumV2 object 6395**** DONE Add unit tests 6396*** DONE Update utilities 6397 - [X] cd2track 6398 - [X] trackverify 6399** DONE Update Sheet interface 6400 Although cuesheets are mostly a repository of index points, 6401 it would be useful to support a wider subset of options 6402 when converting one form to another. 6403*** DONE Sheet 6404 - [X] @classmethod converted(sheet) -> Sheet 6405 builds Sheet object from Sheet-compatible object 6406 - [X] __len__() -> total_tracks 6407 - [X] __getitem__(track_index) -> SheetTrack 6408 - [X] __eq__(sheet) -> boolean 6409 - [X] track_numbers() -> [int] 6410 - [X] track(track_number) -> SheetTrack 6411 - [X] get_metadata() -> MetaData 6412 MetaData contains catalog_number and CD-TEXT information 6413*** DONE SheetTrack 6414 - [X] @classmethod converted(sheet_track) -> SheetTrack 6415 builds SheetTrack object from SheetTrack-compatible object 6416 - [X] __len__() -> total_indexes 6417 - [X] __getitem__(index_index) -> SheetIndex 6418 - [X] __eq__(sheet_track) -> boolean 6419 - [X] indexes() -> [int] 6420 - [X] index(index_number) -> SheetIndex 6421 - [X] filename() -> string 6422 - [X] number() -> track_number 6423 - [X] get_metadata() -> MetaData 6424 MetaData contains track_number, ISRC and CD-TEXT information 6425 - [X] is_audio() -> boolean 6426 - [X] pre_emphasis() -> boolean 6427 - [X] copy_peritted() -> boolean 6428*** DONE SheetIndex 6429 - [X] @classmethod converted(sheet_index) -> SheetIndex 6430 - [X] __eq__(sheet_index) -> boolean 6431 - [X] number() -> index_number 6432 pre-gap is index_number 0 6433 - [X] offset() -> Fraction 6434 offset of index in seconds from start of stream 6435*** DONE Update audiotools.cue.Cuesheet 6436*** DONE Update audiotools.toc.TOCFile 6437*** DONE Update audiotools.flac.Flac_CUESHEET 6438*** DONE Ensure non-image cuesheets are handled properly 6439 Given a non-image cuesheet and list of track lengths, 6440 it may be possible to convert a non-image cuesheet 6441 to an image cuesheet. 6442*** DONE Handle 1st track pre-gap correctly 6443 Discs with a pre-gap before the 1st track 6444 should have that gap removed when split 6445 and re-added when concatenating them back together 6446 based on the cuesheet contents. 6447 - [X] update tracksplit 6448 - [X] update trackcat 6449 - [X] add unit tests 6450*** DONE Update utilities 6451 - [X] trackcat 6452 - [X] tracksplit 6453 - [X] track2cd 6454 - [X] trackinfo 6455*** DONE Update functions/methods which take cuesheets 6456 - [X] sheet_metadata_lookup 6457 - [X] accuraterip_sheet_lookup 6458*** DONE Update documentation 6459*** DONE Update unit tests 6460** DONE Converts AudioFile.seconds_length() method to Fraction 6461 This should be more useful than the Decmial it was using before. 6462*** DONE Update method 6463*** DONE Update documentation 6464*** DONE Update utilities 6465 - [X] track2cd 6466 - [X] trackcat 6467 - [X] trackinfo 6468 - [X] tracklength 6469 - [X] trackplay 6470 - [X] tracksplit 6471* TODO Add support for genre tag? 6472 I'm not a big fan of the genre tag. 6473 Unlike track number, album name, ISRC, etc. in which a value 6474 can be reliably determined from the source material (e.g. back of the CD), 6475 genre is akin to a "rating" tag. Its value varies from person to person 6476 and this makes it less valuable for archival purposes. 6477 6478 In addition, the genre tag itself is implemented in incompatible ways. 6479 APEv2 uses a chunk of text, ID3v1 uses an integer representing one 6480 of many designated genre labels, ID3v2 uses a mix of genre byte 6481 and/or text string, and so on. 6482 6483 That said, the genre field shows up in a lot of players. 6484 So, some grudging support for it would probably be appreciated. 6485* TODO Replace magic numbers with named constants 6486 There's still a few instances of magic numbers in use, 6487 in the __flac__.py module, for instance. 6488* TODO Support disc metadata submission 6489 If a disc is not found on FreeDB or MusicBrainz, 6490 there should be some mechanism to submit user-defined data 6491 to those services. 6492* TODO build track2cover utility 6493 It would be helpful to have tools that could query 6494 online cover databases and retrieve images for tagging purposes. 6495 track2cover can replace coverdump, functioning like trac2xmcd 6496 which allows it to pull from existing metadata or from online sources. 6497* TODO build trackverify utility 6498 Much like flac(1)'s --verify option, this should check 6499 a file for correctness and, if possible, verify its output 6500 matches any internal hashes/checksums. 6501 May work recursively to check a user's entire collection. 6502** DONE add a .verify() method to AudioFile classes 6503 Returns True if the file is okay. Raises InvalidFile if not. 6504 Include unit test. 6505 - [X] AiffAudio 6506 - [X] ALACAudio 6507 - [X] AuAudio 6508 - [X] FlacAudio 6509 - [X] M4AAudio 6510 - [X] MP2Audio 6511 - [X] MP3Audio 6512 - [X] OggFlacAudio 6513 - [X] SpeexAudio 6514 - [X] ShortenAudio 6515 - [X] VorbisAudio 6516 - [X] WaveAudio 6517 - [X] WavPackAudio 6518** TODO add trackverify unit tests for all known verifiable problems 6519** DONE add trackverify man page 6520** DONE link trackverify man page to others 6521* TODO Add a -r/--no-results flag to trackcmp/trackverify 6522 Listing only the final results and not the running list 6523** TODO Update man page 6524* TODO Add DVD-A support 6525** DONE Build AOB parser/extractor 6526*** DONE Optimize AOB extractor for better offset handling 6527 The current version works, but is a little too naive 6528** TODO Build CPPM handler 6529*** DONE Create audiotools.prot module 6530*** TODO Create audiotools.prot.CPPMDecoder object 6531**** DONE Add CPPMDecoder.__init__() method 6532**** DONE Add CPPMDecoder.decode() method 6533**** TODO Ensure CPPMDecoder is cross-platform 6534** DONE Document AOB parser 6535** DONE Build raw PCM decoder 6536 The PCM data doesn't appear to be stored raw, 6537 so some additional calculation will likely be necessary 6538** TODO Build MLP decoder 6539*** DONE Create decoders.MLPDecoder class 6540**** DONE Add MLPDecoder.init() method 6541**** DONE Add MLPDecoder.sample_rate attribute 6542**** DONE Add MLPDecoder.channels attribute 6543**** DONE Add MLPDecoder.bits_per_sample attribute 6544**** DONE Add MLPDecoder.channel_mask attribute 6545**** DONE Add MLPDecoder.read() method 6546**** DONE Add MLPDecoder.analyze_frame() method 6547**** DONE Add MLPDecoder.close() method 6548*** DONE Perform MLP frame parsing 6549**** DONE Perform frame size parsing 6550**** DONE Perform major sync parsing 6551**** DONE Perform substream sizes parsing 6552**** DONE Perform substream datas parsing 6553***** DONE Perform block parsing 6554****** DONE Perform restart header parsing 6555****** DONE Perform decoding parameters parsing 6556******* DONE Perform parameter presence flags parsing 6557******* DONE Perform block size parsing 6558******* DONE Perform matrix parameters parsing 6559******* DONE Perform output shifts parsing 6560******* DONE Perform quant step sizes parsing 6561******* DONE Perform channel parameters parsing 6562******** DONE Perform FIR filter parameters parsing 6563******** DONE Perform IIR filter parameters parsing 6564******** DONE Perform Huffman offset parsing 6565******** DONE Perform Codebook parsing 6566******** DONE Perform Huffman least-significant bits parsing 6567****** DONE Perform block data parsing 6568***** DONE Perform block alignment 6569***** DONE Perform CRC parsing 6570*** TODO Perform MLP data decoding 6571**** DONE Handle FIR/IIR filtering 6572**** DONE Handle matrix reconstruction 6573***** DONE Build noise channels 6574**** DONE Handle quant_step_sizes 6575**** DONE Combine multiple substreams into single output frame 6576**** DONE Handle output shifts 6577**** TODO Handle checksums 6578***** TODO restart header lossless check 6579***** DONE end-of-frame parity 6580***** DONE end-of-frame checksum 6581**** DONE Build pcm.FrameList from PCM data arrays 6582***** DONE Reorder MLP channels to wave order 6583**** DONE Add bs_try for proper EOF aborts 6584**** DONE Add end-of-stream marker checking to read() 6585**** TODO Add end-of-stream marker checking to analyze_frame() 6586**** DONE Optimize to work faster 6587 Perhaps with multiple blocks per call to read() 6588**** TODO Support 1 substream output 6589 MLP decoding supports 1 or 2 substreams. 6590 In some cases, substream 1 will contain the first 2 channels 6591 while substream 2 will contain the rest, 6592 which provides two different "mixes" depending on whether 6593 one is decoding to 2 channels or not. 6594***** TODO Update dvda2track with 1 substream output option 6595 This would allow the user to decide which "mix" is desired 6596 during extraction. 6597*** DONE Perform sanity checks 6598** TODO Document MLP decoder 6599*** DONE major sync 6600*** DONE substream size 6601*** DONE substream data 6602*** DONE restart header 6603*** DONE decoding parameters 6604**** DONE parameter presence flags 6605**** DONE block size 6606**** DONE matrix parameters 6607**** DONE output shifts 6608**** DONE quant step sizes 6609*** DONE checksums 6610*** DONE block data 6611*** DONE channel filtering 6612*** DONE channel rematrixing 6613**** DONE noise channels 6614**** DONE rematrixing 6615*** DONE end of stream marker 6616*** TODO decoding XOR byte 6617** DONE Document PCM decoder 6618** DONE Link MLP decoder to AOB extractor 6619** DONE Link PCM decoder to AOB extractor 6620** TODO Build DVD-A postprocessor 6621** DONE Document Python interface 6622** DONE Build dvdainfo utility 6623*** DONE Add dvdainfo.1 man page 6624*** DONE Ensure -A with invalid dir generates error message 6625** DONE Build dvda2track utility 6626*** DONE Fix to work without -d 6627*** DONE Add --track-start / --track-total options 6628 Since some especially long discs split tracks across titles, 6629 it makes sense to have a way to specify the starting track number 6630 and the total number of tracks. 6631**** DONE Add options to man page 6632*** DONE Add dvda2track.1 man page 6633*** DONE Ensure -A with invalid dir generates error message 6634** DONE Build dvda2xmcd utility 6635 Querying FreeDB and MusicBrainz are possible, 6636 but I expect most of the time they'll generate empty templates. 6637*** DONE Add dvda2xmcd.1 man page 6638*** DONE Ensure -A with invalid dir generates error message 6639* TODO Add cdplay utility 6640 Should work similarly to trackplay, 6641 taking track number(s) and playing them to OSS/PulseAudio 6642 or whatever other audio output is available. 6643** DONE Add audiotools.player.CDPlayer class 6644*** DONE Add docstrings 6645*** DONE Add programming docs 6646** DONE Add audiotools.player.CDPlayerThread class 6647*** DONE Add docstrings 6648** DONE Add non-interactive mode to cdplay 6649** DONE Add interative mode to cdplay 6650 Urwid-based display should have various standard features 6651 - [X] display CD info 6652 - [X] progress monitor 6653 - [X] start 6654 - [X] pause 6655 - [X] next track 6656 - [X] previous track 6657** DONE Silence CD query messages 6658** DONE Support command-line tracks 6659 One might want to play only a subset of the whole CD 6660** DONE Add -V/--verbose option 6661** DONE Add --shuffle option 6662** DONE Add -x/--xmcd file support 6663** DONE Avoid spinning down CDs between tracks 6664 This makes playback less seamless than I'd like 6665** TODO Improve stability 6666** DONE Add man page for cdplay.1 6667** TODO Add basic unit tests 6668 - [ ] Check command-line arguments 6669* TODO Reorganize test suite 6670 The current haphazard layout makes it too difficult to deterimine 6671 if some feature has been fully unit tested. 6672 Or, if a new feature is added, the logical place to put new tests 6673 is not obvious. 6674** TODO Group tests for the audio formats 6675*** DONE AudioFile 6676 - [X] test_init 6677 - [X] test_is_type 6678 - [X] test_bits_per_sample 6679 - [X] test_metadata 6680 - [X] test_length 6681 - [X] test_track_number 6682 - [X] test_album_number 6683 - [X] test_track_name 6684 - [X] test_replay_gain 6685*** DONE LosslessAudioFile 6686 - [X] test_lossless 6687 - [X] test_channels 6688 - [X] test_channel_mask 6689 - [X] test_sample_rate 6690 - [X] test_pcm 6691 - [X] test_convert 6692*** DONE LossyAudioFile 6693 - [X] test_bits_per_sample 6694 - [X] test_lossless 6695 - [X] test_channels 6696 - [X] test_channel_mask 6697 - [X] test_sample_rate 6698 - [X] test_pcm 6699 - [X] test_convert 6700*** DONE ALACAudio 6701 - [X] test_init 6702 - [X] test_bits_per_sample 6703 - [X] test_channel_mask 6704 - [X] test_verify 6705 - [X] test_streams 6706 - [X] test_small_files 6707 - [X] test_full_scale_deflection 6708 - [X] test_sines 6709 - [X] test_wasted_bps 6710 - [X] test_blocksizes 6711 - [X] test_noise 6712 - [X] test_fractional 6713 - [X] test_frame_header_variations 6714*** TODO AiffAudio 6715 - [ ] test_init 6716 - [X] test_channel_mask 6717 - [X] test_verify 6718 - [X] test_roundtrip_aiff_chunks 6719 - [X] test_convert_aiff_chunks 6720*** TODO AuAudio 6721 - [ ] test_init 6722 - [X] test_verify 6723 - [X] test_channel_mask 6724*** TODO FlacAudio 6725 - [ ] test_init 6726 - [ ] test_metadata2 6727 - [X] test_verify 6728 - [ ] test_cuesheet 6729 - [X] test_roundtrip_aiff_chunks 6730 - [X] test_convert_aiff_chunks 6731 - [X] test_roundtrip_wave_chunks 6732 - [X] test_convert_wave_chunks 6733 - [X] test_streams 6734 - [X] test_small_files 6735 - [X] test_full_scale_deflection 6736 - [X] test_sines 6737 - [X] test_wasted_bps 6738 - [X] test_blocksizes 6739 - [X] test_frame_header_variations 6740 - [X] test_option_variations 6741 - [X] test_noise 6742 - [X] test_fractional 6743*** TODO M4AAudio 6744 - [ ] test_init 6745 - [ ] test_verify 6746*** TODO MP2Audio 6747 - [ ] test_init 6748 - [X] test_length 6749 - [ ] test_verify 6750*** TODO MP3Audio 6751 - [ ] test_init 6752 - [X] test_length 6753 - [ ] test_verify 6754*** TODO OggFlacAudio 6755 - [ ] test_init 6756 - [X] test_verify 6757 - [ ] test_cuesheet 6758*** TODO ShortenAudio 6759 - [ ] test_init 6760 - [X] test_bits_per_sample 6761 - [X] test_verify 6762 - [X] test_roundtrip_wave_chunks 6763 - [X] test_convert_wave_chunks 6764 - [X] test_streams 6765 - [X] test_small_files 6766 - [X] test_full_scale_deflection 6767 - [X] test_sines 6768 - [X] test_blocksizes 6769 - [X] test_noise 6770*** TODO VorbisAudio 6771 - [ ] test_init 6772 - [X] test_channels 6773 - [X] test_verify 6774*** TODO WavPackAudio 6775 - [ ] test_init 6776 - [X] test_verify 6777 - [ ] test_cuesheet 6778 - [X] test_roundtrip_wave_chunks 6779 - [X] test_convert_wave_chunks 6780 - [X] test_small_files 6781 - [X] test_full_scale_deflection 6782 - [X] test_wasted_bps 6783 - [X] test_blocksizes 6784 - [X] test_silence 6785 - [X] test_noise 6786 - [X] test_fractional 6787 - [X] test_multichannel 6788 - [X] test_sines 6789 - [X] test_option_variations 6790*** TODO WaveAudio 6791 - [ ] test_init 6792 - [X] test_verify 6793 - [X] test_roundtrip_wave_chunks 6794 - [X] test_convert_wave_chunks 6795** DONE Group tests for the metadata formats 6796*** DONE ApeTag 6797*** DONE FLAC 6798*** DONE ID3v1 6799*** DONE ID3v2.2 6800*** DONE ID3v2.3 6801*** DONE ID3v2.4 6802*** DONE IDCommentPair 6803*** DONE M4A 6804*** DONE VorbisComment 6805*** DONE Ensure that merge() works properly 6806 It has to handle all supported text fields 6807 *and* must handle images if supported. 6808** TODO Group tests for the core libraries 6809*** TODO audiotools.__init__ 6810**** TODO AlbumMetaData 6811**** DONE BufferedPCMReader 6812**** DONE CDDA 6813**** DONE ChannelMask 6814**** DONE Image 6815**** DONE LimitedPCMReader 6816**** TODO Messenger 6817**** DONE PCMCat 6818**** DONE PCMConverter 6819**** DONE PCMReaderWindow 6820**** TODO ReorderedPCMReader 6821**** DONE ReplayGain 6822**** DONE applicable_replay_gain 6823**** DONE at_a_time 6824**** DONE build_timestamp 6825**** DONE calculate_replay_gain 6826**** DONE filename_to_type 6827**** DONE group_tracks 6828**** TODO make_dirs 6829**** DONE open 6830**** DONE open_directory 6831**** DONE open_files 6832**** DONE parse_timestamp 6833**** DONE pcm_frame_cmp 6834**** DONE pcm_split 6835**** DONE read_sheet 6836**** DONE str_width 6837**** DONE transfer_framelist_data 6838**** DONE XMCD 6839**** DONE MusicBrainzReleaseXML 6840*** DONE audiotools.pcm 6841**** DONE FloatFrameList 6842**** DONE FrameList 6843**** DONE from_channels 6844**** DONE from_float_Frames 6845**** DONE from_float_channels 6846**** DONE from_frames 6847**** DONE from_list 6848*** DONE audiotools.player 6849**** DONE Player 6850**** DONE CDPlayer 6851*** DONE audiotools.replaygain 6852**** DONE ReplayGain 6853**** DONE ReplayGainReader 6854*** DONE audiotools.decoders 6855**** DONE BitstreamReader 6856*** DONE audiotools.encoders 6857**** DONE BitstreamWriter 6858*** TODO audiotools.verify 6859**** TODO mpeg 6860**** TODO ogg 6861** TODO Group tests for the individual tools 6862*** TODO audiotools-config 6863**** TODO test_options 6864**** TODO test_errors 6865*** DONE cd2track 6866**** DONE test_options 6867**** DONE test_errors 6868*** DONE cd2xmcd 6869**** DONE test_options 6870**** DONE test_errors 6871*** TODO cdinfo 6872**** TODO test_options 6873**** TODO test_errors 6874*** TODO cdplay 6875**** TODO test_options 6876**** TODO test_errors 6877*** DONE coverdump 6878**** DONE test_options 6879**** DONE test_errors 6880*** DONE dvdainfo 6881**** DONE test_errors 6882*** DONE dvda2track 6883**** DONE test_errors 6884*** DONE dvda2xmcd 6885**** DONE test_errors 6886*** DONE track2track 6887**** DONE test_options 6888**** DONE test_errors 6889*** DONE track2xmcd 6890**** DONE test_options 6891**** DONE test_errors 6892*** DONE trackcat 6893**** DONE test_options 6894*** DONE trackcmp 6895**** DONE test_options 6896*** TODO trackinfo 6897**** TODO test_options 6898**** TODO test_errors 6899*** DONE tracklength 6900*** DONE tracklint 6901*** TODO trackplay 6902**** TODO test_options 6903**** TODO test_errors 6904*** DONE trackrename 6905**** DONE test_options 6906**** DONE test_errors 6907*** DONE tracksplit 6908**** DONE test_options 6909**** DONE test_errors 6910*** TODO tracktag 6911**** DONE test_options 6912**** TODO test_errors 6913*** TODO trackverify 6914**** TODO test_options 6915**** TODO test_errors 6916** DONE Split tests into multiple files 6917* TODO Handle write errors more gracefully 6918 Just as the BitstreamReader uses an exception mechanism to detect 6919 and handle read errors, the BitstreamWriter should use a similar 6920 mechanism to detect write errors and bubble-up a Python exception. 6921 6922 The problem is that invalid writes are difficult to unit test. 6923 With a reader, one can simply truncate a valid file. 6924 It's harder to constrict a writer to only have X number of bytes 6925 available so that any errors can be checked. 6926** TODO Add try/etry support to BitstreamWriter 6927** DONE Update BitstreamWriter methods to raise exceptions 6928** TODO Update Python-based BitstreamWriter to catch C exceptions 6929** TODO Update encoders to catch C exceptions and raise Python exceptions 6930** TODO Unit test write errors 6931* TODO Verify metadata against reference implementations 6932 Where feasible, try to ensure our metadata 6933 matches what's read/written by known reference implementations. 6934** TODO FlacAudio 6935 against metaflac 6936** TODO M4AAudio/ALACAudio 6937 against taglib? 6938** TODO MP3Audio/MP2Audio 6939 Against taglib, perhaps? Venerable id3lib doesn't work with UCS-2. 6940** TODO VorbisAudio 6941 against vorbis-tools 6942** TODO WavPackAudio 6943 against tablib? 6944* TODO Add lyrics metadata support 6945 Supporting storing lyrics text in the audio files themselves 6946 would be quite useful. 6947** TODO Add .lyrics field to MetaData 6948 Analagous to the lengthy .comment field, most likely. 6949** TODO Add unit testing for .lyrics field 6950** TODO Find automated source for lyrics 6951 Analagous to CDDB. 6952 This will be challenging since online sources for lyrics are rare. 6953 Unfortunately, expecting everyone to transcribe lyrics for songs 6954 is unrealistic - even moreso than filling in song names 6955 or scanning in covers by hand. 6956 If it's too much work, there's little point in having it. 6957** TODO Add tool support for lyrics 6958** TODO Add unit testing to tools 6959* TODO Convert format reference to HTML 6960 Not only would it be more accessible, 6961 but I could better integrate examples and give it basic interactivity. 6962 All of the diagrams and formulas must be kept as vector art 6963 so that they'll remain crisp when scaled. 6964 6965 Unfortunately, Chrome doesn't do MathML and IE doesn't do SVG 6966 which makes it non-viable right now. 6967* TODO Add a dvdaplay utility 6968** TODO Unify trackplay/cdplay/dvdaplay widgets into audiotools.ui 6969** TODO Unify non-Urwid player into audiotools.ui 6970** TODO Add man page 6971* TODO Make internal functions static 6972 Encoders and decoders come with lots of helper functions. 6973 These should be defined statically whenever possible 6974 to avoid colliding with one another. 6975 As a side effect, these function names can now be shortened. 6976 (not applicable to FLAC and Ogg FLAC, which share a lot of functions) 6977** TODO decoders 6978 - [X] src/decoders/alac.c 6979 - [ ] src/decoders/aobpcm.c 6980 - [ ] src/decoders/mlp.c 6981 - [ ] src/decoders/ogg.c 6982 - [ ] src/decoders/shn.c 6983 - [ ] src/decoders/sine.c 6984 - [ ] src/decoders/vorbis.c 6985 - [X] src/decoders/wavpack.c 6986** TODO encoders 6987 - [X] src/encoders/alac.c 6988 - [ ] src/encoders/flac.c 6989 - [ ] src/encoders/shn.c 6990 - [X] src/encoders/wavpack.c 6991* TODO handle AIFF offset/block size in SSND chunk 6992* TODO Assimilate external codecs 6993 More of a long-term plan than anything else. 6994 It would be best to have as few external program 6995 dependencies as possible 6996** TODO Add internal MP3 codec 6997 This is likely the codec people are most interested in 6998 and so it should be folded in so it can be used 6999 without any external dependencies. 7000*** TODO Add C-based MP3 decoder 7001*** TODO Add MP3 decoding reference documentation 7002*** TODO Add C-based MP3 encoder 7003 Unlike lossless codecs where output can be verified automatically, 7004 lossy codecs offer no similar guarantees. 7005 So like libsamplerate, it would be better to import 7006 a known correct implementation like LAME 7007 than to reimplement the wheel. 7008*** TODO Add MP3 encoding reference documentation 7009 A rundown of how LAME operates, in the hope of demystifying 7010 the format. 7011** TODO Add internal MP2 encoder 7012** TODO Add internal Vorbis codec 7013*** TODO Add Vorbis decoder 7014**** TODO Add VorbisDecoder Python object to decoders 7015**** TODO Document Vorbis decoding 7016***** DONE identification header packet 7017***** DONE comment header packet 7018***** TODO setup header packet 7019****** TODO codebooks 7020****** TODO time domain transforms 7021****** TODO floors 7022****** TODO residues 7023****** TODO mappings 7024****** TODO modes 7025***** TODO audio packet decoding 7026****** TODO decode packet type flag 7027****** TODO decode mode number 7028****** TODO decode window shape 7029****** TODO decode floor 7030****** TODO decode residue into residue vectors 7031****** TODO inverse channel coupling of reside vectors 7032****** TODO generate floor curve from decoded floor data 7033****** TODO compute dot product of floor and residue 7034 producing audio spectrum vector 7035****** TODO inverse monolithic transform of audio spectrum vector 7036****** TODO overlap / add left-hand output with right-hand output 7037****** TODO store right-hand data from transform of current frame 7038 for future lapping 7039****** TODO if not first frame, return results of overlap/add as audio 7040**** TODO Add VorbisDecoder to VorbisAudio's to_pcm() method 7041***** DONE handle identification header packet 7042***** DONE skip comment header packet 7043***** TODO handle setup header packet 7044****** TODO codebooks 7045 store result of codebooks decoding somewhere 7046****** TODO time domain transforms 7047 store result of time domain transforms somewhere? 7048****** TODO floors 7049****** TODO residues 7050****** TODO mappings 7051****** TODO modes 7052***** TODO perform data decoding 7053****** TODO decode packet type flag 7054****** TODO decode mode number 7055****** TODO decode window shape 7056****** TODO decode floor 7057****** TODO decode residue into residue vectors 7058****** TODO inverse channel coupling of reside vectors 7059****** TODO generate floor curve from decoded floor data 7060****** TODO compute dot product of floor and residue 7061 producing audio spectrum vector 7062****** TODO inverse monolithic transform of audio spectrum vector 7063****** TODO overlap / add left-hand output with right-hand output 7064****** TODO store right-hand data from transform of current frame 7065 for future lapping 7066****** TODO if not first frame, return results of overlap/add as audio 7067***** TODO return FloatFrameList via read_float() method 7068***** TODO return FrameList via read() method 7069**** TODO Add unit tests for VorbisDecoder 7070*** TODO Add Vorbis encoder 7071** TODO Add internal Opus codec 7072** TODO Add internal Monkey's Audio codec 7073 This needs to be assimilated with a native decoder/encoder. 7074 I've seen these out in the wild, but only rarely. 7075*** TODO Add Python-based Monkey's Audio decoder 7076*** TODO Document Monkey's Audio decoding 7077*** TODO Add C-based Monkey's Audio decoder 7078*** TODO Add Python-based Monkey's Audio encoder 7079*** TODO Document Monkey's Audio encoding 7080*** TODO Add C-based Monkey's Audio encoder 7081*** TODO Add Monkey's Audio-specific unit tests 7082*** TODO Test encoder/decoder against reference 7083*** TODO Restore AudioFile-compatible Python interface 7084* TODO Finish version 3.0 7085** DONE Make compatible with Python 2.7 and 3.X 7086 Like Urwid and PLY, the same code should work on both versions. 7087*** DONE Update setup script 7088*** DONE Update C-based extensions 7089 Use #ifdefs as needed to support both Python versions. 7090 7091 - [X] audiotools.pcm 7092 - [X] audiotools.pcmconverter 7093 - [X] audiotools.replaygain 7094 - [X] audiotools.decoders 7095 - [X] audiotools.encoders 7096 - [X] audiotools.bitstream 7097 - [X] audiotools._ogg 7098 - [X] audiotools._accuraterip 7099 - [X] audiotools.output 7100*** DONE Update Python modules 7101**** DONE audiotools 7102 - [X] __init__ 7103 - [X] accuraterip 7104 - [X] aiff 7105 - [X] ape 7106 - [X] au 7107 - [X] dvda 7108 - [X] flac 7109 - [X] freedb 7110 - [X] id3 7111 - [X] id3v1 7112 - [X] image 7113 - [X] m4a_atoms 7114 - [X] m4a 7115 - [X] mp3 7116 - [X] musicbrainz 7117 - [X] ogg 7118 - [X] opus 7119 - [X] player 7120 - [X] shn 7121 - [X] text 7122 - [X] tta 7123 - [X] ui 7124 - [X] vorbiscomment 7125 - [X] vorbis 7126 - [X] wavpack 7127 - [X] wav 7128**** DONE audiotools.cue 7129 - [X] __init__ 7130 - [X] tokrules 7131 - [X] yaccrules 7132**** DONE audiotools.toc 7133 - [X] __init__ 7134 - [X] tokrules 7135 - [X] yaccrules 7136*** DONE Update utilities 7137 - [X] audiotools-config 7138 - [X] cd2track 7139 - [X] cdinfo 7140 - [X] cdplay 7141 - [X] coverdump 7142 - [X] covertag 7143 - [X] coverview 7144 - [X] dvda2track 7145 - [X] dvdainfo 7146 - [X] track2cd 7147 - [X] track2track 7148 - [X] trackcat 7149 - [X] trackcmp 7150 - [X] trackinfo 7151 - [X] tracklength 7152 - [X] tracklint 7153 - [X] trackplay 7154 - [X] trackrename 7155 - [X] tracksplit 7156 - [X] tracktag 7157 - [X] trackverify 7158*** DONE Update Python-based decoders 7159 - [X] alac 7160 - [X] flac 7161 - [X] shn 7162 - [X] tta 7163 - [X] wavpack 7164*** DONE Update Python-based encoders 7165 - [X] alac 7166 - [X] flac 7167 - [X] shn 7168 - [X] tta 7169 - [X] wavpack 7170*** DONE Update documentation 7171*** DONE Update unit tests 7172 - [X] test 7173 - [X] test_core 7174 - [X] test_formats 7175 - [X] test_metadata 7176 - [X] test_streams 7177 - [X] test_utils 7178**** TODO Update unit test utilities 7179 - [ ] error.py 7180 - [ ] test_cdrdao 7181 - [ ] test_cdrecord 7182*** DONE Ensure unit tests pass 7183**** DONE Python 2.7 7184***** DONE Lib 7185 - [X] core 7186 - [X] cuesheet 7187 - [X] cdio 7188 - [X] freedb 7189 - [X] image 7190 - [X] musicbrainz 7191 - [X] accuraterip 7192 - [X] pcm 7193 - [X] bitstream 7194 - [X] replaygain 7195 - [X] resample 7196 - [X] tocfile 7197 - [X] verify 7198 - [X] ogg 7199***** DONE Format 7200 - [X] audiofile 7201 - [X] lossless 7202 - [X] lossy 7203 - [X] aiff 7204 - [X] alac 7205 - [X] au 7206 - [X] dvda 7207 - [X] flac 7208 - [X] m4a 7209 - [X] mp2 7210 - [X] mp3 7211 - [X] oggflac 7212 - [X] opus 7213 - [X] shorten 7214 - [X] sines 7215 - [X] tta 7216 - [X] vorbis 7217 - [X] wave 7218 - [X] wavpack 7219***** DONE Metadata 7220 - [X] metadata 7221 - [X] flac 7222 - [X] wavpack 7223 - [X] id3v1 7224 - [X] id3v2 7225 - [X] vorbis 7226 - [X] opus 7227 - [X] m4a 7228 - [X] tta 7229***** DONE Util 7230 - [X] audiotools-config 7231 - [X] cd2track 7232 - [ ] cdinfo 7233 - [X] cdplay 7234 - [X] coverdump 7235 - [X] covertag 7236 - [X] coverview 7237 - [X] dvda2track 7238 - [X] dvdainfo 7239 - [X] track2cd 7240 - [X] track2track 7241 - [X] trackcat 7242 - [X] trackcmp 7243 - [X] trackinfo 7244 - [X] tracklength 7245 - [X] tracklint 7246 - [X] trackplay 7247 - [X] trackrename 7248 - [X] tracksplit 7249 - [X] tracktag 7250 - [X] trackverify 7251**** DONE Python 3 7252***** DONE Lib 7253 - [X] core 7254 - [X] cuesheet 7255 - [X] cdio 7256 - [X] freedb 7257 - [X] image 7258 - [X] musicbrainz 7259 - [X] accuraterip 7260 - [X] pcm 7261 - [X] bitstream 7262 - [X] replaygain 7263 - [X] resample 7264 - [X] tocfile 7265 - [X] verify 7266 - [X] ogg 7267***** DONE Format 7268 - [X] audiofile 7269 - [X] lossless 7270 - [X] lossy 7271 - [X] aiff 7272 - [X] alac 7273 - [X] au 7274 - [X] dvda 7275 - [X] flac 7276 - [X] m4a 7277 - [X] mp2 7278 - [X] mp3 7279 - [X] oggflac 7280 - [X] opus 7281 - [X] shorten 7282 - [X] sines 7283 - [X] tta 7284 - [X] vorbis 7285 - [X] wave 7286 - [X] wavpack 7287***** DONE Metadata 7288 - [X] metadata 7289 - [X] flac 7290 - [X] wavpack 7291 - [X] id3v1 7292 - [X] id3v2 7293 - [X] vorbis 7294 - [X] opus 7295 - [X] m4a 7296 - [X] tta 7297***** DONE Util 7298 - [X] audiotools-config 7299 - [X] cd2track 7300 - [X] cdinfo 7301 - [X] cdplay 7302 - [X] coverdump 7303 - [X] covertag 7304 - [X] coverview 7305 - [X] dvda2track 7306 - [X] dvdainfo 7307 - [X] track2cd 7308 - [X] track2track 7309 - [X] trackcat 7310 - [X] trackcmp 7311 - [X] trackinfo 7312 - [X] tracklength 7313 - [X] tracklint 7314 - [X] trackplay 7315 - [X] trackrename 7316 - [X] tracksplit 7317 - [X] tracktag 7318 - [X] trackverify 7319** DONE Add context manager support 7320 Having file-like objects work with "with" context managers 7321 should hopefully make file handle management a bit simpler. 7322*** DONE BitstreamReader 7323 Call .close() on internal stream, 7324 eat any exception (like the "file" object does) and return a False value 7325**** DONE Add documentation 7326**** DONE Add unit tests 7327*** DONE BitstreamWriters 7328 If no exception, call .flush() on internal stream and eat any exception. 7329 Then call .close() on internal stream and eat any exception also. 7330 Returns a False value. 7331**** DONE Add documentation 7332**** DONE Add unit tests 7333*** DONE PCMReaders 7334 Call .close() and eat any exception (like the "file" object does). 7335 - [X] aiff/AIFFReader 7336 - [X] au/AuReader 7337 - [X] audiotools/BufferedPCMReader 7338 - [X] audiotools/CounterPCMReader 7339 - [X] audiotools/LimitedPCMReader 7340 - [X] audiotools/PCMCat 7341 - [X] audiotools/PCMReader 7342 - [X] audiotools/PCMReaderDeHead 7343 - [X] audiotools/PCMReaderError 7344 - [X] audiotools/PCMReaderHead 7345 - [X] audiotools/PCMReaderProgress 7346 - [X] audiotools/ReorderedPCMReader 7347 - [X] decoders/ALACDecoder 7348 - [X] decoders/DVDA_Title 7349 - [X] decoders/FlacDecoder 7350 - [X] decoders/MP3Decoder 7351 - [X] decoders/OggFlacDecoder 7352 - [X] decoders/OpusDecoder 7353 - [X] decoders/SHNDecoder 7354 - [X] decoders/SameSample 7355 - [X] decoders/Sine_Mono 7356 - [X] decoders/Sine_Simple 7357 - [X] decoders/Sine_Stereo 7358 - [X] decoders/TTADecoder 7359 - [X] decoders/VorbisDecoder 7360 - [X] decoders/WavPackDecoder 7361 - [X] player/ThreadedPCMReader 7362 - [X] py_decoders/ALACDecoder 7363 - [X] py_decoders/FlacDecoder 7364 - [X] py_decoders/SHNDecoder 7365 - [X] py_decoders/TTADecoder 7366 - [X] py_decoders/WavPackDecoder 7367 - [X] test/EXACT_RANDOM_PCM_Reader 7368 - [X] test/Join_Reader 7369 - [X] test/MD5_Reader 7370 - [X] test/RANDOM_PCM_Reader 7371 - [X] test/Variable_Reader 7372 - [X] test_formats/CLOSE_PCM_Reader 7373 - [X] test_formats/ERROR_PCM_Reader 7374 - [X] test_streams/FrameListReader 7375 - [X] test_streams/MD5Reader 7376 - [X] test_streams/Raw 7377 - [X] test_streams/Simple_Sine 7378 - [X] test_streams/WastedBPS16 7379 - [X] wav/WaveReader 7380**** DONE Add documentation 7381**** DONE Add unit tests 7382** DONE Update interactive utilities 7383 Ensure they run under Python 2 and 3 7384 - [X] audiotools/ui.py 7385 - [X] audiotools-config 7386 - [X] cd2track 7387 - [X] cdplay 7388 - [X] dvda2track 7389 - [X] track2track 7390 - [X] trackcat 7391 - [X] trackplay 7392 - [X] trackrename 7393 - [X] tracksplit 7394 - [X] tracktag 7395** TODO Improve test coverage 7396 - [X] set_metadata(None) to all formats 7397*** TODO Check repr on everything 7398 Verifying the contents isn't important; 7399 just make sure calling repr() doesn't throw an exception. 7400*** TODO audiotools/__init__ 7401 - [X] output_text 7402 - [X] output_list 7403 - [X] output_table 7404 - [ ] threaded_transfer_framelist_data 7405 - [ ] pcm_cmp 7406 - [ ] pcm_frame_cmp 7407 - [ ] resampled_frame_count 7408 - [ ] read_sheet (IOError) 7409 - [X] iter_first 7410 - [X] iter_last 7411 - [X] most_numerous (len(item_list) == 0) 7412 - [X] most_numerous (all_differ) 7413 - [ ] cddareader_metadata_lookup 7414 - [ ] track_metadata_lookup 7415 - [ ] sheet_metadata_lookup 7416 - [ ] accuraterip_lookup (len(sorted_tracks) == 0) 7417**** TODO MetaData 7418 - [ ] __delattr__ 7419 - [ ] empty_fields 7420 - [ ] __unicode__ 7421 - [ ] delete_image 7422 - [ ] clean 7423**** TODO AudioFile 7424 - [ ] rich compare operators 7425**** DONE Sheet 7426 - [X] converted 7427 - [X] __eq__ 7428 - [X] track_numbers 7429 - [X] track (KeyError) 7430 - [X] pre_gap 7431 - [X] track_offset 7432 - [X] track_length 7433**** DONE SheetTrack 7434 - [X] converted 7435 - [X] indexes 7436 - [X] index (KeyError) 7437 - [X] __eq__ 7438**** DONE SheetIndex 7439 - [X] converted 7440 - [X] __eq__ 7441**** TODO PCMReaderHead 7442 - [ ] check for negative pcm_frames 7443**** TODO PCMReaderDeHead 7444 - [ ] truncation longer than entire stream 7445 - [ ] read_closed 7446**** DONE ExecProgressQueue 7447*** DONE audiotools/accuraterip 7448 - [X] match_offset 7449*** TODO audiotools/aiff 7450**** TODO AiffAudio 7451 - [ ] verify 7452 - [ ] clean (with metadata) 7453*** TODO audiotools/ape 7454**** TODO ApeTag 7455 - [ ] get 7456 - [ ] index 7457**** DONE ApeTaggedAudio 7458 - [X] set_metadata(None) 7459 - [X] set_metadata with cuesheet 7460 - [X] delete_metadata with ReplayGain 7461 - [X] delete_metadata with cuesheet 7462*** TODO audiotools/cue 7463 - [ ] read_cuesheet_string (with ValueError) 7464**** DONE Track 7465 - [X] filename 7466 - [X] pre_emphasis 7467 - [X] copy_permitted 7468**** TODO audiotools/cue/tokrules 7469 - [ ] with illegal character 7470**** TODO audiotools/cue/yaccrules 7471 - [X] with flags 7472 - [ ] with syntax error 7473*** TODO audiotools/flac 7474**** DONE FlacMetaData 7475 - [X] converted(None) 7476 - [X] clean (multiple STREAMINFO) 7477 - [X] clean (multiple VORBIS_COMMENT) 7478 - [X] clean (multiple SEEKTABLE) 7479 - [X] clean (multiple CUESHEET) 7480 - [X] raw_info() 7481 check with all metadata blocks 7482**** DONE Flac_VORBISCOMMENT 7483 - [X] converted(Flac_VORBISCOMMENT) 7484 should return newly created object 7485**** TODO Flac_Cuesheet 7486 - [ ] track_length 7487 - [ ] get_metadata with catalog 7488 - [ ] converted with padding 7489**** TODO Flac_Cuesheet_track 7490 - [ ] filename 7491**** TODO Flac_PICTURE 7492 - [ ] setattr(type, ???) 7493 - [ ] type_string 7494**** TODO FlacAudio 7495 - [X] set_metadata(None) 7496 - [ ] set_metadata with channel mask in old comment 7497 - [X] get_cuesheet() -> None 7498 - [ ] from_pcm with UnsupportedChannelMask 7499 - [ ] has_foreign_wave_chunks() -> False 7500 - [ ] wave_header_footer() without chunks 7501 - [ ] has_foreign_aiff_chunks() -> False 7502 - [ ] aiff_header_footer() without chunks 7503 - [ ] convert() to WaveContainer 7504 - [ ] convert() to AiffContainer 7505 - [ ] delete_replay_gain() without VORBIS_COMMENT 7506 - [ ] clean on < 128 byte file 7507**** DONE FLAC_Data_Chunk 7508 is this still in use? 7509**** DONE FLAC_SSND_Chunk 7510 is this still in use? 7511**** DONE OggFlacMetaData 7512 - [X] converted(None) 7513**** TODO OggFlacAudio 7514 - [ ] from_pcm with UnsupportedChannelMask 7515*** TODO audiotools/freedb 7516 - [ ] xmcd_metadata without album artist 7517 - [ ] xmcd_metadata without track artist 7518*** TODO audiotools/id3 7519 - [ ] read_id3v2_comment (invalid header) 7520 - [ ] read_id3v2_comment (unsupported version) 7521 - [ ] skip_id3v2_comment (unsupported version) 7522 - [ ] skip_id3v2_comment (IOError) 7523 - [ ] total_id3v2_comments (unsupported version) 7524 - [ ] total_id3v2_comments (IOError) 7525**** TODO ID3v22Comment 7526 - [X] raw_info 7527 - [ ] parse 7528 - [ ] build 7529 - [ ] size 7530 - [ ] clean 7531**** TODO ID3v22_T__Frame 7532 - [ ] number() -> 0, no total 7533 - [ ] number() -> not numerical type 7534 - [ ] total() -> not numerical type 7535**** TODO ID3v22_TXX_Frame 7536**** TODO ID3v22_W__Frame 7537**** TODO ID3v22_WXX_Frame 7538**** TODO ID3v22_COM_Frame 7539 - [ ] clean 7540**** TODO ID3v22_PIC_Frame 7541 - [ ] invalid image from data 7542 - [ ] type_string 7543 - [ ] getattr -> AttributeError 7544 - [ ] setattr(type, ???) 7545 - [ ] setattr(desription, ???) 7546 - [ ] clean 7547**** TODO ID3v22Comment 7548 - [ ] copy 7549 - [ ] parse (invalid header) 7550 - [ ] parse (invalid major version) 7551 - [ ] parse (invalid minor version) 7552 - [ ] parse (TXX, WXX, W??) 7553 - [ ] delitem 7554 - [ ] items 7555 - [ ] getattr -> AttributeError 7556 - [ ] delattr(track/alum_number) unslashed 7557 - [ ] delattr unsupported field 7558 - [X] converted(None) 7559**** TODO ID3v23_TXXX_Frame 7560**** TODO ID3v23_WXXX_Frame 7561**** TODO ID3v23_APIC_Frame 7562 - [ ] __init__ invalid image 7563 - [ ] getattr -> AttributeError 7564 - [ ] setattr(pic_type) 7565 - [ ] setattr(description) 7566 - [ ] setattr(mime_type) 7567 - [ ] clean 7568**** TODO ID3v23Comment 7569 - [ ] parse invalid ID3 header 7570 - [ ] invalid major version 7571 - [ ] invalid minor version 7572 - [ ] parse (WXXX, W???) 7573**** TODO ID3v24_TXXX_Frame 7574 - [ ] __unicode__ 7575 - [ ] parse 7576**** TODO ID3v24_APIC_Frame 7577 - [ ] setattr(type) 7578 - [ ] setattr(description) 7579 - [ ] setattr(mime_type) 7580 - [ ] clean 7581**** TODO ID3v24_WXXX_Frame 7582 - [ ] parse 7583**** TODO ID3v24_COMM_Frame 7584 - [ ] clean 7585**** TODO ID3v24Comment 7586 - [ ] parse (invalid ID3 header) 7587 - [ ] parse (invalid major version) 7588 - [ ] parse (invalid minor version) 7589 - [ ] parse (TXXX, WXXX, W???) 7590**** TODO ID3CommentPair 7591 - [ ] init id3v1 is not None 7592 - [X] converted(None) 7593 - [ ] convert(ID3v2Comment) 7594 - [X] raw_info 7595 - [ ] images (id3v2 is None) 7596 - [ ] clean 7597*** TODO audiotools/id3v1 7598**** TODO ID3v1Comment 7599 - [ ] getattr -> AttributeError 7600 - [ ] setattr(non field) 7601 - [ ] delattr(non field) 7602 - [X] converted(None) 7603 - [ ] images 7604***** TODO parse 7605 - [ ] track_name length != 30 7606 - [ ] artist_name length != 30 7607 - [ ] album_name length != 30 7608 - [ ] year length != 4 7609 - [ ] comment length != 28 7610 - [ ] track_number length != 1 7611 - [ ] genre length != 1 7612*** TODO audiotools/image 7613 - [ ] rename classes without __s 7614 - [ ] image_metrics -> InvalidImage 7615**** TODO __JPEG__ 7616 - [ ] parse -> IOError 7617**** TODO __PNG__ 7618 - [ ] parse -> InvalidPNG 7619 - [ ] parse -> IOError 7620 - [ ] parse -> grayscale 7621 - [ ] parse -> invalid PLTE 7622 - [ ] parse -> grayscale + alpha 7623**** TODO __BMP__ 7624 - [ ] parse -> IOError 7625 - [ ] parse -> InvalidBMP 7626**** TODO __GIF__ 7627 - [ ] parse -> IOError 7628 - [ ] parse -> InvalidGIF 7629**** TODO __TIFF__ 7630 - [ ] parse big-endian TIFF 7631 - [ ] parse invalid magic number 7632*** TODO audiotools/m4a 7633 - [ ] get_m4a_atom -> KeyError 7634 - [ ] get_m4a_atom_offset -> KeyError 7635 - [ ] get_m4a_atom_offset -> IOError/KeyError 7636 - [ ] has_m4a_atom (if (length - 8) <= 0) 7637 - [ ] has_m4a_atom -> IOError 7638**** TODO M4ATaggedAduio 7639 - [ ] get_metadata -> KeyError if no meta 7640 - [ ] update_metadata (generate moov) 7641 - [ ] update_metadata (generate udta) 7642 - [ ] update_metadata (generate meta) 7643 - [X] set_metadata(None) 7644*** TODO audiotools/m4a_atoms 7645**** TODO M4A_Tree_Atom 7646 - [ ] has_child -> False 7647 - [ ] remove_child 7648 - [ ] child_offset -> KeyError 7649**** TODO M4A_META_Atom 7650 - [ ] getattr -> AttributeError 7651 - [ ] setattr -> replace_data_atom 7652 - [ ] delattr -> AttributeError 7653 - [X] converted(None) 7654*** TODO audiotools/mp3 7655**** TODO MP3Audio 7656 - [X] set_metadata(None) 7657 - [ ] update_metadata (id3v2 not None, id3v1 is None) 7658 - [ ] update_metadata (id3v2 None, id3v1 not None) 7659 - [ ] update_metadata (id3v2 None, id3v1 None) 7660 - [ ] clean (output_filename None, metadata None) 7661 - [ ] clean (output_filename not None, metadata None) 7662**** TODO MP2Audio 7663 - [ ] from_pcm (nonstandard sample rate) 7664*** TODO audiotools/opus 7665**** DONE OpusAudio 7666 - [X] init (invalid Ogg magic number) 7667 - [X] init (invalid Ogg version) 7668 - [X] init (invalid Opus type) 7669 - [X] init (invalid Opus version) 7670 - [X] init (invalid Opus channels) 7671 - [X] get_replay_gain 7672 - [X] set_replay_gain 7673 - [X] delete_replay_gain 7674*** TODO audiotools/shn 7675**** TODO ShortenAudio 7676 - [ ] __init__ -> IOError 7677 - [ ] has_foreign_wave_chunks -> True 7678 - [ ] has_foreign_wave_chunks -> odd-sized wave chunks 7679 - [ ] has_foreign_wave_chunks -> no foreign chunks found 7680 - [ ] has_foreign_aiff_chunks -> True 7681 - [ ] has_foreign_aiff_chunks -> odd-sized aiff chunks 7682 - [ ] has_foreign_aiff_chunks -> no foreign chunks found 7683 - [ ] from_pcm using external function 7684 - [ ] from_pcm (len(footer) == 0) 7685 - [ ] convert to wave container 7686 - [ ] convert to aiff container 7687*** TODO audiotools/toc 7688 - [ ] read_tocfile -> IOError 7689 - [ ] read_tocfile_string -> SheetException 7690 - [ ] write_tocfile 7691**** TODO TOCFile 7692 - [ ] get_metadata (catalog not None, cd_text not None) 7693**** TODO TOCTrack 7694 - [ ] get_metadata (isrc not None, cd_text not None) 7695 - [X] filename 7696 - [X] pre_emphasis 7697 - [X] copy_permitted (not False) 7698**** TODO audiotools/toc/tokrules 7699 - [ ] illegal character 7700**** TODO audiotools/toc/yaccrules 7701 - [ ] syntax error 7702*** TODO audiotools/tta 7703**** TODO TrueAudio 7704 - [ ] init -> invalid signature 7705 - [ ] init -> invalid format 7706 - [ ] from_pcm -> IOError to EncodingError 7707 - [ ] from_pcm -> frame count mismatch 7708 - [X] set_metadata(None) 7709 - [X] cuesheet in old metadata 7710 - [X] cuesheet in new metadata 7711 - [ ] get_cuesheet -> CueException 7712 - [X] set_cuesheet(None) 7713 - [ ] clean when metadata is None 7714*** TODO audiotools/vorbis 7715**** TODO VorbisAudio 7716 - [X] init -> invalid Ogg magic number 7717 - [X] init -> invalid Ogg version 7718 - [X] init -> invalid Vorbis type 7719 - [X] init -> invalid Vorbis header 7720 - [X] init -> invalid Vorbis version 7721 - [X] init -> invalid Vorbis framing bit 7722**** TODO VorbisChannelMask 7723 - [ ] channels 7724*** TODO audiotools/vorbiscomment 7725**** TODO VorbisComment 7726 - [ ] values 7727 - [ ] __contains__ 7728 - [ ] getattr(non-MetaData attrib) 7729 - [ ] delattr(non-MetaData attrib) 7730 - [X] converted(None) 7731 - [ ] converted(FlacMetaData without VORBISCOMMENT) 7732 - [ ] clean(track_total/album_total with leading 0s) 7733*** TODO audiotools/wav 7734 - [X] wave_header -> total size too large 7735**** TODO RIFF_Chunk 7736 - [ ] handle odd sized chunks 7737**** TODO WaveReader 7738 - [ ] init -> file too small 7739 - [ ] init -> invalid RIFF 7740 - [ ] init -> invalid WAVE 7741 - [ ] init -> chunk header too small 7742 - [ ] init -> invalid chunk ID 7743 - [ ] init -> data chunk before fmt chunk 7744 - [ ] init -> no audio chunks 7745 - [ ] init -> no data chunk 7746 - [ ] read -> data chunk too small 7747**** TODO WaveAudio 7748 - [X] from_pcm -> total_pcm_frames too large 7749 - [X] from_pcm -> total_pcm_frames mismatch 7750 - [ ] track_name(format=None) 7751 - [ ] verify -> not enough data chunk 7752 - [ ] clean -> non audio chunk 7753*** TODO audiotools/wavpack 7754**** TODO WavPackAudio 7755 - [ ] blocks -> blocks_iter -> non wvpk block header 7756 - [ ] __read_info__ -> non wvpk block ID 7757 - [ ] __read_info__ -> nonstandard sample rate 7758 - [ ] __read_info__ -> no channel info sub block 7759 - [X] from_pcm -> total_pcm_frames mismatch 7760 - [ ] fmt_chunk 7761 - [ ] get_cuesheet -> CueException 7762 - [X] set_cuesheet(None) 7763*** TODO audiotools/py_decoders/flac 7764**** TODO FlacDecoder 7765 - [ ] init -> invalid FLAC file 7766 - [ ] read -> MD5 checksum mismatch 7767 - [ ] read -> invalid channel assignment 7768 - [ ] read -> CRC16 mismatch 7769 - [ ] read_frame_header -> invalid sync code 7770 - [ ] read_frame_header -> invalid sample rate 7771 - [ ] read_frame_header -> invalid bits-per-sample 7772 - [ ] read_frame_header -> CRC8 mismatch 7773 - [ ] read_subframe_header -> invalid subframe type 7774 - [ ] read_fixed_subframe -> invalid order 7775 - [ ] read_residual_partition(coding 0) -> escape code 7776 - [ ] read_residual_partition(coding 1) -> escape code 7777 - [ ] close 7778*** TODO audiotools/py_decoders/shn 7779**** TODO SHNDecoder 7780 - [ ] init -> unsupported file type 7781 - [ ] init -> non-audio RIFF chunks 7782 - [ ] init -> AIFF chunks 7783 - [ ] read_header -> invalid magic number 7784 - [ ] read_header -> unsupported version 7785 - [ ] read -> QLPC options 7786*** TODO audiotools/py_decoders/tta 7787**** TODO TTADecoder 7788 - [ ] init -> CRC mismatch in header 7789 - [ ] init -> CRC mismatch in seektable 7790 - [ ] init -> CRC mismatch in frame 7791 - [ ] close 7792*** TODO audiotools/py_decoders/wavpack 7793**** TODO WavPackDecoder 7794 - [ ] init -> nonstandard sample rate 7795 - [ ] read -> MD5 mismatch at end of stream 7796 - [ ] read -> IOError/ValueError 7797 - [ ] close 7798**** TODO Block_Header 7799 - [ ] invalid block ID 7800**** TODO Sub_Block 7801 - [ ] total_size large 7802**** TODO read_block 7803 - [ ] weights before terms 7804 - [ ] samples before terms 7805 - [ ] invalid samples byte count 7806 - [ ] bitstream before entropy vars 7807 - [ ] decorrelation weights not found 7808 - [ ] decorrelation samples not found 7809 - [ ] bitstream not found 7810 - [ ] CRC mismatch 7811**** TODO read_decorrelation_terms 7812 - [ ] invalid passes count 7813 - [ ] invalid term 7814**** TODO read_decorrelation_weights 7815 - [ ] invalid weight count 7816**** TODO read_decorrelation_samples 7817 - [ ] sub_block_size < 8, two channels 7818 - [ ] sub_block_size < 8, one channel 7819 - [ ] invalid term 7820*** TODO audiotools/py_encoders/alac 7821 - [ ] encode_frame -> residual overflow 7822 - [ ] tukey_window -> n > window2 7823 - [ ] encode_residuals -> residual overflow 7824*** TODO audiotools/py_encoders/flac 7825 - [ ] write_utf8 (value > 127) 7826 - [ ] tukey_window (n > window2) 7827 - [ ] compute_lpc_coefficients (estimate_best_order) 7828 - [ ] estimate_best_order 7829*** TODO audiotools/py_encoders/shn 7830**** TODO encode_shn 7831 - [X] all zeroes 7832 - [ ] write footer 7833*** TODO audiotools/py_encoders/wavpack 7834**** TODO encode_wavpack 7835 - [ ] write wave footer 7836**** TODO write_block 7837 - [ ] all samples are 0 7838** DONE Calculate ReplayGain at rip-time 7839 For utilities that operated single-threaded, 7840 calculate ReplayGain during operation rather 7841 than put off until ripping is done. 7842*** DONE cd2track 7843*** DONE dvda2track 7844** TODO Improve utility test coverage 7845*** TODO Add some basic tests to ensure they still works 7846 - [ ] cdinfo 7847 - [ ] cdplay 7848 - [ ] trackplay 7849 - [ ] trackverify 7850** DONE Re-add DVD-A support using libdvdaudio 7851 Supporting DVD-A in an external library should provide a useful decoupling. 7852*** DONE Add audiotools.dvda module 7853 This contains thin wrappers around libdvdaudio structures and functions. 7854**** DONE Add DVDA object 7855**** DONE Add Titleset object 7856**** DONE Add Title object 7857**** DONE Add Track object 7858**** DONE Add TrackReader object 7859**** DONE Add documentation 7860*** DONE Re-add dvda2track script 7861**** DONE Re-add dvda2track.1 man page 7862*** DONE Re-add dvdainfo script 7863**** DONE Re-add dvdainfo.1 man page 7864*** DONE Update setup script 7865 Probe for libdvdaudio and add module and scripts if present, 7866 analagous to libcdio. 7867* TODO Finish version 3.1 7868** TODO Cleanup chunk-based interface (again) 7869 There needs to be a single-pass approach to encoding chunked files 7870 that doesn't involve pulling out the chunk data ahead of time. 7871 7872 Perhaps some sort of chunk iterator which indicates the appropriate 7873 place where the PCM data will go. 7874** TODO Make AudioFile.available() classmethod finer-grained 7875 That is, formats can be readable but not writable, or taggable but 7876 not readable or writeable. This will allow read-only support for 7877 some obscure formats like .tak or .ape by porting implementations 7878 from ffmpeg but without having to build encoders for them as well. 7879*** TODO Add AudioFile.supports_to_pcm() 7880 - [ ] AudioFile 7881 - [ ] ALACAudio 7882 - [ ] AiffAudio 7883 - [ ] AuAudio 7884 - [ ] FlacAudio 7885 - [ ] M4AAudio 7886 - [ ] MP2Audio 7887 - [ ] MP3Audio 7888 - [ ] OggFlacAudio 7889 - [ ] OpusAudio 7890 - [ ] ShortenAudio 7891 - [ ] TrueAudio 7892 - [ ] VorbisAudio 7893 - [ ] WavPackAudio 7894 - [ ] WaveAudio 7895*** TODO Add AudioFile.supports_from_pcm() 7896 - [ ] AudioFile 7897 - [ ] ALACAudio 7898 - [ ] AiffAudio 7899 - [ ] AuAudio 7900 - [ ] FlacAudio 7901 - [ ] M4AAudio 7902 - [ ] MP2Audio 7903 - [ ] MP3Audio 7904 - [ ] OggFlacAudio 7905 - [ ] OpusAudio 7906 - [ ] ShortenAudio 7907 - [ ] TrueAudio 7908 - [ ] VorbisAudio 7909 - [ ] WavPackAudio 7910 - [ ] WaveAudio 7911*** TODO Add AudioFile.supports_verify() 7912 in most instances, this should be the same as supports_to_pcm() 7913 - [ ] AudioFile 7914 - [ ] ALACAudio 7915 - [ ] AiffAudio 7916 - [ ] AuAudio 7917 - [ ] FlacAudio 7918 - [ ] M4AAudio 7919 - [ ] MP2Audio 7920 - [ ] MP3Audio 7921 - [ ] OggFlacAudio 7922 - [ ] OpusAudio 7923 - [ ] ShortenAudio 7924 - [ ] TrueAudio 7925 - [ ] VorbisAudio 7926 - [ ] WavPackAudio 7927 - [ ] WaveAudio 7928*** DONE Add AudioFile.supports_metadata() 7929*** TODO Remove AudioFile.missing_components() ? 7930 Leave this job to setup.py and audiotools-config, perhaps. 7931*** TODO Utilities 7932**** TODO audiotools-config 7933 Needs to display format availability in a more fine-grained fashion. 7934**** TODO cd2track 7935 - [ ] output format must supports_from_pcm() 7936**** TODO track2cd 7937 - [ ] input format must supports_to_pcm() 7938**** TODO track2track 7939 - [ ] input format(s) must supports_to_pcm() 7940 - [ ] output format must supports_from_pcm() 7941**** TODO trackcat 7942 - [ ] input format(s) must supports_to_pcm() 7943 - [ ] output format must supports_from_pcm() 7944**** TODO trackcmp 7945 - [ ] input format(s) must supports_to_pcm() 7946**** TODO trackplay 7947 - [ ] input format(s) must supports_to_pcm() 7948**** TODO tracksplit 7949 - [ ] input format must supports_to_pcm() 7950 - [ ] output format must supports_from_pcm() 7951**** TODO tracktag 7952 - [ ] files must supports_metadata() 7953**** TODO trackverify 7954 - [ ] input format must supports_verify() 7955*** TODO Update documentation 7956*** TODO Update unit tests 7957** TODO Add seeking to Ogg FLAC decoder 7958 Might as well make the format consistent 7959** TODO Support building cue sheets from discs 7960 Find some way of grabbing the index points from a disc 7961 so cuesheets can be populated. 7962** TODO Cleanup AAC support 7963 Although the fdk-aac library doesn't have a compatible license, 7964 there must be *some* way to support AAC without the nasty 7965 hacks in place now. 7966