Fork of https://github.com/mv2devnul/taglib
|
|
12 年 前 | |
|---|---|---|
| .gitignore | 12 年 前 | |
| LICENSE | 12 年 前 | |
| README.md | 12 年 前 | |
| audio-streams.lisp | 12 年 前 | |
| id3-frame.lisp | 12 年 前 | |
| iso-639-2.lisp | 12 年 前 | |
| logging.lisp | 12 年 前 | |
| mp3-tag.lisp | 12 年 前 | |
| mp4-atom.lisp | 12 年 前 | |
| mp4-tag.lisp | 12 年 前 | |
| mpeg.lisp | 12 年 前 | |
| packages.lisp | 12 年 前 | |
| profile.lisp | 12 年 前 | |
| taglib-tests.asd | 12 年 前 | |
| taglib-tests.lisp | 12 年 前 | |
| taglib.asd | 12 年 前 | |
| utils.lisp | 12 年 前 |
Copyright (c) 2013, Mark VandenBrink. All rights reserved.
A pure Lisp implementation for reading MPEG-4 audio and MPEG-3 audio tags and audio information.
Mostly complete. Your mileage may vary. Most definitely, NOT portable. Heavily dependent on Clozure CCL.
All avalailable via quicklisp
Note: There a lot of good (some great) audio file resources out there. Here are a few of them that I found useful:
Things to consider adding/changing:
(let (foo)
(unwind-protect
(setf foo (parse-mp4-file "01 Keep Yourself Alive.m4a"))
(when foo
(mp4-tag:show-tags foo)
(stream-close foo)))
Yields:
01 Keep Yourself Alive.m4a
sample rate: 44100.0 Hz, # channels: 2, bits-per-sample: 16, max bit-rate: 314 Kbps, avg bit-rate: 256 Kbps, duration: 4:03
album: Queen I
album-artist: Queen
artist: Queen
compilation: no
disk: (1 1)
genre: 80 (Hard Rock)
title: Keep Yourself Alive
track: (1 11)
year: 1973
The show-tags methods also have a "raw" capability. Example:
(let (foo)
(unwind-protect
(setf foo (parse-mp3-file "Queen/At the BBC/06 Great King Rat.mp3"))
(when foo
(mp3-tag:show-tags foo :raw t)
(stream-close foo)))
Yields:
Queen/At the BBC/06 Great King Rat.mp3: MPEG 1, Layer III, VBR, sample rate: 44,100 Hz, bit rate: 128 Kbps, duration: 5:60
Header: version/revision: 3/0, flags: 0x00: 0/0/0/0, size = 11,899 bytes; No extended header; No V21 tag
Frames[9]:
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 0, version = 3, id: TIT2, len: 15, NIL, encoding = 0, info = <Great King Rat>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 25, version = 3, id: TPE1, len: 6, NIL, encoding = 0, info = <Queen>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 41, version = 3, id: TPE2, len: 6, NIL, encoding = 0, info = <Queen>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 57, version = 3, id: TALB, len: 11, NIL, encoding = 0, info = <At the BBC>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 78, version = 3, id: TRCK, len: 4, NIL, encoding = 0, info = <6/8>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 92, version = 3, id: TPOS, len: 4, NIL, encoding = 0, info = <1/1>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 106, version = 3, id: TYER, len: 5, NIL, encoding = 0, info = <1995>
frame-text-info: flags: 0x0000: 0/0/0/0/0/0, offset: 121, version = 3, id: TCON, len: 5, NIL, encoding = 0, info = <(79)>
frame-txxx: flags: 0x0000: 0/0/0/0/0/0, offset: 136, version = 3, id: TXXX, len: 33, NIL, <Tagging time/2013-08-08T16:38:38>
I have a semi-complete logging strategy in place that is primarily used to figure out what happened when I get an unexpected error parsing a file. To see the output of ALL logging statements to STANDARD-OUTPUT, you can do the following:
(with-logging ()
(test2::test2))
To see only the MP4-ATOM related logging stuff and redirect logging to to a file called "foo.txt":
(with-logging ("foo.txt" :categories (categories '(mp4-atom::cat-log-mp4-atom)))
(taglib-tests::test2))
See logging.lisp for more info.
If you really want to create a lot of output, you can do the following:
(with-logging ("log.txt")
(redirect "q.txt" (test2 :dir "somewhere-where-you-have-all-your-audio" :raw t)))
For my 21,000+ files, this generates 218,788,792 lines in "log.txt" and 240,727 lines in "q.txt".
For any class we don't want to parse (eg, haven't gotten around to it yet, etc), we create a RAW-FRAME class that can be subclassed. RAW-FRAME simply reads in the frame header, and then the frame "payload" as raw OCTETS.
As noted in the comments of this file, there are three kinds of "boxes/atoms":
* Pure container atoms: have no data and are only used to contain other atoms. This is akin to a UNIX filesystem's directory notion.
* Pure "data" atoms: has no nested atoms. Only has a payload.
* A mixture of both.
In previous versions of this library, if we ran into a Xing header with the number of frames set to zero, I just set the duration as 0. This was fast, but not really "nice." In new revs, I decided that if I hit a bad Xing header, the correct thing to do is to read every frame and calculate the duration/avg bit-rate that way. The resulting calculations match those of iTunes, but it can really slow things down.
More info later...
I've recently added some (very) rudimentary multi-threading (see taglib-tests.lisp) using the CHANL package. First, the filesystem walker (main thread) walks the requested directory, adding each filename to an unbounded channel (*channel*). The main thread then sends *MAX-THREADS* *END-THREAD* symbols, creates *MAX-THREADS* worker threads who read from the channel, and then sits in a loop reading from *dead-channel* until it has done *MAX-THREADS* recv's.
The worker threads parse the filename they retrieve from *channel* until they get the *END-THREAD* symbol, whereupon they write their thread id to *dead-channel* and return (ie exit). Here are some timings:
| # Threads | Time (seconds) |
|---|---|
| 10 | ~28 |
| 5 | ~18 |
| 2 | ~17 |
| 1 | ~25 |