Skip to content

Instantly share code, notes, and snippets.

@RobertAudi
Last active September 30, 2023 19:54
Show Gist options
  • Save RobertAudi/6045338 to your computer and use it in GitHub Desktop.
Save RobertAudi/6045338 to your computer and use it in GitHub Desktop.
This is a walkthrough on how to install the MOC command-line music player on OS X. The procedure was tested in Mountain Lion.

MOC on OS X

I waited for years for a Homebrew formula for MOC. I finally found one today, but it didn't work for me. So I decided to try to compile it from source.

Requirements

Here is a list of requirements, taken directly from the MOC README:

  • UNIX system with POSIX threads (e.g., Linux or FreeBSD)
  • ncurses (probably already installed in your system)
  • C and C++ compilers (MOC is written in C, but libtool and some decoder plugins require a C++ compiler)
  • libdb version 4 or later (unless configured with --disable-cache)

To support audio formats you need:

For network streams:

For resampling (playing files with sample rate not supported by your hardware):

For JACK (low-latency audio server):

For librcc (fixes encoding in broken mp3 tags):

So first you need to install Xcode and Homebrew if you don't already have them installed; I'll let you Google on how to do that. You also need to install a dependency that is not listed above: BerkeleyDB. Luckily there is a Homebrew package for it:

% brew install berkeley-db

Edit: The BerkeleyDB dependency is actually listed above, as libdb. Thanks to John Fitzgerald, MOC's Maintainer, for the note.

NOTE: % is my prompt, don't copy it, copy just the brew command!

Then you need to install JACK, because it's the audio server that will be used by MOC:

% brew install jack

Finally you need to install the required library to play MP3s, and other audio formats. All my music is in MP3 so I just had to install two libraries:

% brew install libmad
% brew install libid3tag

Compiling MOC from source

First you need to download MOC from here. I downloaded the Development release (2.5.0-beta1). Next you need to go extract the archive you just downloaded:

% cd ~/Downloads
% tar xvjf moc-2.5.0-beta1.tar.bz2
% cd moc-2.5.0-beta1

Next you need to configure, compile and install MOC:

% ./configure --prefix=/usr/local/Cellar/moc/2.5.0-beta1 --with-jack --enable-debug --without-ffmpeg
% make
% make install

NOTE: I haven't compiled MOC with the --without-ffmpeg option myself, but it should work. If it doesn't, uninstall ffmpeg using brew uninstall ffmpeg. A big Thank you to jcf for the tip!

Configuring MOC

Now that you installed MOC, you need to configure it. The first thing I needed to do, is add the bin directory to my $PATH:

  • If you are using ZSH, add this line to your .zshrc:
path=( /usr/local/Cellar/moc/2.5.0-beta1/bin $path )
  • If you're using Bash, add this line to your .bashrc:
PATH=/usr/local/Cellar/moc/2.5.0-beta1/bin:$PATH

Next, you need to create a directory for MOC, in your home directory:

% mkdir ~/.moc

Let's skip the config file step for a minute and let's create a custom theme. First, create the themes directory:

% mkdir ~/.moc/themes

I use a theme I found on the CrunchBang forums. All you need to do is to create a new file for the theme with the following content:

% vim ~/.moc/themes/rhowaldt_theme
background           = default    default
frame                = default    default
window_title         = default    default
directory            = blue       default
selected_directory   = blue       default    reverse
playlist             = default    default
selected_playlist    = default    default    reverse
file                 = default    default
selected_file        = default    default    reverse
marked_file          = blue       default    bold
marked_selected_file = blue       default    reverse
info                 = default    default
selected_info        = default    default
marked_info          = blue       default    bold
marked_selected_info = blue       default    bold
status               = default    default
title                = blue       default    bold
state                = default    default
current_time         = default    default
time_left            = default    default
total_time           = default    default
time_total_frames    = default    default
sound_parameters     = default    default
legend               = default    default
disabled             = default    default
enabled              = blue       default    bold
empty_mixer_bar      = default    default
filled_mixer_bar     = default    default    reverse
empty_time_bar       = default    default
filled_time_bar      = default    default    reverse
entry                = default    default
entry_title          = default    default
error                = default    default    bold
message              = default    default    bold
plist_time           = default    default

NOTE: I removed the documentation comments from the theme, but you can find the whole theme file here

Now you need a config file. Let's copy the example config file that came with MOC:

% cp /usr/local/Cellar/moc/2.5.0-beta1/share/doc/moc/config.example ~/.moc/config

Next, edit it with the following config:

% vim ~/.moc/config

NOTE: This configuration assumes that you are using iTerm2. Feel free to fiddle with it.

ReadTags = yes
MusicDir = /Users/aziz/Music
StartInMusicDir = yes
SoundDriver = JACK
XTerms = xterm-256color
Theme = rhowaldt_theme
MOCDir = ~/.moc
UseRCC = no

And...you're done configuring MOC!

Running MOC

Before you run MOC, you need to run JACK, otherwise it won't work! You can run it manually using this command:

% jackd -d coreaudio

But that's tedious to do! So let's create a launch agent:

% vim ~/Library/LaunchAgents/org.jackaudio.jackd.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>org.jackaudio.jackd</string>
    <key>WorkingDirectory</key>
    <string>/Users/aziz/</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/Cellar/jack/1.9.7/bin/jackd</string>
      <string>-d</string>
      <string>coreaudio</string>
    </array>
    <key>EnableGlobbing</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
  </dict>
</plist>

And load that launch agent:

% launchctl load ~/Library/LaunchAgents/org.jackaudio.jackd.plist

Now you are finally ready to use MOC!!!

% mocp

To see the list of available commands, type ? once in MOC. The cool thing about this is that you can run MOC in the background: just type q (lowercase not upercast).

One more thing

I found a Gist that I created a while ago. It's a bash script to enable Growl notifications for MOC! I doubt I wrote it myself, but I can't find its origins so I can't really give credit where credit is due; if you wrote this little script, post a comment and I'll update the Gist. Here it is:

#!/bin/bash

while out=$(/usr/local/Cellar/moc/2.5.0-beta1/bin/mocp -i); do

  # Parse mocp output.
  while IFS=: read -r field value; do
    case $field in
      Artist) artist=$value;;
      Album) album=$value;;
      SongTitle) title=$value;;
    esac
  done <<< "$out"

  # Don't do anything if we're still on the same song.
  [[ "$artist-$album-$title" = "$current" ]] && { sleep 1; continue; }

  # Growl notify this information
  if [[ $album && $artist && $title ]]; then
    /usr/local/bin/growlnotify -t "moc: $title" -n "mocp" -m "by $artist"$'\n'"(album: $album)"
  fi

  # Remember the current song.
  current="$artist-$album-$title"

done

Put that anywhere you want, it really doesn't matter. I've put it the bin directory in my Home directory. Make sure you make the script executable with chmod a+x moc-growl.sh. Again, you can run the script manually, but it's tedious, so I created a launch agent:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>me.azizlight.mocgrowl</string>
    <key>WorkingDirectory</key>
    <string>/Users/aziz/</string>
    <key>ProgramArguments</key>
    <array>
      <string>/bin/sh</string>
      <string>/Users/aziz/bin/moc-growl.sh</string>
    </array>
    <key>EnableGlobbing</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
  </dict>
</plist>

And don't forget to load the launch agent:

% launchctl load ~/Library/LaunchAgents/me.azizlight.mocgrowl.plist

The cherry on the cake

Yes there is YET ONE MORE THING! I managed to map the function keys F7, F8 and F9 to moc actions using applescript! Here is how to do it:

  • Open Automator
  • Create a new Service
  • Choose "Run AppleScript" from the list of actions
  • Insert the script below in the mini AppleScript editor
  • Save
  • Go in the Keyboard Shortcuts System Preferences
  • Locate your new service
  • Assign it a shortcut

I chose those function keys because they match the media keys. Do this for every script show below (three times in total):

-- This is the script to Play/Pause
do shell script "/usr/local/Cellar/moc/2.5.0-beta1/bin/mocp -G"
-- This is the script to go to the Next Song
do shell script "/usr/local/Cellar/moc/2.5.0-beta1/bin/mocp -f"
-- This is the script to go to the Previous Song
do shell script "/usr/local/Cellar/moc/2.5.0-beta1/bin/mocp -r"

Alfred Workflow

I also created an Alfred Workflow to show the current playing song and triggering the play/pause/next/previous functionality. The Workflow can be downloaded here. Once downloaded, just double-click on the file and it should install it.

Voila! A full headless command-line alternative to iTunes!

Enjoy!

@hankchanocd
Copy link

Just a quick shoutout: If you are downloading MOC directly from Homebrew, the version of Jack that comes with it is 0.125.0_2 (as of 4 Feb, 2018). Don't forget to reflect this change in the xml file for running Jack, as in
<string>/usr/local/Cellar/jack/1.9.7/bin/jackd</string>
should be replaced with
<string>/usr/local/Cellar/jack/0.125.0_2/bin/jackd</string>

or you would get a crash alarm saying "Jack: not a valid server"...

@myelsukov
Copy link

This thread refuses to die :)

Notifications using polling is overkill.
MOC has nice built-in feature for that:

# Run the OnSongChange command when a new song starts playing.
# Specify the full path (i.e. no leading '~') of an executable to run.
# Arguments will be passed, and you can use the following escapes:
#
#     %a artist
#     %r album
#     %f filename
#     %t title
#     %n track
#     %d file duration in XX:YY form
#     %D file duration, number of seconds
#
# No pipes/redirects can be used directly, but writing a shell script
# can do the job.
#
# Example:    OnSongChange = "/home/jack/.moc/myscript %a %r"
#
#OnSongChange =

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment