On this page:
4.1 Opening and closing tag handles
id3-tags
call-with-id3-tags
tags-valid?
tags-read-write?
tags-closed?
tags-save!
tags-close!
4.2 Common tag fields
tags-title
tags-album
tags-artist
tags-comment
tags-genre
tags-year
tags-track
tags-title!
tags-album!
tags-artist!
tags-comment!
tags-genre!
tags-year!
tags-track!
4.3 Selected generic fields
tags-composer
tags-album-artist
tags-disc-number
tags-composer!
tags-album-artist!
tags-disc-number!
4.4 Audio properties
tags-length
tags-sample-rate
tags-bit-rate
tags-channels
4.5 Generic properties
tags-keys
tags-ref
tags-set!
tags-set-values!
tags-append!
tags-clear!
4.6 Embedded pictures
tags-picture
tags-picture->kind
tags-picture->mimetype
tags-picture->description
tags-picture->size
tags-picture->ext
tags-picture->bitmap
tags-picture->file
make-tags-picture
make-tags-picture-from-bitmap
tags-picture!
tags-append-picture!
tags-clear-picture!
4.7 Picture values
id3-picture?
id3-picture-mimetype
id3-picture-kind
id3-picture-size
id3-picture-bytes
id3-picture-description
4.8 Converting to a hash
tags->hash
4.9 Copying tags and pictures
4.10 Example
4.11 Implementation notes
9.2.0.5

4 TagLib Metadata🔗ℹ

Hans Dijkema <hans@dijkewijk.nl>

 (require racket-audio/taglib) package: racket-audio

The racket-audio/taglib module provides the high level metadata API used by the audio package. It wraps the lower level TagLib C FFI module and presents a Racket API for common tags, generic properties, audio properties, and embedded cover art.

The module can be used in two modes. The default mode is read-only and returns a snapshot of the metadata. A handle opened with #:mode 'read-write keeps the native TagLib file open and can be modified with the setter procedures documented below. Changes are written to the media file by calling tags-save!.

The name id3-tags is historical. The implementation uses TagLib, so the usable file types are the file types supported by the TagLib library available at run time.

4.1 Opening and closing tag handles🔗ℹ

procedure

(id3-tags file [#:mode mode])  any/c

  file : path-string?
  mode : (or/c 'read 'read-only 'read-write 'write) = 'read
Opens file through TagLib and returns an opaque tag handle. In the default read-only mode, the module copies the values needed on the Racket side, frees the native TagLib objects, and returns a snapshot handle.

In read-write mode, the native TagLib file remains open. Setter procedures may then be used to modify fields, properties, and pictures. Call tags-save! to write changes and tags-close! to close the native handle.

On Windows, the implementation retries with the wide-character TagLib open function when the normal open function does not produce a valid TagLib file.

procedure

(call-with-id3-tags file proc [#:mode mode])  any/c

  file : path-string?
  proc : procedure?
  mode : (or/c 'read 'read-only 'read-write 'write) = 'read
Opens file, calls proc with the tag handle, and closes the handle afterwards with tags-close!. This is most useful for read-write code because it avoids leaking the native TagLib file handle.

procedure

(tags-valid? tags)  boolean?

  tags : any/c

procedure

(tags-read-write? tags)  boolean?

  tags : any/c

procedure

(tags-closed? tags)  boolean?

  tags : any/c
Return handle state. tags-valid? reports whether TagLib opened the file successfully. tags-read-write? reports whether the handle was opened in read-write mode. tags-closed? reports whether the native TagLib file handle has been closed.

procedure

(tags-save! tags)  boolean?

  tags : any/c

procedure

(tags-close! tags)  void?

  tags : any/c
tags-save! writes pending changes for a read-write handle to the media file. tags-close! closes the native TagLib file handle. Closing a read-only snapshot is harmless.

(call-with-id3-tags "track.flac"
  (lambda (tags)
    (when (tags-valid? tags)
      (tags-title! tags "New title")
      (tags-save! tags)))
  #:mode 'read-write)

4.2 Common tag fields🔗ℹ

procedure

(tags-title tags)  string?

  tags : any/c

procedure

(tags-album tags)  string?

  tags : any/c

procedure

(tags-artist tags)  string?

  tags : any/c

procedure

(tags-comment tags)  string?

  tags : any/c

procedure

(tags-genre tags)  string?

  tags : any/c
Return the common textual fields from the TagLib tag interface. Missing fields are returned as the empty string.

procedure

(tags-year tags)  integer?

  tags : any/c

procedure

(tags-track tags)  integer?

  tags : any/c
Return the year and track number from the common TagLib tag interface. Missing numeric values are returned as -1.

procedure

(tags-title! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-album! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-artist! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-comment! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-genre! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)
Set common textual fields on a read-write handle. Passing 'clear clears the field. Call tags-save! to persist the change.

procedure

(tags-year! tags value)  void?

  tags : any/c
  value : (or/c exact-nonnegative-integer? 'clear)

procedure

(tags-track! tags value)  void?

  tags : any/c
  value : (or/c exact-nonnegative-integer? 'clear)
Set numeric common fields on a read-write handle. Passing 'clear writes zero through the TagLib C API and updates the Racket-side cache to -1.

4.3 Selected generic fields🔗ℹ

procedure

(tags-composer tags)  (or/c string? (listof string?))

  tags : any/c

procedure

(tags-album-artist tags)  (or/c string? (listof string?))

  tags : any/c

procedure

(tags-disc-number tags)  (or/c number? #f)

  tags : any/c
Return selected values from the generic TagLib property store. The composer is read from the 'composer key, the album artist from 'albumartist, and the disc number from 'discnumber. Use tags-keys and tags-ref for direct access to the complete generic property store.

procedure

(tags-composer! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-album-artist! tags value)  void?

  tags : any/c
  value : (or/c string? 'clear)

procedure

(tags-disc-number! tags value)  void?

  tags : any/c
  value : (or/c exact-nonnegative-integer? string? 'clear)
Set selected generic properties on a read-write handle. The disc number may be provided as a number or as the exact string that should be written.

4.4 Audio properties🔗ℹ

procedure

(tags-length tags)  integer?

  tags : any/c

procedure

(tags-sample-rate tags)  integer?

  tags : any/c

procedure

(tags-bit-rate tags)  integer?

  tags : any/c

procedure

(tags-channels tags)  integer?

  tags : any/c
Return audio properties reported by TagLib: length in seconds, sample rate in Hz, bit rate in kbit/s, and number of channels. These values are read-only properties of the media stream, not editable tags. Missing values are returned as -1.

4.5 Generic properties🔗ℹ

procedure

(tags-keys tags)  (listof symbol?)

  tags : any/c
Returns the generic TagLib property keys found in the file. Keys are lower-cased and converted to symbols.

procedure

(tags-ref tags key)  (or/c (listof string?) #f)

  tags : any/c
  key : symbol?
Returns the list of values associated with key, or #f when the property was not found. Use lower-case symbol keys, matching the values returned by tags-keys.

procedure

(tags-set! tags key value)  void?

  tags : any/c
  key : (or/c symbol? string?)
  value : (or/c string? 'clear)
Sets a generic property on a read-write handle. Symbol keys are converted to upper-case TagLib property names; string keys are passed as supplied. Passing 'clear clears the property.

procedure

(tags-set-values! tags key values)  void?

  tags : any/c
  key : (or/c symbol? string?)
  values : (or/c (listof string?) 'clear)
Replaces a generic property with zero or more values. Passing 'clear removes the property.

procedure

(tags-append! tags key value)  void?

  tags : any/c
  key : (or/c symbol? string?)
  value : string?
Appends a value to a generic property on a read-write handle.

procedure

(tags-clear! tags key)  void?

  tags : any/c
  key : (or/c symbol? string?)
Clears a generic property on a read-write handle.

(call-with-id3-tags "track.flac"
  (lambda (tags)
    (tags-set-values! tags 'composer '("Johann Sebastian Bach"))
    (tags-set! tags 'discnumber "1")
    (tags-save! tags))
  #:mode 'read-write)

Generic properties may contain multiple values for a single key. The API keeps those values as lists instead of joining them into one string.

4.6 Embedded pictures🔗ℹ

The module represents embedded artwork as an opaque picture value. The picture value is returned by tags-picture and can be inspected with the picture procedures documented below. It can also be written to another file with tags-picture! or tags-append-picture!.

procedure

(tags-picture tags)  (or/c any/c #f)

  tags : any/c
Returns the embedded picture value, or #f when the file has no picture that the underlying FFI layer could read.

procedure

(tags-picture->kind tags)  (or/c integer? #f)

  tags : any/c

procedure

(tags-picture->mimetype tags)  (or/c string? #f)

  tags : any/c

procedure

(tags-picture->description tags)  (or/c string? #f)

  tags : any/c

procedure

(tags-picture->size tags)  (or/c integer? #f)

  tags : any/c

procedure

(tags-picture->ext tags)  (or/c symbol? #f)

  tags : any/c
Return selected information about the embedded picture. The kind is the numeric picture type reported by the FFI layer. The MIME type is the stored MIME type, such as "image/jpeg" or "image/png". The size is the number of bytes in the embedded image. The extension helper returns 'jpg, 'png, or #f when the MIME type is not recognized.

procedure

(tags-picture->bitmap tags)  (or/c (is-a?/c bitmap%) #f)

  tags : any/c
Reads the embedded picture bytes with read-bitmap and returns a bitmap% object. If there is no embedded picture, the result is #f.

procedure

(tags-picture->file tags path)  boolean?

  tags : any/c
  path : path-string?
Writes the embedded picture bytes to path in binary mode, replacing an existing file. The procedure returns #t when a picture was written and #f when the tag handle has no picture.

procedure

(make-tags-picture mimetype    
  kind    
  data    
  [#:description description])  id3-picture?
  mimetype : string?
  kind : integer?
  data : (or/c bytes? (is-a?/c bitmap%))
  description : string? = ""
Creates a picture value from encoded image bytes or from a bitmap%. The MIME type should normally be "image/jpeg" or "image/png".

procedure

(make-tags-picture-from-bitmap bitmap 
  kind 
  [#:mimetype mimetype 
  #:description description]) 
  id3-picture?
  bitmap : (is-a?/c bitmap%)
  kind : integer?
  mimetype : string? = "image/png"
  description : string? = ""
Creates a picture value by encoding bitmap as PNG or JPEG.

procedure

(tags-picture! tags picture)  void?

  tags : any/c
  picture : (or/c id3-picture? 'clear)

procedure

(tags-append-picture! tags picture)  void?

  tags : any/c
  picture : id3-picture?

procedure

(tags-clear-picture! tags)  void?

  tags : any/c
Set, append, or clear embedded artwork on a read-write handle. The procedures use TagLib complex properties underneath. Call tags-save! to persist the change.

(define cover
  (make-tags-picture "image/jpeg" 3 (file->bytes "cover.jpg")
                     #:description "Cover"))
 
(call-with-id3-tags "track.flac"
  (lambda (tags)
    (tags-picture! tags cover)
    (tags-save! tags))
  #:mode 'read-write)

4.7 Picture values🔗ℹ

procedure

(id3-picture? v)  boolean?

  v : any/c

procedure

(id3-picture-mimetype picture)  string?

  picture : id3-picture?

procedure

(id3-picture-kind picture)  integer?

  picture : id3-picture?

procedure

(id3-picture-size picture)  integer?

  picture : id3-picture?

procedure

(id3-picture-bytes picture)  bytes?

  picture : id3-picture?

procedure

(id3-picture-description picture)  string?

  picture : id3-picture?
Access the fields of a picture value. These procedures are useful when the caller wants to process the image bytes directly or pass a picture to another component.

4.8 Converting to a hash🔗ℹ

procedure

(tags->hash tags)  hash?

  tags : any/c
Returns a mutable hash containing the core values copied from the tag handle. The hash contains the keys 'valid?, 'read-write?, 'closed?, 'title, 'album, 'artist, 'comment, 'composer, 'genre, 'year, 'track, 'length, 'sample-rate, 'bit-rate, 'channels, 'picture, and 'keys.

The hash is intended as a convenient snapshot for application code. Generic property values are not expanded into the hash; use tags-ref for those values.

4.9 Copying tags and pictures🔗ℹ

The encoder pipeline uses this module for metadata transfer. For FLAC output, audio-encode first writes the audio stream and then opens the resulting file with id3-tags in read-write mode to copy tags and pictures through TagLib. For Opus output, comments and pictures are supplied to libopusenc before encoding starts, because OpusTags are written at the start of the Ogg Opus stream.

Applications that need explicit metadata editing should use the read-write API directly, as in the examples above.

4.10 Example🔗ℹ

(define tags (id3-tags "track.flac"))
 
(cond
  [(not (tags-valid? tags))
   (printf "No readable tags\n")]
  [else
   (printf "Title:  ~a\n" (tags-title tags))
   (printf "Artist: ~a\n" (tags-artist tags))
   (printf "Album:  ~a\n" (tags-album tags))
   (printf "Length: ~a seconds\n" (tags-length tags))
 
   (when (tags-picture tags)
     (define ext (or (tags-picture->ext tags) 'bin))
     (tags-picture->file tags (format "cover.~a" ext)))])

4.11 Implementation notes🔗ℹ

This chapter documents the public "taglib.rkt" layer. The native TagLib calls are delegated to "taglib-ffi.rkt", but callers normally should not use that lower level module directly.

A read-only tag handle is a Racket-side snapshot. A read-write tag handle keeps the native TagLib file open until tags-close! is called. Setter procedures update both the native file and the Racket-side cache; the changes are persisted only after tags-save! succeeds.

The implementation normalizes generic property names by lower-casing TagLib property keys and converting them to symbols. Values remain lists of strings because TagLib properties may contain multiple values for one key.