Programming, philosophy, pedaling.

Muzak, Week 2

Dec 12, 2016

Tags: programming, ruby, muzak

Preword: This is the second weekly post on muzak’s development, following the introductory post and last week’s post. It’s finals (and holiday) season, so there may not be a post next week or the week after.

Just like last week’s post, some quick statistics:

Although the number of commits week-over-week rose substantially, the actual number of line changes dropped dramatically. I attribute this to muzak’s internal API becoming more stable and most of this week’s work being user-facing.

As of today, this is what a typical muzak session (muzakd + muzak-dmenu + muzak-cmd) can look like:

muzak session

(screenkey is being used to display my keybindings)

Big(ger) changes

New user interfaces

Last week, the only way to control a muzak instance was through the muzak command, which provided a pseudo-shell and tab completions for both commands and albums/artists.

This week, I added muzakd, a daemonized version of muzak that reads commands from a named pipe (~/.config/muzak/muzak/muzak.fifo) and passes them on to an instance. I also added two simple scripts for controlling muzakd:

Both of these scripts work very nicely when bound to key sequences. I have the following mapping, locally (i3 config):

bindsym Control+End exec muzak-cmd toggle
bindsym Control+Left exec muzak-cmd previous
bindsym Control+Right exec muzak-cmd next
bindsym Control+Delete exec muzak-dmenu

“Deep” index support

Previously, muzak’s index (~/.config/muzak/index.yml) stored only a representation of the file tree, with no ID3 tagging in the index itself (as explained in the previous post, ID3 tags were stored in playlists and loaded on-demand as required for events).

Now, when deep-index is set to true in muzak’s configuration, a “deep” index will be stored alongside the standard “shallow” representation. This index (really just an extra key-array pair under each album) contains a serialized Muzak::Song instance for each song in the album. The primary benefit of this is significantly faster playlist loading (Muzak::Song.new can be quite slow when called hundreds of times in a row) and generally diminished disk access, which should help when muzak is being used with a nonlocal music tree.

Generic player API

As promised last week, muzak now specifies its expected player API in the form of Muzak::Player::StubPlayer. All implemented players should inherit from this class, which currently contains 15 necessary methods.

More flexible plugin support

Muzak’s plugin API is virtually unchanged from last week. However, plugins can now be loaded from two locations: either the lib/muzak/plugins tree (reserved for plugins shipped with muzak), or ~/.config/muzak/plugins. The latter is for users to add their own custom plugins, and plugins added to it behave identically to plugins added via the reserved tree.

Just remember, plugins are only activated if plugin-<name> is present as a key in the configuration!

Small(er) changes

gem availability

Muzak is now available on rubygems, which means that installing it is as simple as:

$ sudo gem install muzak


$ gem install --user-install muzak # make sure that you've configured your PATH

This will install muzak’s entire library, as well as the muzak, muzakd, muzak-cmd, and muzak-dmenu executables.

Jukebox mode

Previously, muzak only allowed songs to be enqueued from three sources: albums, artists, and playlists. This covers a lot of use-cases, but another common use case is a random shuffle throughout the entire library. This is now accomplished with the jukebox [N], where [N] is an optional number of random songs to enqueue. If not included, jukebox defaults to the value stored in jukebox-size in the configuration.

Isolated configuration

The config-set command has been removed, for a few reasons:

Next Week

Development is definitely going to slow down as I go into my final exams and the winter break, but here are some of my general goals for muzak over that period:

Thanks for reading!

- William