cue-parser is a parser for audio CUE sheets based on esrap.
You can parse a CUE sheet ether from a character stream using function
parse-cue or a file using parse-cue-file. parse-cue-file uses an
external format stored in *cue-external-format* by default for reading
from files. Each function returns a parsed representation of the file in form
of list. There are some helper functions to get data from that
representation.
For example, if you parse following CUE file:
REM GENRE Gothic
REM DATE 2010
REM DISCID 4807E106
REM COMMENT "ExactAudioCopy v1.0b1"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
TITLE "A Strange Thing To Say"
FILE "Sopor Aeternus & The Ensemble Of Shadows - A Strange Thing To Say.flac" WAVE
TRACK 01 AUDIO
TITLE "A Strange Thing To Say"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 01 00:00:00
TRACK 02 AUDIO
TITLE "Polishing Silver"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 00 09:41:69
INDEX 01 09:43:47
TRACK 03 AUDIO
TITLE "The Urine Song"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 00 14:52:58
INDEX 01 14:55:06
TRACK 04 AUDIO
TITLE "Stains Of You"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 00 19:11:22
INDEX 01 19:13:26
TRACK 05 AUDIO
TITLE "20.000 Leagues Under The Sea"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 00 23:17:62
INDEX 01 23:19:40
TRACK 06 AUDIO
TITLE "Oh, Chimney Sweep"
PERFORMER "Sopor Aeternus & The Ensemble Of Shadows"
INDEX 00 29:57:03
INDEX 01 29:59:14
you will get the following parsed representation:
(((:REM . " GENRE Gothic")(:REM . " DATE 2010")(:REM . " DISCID 4807E106")
(:REM . " COMMENT \"ExactAudioCopy v1.0b1\"")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:TITLE . "A Strange Thing To Say"))
(((:FILE :NAME
"Sopor Aeternus & The Ensemble Of Shadows - A Strange Thing To Say.flac"
:TYPE "WAVE")
(:TRACK :NUMBER 1 :TYPE "AUDIO")(:TITLE . "A Strange Thing To Say")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 1 :MIN 0 :SEC 0))
((:TRACK :NUMBER 2 :TYPE "AUDIO")(:TITLE . "Polishing Silver")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 9 :SEC 41)(:INDEX :NUMBER 1 :MIN 9 :SEC 43))
((:TRACK :NUMBER 3 :TYPE "AUDIO")(:TITLE . "The Urine Song")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 14 :SEC 52)(:INDEX :NUMBER 1 :MIN 14 :SEC 55))
((:TRACK :NUMBER 4 :TYPE "AUDIO")(:TITLE . "Stains Of You")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 19 :SEC 11)(:INDEX :NUMBER 1 :MIN 19 :SEC 13))
((:TRACK :NUMBER 5 :TYPE "AUDIO")(:TITLE . "20.000 Leagues Under The Sea")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 23 :SEC 17)(:INDEX :NUMBER 1 :MIN 23 :SEC 19))
((:TRACK :NUMBER 6 :TYPE "AUDIO")(:TITLE . "Oh, Chimney Sweep")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 29 :SEC 57)(:INDEX :NUMBER 1 :MIN 29 :SEC 59))))
As you probably see, this representation is a list with 2 elements. The first
element contains all CUE commands preceding the first TRACK command, and
the second is a list of tracks. You can get both with first and
second functions, or, which is the same, with get-toplevel and
get-tracks.
If you want, for example, get the name of the album, you can use
get-command-arg function with toplevel block:
(let ((tree (parse-cue-file "album.cue")))
(get-command-arg (get-toplevel tree) :title))
>>> "A Strange Thing To Say"
You can get a track by an index in the block of tracks, for example, (nth 1
(second tree)) returns the second track. You can also use a function called
get-track-by-idx for the same purpose. In the following example the name
of the second track is returned:
(let ((tree (parse-cue-file "album.cue")))
(get-command-arg (get-track-by-idx tree 1) :title))
>>> "Polishing Silver"
If a command argument is a property list, you can use
get-command-named-arg to get what you want. Calling
(get-command-named-arg tree command arg-name) equals to (getf
(get-command-arg tree command) arg-name).
You can get a file name in which the track is stored by calling
get-file-name:
(let ((tree (parse-cue-file "album.cue")))
(get-file-name tree (get-track-by-idx tree 3)))
>>> "Sopor Aeternus & The Ensemble Of Shadows - A Strange Thing To Say.flac"
This is the only way to get a file name. Calling get-command-arg in this
case is incorrect.
If you want to get a time offset in seconds from the beggining of the file
for a particular track, use get-track-index-sec.
Finally, if you want to search for a track by a specific criterion, use
find-track function. This is simply a wrapper around find-if and
requires a predicate to do the search. For example, you can find a track
which name is "The Urine Song" (yep, sounds suspicious, I know ;):
(let ((tree (parse-cue-file "album.cue")))
(find-track tree
(lambda (track)(string= "The Urine Song"
(get-command-arg track :title)))))
>>> ((:TRACK :NUMBER 3 :TYPE "AUDIO")(:TITLE . "The Urine Song")
(:PERFORMER . "Sopor Aeternus & The Ensemble Of Shadows")
(:INDEX :NUMBER 0 :MIN 14 :SEC 52)(:INDEX :NUMBER 1 :MIN 14 :SEC 55))
That's all. If you wish, you can totally ignore these functions and use
find/car/cdr or whatever you wish to get data from parsed file as
its representation is a simple list.