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.6.23 Copyright (C) 2017-2022 Michael Herstine <sp1ff@pobox.com> You are in the Guile REPL; in your shell, type `info scribbu' for documentation. GNU Guile 3.0.9 Copyright (C) 1995-2023 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 expressions & have your them 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!\n")) 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 ownerless
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.
Read all ID3v2 tags from the beginning of
file. Return a list of three-tuples, one for each tag. Each
three tuple consists of an <id3v2-tag>
instance, the ID3v2
version (“3” in this case) and a boolean indicating whether the
unsynchronisation flag is set.
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
Reads the ID3v1 tag, if any, from file.
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.