3.1.1 The Scheme REPL

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.)