Using Interactively With MacVim

With Beats Drum Machine you can use your favorite text editor to create beats. However, a drawback compared to GUI drum machines is that you have to switch back and forth between your text editor and the command line to hear your beat as you’re working on it.

But! What if I told you that you can script MacVim so that you can listen to your beat while you’re working on it, without having to switch to the command line? For example, on my machine I have it set up so that if I type <SPACE>s it will play the song in the current buffer. If I type <SPACE>p it figures out what pattern the cursor is inside, and plays that pattern. This turns MacVim into an interactive drum machine.

To enable this, add the code below to your .vimrc file. This adds two new custom Vim commands, :Song and :Pattern. It also adds shortcuts: <LEADER>s for :Song, and <LEADER>p for :Pattern. On my machine, <LEADER> is set to the space character so these translate to <SPACE>s and <SPACE>p.

command -nargs=0 Song silent exec "w | ! beats % && afplay %:r.wav"
command -nargs=? Pattern silent exec BuildPatternCommand("<args>")
map <silent> <Leader>s :Song<CR>
map <silent> <Leade>>p :Pattern<CR>

function BuildPatternCommand(...)
  let patternName = a:1
  if a:1 == ""
    let patternName = DetectCurrentPattern()
  endif

  return "w | ! beats -p " . patternName . " % && afplay %:r.wav"
endfunction

"Search backwards to find the previous line that starts with alphanumeric characters,
"which will indicate the name of the pattern the cursor is currently in.
function DetectCurrentPattern()
  let target_pattern  = '^\w\+'
  let target_line_num = search(target_pattern, 'bnW')

  if !target_line_num
    return ""
  else
    return matchstr(getline(target_line_num), target_pattern)
  endif
endfunction

Notes

Quit and restart MacVim for the changes in your .vimrc to take effect.

To stop the song while it’s playing, use CTRL+C.

This should theoretically work with other versions of Vim besides MacVim, but I haven’t tested it out. On Linux or Windows, you’d need to replace afplay with an alternate command. A Google search indicates that play might be the command to use on Linux, but I haven’t actually tested this out.

If the script is not working (i.e. you run a command and don’t hear anything), try removing the silent declaration from the :Song and :Pattern commands. This will cause the output of the shell commands that are running to be displayed at the bottom of the MacVim window, which might reveal the particular error.

© 2010-2020 Joel Strait