At the end of “scribbu rename” (See scribbu rename,) there were a
number of tag hygiene issues to be cleaned up. Let us begin
experimenting with solutions. Invoking scribbu
with no
arguments at all will start the Scheme REPL:
$>: scribbu scribbu 0.5 Copyright (C) 2017-2019 Michael Herstine <sp1ff@pobox.com> You are in the Guile REPL; in your shell, type `info scribbu' for documentation. GNU Guile 2.2.2 Copyright (C) 1995-2017 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)>
You are now at the Scheme prompt (“scheme” refers to the language currently in use and “guile-user” refers to the current module). You can type Scheme statements & have your statements evaluated:
scheme@(guile-user)> (format #t "Hello, world!") Hello, world!$1 = #t scheme@(guile-user)> (define x 1) scheme@(guile-user)> (set! x (+ x 1)) scheme@(guile-user)> x $2 = 2 scheme@(guile-user)> (if (> x 1) (format #t "Yes!")) Yes!$3 = # scheme@(guile-user)>
scribbu
exports assorted types & functions for working with ID3
tags to the Guile interpreter. Let’s take a look at that owner-less
comment frame. We begin by reading in the ID3v2 tagset:
scheme@(guile-user)> (use-modules (oop goops) (scribbu)) scheme@(guile-user)> (define tags (read-tagset "opium.mp3")) scheme@(guile-user)> tags $4 = ((#<<id3v2-tag> 1ccf780> 3 #f))
read-tagset
returns a list of three-tuples, one for each ID3v2
tag present in its argument. Since “opium.mp3” has only one ID3v2
tag, the list has only one element. The triplet consists of an
<id3v2-tag>
instance, the ID3v2 version (“3” in this case)
and a boolean indicating whether the unsynchronisation flag is set (it
is not). Let’s examine the tag:
scheme@(guile-user)> (define tag (caar tags)) scheme@(guile-user)> tag $5 = #<<id3v2-tag> 1ccf780> scheme@(guile-user)> (let ((frames (slot-ref tag 'frames)) (i 0)) (while (> (length frames) 0) (format #t "~d: ~a\n" i (slot-ref (car frames) 'id)) (set! i (+ i 1)) (set! frames (cdr frames)))) 0: encoded-by-frame 1: track-frame 2: comment-frame 3: publisher-frame 4: part-of-a-set-frame 5: year-frame 6: genre-frame 7: album-frame 8: band-frame 9: artist-frame 10: unknown-frame 11: title-frame 12: play-count-frame 13: pop-frame $6 = #f
We see that tag
is an instance of the GOOPS class
<id3v2-tag>
, and that it has 14 frames. Frame two (counting
from zero) is that comment frame:
scheme@(guile-user)> (slot-ref (list-ref (slot-ref tag 'frames) 2) 'dsc) $7 = ""
As expected, the description field is an empty string– let’s fix that:
scheme@(guile-user)> (slot-set! (list-ref (slot-ref tag 'frames) 2) 'dsc "sp1ff@pobox.com") $8 = "sp1ff@pobox.com" # check scheme@(guile-user)> (slot-ref (list-ref (slot-ref tag 'frames) 2) 'dsc) $9 = "sp1ff@pobox.com"
Now what about that ID3v1 genre?
scheme@(guile-user)> (define v1 (read-id3v1-tag "opium.mp3")) scheme@(guile-user)> v1 $10 = #<<id3v1-tag> 18fb8c0> scheme@(guile-user)> (slot-ref v1 'genre) $11 = 255
Let’s set that to “Lounge”– the Winamp genre list sets that to 171:
scheme@(guile-user)> (slot-set! v1 'genre 171) $12 = 171
What remains is writing out our modifications to their respective
tags. We could do this directly in the REPL, but let’s capture
our work in the form of a program (See Writing Scheme Programs with scribbu
.)