<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>SuperMegaUltraGroovy Blog</title>
  <id>https://supermegaultragroovy.com/</id>
  <description>News and information about SuperMegaUltraGroovy, Inc., with the occasional post about software development and other tech topics.</description>
  <link href="https://supermegaultragroovy.com/"/>
  <link href="https://supermegaultragroovy.com/feed.xml" rel="self"/>
  <updated>2026-06-04T10:00:00-04:00</updated>
  <author>
    <name>SuperMegaUltraGroovy, Inc.</name>
  </author>
  <entry>
    <title>Capo 4.7 is Here</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2026/06/04/capo-4-7-is-here/"/>
    <id>https://supermegaultragroovy.com/2026/06/04/capo-4-7-is-here/</id>
    <published>2026-06-04T10:00:00-04:00</published>
    <updated>2026-06-04T11:47:39-04:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;Today I am pleased to share that Capo 4.7 is now available:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://itunes.apple.com/us/app/capo-3/id696977615?ls=1&amp;amp;mt=12&amp;amp;pt=15168&amp;amp;ct=4-7-blog&amp;amp;at=10l5V6"&gt;Get Capo 4.7 for macOS&lt;/a&gt; on the App Store&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://itunes.apple.com/us/app/capo-touch/id887497388?ct=4-7-blog"&gt;Get Capo 4.7 for iOS&lt;/a&gt; on the App Store&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="lead-sheets"&gt;Lead Sheets&lt;/h2&gt;

&lt;p&gt;The biggest feature of this release is &lt;em&gt;exclusive to the Mac&lt;/em&gt;. Capo can now produce publication-quality printouts or PDF files using the chords and sections that you set up in the project.&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/2026-06-04-capo-4-7/lead-sheet@2x.png" /&gt;&lt;/p&gt;

&lt;p&gt;You can try this out today if you have an active subscription. Just choose &lt;strong&gt;File &amp;gt; Print…&lt;/strong&gt; from the main menu once your song is ready to go. Then, add a title and subheadings, decide whether you want to include the chord vocabulary, and the rest works just like any other Mac app.&lt;/p&gt;

&lt;h2 id="call--response-mode"&gt;Call &amp;amp; Response Mode&lt;/h2&gt;

&lt;p&gt;Inspired by my research, Capo now provides a new way to play your looping regions: alternating between the recording, and &lt;em&gt;playing quietly&lt;/em&gt;. To enable this mode, you long-press on the loop button while a region is selected. You can also make the &lt;em&gt;quiet part&lt;/em&gt; play as loudly as 50% of the original volume, in case you find that helpful.&lt;/p&gt;

&lt;p&gt;This mode is helpful in a number of ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If you just listen in this mode, you can use the (totally) quiet period as an opportunity to hear it again in your head. This &lt;em&gt;musical imagery&lt;/em&gt; exercise helps you build your memory of the melody/solo that you're trying to copy from the recording.&lt;/li&gt;
  &lt;li&gt;While practicing, you can test your sense of time against the original. If you can play the notes yourself during the quiet period, you know you are able to play it at the current tempo.&lt;/li&gt;
  &lt;li&gt;When you play the part yourself during the quiet period, you're comparing what you hear against your memory rather than the recording—this is &lt;em&gt;much less distracting&lt;/em&gt; than trying to listen for the recording at the same time you're listening to your own playing.&lt;/li&gt;
  &lt;li&gt;On the Mac, you can use this mode in the Tabbing song view to confirm your note entries. The Call &amp;amp; Response settings let you configure the note entries to play during the quiet period so that you can confirm your entries against your memory of the notes you're trying to copy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote a bit more about this in my &lt;a href="/2026/04/24/call-response-mode-coming-soon/"&gt;last blog post&lt;/a&gt;, where you can learn more about the rationale behind this feature.&lt;/p&gt;

&lt;p&gt;I've been playing with this new mode for the past few weeks while testing the update, and I think you're going to love how well it works.&lt;/p&gt;

&lt;h2 id="fixes-and-improvements"&gt;Fixes and Improvements&lt;/h2&gt;

&lt;p&gt;There is a lot of stuff that goes into the "miscellaneous bin" for this update. Some of these are fixes for issues I found while building the new features, and some can be tied directly to user feedback that I received during the same time. I'm always thankful to those of you who &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#115;&amp;#117;&amp;#112;&amp;#112;&amp;#111;&amp;#114;&amp;#116;&amp;#064;&amp;#115;&amp;#117;&amp;#112;&amp;#101;&amp;#114;&amp;#109;&amp;#101;&amp;#103;&amp;#097;&amp;#117;&amp;#108;&amp;#116;&amp;#114;&amp;#097;&amp;#103;&amp;#114;&amp;#111;&amp;#111;&amp;#118;&amp;#121;&amp;#046;&amp;#099;&amp;#111;&amp;#109;"&gt;reach out&lt;/a&gt; to let me know about the sharp edges that need attention.&lt;/p&gt;

&lt;p&gt;You can learn more about what changed by reading the What's New pages for each platform:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="/products/capo/whats-new/mac/4.7/"&gt;What's New in Capo 4.7 for macOS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/products/capo/whats-new/ios/4.7/"&gt;What's New in Capo 4.7 for iOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="user-guide-changes"&gt;User Guide Changes&lt;/h3&gt;

&lt;p&gt;One big item on this list is a totally new &lt;a href="/products/capo/user-guide/4.7/"&gt;User Guide&lt;/a&gt; that now covers both platforms in the same place. But it's also searchable, and I'm trying to be mindful about where I put different kinds of content.&lt;sup id="fnref:dia" role="doc-noteref"&gt;&lt;a href="#fn:dia" class="footnote" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I really wanted the user guide to be "more finished" than it is right now, but I really needed to get this release out the door before WWDC hijacks all my focus for a week or so. I'm going to keep plugging away at it, and I would like to hear your &lt;a href="&amp;#109;&amp;#097;&amp;#105;&amp;#108;&amp;#116;&amp;#111;:&amp;#115;&amp;#117;&amp;#112;&amp;#112;&amp;#111;&amp;#114;&amp;#116;&amp;#064;&amp;#115;&amp;#117;&amp;#112;&amp;#101;&amp;#114;&amp;#109;&amp;#101;&amp;#103;&amp;#097;&amp;#117;&amp;#108;&amp;#116;&amp;#114;&amp;#097;&amp;#103;&amp;#114;&amp;#111;&amp;#111;&amp;#118;&amp;#121;&amp;#046;&amp;#099;&amp;#111;&amp;#109;"&gt;feedback&lt;/a&gt; about the guide.&lt;/p&gt;

&lt;div class="footnotes" role="doc-endnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:dia" role="doc-endnote"&gt;
      &lt;p&gt;In case you also write documentation, or you are curious about the process, I'm trying to follow the &lt;a href="https://diataxis.fr"&gt;Diàtaxis&lt;/a&gt; framework. This seems to have caught on mostly for API documentation, but I find it is helpful to know where different kinds of content should live. &lt;a href="#fnref:dia" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Call &amp; Response Mode: Coming Soon</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2026/04/24/call-response-mode-coming-soon/"/>
    <id>https://supermegaultragroovy.com/2026/04/24/call-response-mode-coming-soon/</id>
    <published>2026-04-24T14:05:00-04:00</published>
    <updated>2026-04-24T14:07:56-04:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;My research uncovered a few ways that software could support musicians' interactions with recordings. Some of my findings pointed at features Capo already had, but I didn't recognize their importance when they shipped. For example, I recommended that software should allow musicians to easily trigger the playback of a few notes at a time—Capo's Transcription Playhead already offers that interaction. I also suggested that supports should be in place for musicians who can't whistle or remember notes while hunting on their instrument, and the Audio Freezer helps with that. These features were footnotes in their respective releases, but now I consider them foundational tools.&lt;/p&gt;

&lt;p&gt;In the next Capo update, you'll get the first feature that I originally proposed in my research: Call &amp;amp; Response Mode. When enabled, Capo alternates between playing the original recording and quiet&lt;sup id="fnref:silence" role="doc-noteref"&gt;&lt;a href="#fn:silence" class="footnote" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; while a region is looping. This feature has three main benefits: (1) it primes your memory for learning, (2) helps you judge your own playing better, and (3) reveals the target notes in a dense mix.&lt;/p&gt;

&lt;p&gt;Using the Transcription Playhead, you'll find notes more quickly if you don't have to keep consulting the recording over and over again. Ideally, you want the notes in your mind, with the recording handy to refresh your memory. Before Call &amp;amp; Response mode, you'd place a region around a bar or two of the solo, and hear it over and over again. But that won't work, because memories are made stronger each time we retrieve them. During the quiet period of a Call &amp;amp; Response loop, you'll start to "hear" that music playing in your mind. Whistle or sing, and the memory gets even stronger. After you've "primed" your memory, it gets easier to work through the solo with a copy of the music etched into your mind.&lt;/p&gt;

&lt;p&gt;Once you have the notes under your fingers, it's time to practice with looping regions. Unfortunately, without Call &amp;amp; Response mode, this is taxing for your brain—when you play along with the recording, you have two streams of sound to process at once. Are you comparing your playing against the recording, or your &lt;em&gt;memory&lt;/em&gt; of the recording? And if you're trying to listen to the recording, you'll play quieter and out of time until you hear it better. But with Call &amp;amp; Response mode, the recording refreshes your memory, and you use the quiet period to compare your playing against the notes in your mind. Rinse, and repeat. Again, when you work from memory, those connections get stronger in your mind. Judging your playing without the recording is going to help you develop a critical ear for what sounds right.&lt;/p&gt;

&lt;p&gt;If you're working with a recording that has too much going on, you might be tempted to reach for a "stem splitter" in hopes that AI is going to make those notes easier to hear. But your musical heroes did this long before AI existed, and those tools aren't always going to work. If you're on a Mac, there's a novel way to use your (very capable) brain and ears to locate the right notes with the Tabbing song view and Call &amp;amp; Response mode. Draw out the notes on the spectrogram to match what you're hearing, and playback alternates between the recording and your note entries.&lt;sup id="fnref:sing" role="doc-noteref"&gt;&lt;a href="#fn:sing" class="footnote" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt; Listen carefully to those notes in the recording, then compare Capo's note entry playback with your memory of the music—make adjustments while the recording plays until you get them right. Here you're trying to interpret what you hear in the recording, which is a key part of learning by ear. You're judging what sounds correct, and your brain is really good at telling you when you don't quite have it yet.&lt;/p&gt;

&lt;p&gt;So that's Call &amp;amp; Response mode, useful in three ways: priming your memory of the recording before you learn from it, getting out of your way while you practice, and helping you find notes in dense recordings. With features like these, Capo continues to grow as a tool that helps your brain do what it does best while learning by ear.&lt;/p&gt;

&lt;div class="footnotes" role="doc-endnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:silence" role="doc-endnote"&gt;
      &lt;p&gt;The "quiet period" can play anywhere between 0 and 50% of the original volume. &lt;a href="#fnref:silence" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:sing" role="doc-endnote"&gt;
      &lt;p&gt;If you're using an iPhone or iPad, you can also do this by singing, humming, or whistling the notes. You'll be relying more on your memory and skills here, but you're also building them up while you do this. Try it out! &lt;a href="#fnref:sing" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Capo's Own Language</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2026/04/08/capos-own-language/"/>
    <id>https://supermegaultragroovy.com/2026/04/08/capos-own-language/</id>
    <published>2026-04-08T15:32:00-04:00</published>
    <updated>2026-04-09T08:38:02-04:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;Just before I started grad school in 2022, I began picking away at the "Keyboard and MIDI Overhaul" project that was meant to improve Capo's support for MIDI controls and extend them to iOS. It was an ambitious project, and it ultimately spawned a little domain-specific language (DSL) for configuration.&lt;/p&gt;

&lt;p&gt;Keyboard and MIDI controls are "power-user" features, and a combination of configuration files and documentation seems like a good power-user interface. But even power users are unlikely to know what specific messages their MIDI hardware spits out, and users on iOS would have a harder time writing and editing code. So I committed to building a comprehensive UI to configure keyboard and MIDI bindings in Capo. The DSL is still there, but it's used entirely behind the scenes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.caporemote&lt;/code&gt; configuration file contains a list of &lt;em&gt;bindings&lt;/em&gt;, and each binding consists of a &lt;em&gt;trigger&lt;/em&gt; that executes one or more &lt;em&gt;commands&lt;/em&gt;. Here is a simple example of a keyboard binding:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keyDown(rightArrow) {
  goToNextEntry(in: bars)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This language is easy to read: when you press the right arrow key, Capo will go to the next bar entry. Even complex bindings remain quite readable:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;controlChange(channel: 2, number: 16, value: $value) {
  setSpeed(to: $value[25:100])
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This one triggers when Capo receives MIDI Control Change (CC) #16 messages on channel 2, and it passes the current &lt;code&gt;$value&lt;/code&gt; to &lt;code&gt;setSpeed(to:)&lt;/code&gt;. The numbers in the square brackets define the output range: we only want values between 25% and 100%.&lt;/p&gt;

&lt;p&gt;Compared to an XML, JSON, or YAML configuration file, this DSL isn't just easy to read—its parser can also tell you when something's wrong. For example, writing &lt;code&gt;goToNextEntry(in: potato)&lt;/code&gt; produces an error pointing at the exact line and column, along with the expected values: &lt;code&gt;bars&lt;/code&gt;, &lt;code&gt;beats&lt;/code&gt;, or &lt;code&gt;markers&lt;/code&gt;. By contrast, an XML, JSON, or YAML parser would happily accept it, leaving the user to hunt for their mistake without guidance.&lt;/p&gt;

&lt;p&gt;I built my DSL's parser using the &lt;a href="https://github.com/pointfreeco/swift-parsing"&gt;&lt;code&gt;swift-parsing&lt;/code&gt;&lt;/a&gt; library from &lt;a href="https://pointfree.co"&gt;Point-Free&lt;/a&gt;. In addition to parsing, this library lets you build a Printer so that you can work in reverse. In my case, this is how the configuration gets saved to disk.&lt;sup id="fnref:configfile" role="doc-noteref"&gt;&lt;a href="#fn:configfile" class="footnote" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The parsers themselves use ResultBuilder syntax. Here's a modified version of the command parser:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;CommandParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ParserPrinter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;ParserPrinter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Substring&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;UTF8View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CapoRemoteCommandDescriptor&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;OneOf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// ... skipped&lt;/span&gt;
      
      &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"goToNextEntry"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nv"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CapoRemoteCommandDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goToNextEntry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ConstantParameter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CapoRemoteCommandDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;NavigableEntry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      
      &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"setSpeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nv"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CapoRemoteCommandDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setSpeed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;PercentageParameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      
      &lt;span class="c1"&gt;// ... skipped&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It's not important what each &lt;code&gt;Command&lt;/code&gt; parser does, or why it takes a &lt;code&gt;converter:&lt;/code&gt; parameter—those are boring implementation details. Instead, I want you to recognize the simplicity of this overall structure: it parses (and prints) &lt;code&gt;OneOf&lt;/code&gt; these named &lt;code&gt;Command&lt;/code&gt;s. The &lt;code&gt;goToNextEntry&lt;/code&gt; command takes a named &lt;code&gt;ConstantParameter&lt;/code&gt; of type &lt;code&gt;NavigableEntry&lt;/code&gt;, and the &lt;code&gt;setSpeed&lt;/code&gt; command takes a named &lt;code&gt;PercentageParameter&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;CommandParser&lt;/code&gt; &lt;em&gt;composes&lt;/em&gt; a collection of smaller, focused &lt;code&gt;Command&lt;/code&gt; parsers to form the larger one. Adding a new command to Capo means adding a new &lt;code&gt;Command&lt;/code&gt; parser to the list above.&lt;/p&gt;

&lt;p&gt;Parsing was the easy part. The harder problem was designing the system that consumes those parsed values. First, I had to catalog every action in Capo worth exposing to a binding—that took a while. Later, I realized I needed &lt;em&gt;two types&lt;/em&gt; for this to work.&lt;/p&gt;

&lt;p&gt;Incoming MIDI values arrive as integers from 0–127, but the command they trigger often wants something else—a speed between 25% and 100%, say. &lt;code&gt;CapoRemoteCommandDescriptor&lt;/code&gt; is the "recipe" that bridges the two: it describes how to produce a &lt;code&gt;CapoRemoteCommand&lt;/code&gt; from whatever value comes in. The variable-speed example above produces a descriptor of &lt;code&gt;.setSpeed(to: .variable(.percentageInRange(25...100)))&lt;/code&gt;, which then emits commands like &lt;code&gt;.setSpeed(percent: 25)&lt;/code&gt; or &lt;code&gt;.setSpeed(percent: 30)&lt;/code&gt; as MIDI values stream in. For simpler bindings the two types look nearly identical—&lt;code&gt;.goToNextEntry(in: .bars)&lt;/code&gt; vs. &lt;code&gt;.goToNext(.bar)&lt;/code&gt;—and without variable support, having two types would just be duplication.&lt;/p&gt;

&lt;p&gt;This was a challenging project, and I'm proud of the result. I'm also disappointed that all this work on the DSL got hidden behind the scenes—I had a grand vision of a bespoke code editor with inline error reporting, and nifty tools for learning MIDI messages. But I had to be realistic about my strengths and weaknesses—text editing and syntax highlighting are not in my wheelhouse. So I'll settle for a pat on the back for spotting that rabbit hole and stepping around it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This piece was inspired by this month's &lt;a href="https://christiantietze.de/posts/2026/04/swift-blog-carnival-tiny-languages/"&gt;Swift Blog Carnival on Tiny Languages&lt;/a&gt;. I've been trying to write more on this space lately, and this month's prompt gave me an excuse to think and write about my work on this project. Thanks for the nudge, Christian!&lt;/p&gt;

&lt;div class="footnotes" role="doc-endnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:configfile" role="doc-endnote"&gt;
      &lt;p&gt;If you're using Capo already, you can take a look at &lt;code&gt;~/Library/Containers/com.supermegaultragroovy.capo3.mac/Data/Library/Application Support/commands.caporemote&lt;/code&gt; to see this in action. &lt;a href="#fnref:configfile" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>My Overdue Eulogy for the Mac Pro</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2026/03/27/my-overdue-eulogy-for-the-mac-pro/"/>
    <id>https://supermegaultragroovy.com/2026/03/27/my-overdue-eulogy-for-the-mac-pro/</id>
    <published>2026-03-27T15:25:00-04:00</published>
    <updated>2026-03-27T17:09:39-04:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;The Mac Pro is now &lt;a href="https://9to5mac.com/2026/03/26/apple-discontinues-the-mac-pro/"&gt;officially dead&lt;/a&gt;—but it's been &lt;em&gt;dead to me&lt;/em&gt; for years.&lt;/p&gt;

&lt;p&gt;I ordered my first quad-core Mac Pro in early 2008, and later got an 8-core 2013 Mac Pro.&lt;sup id="fnref:9" role="doc-noteref"&gt;&lt;a href="#fn:9" class="footnote" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; These two Macs helped me bootstrap the OpenCL spectrogram kernel that put Capo on the map.&lt;/p&gt;

&lt;p&gt;During the "dark period", while we all waited for the follow-up to the trashcan Mac&lt;sup id="fnref:2" role="doc-noteref"&gt;&lt;a href="#fn:2" class="footnote" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;, I decided to go &lt;em&gt;hard&lt;/em&gt; when I configured my iMac Pro: 18 cores, 64GB RAM, and a Vega 64 GPU. With &lt;em&gt;this Mac&lt;/em&gt; (and the help of two eGPUs) I developed and trained the neural network that powers Capo's world-class chord detection engine.&lt;/p&gt;

&lt;p&gt;I was nervous about splashing out on the iMac Pro, because we were promised that something big was coming soon. But the polished-stainless-steel Mac that Apple introduced in 2019 was…clearly not for me. Instead, it was aimed squarely at movie and music production environments: with multi-GPU upgrade options for 3D work, video codec accelerators, PCIe slots for wacky audio gear. They even offered a rackmount option to complete a tidy installation in the million-dollar studios they were meant for.&lt;sup id="fnref:7" role="doc-noteref"&gt;&lt;a href="#fn:7" class="footnote" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I think Apple would have been wise to call that product the "Mac Studio", but I digress…&lt;/p&gt;

&lt;p&gt;For me, the death of the Mac Pro as a viable development system started around 2013. It wasn't about upgrades or GPUs. It was simpler than that: I felt like one of &lt;em&gt;very few suckers&lt;/em&gt; who bought my specific configuration, and nobody at Apple actually used a similar machine. For example, my 2013 Mac Pro had AMD FirePro D700 GPUs (a rare configuration) that often had issues with graphics corruption. Later, my iMac Pro—with its 18 cores—gave me &lt;em&gt;all sorts of trouble&lt;/em&gt; in Xcode, often compiling Capo more slowly than my 2013 Mac Pro could.&lt;sup id="fnref:4" role="doc-noteref"&gt;&lt;a href="#fn:4" class="footnote" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt; Adding insult to injury, &lt;em&gt;these machines were not cheap&lt;/em&gt;! I tried to "throw money at the problem (of making big computations go faster)", but I actually just bought headaches.&lt;/p&gt;

&lt;p&gt;My own software pushed these machines to their limits. Final Cut Pro and Logic ran great too. But Xcode—the thing I use most every day—was a mess.&lt;/p&gt;

&lt;p&gt;Anyway, from 2008–2022 I was living the two-Mac lifestyle: a powerful desktop for the heavy development, and a MacBook Pro for work outside the office. And you know what? Those machines didn't just work, they worked &lt;em&gt;great&lt;/em&gt;: excellent displays, and they were getting pretty fast—&lt;em&gt;especially&lt;/em&gt; after they moved to SSD storage.&lt;sup id="fnref:6" role="doc-noteref"&gt;&lt;a href="#fn:6" class="footnote" rel="footnote"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;But do you know what still sucked about these portable Macs? The desktop experience. You plugged it into a power adapter, and then a second cable for the screen. And that was a crapshoot: weird delays, maybe the wrong resolution (with third-party displays), the keyboard didn't wake the Mac, and sometimes you just had to unplug and try again. It was so frustrating! So I still clung to my dreams of a "Professional Desktop Mac", hoping for a better solution.&lt;/p&gt;

&lt;p&gt;Finally, in March 2022 I got my 14-inch MacBook Pro with an M1 Max and 64GB RAM. This machine &lt;em&gt;absolutely ripped apart&lt;/em&gt; my iMac Pro—it even trained Capo's custom neural network faster than my Radeon 7 eGPU! But it wasn't until later that summer, when I got a Studio Display, that I got to experience my new favorite "Professional Desktop Mac".&lt;/p&gt;

&lt;p&gt;In the morning, my MacBook Pro went into my backpack, I dropped my kids off at school, and went to my office at the University.&lt;sup id="fnref:5" role="doc-noteref"&gt;&lt;a href="#fn:5" class="footnote" rel="footnote"&gt;6&lt;/a&gt;&lt;/sup&gt; I did my schoolwork, attended classes, and worked on my thesis. In the afternoon, I returned to my home office and—after attaching a single cable to my Mac—I was right back where I left off. There were no delays, no fiddling. Everything Just Worked™.&lt;/p&gt;

&lt;p&gt;Four years later, and it's still my daily driver. Sometimes when I'm "done for the day", I'll unplug the Mac from the Studio Display and bring it up to the living room. I might check in with support after dinner, or tackle short development tasks from my couch. Some days I'll start work from that spot, because it gets cold in my basement office. When I need more screen space, I head down to the office, and boom: one plug, right back where I left off.&lt;/p&gt;

&lt;p&gt;This is something that the Mac Pro could never do: pause the work at my desk in whatever state I left it, resume it from a completely different location—in a library, a coffee shop, or waiting for my car to be serviced—and then cap off the work back at home. And the best part is that this all happens with almost no compromise in performance, and no "range anxiety" that has me carrying a charger.&lt;/p&gt;

&lt;p&gt;For me, this "Professional Desktop Mac" experience is nearly perfect&lt;sup id="fnref:8" role="doc-noteref"&gt;&lt;a href="#fn:8" class="footnote" rel="footnote"&gt;7&lt;/a&gt;&lt;/sup&gt;, and I haven't looked back at those days of heavy, expensive, power-hungry, heat-generating desk ornaments with anything but disdain. Good riddance, I say!&lt;/p&gt;

&lt;div class="footnotes" role="doc-endnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:9" role="doc-endnote"&gt;
      &lt;p&gt;I also had a PowerMac G4 with the mirrored drive doors in 2004, but we're talking about the Mac Pro, so… &lt;a href="#fnref:9" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2" role="doc-endnote"&gt;
      &lt;p&gt;I always disliked the "trashcan" nickname because I absolutely &lt;em&gt;loved&lt;/em&gt; the design of the machine: it wasn't trash at all! &lt;a href="#fnref:2" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:7" role="doc-endnote"&gt;
      &lt;p&gt;And yes, you could also buy wheels! &lt;a href="#fnref:7" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:4" role="doc-endnote"&gt;
      &lt;p&gt;Capo would often take more than 8 minutes to compile on the iMac Pro, with the CPU sitting idle for most of that time. Things eventually improved, but it took &lt;em&gt;years&lt;/em&gt;. &lt;a href="#fnref:4" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:6" role="doc-endnote"&gt;
      &lt;p&gt;OK, so it wasn't &lt;em&gt;all&lt;/em&gt; good: the keyboards got really, really bad for a while there. But I think that I only ever owned one butterfly machine: the late 2016 MacBook Pro with the Touch Bar, which I thoroughly enjoyed using, and gave my 2013 Mac Pro a run for its money. &lt;a href="#fnref:6" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:5" role="doc-endnote"&gt;
      &lt;p&gt;I was in grad school during that time, and it feels like forever ago. &lt;a href="#fnref:5" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:8" role="doc-endnote"&gt;
      &lt;p&gt;They were &lt;em&gt;so close&lt;/em&gt;, but they really soured the experience with the Studio Display camera. The one in the iMac Pro was &lt;em&gt;incredible&lt;/em&gt;, and this one is &lt;em&gt;garbage&lt;/em&gt;. I'm sure the updated 2026 model is better, but I don't take enough video calls to justify the expense. &lt;a href="#fnref:8" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <title>Printing in Capo: Should be Easy, Right?</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2026/03/06/printing-in-capo-should-be-easy-right/"/>
    <id>https://supermegaultragroovy.com/2026/03/06/printing-in-capo-should-be-easy-right/</id>
    <published>2026-03-06T15:06:00-05:00</published>
    <updated>2026-03-06T15:07:05-05:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;I cannot express how big of a deal it is for Capo to let users print chords. It is easily the most-requested feature.&lt;/p&gt;

&lt;p&gt;Fortunately for my users, I am not one of those people that says "printed charts are silly" and ignores the feedback. Heck, I bought a binding machine and printed most of the research papers I read during grad school. But &lt;em&gt;unfortunately for my users&lt;/em&gt;, I care a lot about quality printouts, and I want to get this right. So that's partly why it's taken so long for me to make progress on this.&lt;/p&gt;

&lt;p&gt;What my users often ask for is a printout of the Chords Song View—they can &lt;em&gt;see&lt;/em&gt; the chords, so &lt;em&gt;just put that on paper&lt;/em&gt;. But that would actually be disappointing: chords would get cut in half across pages, and the paper would be filled with lots of wasted space.&lt;/p&gt;

&lt;p&gt;And even if I wanted to do exactly what the users asked, I hit some snags along the way that made it impossible: mixed SwiftUI and AppKit drawing cannot be printed to a PDF context. Fortunately, this technical limitation forced me to work on a new chord layout and rendering pipeline just for printing, and now I have some flexibility in how I approach this.&lt;/p&gt;

&lt;p&gt;I have a really bold vision for Capo's printed output, and while I might not achieve &lt;em&gt;everything&lt;/em&gt; on my wish list in the first iteration, I think that I can produce something that will please the people who requested the feature. Sure, it's not the full vision. But it's useful, and it's a realistic goal.&lt;/p&gt;

&lt;p&gt;It will still be a little while until this is ready to see the light of day, but I feel so much closer than I ever did before.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The SuperMegaUltraGroovy Newsletter is Back!</title>
    <link rel="alternate" href="https://supermegaultragroovy.com/2025/10/15/smug-newsletter-is-back/"/>
    <id>https://supermegaultragroovy.com/2025/10/15/smug-newsletter-is-back/</id>
    <published>2025-10-15T10:05:00-04:00</published>
    <updated>2025-10-15T15:18:45-04:00</updated>
    <author>
      <name>Chris Liscio</name>
    </author>
    <content type="html">&lt;p&gt;The recent &lt;a href="/2025/10/09/i-guess-i-let-it-go-too-long/"&gt;loss of access&lt;/a&gt; to my Campaign Monitor account was quite the fire-under-my-ass wake-up call that I needed to revive the &lt;a href="https://supermegaultragroovy.com/newsletter"&gt;SuperMegaUltraGroovy Newsletter&lt;/a&gt;. After I spent some time &lt;em&gt;taking it on the chin&lt;/em&gt;, waiting for my inner critic&lt;sup id="fnref:1" role="doc-noteref"&gt;&lt;a href="#fn:1" class="footnote" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; to end his tirade, I buckled down and got to work trying to rebuild this project from the ground up.&lt;/p&gt;

&lt;h3 id="why-this-matters"&gt;Why this matters&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://supermegaultragroovy.com/newsletter"&gt;The newsletter&lt;/a&gt; really serves no purpose other than to keep customers informed about what's going on with the company (and to a much lesser extent, &lt;em&gt;me&lt;/em&gt;). I originally created the newsletter because social media hasn't worked properly for &lt;em&gt;years&lt;/em&gt;&lt;sup id="fnref:socialmedia" role="doc-noteref"&gt;&lt;a href="#fn:socialmedia" class="footnote" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;. And while this blog serves a very similar purpose, it's more of an information firehose&lt;sup id="fnref:firehose" role="doc-noteref"&gt;&lt;a href="#fn:firehose" class="footnote" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt; where posts will vary wildly in quality and content. I don't expect most of my customers to read this on a regular basis, nor would I ask them to check in regularly or install an RSS reader to keep up.&lt;/p&gt;

&lt;p&gt;The SMUG newsletter is a narrowly focused "social media feed" for people who use Capo.&lt;sup id="fnref:spoiler" role="doc-noteref"&gt;&lt;a href="#fn:spoiler" class="footnote" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt; I think that people enjoyed reading the little notes I dropped to them, and on more than one occasion I was thanked for the tips and other information that we shared.&lt;/p&gt;

&lt;p&gt;So I think it was worth rebooting, and I didn't mind spending the last few recovering my content from the newsletters still hosted on Campaign Monitor. It gave me an excuse to clean up the Middleman project that we used to use to generate the newsletters in the beginning.&lt;/p&gt;

&lt;h3 id="how-you-can-help"&gt;How You Can Help&lt;/h3&gt;

&lt;p&gt;This is a &lt;em&gt;big ask&lt;/em&gt;, but if you or anybody that you know happens to have been a subscriber in the past, please &lt;a href="https://supermegaultragroovy.com/newsletter"&gt;sign up for the list at the newsletter page&lt;/a&gt;. I'm re-building the list from &lt;em&gt;nothing&lt;/em&gt;, and I will happily take every subscriber I can get.&lt;/p&gt;

&lt;p&gt;If signing up for another e-mail newsletter isn't your thing, &lt;em&gt;I totally get it&lt;/em&gt;. At the very least, maybe just head over and &lt;a href="https://supermegaultragroovy.com/newsletter/015/"&gt;read Newsletter #015&lt;/a&gt; to see the fruit of my labor.&lt;/p&gt;

&lt;div class="footnotes" role="doc-endnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1" role="doc-endnote"&gt;
      &lt;p&gt;As if this wasn't painful enough, my mind &lt;em&gt;really&lt;/em&gt; wanted to let me me how badly I had screwed this up by neglecting the project for so long. I don't want to jinx it, but I've been a bit better recently about handling this stuff. My inner critic can scream at me all it wants, but nobody said I had to &lt;em&gt;listen&lt;/em&gt; to the vitriol. &lt;a href="#fnref:1" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:socialmedia" role="doc-endnote"&gt;
      &lt;p&gt;Don't believe me? Go to Facebook, Instagram, etc., and count the number of items in your feed that come from your friends, family, or legitimate interests. Then, compare that to the number of "promoted" posts from things you could care less about. &lt;a href="#fnref:socialmedia" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:firehose" role="doc-endnote"&gt;
      &lt;p&gt;In theory, anyway. I haven't been doing a good job with that the past few years, but look at me now—three posts in the span of a week! Manic episode? Hopefully not! &lt;a href="#fnref:firehose" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:spoiler" role="doc-endnote"&gt;
      &lt;p&gt;…and maybe other products I have in the pipeline? Don't hold your breath! I have five lifetimes worth of work to do on Capo. &lt;a href="#fnref:spoiler" class="reversefootnote" role="doc-backlink"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
  </entry>
</feed>
