<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.7">Jekyll</generator><link href="https://truthindustri.es/feed.xml" rel="self" type="application/atom+xml" /><link href="https://truthindustri.es/" rel="alternate" type="text/html" /><updated>2023-10-28T18:39:12-07:00</updated><id>https://truthindustri.es/feed.xml</id><title type="html">truth industri.es</title><subtitle>giles bowkett's blog about code and music</subtitle><author><name>giles bowkett</name></author><entry><title type="html">Simplified Hardware Arx</title><link href="https://truthindustri.es/hardware/2020/07/05/simplified-hardware-arx.html" rel="alternate" type="text/html" title="Simplified Hardware Arx" /><published>2020-07-05T09:58:10-07:00</published><updated>2020-07-05T09:58:10-07:00</updated><id>https://truthindustri.es/hardware/2020/07/05/simplified-hardware-arx</id><content type="html" xml:base="https://truthindustri.es/hardware/2020/07/05/simplified-hardware-arx.html"><![CDATA[<p>I’m taking an online workshop
on building electronic musical instruments.
So last week I put together a sketch, in blog post form,
of what it might look like to make a
<a href="/hardware/2020/06/23/hardware-arx.html">hardware Arx</a> —
which is to say,
a hardware version of
<a href="http://videos.goruco.com/2008/giles-bowkett-archaeopteryx-a-ruby-midi-generator">my Ruby breakbeat improviser Archaeopteryx</a>
(renamed for simplicity).</p>

<p>Here’s the basic design I came up with.</p>

<p><img src="/assets/06232020-hardware-arx/kick-selected.png" /></p>

<p>These dimensions weren’t exact.
This was just a way to flesh out the UI controls.
But I wanted to get specific about the controls
so I could figure out what parts to buy from SparkFun.</p>

<p>These are the parts I had in mind:
<a href="https://www.sparkfun.com/products/15083">a pushbutton rotary encoder with built-in RGB LEDs</a>,
<a href="https://www.sparkfun.com/products/10597">a transparent plastic cap</a>,
<a href="https://www.sparkfun.com/products/8681">a membrane potentiometer (a touch strip)</a>,
and <a href="https://www.sparkfun.com/products/16426">a 14-segment display</a>.</p>

<p><img src="/assets/07052020-simplified-hardware-arx/encoder.png" /></p>

<p><img src="/assets/07052020-simplified-hardware-arx/plastic-knob.png" /></p>

<p><img src="/assets/07052020-simplified-hardware-arx/membrane.png" /></p>

<p><img src="/assets/07052020-simplified-hardware-arx/display.png" /></p>

<p>But my design has 17 encoders, and at over $20 apiece (if you count the caps),
that’s well over $300, just for an experiment.
Also, although I’ve built some stuff from kits —
including a Moog Subharmonicon —
I still don’t really know what I’m doing.
Finally, SparkFun didn’t have the touch strip I wanted in stock,
but they did have a shorter one.
So I came up with a simpler design that will still allow me to build
a 4-drum, 16-beat Arx,
but which has fewer moving parts.</p>

<p>Here’s the new, simpler design:</p>

<p><img src="/assets/07052020-simplified-hardware-arx/simplified.png" /></p>

<p>This design still uses the display,
and the encoder beside it,
for a menu-driven interface,
and it still uses the touch strip
to override the probability generation
and provide values manually.
This allows you to switch between a generative approach
and a more hands-on, layer-oriented approach,
as I explained in
<a href="/hardware/2020/06/23/hardware-arx.html">the previous post</a>.
Long story short, the display, its encoder, and the touch strip
all still function as in the original design.</p>

<p>The main thing which changed is the purpose of the top row of knobs.
In most drum machine designs, that usually represents the number of beats.
For instance, consider this basic drum pattern:</p>

<p><img src="/assets/06232020-hardware-arx/simple-drum-mesh.png" /></p>

<p>You might implement that by having each knob in the top row represent a beat:</p>

<p><img src="/assets/07052020-simplified-hardware-arx/kick-selected.png" /></p>

<p>Then you’d use the encoder next to the display to choose between the drums.
In this type of UI,
the row of buttons represents a row in the drum grid above.
This is how most drum machines work.
But if I did it that way,
I’d only get a 4-step sequencer out of it.
Each individual button would represent a column,
which is to say a beat,
and there’s only four of them.
That’s pretty much only fit for polka, military marches,
and extremely simplistic examples in blog posts.
To make the kind of music I want to make,
I want a 16-step sequencer at least.
But if I’m starting with just 4 encoders (or really 5),
then I can’t use a design which maps beats to encoders, one for one.</p>

<p>But you can also have each button represent an individual drum,
and have the row of buttons map to a <em>column</em> in the drum grid.
That’s what I plan to do.
I’ll have each top row knob represent a drum,
and let the user scroll through the beats using the display and its knob.
So if your first beat has a kick drum (knob 1) and a closed hi-hat,
per the grid diagram above,
that first column in the grid might map to the row of encoders like this:</p>

<p><img src="/assets/07052020-simplified-hardware-arx/kick-hat.png" /></p>

<p>And each beat maps its column to the encoders in the same way.
So when you use the knob next to the display to scroll to the next beat,
which has a kick, a clap, and an open hat,
you see this:</p>

<p><img src="/assets/07052020-simplified-hardware-arx/beat-two.png" /></p>

<p>And, as in
<a href="/hardware/2020/06/23/hardware-arx.html">the previous post</a>,
the intensity of the LED
would reflect the probability of the drum playing on that beat.</p>

<p>This UI would probably be a little less obvious at first,
with a marginally steeper learning curve,
but it would look a lot cooler when playing the beat,
since it could scroll through the steps as it played.
In practice, that would mean a lot of flashing lights.
And there’s no reason a drum sequencer built this way
couldn’t have 16 steps, or 32, or 64.</p>

<p>Big caveat: since I have no idea how to build a case for this,
and this is my first time designing and building my own hardware,
it’s probably going to look like a lot more chaotic than these mockups.
Still, I think this is a good compromise design.</p>]]></content><author><name>giles bowkett</name></author><category term="hardware" /><summary type="html"><![CDATA[I’m taking an online workshop on building electronic musical instruments. So last week I put together a sketch, in blog post form, of what it might look like to make a hardware Arx — which is to say, a hardware version of my Ruby breakbeat improviser Archaeopteryx (renamed for simplicity).]]></summary></entry><entry><title type="html">Hardware Arx</title><link href="https://truthindustri.es/hardware/2020/06/23/hardware-arx.html" rel="alternate" type="text/html" title="Hardware Arx" /><published>2020-06-23T09:58:10-07:00</published><updated>2020-06-23T09:58:10-07:00</updated><id>https://truthindustri.es/hardware/2020/06/23/hardware-arx</id><content type="html" xml:base="https://truthindustri.es/hardware/2020/06/23/hardware-arx.html"><![CDATA[<p>Back in 2007 and 2008, I put together a system in Ruby
which emulated a hardware drum machine,
but changed one piece of the classic design:
where most drum machines map beats to drums using booleans,
this used floats.
The floats expressed probability.
Since then Arturia, Elektron, and other companies have released drum machines
which allow you to do similar things, although they default
every probability to 1.0,
and you need to do some menu-diving in order to change that.</p>

<p>I can’t criticize menu-diving too harshly, as my own system
required me to edit raw code, live, while it sent MIDI into Reason.
Here’s a demo:</p>

<div class="responsive-video-size-hack">
  <iframe src="https://player.vimeo.com/video/88819530" width="640" height="359" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>
</div>

<p>However, I do think 1.0 is an overly cautious default for drum probability.
And although my system is now unnecessary
if you want to pit a random number against a mesh of probabilities,
it had another, simpler feature which allowed you to use
the probability mesh in a simpler and more dramatic way.
You could also just set the “probability” by hand.</p>

<p>Say that you have a random number generator,
it generates numbers between 0 and 1, and
the rule for your probabilistic drum system is that
the drum will only make a sound on any given beat if
the random number for the drum, on that beat,
is less than or equal to the drum probability.</p>

<p>Say also that you’ve got this probability mesh generating your drum patterns:</p>

<p><img src="/assets/06232020-hardware-arx/simple-drum-mesh.png" /></p>

<p>You could use this mesh in a couple different ways:</p>

<ul>
  <li>You could say “generate a new random number for each beat, and each drum, and compare that to the probability value for the beat and the drum.”</li>
  <li>You could say “generate a new random number for each measure, and compare that to the probability value for each drum and beat.”</li>
  <li>You could say “allow the user to simply choose a number, and compare that to the probability value for each beat/drum pair.”</li>
</ul>

<p>The first two options are subtly different.
Generating a random number on a per-measure basis puts the focus on layers;
generating it on a per-drum and/or per-beat basis creates breaks and fills.
When it comes to the probabilistic drum machines that are on the market today,
I don’t know which approach they use,
and to find out, I’d have to do some real digging through manuals (and possibly forums).
My system used both.</p>

<p>My system is also the only system I know of which gives you the third option.
If you allow the user to specify the number themselves,
you get a very layer-centric approach.
It’s pretty much inevitable that the user will discover they get sparse beats
at one end of the spectrum
and dense beats at the other.
The obvious next step is to transition through that spectrum,
making the beats sparser or denser,
depending on what the rest of the music needs.</p>

<p>I called my system Archaeopteryx.
It’s a very obscure joke:
the archaeopteryx was a transitional species,
either the last dinosaur or the first bird.
Is an instrument which improvises its own breakbeats the last dinosaur or the first bird?
The last instance of primitive humans making music by hand,
or the first instance of sophisticated AIs making music for us?
But I got tired of the joke,
especially since most people didn’t get it,
because they didn’t recognize the name of this species off the top of their heads.
This was my favorite dinosaur when I was a child,
and it never occurred to me that other people might know it by name.
But they didn’t.
What they did notice, instead, was that the name was hard to say.
So let’s call it Arx instead.</p>

<p>Arx was powerful and useful, but the UI was not user-friendly.
I sometimes got confused by it, and I was the one who wrote the code.
Other people found it completely baffling.
I showed a lot of people what it could do,
mostly at various Ruby conferences,
and they were often impressed —
but they couldn’t often <em>use</em> it.</p>

<p>So I’ve been thinking about a hardware user interface.</p>

<p>Here’s what it might look like:</p>

<p><img src="/assets/06232020-hardware-arx/basic-design.png" /></p>

<p>This is a simple, long box with two rows of controls.
The first row has 16 pushbutton rotary encoders with LEDs inside.
The second row has another of these encoders next to a display,
plus a long ribbon controller underneath the row of encoders.</p>

<p>If you were defining a beat, you first might use the bottom encoder
to choose a drum using the display, and then push the buttons on
the quarter notes to set up a standard four-on-the-floor beat for
the kick:</p>

<p><img src="/assets/06232020-hardware-arx/kick-selected.png" /></p>

<p>The idea here is that pushing the buttons would set your drum probability to 1.0.
But you could also use the rotary encoder to set the probability to some number
between 0 and 1.
If you did, the instrument might use the LEDs in the encoder to show the same
basic color, but at a lesser intensity or in a different hue,
and thereby display that number like this:</p>

<p><img src="/assets/06232020-hardware-arx/intermediate-probability.png" /></p>

<p>You could use the same user interface operations to define a hi-hat pattern —
or really, a hi-hat pattern generator —
with a lot more variation in it than the kick had.</p>

<p><img src="/assets/06232020-hardware-arx/hi-hats.png" /></p>

<p>Then you could use the display and its encoder —
a little menu system —
to select any of the three “randomness” types above:</p>

<ul>
  <li>You could say “generate a new random number for each beat, and each drum, and compare that to the probability value for the beat and the drum.”</li>
  <li>You could say “generate a new random number for each measure, and compare that to the probability value for each drum and beat.”</li>
  <li>You could say “allow the user to simply choose a number, and compare that to the probability value for each beat/drum pair.”</li>
</ul>

<p>And if it’s the third type of “randomness,” which is not actually random at all,
you could have the user choose the number by sliding their finger along the ribbon controller.</p>

<p>This means that after you program in your basic beat,
you get an enormous range of variations, breaks, fills, and layers
that you can explore with your hands, in real time, while the music plays.</p>

<p>This hardware UI for Arx would give you the same flexibility and power
as the original system,
but it would be much easier to use.
To put it another way,
using it would be a much more intuitive and musical experience.</p>]]></content><author><name>giles bowkett</name></author><category term="hardware" /><summary type="html"><![CDATA[Back in 2007 and 2008, I put together a system in Ruby which emulated a hardware drum machine, but changed one piece of the classic design: where most drum machines map beats to drums using booleans, this used floats. The floats expressed probability. Since then Arturia, Elektron, and other companies have released drum machines which allow you to do similar things, although they default every probability to 1.0, and you need to do some menu-diving in order to change that.]]></summary></entry><entry><title type="html">Software-Mediated Drum Circle</title><link href="https://truthindustri.es/hardware/2020/06/23/performance-system.html" rel="alternate" type="text/html" title="Software-Mediated Drum Circle" /><published>2020-06-23T08:58:10-07:00</published><updated>2020-06-23T08:58:10-07:00</updated><id>https://truthindustri.es/hardware/2020/06/23/performance-system</id><content type="html" xml:base="https://truthindustri.es/hardware/2020/06/23/performance-system.html"><![CDATA[<p>Here’s a rough sketch for a software-mediated drum circle.
This could be a good fit for Burning Man, a music festival,
or similar settings.</p>

<p>I came up with this idea back in 2014.
I wanted to reconcile two competing aspects of the
typical live electronic music experience.
On the one hand,
I know (like any promoter)
that it’s headliners who sell tickets.
But on the other hand,
I wanted a new way to understand live performance which would
counteract the concept of the superstar DJ
and focus instead on communal experience.</p>

<p><img src="/assets/20200623-performance-system/skrillex.png" /></p>

<p>There’s inherent tension to these two forces.
When superstar DJs make any kind of sense, it’s because
better musicianship results in better music.
On the other hand, a musical experience where dancers interact with <em>each other</em>
is very different, on an emotional and spiritual level,
from one where everybody stares at the superstar.</p>

<p><img src="/assets/20200623-performance-system/soul-train.jpg" /></p>

<p>And, while big stadium DJs often just play their own music,
there’s another school of thought around DJing which treats
reading the crowd, and letting that reading guide your track selection,
as an essential part of the experience.
In this model, a DJ doesn’t just perform,
they also sort of <em>facilitate collaboration</em>.
To be fair to the stadium DJ, however, it’s a lot easier to read a crowd
when that crowd is not unimaginably large and stretching so far into the distance
that you cannot possibly see everyone’s face.
So another way to look at it is to say there’s a spectrum,
from a <em>party</em> to a <em>show</em>.</p>

<p>Either way, I wanted to reconcile these two somewhat oppositional tensions,
and I also had a simpler goal:
to find a way to use modern technology to make live electronic music performance more exciting
than watching some dude poke at his laptop,
without moving too far down towards the show end of the party/show spectrum.</p>

<p>My idea was to leverage <em>user-generated visuals</em> and
<em>software-enabled audience participation</em>.</p>

<p>By user-generated visuals, I mean that
in addition to using the MIDI signals from an electronic drum pad or drum kit to create music,
you can also use those same signals to drive visualization software as well or instead.
I built some software in Clojure along these lines.
<a href="https://github.com/gilesbowkett/clojure-circles/tree/midi-notes">The code is on GitHub</a>.</p>

<p>Here’s a quick video demo I recorded back in 2014.</p>

<div class="responsive-video-size-hack">
  <iframe width="560" height="315" src="https://www.youtube.com/embed/C7kzC9QXWMM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
</div>

<p>Anyway, what I envisioned was a raised drum platform
at the center of the venue,
with video screens and concert lighting attached.
The video screens would plug into software
which accepted MIDI input from the electronic drums,
so that the musician could also function as a VJ, or in collaboration with a VJ
(who could choose to process the MIDI input
through any visualization software which accepted MIDI).</p>

<p>There’s a fun irony here: putting the performer in the center of the venue
<em>de-centers</em> them in terms of the experience.
It pulls the experience closer to the party end of the party/show spectrum.
Because if you’re behind the performer, and they have their back to you,
but you’re surrounded by dancers, you might just
turn around and interact with the dancers instead.</p>

<p><img src="/assets/20200623-performance-system/performer.png" /></p>

<p>Anyway, throughout the room, you would also have a
<em>drum circle</em> of MIDI-enabled drums, which would
<em>not</em> necessarily create any sound, but which would drive visualizations on screens nearby.
Sound would be optional; vision would be the key.
These drums would go on smaller raised platforms,
probably enclosed in “audience participation pods” for security,
and to simplify managing them during the event.</p>

<p><img src="/assets/20200623-performance-system/audience_participation.png" /></p>

<p>That could work a lot of different ways.
Maybe audience members buy tickets, or take turns.
Maybe it’s not audience members in the pods, but percussionists;
you could use this system to distribute a band throughout a venue
in a way that could never have happened without modern technology,
or you can use it blur the boundaries of audience and performer,
creating a new intermediary group which is a little bit of both.</p>

<p>The visualization software which the pods control could be
as goal-oriented and structured as music games like
Guitar Hero, Rocksmith, and Beat Saber,
but what I envision here (and even built a prototype of, per the above video)
is more freeform, artistic material designed to encourage creativity
and spontaneity.
Likewise, these pods could send the MIDI that they capture
from the audience to the main performer,
or to a VJ working with the main performer,
who could process it in real time.
Capturing audience movement data in this way,
and integrating it with the performance visuals,
makes this more of a communal experience to share,
and less of a staged spectacle to consume.</p>

<p>Either way, with the hardware all in one place, it’s easier to manage.
It’s also easier to distribute the pods throughout the venue.
They could be very close to the main performer, or quite far.
You could have four of them, as in these rough sketches,
or forty, or four hundred.
(Also, the main performer wouldn’t need to be a drummer, necessarily.
They could be a DJ, or a band.)</p>

<p><img src="/assets/20200623-performance-system/audience_participation_rear_view.png" /></p>

<p>Dispersing these drum pods throughout the venue
means that the crowd gets several additional areas of local focus.
If this were a concert design, the new areas of focus might just
host video displays, showing you the main performer and reinforcing their centrality.
Instead, it de-centers the main performer.</p>

<p>The drum pod plays a more local role,
creating visuals which <em>may</em> communicate back to the main performer
but which <em>definitely</em> display in front of the nearby audience members.
And the drum pod is <em>optional</em>.
In a stadium crowd where thousands of other people are staring at a performer,
you’re going to turn your head in the same direction.
If you’re in the middle between the main performer and the audience participation pod,
you can turn your attention to either of those focal points,
or to the people around you.</p>

<p><img src="/assets/20200623-performance-system/far_view.png" /></p>

<p>This design can restore party factors to shows, and give you
some control and self-determination in positioning your event
on the party/show spectrum.
If you want a big party with a performer in the middle who most people
don’t even realize is there, you set up a lot of audience participation pods,
and you make the central “stage” pretty modest.
If you just want to sprinkle some magic party dust on top of a big show,
you keep a big, stadium-style stage, but you add a few drum pods here and there,
and you staff them with trained professionals instead of opening them up to audience members.
To crank the hippie factor up to 11,
have the drum pods contribute not just visualization MIDI but audio from the drums as well.
To present a flawless, rehearsed performance,
restrict the drum pods to visualization only,
and have a VJ or team of VJs carefully curate any visualization MIDI
which the drum pods contribute.</p>

<p>Any given event will have its own preferred blend of party factors and show factors.
Big music festivals today often crank <em>both</em> factors up to 11.
This system is a framework that can work well in multiple different contexts.</p>]]></content><author><name>giles bowkett</name></author><category term="hardware" /><summary type="html"><![CDATA[Here’s a rough sketch for a software-mediated drum circle. This could be a good fit for Burning Man, a music festival, or similar settings.]]></summary></entry><entry><title type="html">A Riser in SuperCollider</title><link href="https://truthindustri.es/supercollider/2019/01/05/supercollider-riser.html" rel="alternate" type="text/html" title="A Riser in SuperCollider" /><published>2019-01-05T20:58:10-08:00</published><updated>2019-01-05T20:58:10-08:00</updated><id>https://truthindustri.es/supercollider/2019/01/05/supercollider-riser</id><content type="html" xml:base="https://truthindustri.es/supercollider/2019/01/05/supercollider-riser.html"><![CDATA[<p>In the two <a href="/supercollider/2019/01/04/supercollider-house-drums.html">previous</a>
<a href="/supercollider/2019/01/01/supercollider-house-beat.html">posts</a>,
I’ve shown how a house beat in SuperCollider works.
At the end of every eight bars,
this house beat includes a riser —
a buildup sound used to increase tension prior to a transition.
This is the most complex sound in the beat,
so I’ve saved it for last.</p>

<p>Here’s the beat again:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554150925&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>And here’s the riser:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554742201&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>Next, here’s the code:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// riser</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">riser</span><span class="dl">"</span><span class="p">,</span>
  <span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">startPan</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nx">endPan</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="c1">// envs</span>
    <span class="kd">var</span> <span class="nx">env1</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.4</span><span class="p">,</span> <span class="nx">amp</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.1</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">]],</span> <span class="err">\</span><span class="nx">lin</span><span class="p">);</span> <span class="c1">// amp env</span>
    <span class="kd">var</span> <span class="nx">env2</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">55</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.4</span><span class="p">,</span> <span class="mi">110</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">220</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.1</span><span class="p">,</span> <span class="mi">1760</span><span class="p">]],</span> <span class="err">\</span><span class="nx">lin</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">env3</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">]],</span> <span class="err">\</span><span class="nx">exponential</span><span class="p">);</span>

    <span class="c1">// build oscs on the envs</span>
    <span class="kd">var</span> <span class="nx">squiggly</span> <span class="o">=</span> <span class="nx">Saw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">SinOsc</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">env3</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">)).</span><span class="nx">range</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">19900</span><span class="p">),</span>
      <span class="na">mul</span><span class="p">:</span> <span class="p">(</span><span class="nx">env1</span><span class="p">.</span><span class="nx">kr</span> <span class="o">*</span> <span class="mf">0.6</span><span class="p">))</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">riser</span> <span class="o">=</span> <span class="nx">Saw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">env2</span><span class="p">.</span><span class="nx">kr</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="p">(</span><span class="nx">env1</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.8</span><span class="p">))</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">;</span>

    <span class="c1">// first combine these mono channels in a stereo space, then add reverb</span>
    <span class="kd">var</span> <span class="nx">combined</span> <span class="o">=</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">squiggly</span> <span class="o">+</span> <span class="nx">riser</span><span class="p">,</span> <span class="na">pos</span><span class="p">:</span> <span class="nx">Line</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">endPan</span><span class="p">,</span> <span class="mi">4</span><span class="p">));</span>
    <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">FreeVerb</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">in</span><span class="p">:</span> <span class="nx">combined</span><span class="p">,</span> <span class="na">mix</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">,</span> <span class="na">room</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">));</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>As usual, starting off with <code class="highlighter-rouge">SynthDef("riser", {...}).add;</code>
creates a callback function and registers it under the name “riser.”
The callback function takes three keyword arguments —
<code class="highlighter-rouge">amp</code>, <code class="highlighter-rouge">startPan</code>, and <code class="highlighter-rouge">endPan</code> —
and <code class="highlighter-rouge">amp</code> plays its usual role in defining the amplitude, or volume, of the function.
Likewise, <code class="highlighter-rouge">startPan</code> and <code class="highlighter-rouge">endPan</code> play the same roles they play in the synth hat code
in the <a href="/supercollider/2019/01/04/supercollider-house-drums.html">previous post</a>.</p>

<p>In the previous two posts, we’ve seen <code class="highlighter-rouge">Env.perc</code>, 
a tight, quick envelope well-suited to drum synthesis.
The <code class="highlighter-rouge">Env</code> object has many other methods, each of which generate different types of envelopes,
like <code class="highlighter-rouge">Env.adsr</code>, <code class="highlighter-rouge">Env.dadsr</code>, and <code class="highlighter-rouge">Env.asr</code>.
This code uses <code class="highlighter-rouge">Env.pairs</code>, which is the most flexible option.
<a href="http://depts.washington.edu/dxscdoc/Help/Classes/Env.html#*pairs"><code class="highlighter-rouge">Env.pairs</code></a>
takes an array of two-element arrays.
These pairs each represent the time and level of a point in the envelope.
The envelope can have any number of points,
and you can also pass in a symbol or string to specify the type of curve you want the envelope to have.</p>

<p>With that in mind, let’s look at the envelope code.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// envs</span>
<span class="kd">var</span> <span class="nx">env1</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.4</span><span class="p">,</span> <span class="nx">amp</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.1</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">]],</span> <span class="err">\</span><span class="nx">lin</span><span class="p">);</span> <span class="c1">// amp env</span>
<span class="kd">var</span> <span class="nx">env2</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">55</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.4</span><span class="p">,</span> <span class="mi">110</span><span class="p">],</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">220</span><span class="p">],</span> <span class="p">[</span><span class="mf">3.1</span><span class="p">,</span> <span class="mi">1760</span><span class="p">]],</span> <span class="err">\</span><span class="nx">lin</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">env3</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">pairs</span><span class="p">([[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">],</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">1</span><span class="p">]],</span> <span class="err">\</span><span class="nx">exponential</span><span class="p">);</span></code></pre></figure>

<p>Two of the envelopes use a linear curve; the third is exponential.
The first one lasts three and a half seconds,
the second one lasts a little over three seconds,
and the third lasts for four seconds.
The first envelope starts with a level of zero, goes up, and then goes back down to zero again.
The third envelope likewise ramps down from fifty to one.
The second one is the exception;
it starts at 55 and ramps up to 1760.</p>

<p>As you might guess, <code class="highlighter-rouge">env2</code> is a pitch envelope.
A common technique with risers in dance music is to build up from a low frequency to a high one,
and that’s what happens here.
If you’ve been following along with the previous posts,
you won’t be surprised to learn that the top frequency of 1760 represents a high octave of the note A,
and the bottom frequency of 55 repesents a low octave of A.
Here’s the code which uses this envelope to create a sound running through these frequencies.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">riser</span> <span class="o">=</span> <span class="nx">Saw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">env2</span><span class="p">.</span><span class="nx">kr</span><span class="p">,</span> <span class="nx">mul</span><span class="p">:</span> <span class="p">(</span><span class="nx">env1</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="mf">0.8</span><span class="p">))</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">;</span></code></pre></figure>

<p>This is one half of the riser sound.
To make it easier to understand, I took out the other half for this recording:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554742135&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>That rise in pitch is what the code is doing right now.</p>

<p><code class="highlighter-rouge">Saw</code> is a SuperCollider <em>unit generator</em> or UGen,
an object in SuperCollider which generates sound.
In this case, it generates a sawtooth wave,
a classic element of subtractive synthesis since the 1960s.
By invoking its <code class="highlighter-rouge">.ar</code> method,
we modulate it at audio rate.
So first we pass in the frequency we want with <code class="highlighter-rouge">freq: env2.kr</code>,
which simply means we’re going to take the control output of the pitch envelope
which runs from 55 to 1760,
and supply those values to <code class="highlighter-rouge">freq</code> over time.
Then we pass <code class="highlighter-rouge">env1.kr</code> as the value for the <code class="highlighter-rouge">Saw</code> UGen’s <code class="highlighter-rouge">mul</code> keyword argument.
This means we’ll use <code class="highlighter-rouge">env1</code> as an amp envelope.
A <code class="highlighter-rouge">doneAction</code> of 2 is equal to the value of <code class="highlighter-rouge">Done.freeself</code>,
and means that SuperCollider will free up the <code class="highlighter-rouge">Saw</code> UGen’s memory once it’s done playing this sound.
The code multiplies the amp envelope by 0.8 to tone the volume down a bit,
and the whole thing gets multiplied by <code class="highlighter-rouge">amp</code>,
which allows us to make further volume modifications elsewhere in the code, if we need that.
If we don’t, multiplying by <code class="highlighter-rouge">amp</code> does no harm,
since its default value is 1.</p>

<p>Now, as I said, I took out half of the riser sound so that we could understand that part.
That part, named <code class="highlighter-rouge">riser</code> in the code, does an actual rise in pitch.
The next part adds texture.
Here’s what that other half sounds like.</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554742081&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>And here’s the code.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">squiggly</span> <span class="o">=</span> <span class="nx">Saw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">SinOsc</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">env3</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">)).</span><span class="nx">range</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">19900</span><span class="p">),</span>
  <span class="nx">mul</span><span class="p">:</span> <span class="p">(</span><span class="nx">env1</span><span class="p">.</span><span class="nx">kr</span> <span class="o">*</span> <span class="mf">0.6</span><span class="p">))</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">;</span></code></pre></figure>

<p>As before, we’re just passing <code class="highlighter-rouge">freq</code> and <code class="highlighter-rouge">mul</code> to a <code class="highlighter-rouge">Saw</code> sawtooth wave UGen,
but the results are very different.
Or actually, the results with <code class="highlighter-rouge">mul</code> are virtually the same;
the only differences are that we make the UGen quieter,
by damping it down by a factor of 0.6 instead of 0.8,
and we don’t dispose of it with <code class="highlighter-rouge">doneAction: 2</code>.
The reason for that is the code we pass to <code class="highlighter-rouge">freq</code> needs the <code class="highlighter-rouge">Saw.ar</code> to stick around until <code class="highlighter-rouge">env3</code> is done,
and <code class="highlighter-rouge">env3</code> lasts four seconds, while <code class="highlighter-rouge">env1</code> (the amp envelope controlling <code class="highlighter-rouge">mul</code>) lasts 3.5 seconds.
We could shorten <code class="highlighter-rouge">env3</code> to 3.5 seconds as well if we needed to,
but in practice, it doesn’t cause any problems.</p>

<p>Anyway, the <code class="highlighter-rouge">mul</code> is clear.
What’s going on inside <code class="highlighter-rouge">freq</code> is a little more unusual:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Saw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">SinOsc</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">env3</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">)).</span><span class="nx">range</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">19900</span><span class="p">)</span></code></pre></figure>

<p>In the same way that calling <code class="highlighter-rouge">Saw.ar</code> gets SuperCollider to give us the audio output of a sawtooth wave generator,
<code class="highlighter-rouge">SinOsc.ar</code> gets us the audio output of a sine wave generator.
Passing only one argument to <code class="highlighter-rouge">SinOsc.ar</code> means we’re just defining the frequency of the sine wave,
and that frequency is a slow envelope that, over 4 seconds, starts at 50 and goes down to 1.
However, we then call <code class="highlighter-rouge">range(30, 19900)</code>.
This is actually a method on UGen itself, the superclass,
which scales the output of the UGen to fit within the range of frequencies defined.
So our sine wave actually starts at 19.9 kHz and scales down to 30 Hz,
which is almost the lowest frequency a human being can hear.
But wait!
Will any ear ever hear this frequency?
Because we’re not feeding it into any audio output;
we’re simply using it to generate the <code class="highlighter-rouge">freq</code> argument for our <code class="highlighter-rouge">Saw</code>.
What’s going on here?</p>

<p>We’re using our <code class="highlighter-rouge">SinOsc</code> as an <a href="https://en.wikipedia.org/wiki/Low-frequency_oscillation">LFO</a>.
At the start of its frequency envelope, it’s oscillating at 19.9 kHz,
which is way too fast to really qualify as an LFO —
it stands for low-frequency oscillator, after all —
and instead basically performs FM synthesis, modulating the sawtooth wave very quickly.
As it slows over the course of four seconds, however, it enters LFO territory.
So you get a transition in texture over those four seconds.
I wish I could say I thought of this myself,
but it’s an idea I stole from a <a href="https://en.wikipedia.org/wiki/MicroKORG">Microkorg</a> preset.
The Microkorg version didn’t go into FM territory,
but the idea was the same.</p>

<p>There are a few more lines of code which add just a little special sauce to this sound.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// first combine these mono channels in a stereo space, then add reverb</span>
<span class="kd">var</span> <span class="nx">combined</span> <span class="o">=</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">squiggly</span> <span class="o">+</span> <span class="nx">riser</span><span class="p">,</span> <span class="nx">pos</span><span class="p">:</span> <span class="nx">Line</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">endPan</span><span class="p">,</span> <span class="mi">4</span><span class="p">));</span>
<span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">FreeVerb</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="k">in</span><span class="p">:</span> <span class="nx">combined</span><span class="p">,</span> <span class="nx">mix</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">,</span> <span class="nx">room</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">));</span></code></pre></figure>

<p><code class="highlighter-rouge">Pan2.ar</code> turns mono sounds into stereo sounds,
and the <code class="highlighter-rouge">pos</code> argument (for “position,” i.e., pan position) is the control rate information from a <code class="highlighter-rouge">Line</code> drawn,
over four seconds,
from <code class="highlighter-rouge">startPan</code> to <code class="highlighter-rouge">endPan</code>.
Those values are -1 and 1, respectively,
which in this context stand for a signal panned all the way to the left
and a signal panned all the way to the right.
In other words, we make the sound move across the stereo spectrum.
Meanwhile, <code class="highlighter-rouge">FreeVerb</code> adds some reverb to the sound,
just to give it a bit of presence.</p>

<p>And that’s how we get the end result.</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554742201&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>]]></content><author><name>giles bowkett</name></author><category term="supercollider" /><summary type="html"><![CDATA[In the two previous posts, I’ve shown how a house beat in SuperCollider works. At the end of every eight bars, this house beat includes a riser — a buildup sound used to increase tension prior to a transition. This is the most complex sound in the beat, so I’ve saved it for last.]]></summary></entry><entry><title type="html">A House Track in SuperCollider</title><link href="https://truthindustri.es/supercollider/2019/01/05/supercollider-track.html" rel="alternate" type="text/html" title="A House Track in SuperCollider" /><published>2019-01-05T20:58:10-08:00</published><updated>2019-01-05T20:58:10-08:00</updated><id>https://truthindustri.es/supercollider/2019/01/05/supercollider-track</id><content type="html" xml:base="https://truthindustri.es/supercollider/2019/01/05/supercollider-track.html"><![CDATA[<p>The first several posts on this blog show you how
a <a href="/supercollider/2019/01/01/supercollider-house-beat.html">house beat</a>,
its <a href="/supercollider/2019/01/04/supercollider-house-drums.html">drums</a>,
and its <a href="/supercollider/2019/01/05/supercollider-riser.html">riser sound</a>
work.
Next I’m going to show you how I built a short house track —
around two and a half minutes long —
entirely in SuperCollider.</p>

<p>First, here’s the track:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/555518547&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>This is kind of just a demo, and a real house track would be maybe twice as long,
but I think it serves well as a proof of concept.
If you’ve been following the previous posts,
you recognize these drum sounds, as well as the riser.
The previous posts explain those sounds in detail.
What’s new are some more melodic sounds —
a synth pad and a sound like low bells or perhaps piano strings being scraped —
and the fact that this is a track rather than an eight-bar loop.</p>

<p>So there are just three things to explain:</p>

<ul>
  <li>pattern sequencing in SuperCollider</li>
  <li>the pad synth</li>
  <li>the bells / piano strings synth, which uses Karplus-Strong synthesis</li>
</ul>

<p>We’ll start at the beginning.
As before, there’s <a href="https://github.com/gilesbowkett/supercollider-complete-track">a git repo on GitHub</a>,
and you’ll need to run a simple installer script if you’re following along in SuperCollider.
The git repo has a <a href="https://github.com/gilesbowkett/supercollider-complete-track#how-it-works">README</a> which explains how to do that.</p>

<h2 id="pattern-sequencing-in-supercollider">Pattern Sequencing in SuperCollider</h2>

<p>In
<a href="/supercollider/2019/01/04/supercollider-house-drums.html">previous</a>
<a href="/supercollider/2019/01/01/supercollider-house-beat.html">posts</a>,
we saw that
SuperCollider provides a mechanism for sequencing called <code class="highlighter-rouge">Pbind</code>,
for <em>pattern binding</em>.
Pbinds allow us to play musical patterns
like drumbeats and melodies.
The question is how to sequence them, one after the other.</p>

<p>SuperCollider has a mechanism for this called <code class="highlighter-rouge">Pspawner</code>.
You invoke <code class="highlighter-rouge">Pspawner</code> along with a callback which takes a spawner object as an argument.
It’s idiomatic for this object to be named <code class="highlighter-rouge">spawner</code>,
but in this code,
I went with the name <code class="highlighter-rouge">salmon</code>
since I was in a goofy mood
and spawning is a thing that salmon do.</p>

<p>Here’s how a typical use of <code class="highlighter-rouge">Pspawner</code> might look:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">~</span><span class="nx">synthHatPattern</span> <span class="o">=</span> <span class="nx">Pbind</span><span class="p">(</span>
  <span class="err">\</span><span class="nx">instrument</span><span class="p">,</span> <span class="err">\</span><span class="nx">hat</span><span class="p">,</span>
  <span class="err">\</span><span class="nx">dur</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span>
  <span class="err">\</span><span class="nx">amp</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatAmps</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatStarts</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">endPan</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatEnds</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">pitchVariation</span><span class="p">,</span> <span class="nx">Prand</span><span class="p">([</span><span class="mi">3520</span><span class="p">,</span> <span class="mi">2637</span><span class="p">,</span> <span class="mi">7040</span><span class="p">],</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">release</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatReleases</span><span class="p">,</span> <span class="nx">inf</span><span class="p">)</span>
<span class="p">);</span>

<span class="o">~</span><span class="nx">clock</span> <span class="o">=</span> <span class="nx">TempoClock</span><span class="p">(</span><span class="mi">125</span><span class="o">/</span><span class="mi">60</span><span class="p">);</span>

<span class="nx">Pspawner</span><span class="p">({</span> <span class="nx">arg</span> <span class="nx">salmon</span><span class="p">;</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">synthHatPattern</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">play</span><span class="p">(</span><span class="o">~</span><span class="nx">clock</span><span class="p">);</span></code></pre></figure>

<p>The spawner’s <code class="highlighter-rouge">.par</code> method stands for “parallel,”
and it sets a pattern playing which can play in parallel (i.e., at the same time) with other patterns.
We’ve seen this <code class="highlighter-rouge">Pbind</code> code in previous posts.
All in all, this code will give you results which are basically identical to calling
<code class="highlighter-rouge">.play(~clock)</code> at the end of the <code class="highlighter-rouge">Pbind</code>.
But because we’re using <code class="highlighter-rouge">.par</code>, we can play other <code class="highlighter-rouge">Pbind</code> objects at the same time.</p>

<p>Also, just like “where there’s smoke, there’s fire,”
where there’s parallel, there’s sequential.
The spawner has a <code class="highlighter-rouge">.seq</code> object which will play a pattern, and then,
when that pattern ends,
the spawner will also stop playing any patterns which it was playing in parallel.
That’s what’s going on in this code,
which plays the first few bars of the track:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Pspawner</span><span class="p">({</span> <span class="nx">arg</span> <span class="nx">salmon</span><span class="p">;</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">synthHatPattern</span><span class="p">);</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">6</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">riserPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
<span class="p">}).</span><span class="nx">play</span><span class="p">(</span><span class="o">~</span><span class="nx">clock</span><span class="p">);</span></code></pre></figure>

<p>This code plays a crash pattern twice,
and keeps playing the synth hat pattern and a synth pad
until it’s played a kick pattern 6 times,
at which point it stops and plays a riser pattern once.
That’s how the track begins;
more specifically, that’s the first fifteen seconds of it.</p>

<p>But you’ll notice that I’m not just passing patterns to the spawner in most cases here.
Instead I’m calling <code class="highlighter-rouge">value()</code> on these objects and passing those values to the spawner.
That’s because this code is built on the code in the previous posts which played a drum pattern on inifinite repeat.
All the drum patterns in that existing code worked on the assumption that they would run forever.
Rather than rewrite all that code from scratch,
the easiest thing was to write functions which returned <code class="highlighter-rouge">Pbind</code> objects.
Here’s what one of those functions looks like:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="o">~</span><span class="nx">crashPattern</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">measures</span> <span class="p">;</span>
  <span class="nx">Pbind</span><span class="p">(</span>
    <span class="err">\</span><span class="nx">instrument</span><span class="p">,</span> <span class="err">\</span><span class="nx">crash</span><span class="p">,</span>
    <span class="err">\</span><span class="nx">dur</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span>
    <span class="err">\</span><span class="nx">amp</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">crashAmps</span><span class="p">,</span> <span class="nx">measures</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">)};</span></code></pre></figure>

<p>Invoking these functions works as shown: <code class="highlighter-rouge">functionName.value(argument)</code>.
This is some of the weirdest syntax in all of SuperCollider to me personally,
because I would have expected <code class="highlighter-rouge">functionName(argument)</code> instead.
However, prior to this, every time I’d used SuperCollider,
it’d been through systems like Overtone and Sonic Pi,
which retain SuperCollider’s power but replace its weird programming language
with more familiar, popular languages.
This is easier in terms of writing code,
but it’s also harder in terms of understanding what SuperCollider is actually doing.
SuperCollider is very powerful,
so it’s totally worth the effort to grapple with the syntax a little.
Anyway, long story short: functions which return Pbinds.</p>

<p>These simple mechanisms are almost all you need in order to do pattern sequencing in SuperCollider.
The code for this track uses only two other methods for its sequencing.
First, there’s <code class="highlighter-rouge">salmon.suspendAll;</code>.
This simply stops all running patterns.
Second, there’s <code class="highlighter-rouge">wait()</code>.
You pass this method a number of beats, and it’ll wait for that many beats before the song moves forward.
And that’s it.</p>

<p>Here’s this code in action:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Pspawner</span><span class="p">({</span> <span class="nx">arg</span> <span class="nx">salmon</span><span class="p">;</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">synthHatPattern</span><span class="p">);</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">6</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">riserPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">pluckQuasiArp</span><span class="p">);</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">zapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mf">3.5</span><span class="p">));</span> <span class="c1">// because this amps array is twice as long</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">wait</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">suspendAll</span><span class="p">;</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">wait</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">pluckQuasiArp</span><span class="p">);</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">synthHatPattern</span><span class="p">);</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleClapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleHatPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">zapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">4</span><span class="p">));</span> <span class="c1">// again, double-length amps array</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">snarePattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">6</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">6</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">riserPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleClapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleHatPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">wait</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">snarePattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleClapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">sampleHatPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">7</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">zapPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">4</span><span class="p">));</span>  <span class="c1">// function should handle this</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">kickPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">6</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">riserPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">par</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">stringsPad</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>
  <span class="nx">salmon</span><span class="p">.</span><span class="nx">suspendAll</span><span class="p">;</span>

  <span class="nx">salmon</span><span class="p">.</span><span class="nx">seq</span><span class="p">(</span><span class="o">~</span><span class="nx">crashPattern</span><span class="p">.</span><span class="nx">value</span><span class="p">(</span><span class="mi">2</span><span class="p">));</span>

<span class="p">}).</span><span class="nx">play</span><span class="p">(</span><span class="o">~</span><span class="nx">clock</span><span class="p">);</span></code></pre></figure>

<p>It might make for cleaner/<a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">DRYer</a> code,
and/or a track structure which is easier to understand,
if I were to wrap these sections up into helper functions.
But to get a track going, this is enough.
If you’re curious, try reading this code while the track plays.
It’s pretty easy to match up the lines of code with the parts of the track.</p>

<p>All that’s left to explain now is the two new sounds:
the pad synth and the Karplus-Strong sound.</p>

<h2 id="the-pad-synth">The Pad Synth</h2>

<p>Here’s what the pad synth sounds like:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/558638868&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>Both this and the next patch were created by Bruno Ruviaro,
one of the two instructors at the <a href="https://ccrma.stanford.edu/workshops/supercollider-2018">CCRMA SuperCollider workshop</a> that I took.
This patch was introduced during class.
I <a href="https://doc.sccode.org/1-4Vj">found</a> the next patch coincidentally, via a Google search,
although it’s not really a coincidence per se that a person teaching the workshop
had also written popular patches available online.</p>

<p>Anyway, here’s the code:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// pad synth (from presentation today)</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">padSynth</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">midinote</span><span class="p">,</span> <span class="nx">gate</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">ampEnv</span><span class="p">,</span> <span class="nx">freq</span><span class="p">,</span> <span class="nx">gen</span><span class="p">,</span> <span class="nx">fmod</span><span class="p">,</span> <span class="nx">rqmod</span><span class="p">,</span> <span class="nx">snd</span><span class="p">;</span>
  <span class="nx">ampEnv</span> <span class="o">=</span> <span class="nx">EnvGen</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span>
    <span class="na">envelope</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">adsr</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">),</span>
    <span class="na">gate</span><span class="p">:</span> <span class="nx">gate</span><span class="p">,</span>
    <span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">);</span>

  <span class="nx">freq</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">midinote</span><span class="p">.</span><span class="nx">midicps</span> <span class="o">*</span> <span class="nx">LFNoise2</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mf">0.01</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="p">}</span><span class="o">!</span><span class="mi">12</span><span class="p">;</span>
  <span class="nx">gen</span> <span class="o">=</span> <span class="nx">LFSaw</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">freq</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">ampEnv</span><span class="p">);</span>
  <span class="nx">fmod</span> <span class="o">=</span> <span class="nx">LFCub</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">12</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">ampEnv</span><span class="p">).</span><span class="nx">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">MouseX</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">16</span><span class="p">));</span>
  <span class="nx">rqmod</span> <span class="o">=</span> <span class="nx">LFNoise2</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">8</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">ampEnv</span><span class="p">).</span><span class="nx">range</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">1.0</span><span class="p">);</span>
  <span class="nx">snd</span> <span class="o">=</span> <span class="nx">RLPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">gen</span><span class="p">,</span> <span class="nx">freq</span> <span class="o">*</span> <span class="nx">fmod</span><span class="p">,</span> <span class="nx">rqmod</span><span class="p">,</span> <span class="nx">ampEnv</span><span class="p">);</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">Splay</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">snd</span> <span class="o">*</span> <span class="nx">ampEnv</span> <span class="o">*</span> <span class="mf">0.3</span><span class="p">));</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>First we define a function,
and add that function to SuperCollider’s list of synths
under the name “padSynth”.
The function takes a <code class="highlighter-rouge">midinote</code> and a <code class="highlighter-rouge">gate</code>.
In my hardware studio, I usually <em>either</em> send <a href="https://en.wikipedia.org/wiki/MIDI">MIDI</a> notes
<em>or</em> gate signals, in my Eurorack modular.
But they’re just data in SuperCollider, and you can use both if you want.
The <code class="highlighter-rouge">gate</code> is passed to an amplitude envelope here:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">ampEnv</span> <span class="o">=</span> <span class="nx">EnvGen</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span>
  <span class="nx">envelope</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">adsr</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mf">0.8</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">),</span>
  <span class="nx">gate</span><span class="p">:</span> <span class="nx">gate</span><span class="p">,</span>
  <span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">);</span></code></pre></figure>

<p>The <code class="highlighter-rouge">gate</code> signal is very important.
When the gate closes, it does the <code class="highlighter-rouge">doneAction</code>.
In this case (and most cases) the <code class="highlighter-rouge">doneAction</code> is 2, which is equal to the constant <code class="highlighter-rouge">Done.freeSelf</code>,
so when the gate closes, the synth gets freed.
In other words, SuperCollider garbage-collects it,
freeing up memory.
So without <code class="highlighter-rouge">gate</code>, you can bog down your computer
and produce all sorts of unpleasant glitching.
(SuperCollider can also produce pleasant glitching, of course.)</p>

<p>Anyway, an amp envelope is a fairly standard feature in a synthesizer,
but the rest of this code features some interesting quirks.
Although it holds to the same basic model as a
<a href="https://en.wikipedia.org/wiki/Subtractive_synthesis">classic subtractive synth</a>,
the <code class="highlighter-rouge">freq</code> in this synth isn’t just determined by converting the MIDI note into a frequency.
It also multiplies that frequency by the output of a noise generator,
to produce a wavering and not quite perfectly tuned sound, reminiscent of classic 1970s/80s analog polysynths:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">freq</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">midinote</span><span class="p">.</span><span class="nx">midicps</span> <span class="o">*</span> <span class="nx">LFNoise2</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mf">0.01</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="p">}</span><span class="o">!</span><span class="mi">12</span><span class="p">;</span></code></pre></figure>

<p>The <code class="highlighter-rouge">!12</code> means “create twelve copies of this.”
This thickens the sound.</p>

<p>The next few lines control the <a href="https://en.wikipedia.org/wiki/Voltage-controlled_filter">filter</a>.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">fmod</span> <span class="o">=</span> <span class="nx">LFCub</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">12</span><span class="p">,</span> <span class="nx">mul</span><span class="p">:</span> <span class="nx">ampEnv</span><span class="p">).</span><span class="nx">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nx">MouseX</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">16</span><span class="p">));</span>
<span class="nx">rqmod</span> <span class="o">=</span> <span class="nx">LFNoise2</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">8</span><span class="p">,</span> <span class="nx">mul</span><span class="p">:</span> <span class="nx">ampEnv</span><span class="p">).</span><span class="nx">range</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span><span class="mf">1.0</span><span class="p">);</span>
<span class="nx">snd</span> <span class="o">=</span> <span class="nx">RLPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">gen</span><span class="p">,</span> <span class="nx">freq</span> <span class="o">*</span> <span class="nx">fmod</span><span class="p">,</span> <span class="nx">rqmod</span><span class="p">,</span> <span class="nx">ampEnv</span><span class="p">);</span></code></pre></figure>

<p>With <code class="highlighter-rouge">rqmod</code>, it uses a noise generator to modulate the filter resonance,
and it puts an LFO on the filter frequency with <a href="http://depts.washington.edu/dxscdoc/Help/Classes/LFCub.html"><code class="highlighter-rouge">LFCub</code></a>,
which I believe stands for “low-frequency cubic,”
because it outputs a waveform similar to a sine wave but made of cubic pieces.
The top frequency is determined by the mouse position,
which I actually forgot when I was recording the audio samples in this blog post,
but if you clone the repo and run the installer,
you can experience this effect by moving your mouse while the pad sound plays.
The function then feeds these generators into <a href="http://depts.washington.edu/dxscdoc/Help/Classes/RLPF.html"><code class="highlighter-rouge">RLPF</code></a>,
which stands for “resonant low-pass filter.”
As explained in
<a href="/supercollider/2019/01/04/supercollider-house-drums.html">a previous post</a>,
<code class="highlighter-rouge">Out</code> and <code class="highlighter-rouge">Splay</code> just send the audio to an output bus and pan it across the stereo image, respectively.</p>

<p>So that’s how the pad works.
Let’s look at the Karplus-Strong sound.</p>

<h2 id="karplus-strong-synthesis">Karplus-Strong Synthesis</h2>

<p>The creators of Karplus-Strong synthesis,
Kevin Karplus and Alexander Strong,
originally called it “digitar” synthesis,
because they felt it produced digital guitar hybrid sounds.
It’s easy to understand where they’re coming from.
Here’s the Karplus-Strong or digitar sound from the track:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/558638880&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>Here’s the code:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// Bruno's Karplus-Strong synth</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">plucking</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span><span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">,</span> <span class="nx">freq</span> <span class="o">=</span> <span class="mi">440</span><span class="p">,</span> <span class="nx">decay</span> <span class="o">=</span> <span class="mi">5</span><span class="p">,</span> <span class="nx">dampen</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">;</span>

<span class="kd">var</span> <span class="nx">env</span><span class="p">,</span> <span class="nx">snd</span><span class="p">;</span>
<span class="nx">env</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">linen</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">decay</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">);</span>
<span class="nx">snd</span> <span class="o">=</span> <span class="nx">FreeVerb</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">Pluck</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span>
        <span class="na">in</span><span class="p">:</span> <span class="nx">WhiteNoise</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">amp</span><span class="p">),</span>
        <span class="na">trig</span><span class="p">:</span> <span class="nx">Impulse</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span>
        <span class="na">maxdelaytime</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span>
        <span class="na">delaytime</span><span class="p">:</span> <span class="nx">freq</span><span class="p">.</span><span class="nx">reciprocal</span><span class="p">,</span>
        <span class="na">decaytime</span><span class="p">:</span> <span class="nx">decay</span><span class="p">,</span>
    <span class="na">coef</span><span class="p">:</span> <span class="nx">dampen</span><span class="p">,</span>
    <span class="na">mul</span><span class="p">:</span> <span class="nx">env</span>
  <span class="p">),</span> <span class="na">mix</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span> <span class="na">room</span><span class="p">:</span> <span class="mf">0.8</span><span class="p">);</span>
    <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="nx">snd</span><span class="p">,</span> <span class="nx">snd</span><span class="p">]</span> <span class="o">*</span> <span class="nx">env</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>I didn’t write this code, but I can tell you roughly how it works.
The <code class="highlighter-rouge">Pluck</code> is a Karplus-Strong unit generator;
you set its <code class="highlighter-rouge">delaytime</code> at the reciprocal of the frequency you want to hear
because Karplus-Strong synthesis works by
looping a short burst of noise through a delay which is also set to a quite short time.
In a situation like that, the pitch of the resulting sound —
which is ultimately just white noise echoing a lot —
is inversely proportional to the delay time.
That’s because the looping of the delay functions like an oscillator,
generating a waveform by looping the initial burst of white noise.
In a sense, Karplus-Strong is a relatively simple form of wavetable synthesis.
Anyway, returning to the code, the <code class="highlighter-rouge">WhiteNoise</code> provides the noise, of course,
and the <code class="highlighter-rouge">Impulse</code> makes it a short burst.
The amp envelope generated by <code class="highlighter-rouge">Env.linen</code>
is not staccato,
but that’s applied to the overall sound.</p>

<p>So this is how you construct a complete track in SuperCollider.
This is the capstone of the past few blog posts,
which are so far the only ones on this blog,
so I hope you’ve found this edifying, inspiring, or at least useful.
You can make complete tracks entirely within SuperCollider,
and hopefully these blog posts have shown you how.</p>]]></content><author><name>giles bowkett</name></author><category term="supercollider" /><summary type="html"><![CDATA[The first several posts on this blog show you how a house beat, its drums, and its riser sound work. Next I’m going to show you how I built a short house track — around two and a half minutes long — entirely in SuperCollider.]]></summary></entry><entry><title type="html">Synth Drums in SuperCollider</title><link href="https://truthindustri.es/supercollider/2019/01/04/supercollider-house-drums.html" rel="alternate" type="text/html" title="Synth Drums in SuperCollider" /><published>2019-01-04T12:24:10-08:00</published><updated>2019-01-04T12:24:10-08:00</updated><id>https://truthindustri.es/supercollider/2019/01/04/supercollider-house-drums</id><content type="html" xml:base="https://truthindustri.es/supercollider/2019/01/04/supercollider-house-drums.html"><![CDATA[<p>In <a href="/supercollider/2019/01/01/supercollider-house-beat.html">the first post on this blog</a>,
I started an introduction to a GitHub repo
which defines a house beat.
In this followup post, I’m going to look at how the drums in this beat work.</p>

<p>First off, here’s what the beat sounds like:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554150925&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>There are five types of sound in this beat:</p>

<ul>
  <li>Sample playback (the clap, the open hi-hat)</li>
  <li>Simple drum synthesis (the crash, the closed hat, etc.)</li>
  <li>Complex drum synthesis (the ride)</li>
  <li>A bell-like synthesizer patch</li>
  <li>A riser</li>
</ul>

<p>The riser is complex enough that I’m going to save it for another post.
Plus it’s not a drum.
The bell-like patch is something I copied from Bruno Ruviaro.
I found <a href="https://doc.sccode.org/1-4Vj">his code for the synth on sccode.org</a>
(which currently has an invalid SSL cert, sorry),
but I actually found it while taking a <a href="https://ccrma.stanford.edu/workshops/supercollider-2018">workshop on SuperCollider at CCRMA 2018</a>,
and Bruno was teaching this workshop (along with Fernando Lopez-Lezcano).
It’s a pretty cool sound,
and when it came to getting this code up and running in the workshop, Bruno was instrumental in that
(sorry for the pun).
But it’s not a drum either, so I’m going to skip it for now.</p>

<p>This leaves three drum categories:</p>

<ul>
  <li>Sample playback (the clap, the open hi-hat)</li>
  <li>Simple drum synthesis (the crash, the closed hat, etc.)</li>
  <li>Complex drum synthesis (the rides)</li>
</ul>

<p>I’ll explain them in that order.</p>

<h2 id="sample-playback-drums">Sample Playback Drums</h2>

<p>The simplest way to make a drum sound
is to take a recording of a drum sound
and play it back.
It’s barely even the “Hello, world” of drum synthesis.
But it’s very useful,
and it’s a good simple thing to explain if you’re new to SuperCollider.
So let’s look at how it works.</p>

<p>Here’s the code which defines the sample playback “synthesizer.”</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="sr">//</span> <span class="n">set</span> <span class="n">up</span> <span class="n">clap</span> <span class="n">sample</span>
<span class="o">~</span><span class="n">clapBuffer</span> <span class="o">=</span> <span class="no">Buffer</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s2">"audio/11098__a43__a43-clap.aiff"</span><span class="p">);</span>

<span class="sr">//</span> <span class="n">set</span> <span class="n">up</span> <span class="nb">open</span> <span class="n">hat</span> <span class="n">sample</span>
<span class="o">~</span><span class="n">openHatBuffer</span> <span class="o">=</span> <span class="no">Buffer</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="s2">"audio/165028__rodrigo-the-mad__mini-909ish-open-hat.wav"</span><span class="p">);</span>

<span class="sr">//</span> <span class="n">generic</span> <span class="n">sample</span> <span class="n">player</span> <span class="n">synthdef</span>
<span class="no">SynthDef</span><span class="p">(</span><span class="s2">"samplePlayer"</span><span class="p">,{</span> <span class="n">arg</span> <span class="n">out</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">bufnum</span><span class="p">,</span> <span class="n">amp</span><span class="p">;</span>
  <span class="no">Out</span><span class="p">.</span><span class="nf">ar</span><span class="p">(</span> <span class="n">out</span><span class="p">,</span>
    <span class="no">PlayBuf</span><span class="p">.</span><span class="nf">ar</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">bufnum</span><span class="p">,</span> <span class="no">BufRateScale</span><span class="p">.</span><span class="nf">kr</span><span class="p">(</span><span class="n">bufnum</span><span class="p">),</span> <span class="ss">doneAction: </span><span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">amp</span><span class="p">;</span>
  <span class="p">)</span>
<span class="p">}).</span><span class="nf">add</span><span class="p">;</span></code></pre></figure>

<p>First, the code sets up paths to its audio samples,
one each in the WAV and AIFF formats.
Technically these aren’t the real paths;
as explained in
<a href="/supercollider/2019/01/01/supercollider-house-beat.html">the previous post</a>,
a simple installer script will set you up with explicit pathnames for the audio samples.
After the file paths are set up, 
we use <a href="http://doc.sccode.org/Classes/SynthDef.html"><code class="highlighter-rouge">SynthDef</code></a> to define a synth —
basically an audio-generating function which you can address with a name —
which takes as its arguments the index of an audio bus,
the index of a buffer,
and an amplitude.
A buffer in this context,
like in so many others with file I/O,
is the in-memory storage of the data in the file.
Also note that <code class="highlighter-rouge">Buffer.read</code> returns not the buffer itself,
but the buffer’s index,
so reading the file and keeping track of the index is all you need to use SuperCollider’s API here.</p>

<p>A reasonable person could at first glance think that
this is a strange design decision, and maybe expect <code class="highlighter-rouge">Buffer.read</code> to return the buffer itself.
Likewise, passing around the index for the output bus is a bit weird when you could just be working with the bus itself.
My best guess is that you <em>can’t</em> just work with the bus itself,
and that this weirdness, like most computer-related weirdness, is due to distributed systems.
SuperCollider uses a client/server architecture,
which is beyond the scope of this blog post,
but which would explain why the language could only work with references to buses and buffers,
and not have direct access to those buses or buffers themselves as objects.</p>

<p>Anyway, the most important line in our sample player is here:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">PlayBuf</span><span class="p">.</span><span class="nf">ar</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">bufnum</span><span class="p">,</span> <span class="no">BufRateScale</span><span class="p">.</span><span class="nf">kr</span><span class="p">(</span><span class="n">bufnum</span><span class="p">),</span> <span class="ss">doneAction: </span><span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="n">amp</span><span class="p">;</span></code></pre></figure>

<p>A <a href="http://doc.sccode.org/Classes/PlayBuf.html"><code class="highlighter-rouge">PlayBuf</code></a> is a SuperCollider object which plays an audio buffer.
The <code class="highlighter-rouge">.ar</code> here, and everywhere in SuperCollider, means that we’re going to send signals out from this object at audio rate.
The <code class="highlighter-rouge">2</code> signifies two channels, i.e., it’s a stereo sample.
The <code class="highlighter-rouge">bufnum</code> is the index of the buffer object that we’ll be getting our audio information from.
The next parameter we’re passing in is our <code class="highlighter-rouge">rate</code>,
i.e., the speed at which we’ll be playing back the sample.
We calculate this with the help of a <code class="highlighter-rouge">BufRateScale</code> object,
and we get data from that object at control rate (which is what <code class="highlighter-rouge">.kr</code> always means in SuperCollider).
Think of audio rate and control rate as equivalent to
audio signals and <a href="https://en.wikipedia.org/wiki/CV/gate">control voltage</a> in Eurorack modular synthesis.</p>

<p>Everything within the <code class="highlighter-rouge">{}</code> in the <code class="highlighter-rouge">SynthDef</code> is essentially a callback function
that will be invoked later, like a callback function in Node.js,
so obviously we’re not saying “play this <code class="highlighter-rouge">PlayBuf</code> now.”
We’re setting up <code class="highlighter-rouge">"samplePlayer"</code> as the name for the “synthesizer” which will play
the <code class="highlighter-rouge">PlayBuf</code> whenever we need it to, later on.</p>

<p>To be more specific, let’s look at when that “later on” arrives.
This is the code from <code class="highlighter-rouge">timing.scd</code> and <code class="highlighter-rouge">pbinds.scd</code> which specifies when the clap and hat samples will play:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="sr">//</span> <span class="n">set</span> <span class="n">up</span> <span class="k">when</span> <span class="n">to</span> <span class="n">play</span> <span class="n">the</span> <span class="n">clap</span>
<span class="o">~</span><span class="n">clapAmps</span> <span class="o">=</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span> <span class="p">];</span> <span class="sr">//</span> <span class="mi">16</span> <span class="n">beats</span>

<span class="sr">//</span> <span class="n">timing</span> <span class="k">for</span> <span class="n">sampled</span> <span class="nb">open</span> <span class="n">hat</span>
<span class="o">~</span><span class="n">sampledOpenHatAmps</span> <span class="o">=</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">];</span>

<span class="sr">//</span> <span class="n">sample</span> <span class="ss">player: </span><span class="n">clap</span>
<span class="no">Pbind</span><span class="p">(</span>
  <span class="p">\</span><span class="n">instrument</span><span class="p">,</span> <span class="p">\</span><span class="n">samplePlayer</span><span class="p">,</span>
  <span class="p">\</span><span class="n">dur</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="sr">//</span> <span class="mi">16</span><span class="n">th</span> <span class="n">note</span> <span class="n">is</span> <span class="n">one</span> <span class="n">quarter</span> <span class="n">of</span> <span class="n">a</span> <span class="n">beat!</span>
  <span class="p">\</span><span class="n">bufnum</span><span class="p">,</span> <span class="o">~</span><span class="n">clapBuffer</span><span class="p">,</span>
  <span class="p">\</span><span class="n">amp</span><span class="p">,</span> <span class="no">Pseq</span><span class="p">(</span><span class="o">~</span><span class="n">clapAmps</span><span class="p">,</span> <span class="n">inf</span><span class="p">)</span>
<span class="p">).</span><span class="nf">play</span><span class="p">(</span><span class="n">mainClock</span><span class="p">);</span>

<span class="sr">//</span> <span class="n">sample</span> <span class="ss">player: </span><span class="n">hat</span>
<span class="no">Pbind</span><span class="p">(</span>
  <span class="p">\</span><span class="n">instrument</span><span class="p">,</span> <span class="p">\</span><span class="n">samplePlayer</span><span class="p">,</span>
  <span class="p">\</span><span class="n">dur</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="sr">//</span> <span class="mi">16</span><span class="n">th</span> <span class="n">note</span> <span class="n">is</span> <span class="n">one</span> <span class="n">quarter</span> <span class="n">of</span> <span class="n">a</span> <span class="n">beat!</span>
  <span class="p">\</span><span class="n">bufnum</span><span class="p">,</span> <span class="o">~</span><span class="n">openHatBuffer</span><span class="p">,</span>
  <span class="p">\</span><span class="n">amp</span><span class="p">,</span> <span class="no">Pseq</span><span class="p">(</span><span class="o">~</span><span class="n">sampledOpenHatAmps</span> <span class="o">*</span> <span class="mf">0.65</span><span class="p">,</span> <span class="n">inf</span><span class="p">)</span>
<span class="p">).</span><span class="nf">play</span><span class="p">(</span><span class="n">mainClock</span><span class="p">);</span></code></pre></figure>

<p>A <code class="highlighter-rouge">Pbind</code> in SuperCollider represents a <em>pattern binding</em>,
which is to say a connection between a pattern to play
and the sounds which will play it.
A <code class="highlighter-rouge">PlayBuf</code> doesn’t take specific notes,
so these <code class="highlighter-rouge">Pbind</code> objects just take arrays of amplitudes,
which is to say numbers between 0 and 1 which represent loudness.
In the hat pattern binding, the code multiplies the loudnessnesses
by 0.65 as a way of quieting their overall volume a little.</p>

<p>If this conflation of triggering the sound and adjusting its volume bothers you,
it’s also possible to separate them by using gates,
which are similar to the gate signals used in analog sequencers,
but we won’t get into that in this blog post.</p>

<p>You may be wondering why <code class="highlighter-rouge">~clapAmps</code> has 16 elements,
but <code class="highlighter-rouge">~sampledOpenHatAmps</code> only has 4.
The answer is that,
after hand-coding all 16 elements in <code class="highlighter-rouge">~clapAmps</code>,
I noticed this was wasteful,
and used a terser syntax in <code class="highlighter-rouge">~sampledOpenHatAmps</code>.
That’s it.
SuperCollider will turn both arrays into infinite sequences,
since they’re passed into <code class="highlighter-rouge">Pseq</code> with an <code class="highlighter-rouge">inf</code> argument,
so in this case it doesn’t matter how long they are.</p>

<h2 id="subtractive-synthesis-drums">Subtractive Synthesis Drums</h2>

<p>The simplest subtractive drum in this beat is the crash.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// crash</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">crash</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">whiteNoise</span> <span class="o">=</span> <span class="nx">PinkNoise</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span>
    <span class="na">mul</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="na">releaseTime</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="na">curve</span><span class="p">:</span> <span class="o">-</span><span class="mi">7</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">));</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">HPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">whiteNoise</span><span class="p">,</span> <span class="na">freq</span><span class="p">:</span> <span class="mi">7040</span><span class="p">))</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>Here’s how it sounds.</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554151081&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>There are <a href="https://www.soundonsound.com/techniques/synthesizing-realistic-cymbals">more</a>
sophisticated <a href="http://www.mcld.co.uk/cymbalsynthesis/">ways</a>
to make a cymbal sound, but this is a nice simple example to start with.
Let’s dig into the code.</p>

<p>As usual, this part means “create a sound-generating callback function
named ‘crash’, and add it to the in-memory synth registry”:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// crash</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">crash</span><span class="dl">"</span><span class="p">,</span> <span class="p">{...}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>Now let’s expand that ellipsis.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">whiteNoise</span> <span class="o">=</span> <span class="nx">PinkNoise</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span>
    <span class="nx">mul</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="nx">releaseTime</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="nx">curve</span><span class="p">:</span> <span class="o">-</span><span class="mi">7</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">));</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">HPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">whiteNoise</span><span class="p">,</span> <span class="nx">freq</span><span class="p">:</span> <span class="mi">7040</span><span class="p">))</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>

<p>Starting off, <code class="highlighter-rouge">arg amp = 1;</code> just means that the callback function takes one keyword argument, named <code class="highlighter-rouge">amp</code>, with a default value of <code class="highlighter-rouge">1</code>.
So far so good.
Next we create a <code class="highlighter-rouge">whiteNoise</code> variable,
which is actually generated by invoking the <code class="highlighter-rouge">ar</code> method on a <code class="highlighter-rouge">PinkNoise</code>
UGen.
(A UGen is a <a href="http://depts.washington.edu/dxscdoc/Help/Guides/WritingUGens.html">unit generator</a>, i.e., something which makes sound.)
<code class="highlighter-rouge">.ar</code>, as always in SuperCollider, means we want audio rate output, i.e., sound.
We pass in just one argument, <code class="highlighter-rouge">mul</code>, which stands for “multiply.”
SuperCollider will multiply the output from the PinkNoise UGen by the value of <code class="highlighter-rouge">mul</code>.
As you can see, that value is a little complex:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">mul</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="nx">releaseTime</span><span class="p">:</span> <span class="mi">4</span><span class="p">,</span> <span class="nx">curve</span><span class="p">:</span> <span class="o">-</span><span class="mi">7</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="nx">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">))</span></code></pre></figure>

<p><a href="http://depts.washington.edu/dxscdoc/Help/Classes/Env.html#*perc"><code class="highlighter-rouge">Env.perc</code></a> creates a percussive
<a href="https://en.audiofanzine.com/sound-synthesis/editorial/articles/send-it-in-an-envelope.html">envelope</a>,
and <code class="highlighter-rouge">.kr</code> sends the output of that envelope as a control signal.
I’m not sure what the release time’s units are, but it might be seconds.
At any rate, this value of 4 gives us a longer release than the default of 1,
and that longer release makes sense for a crash cymbal.
Likewise, the -7 curve means that the release curve of this envelope
is gentler than the percussive envelope’s default.
The magic number 2, for <code class="highlighter-rouge">doneAction</code>,
is equal to the value of <code class="highlighter-rouge">Done.freeself</code> —
an important constant in SuperCollider —
and means that we want the UGen to free its own memory after it plays.
This is a very important bit of bookkeeping;
without it, SuperCollider will not free up the UGen.
In this code, you create a new synthesizer in SuperCollider’s memory every time you play this drum.
If you’re not freeing up those resources once you’re done with them,
you could get audio glitching and other memory problems very quickly.</p>

<p>Anyway, at this point we’ve created a crash cymbal sound.
Now we have to play it.
That’s what the next line does:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">HPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">whiteNoise</span><span class="p">,</span> <span class="nx">freq</span><span class="p">:</span> <span class="mi">7040</span><span class="p">))</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">);</span></code></pre></figure>

<p>As is often the case in SuperCollider,
this code works by chaining library objects and invoking them at audio rate via their <code class="highlighter-rouge">.ar</code> methods.
<a href="http://depts.washington.edu/dxscdoc/Help/Classes/Out.html">The <code class="highlighter-rouge">Out</code> object</a> simply sends audio to an output bus.
SuperCollider will set you up with one output bus by default,
and its list is zero-indexed, so that’s the first argument to <code class="highlighter-rouge">Out.ar</code>.
The second argument is an array of channels,
and <code class="highlighter-rouge">Pan2.ar</code> simply takes one channel and splits it into an array of two channels,
i.e., a stereo pair.
We use <code class="highlighter-rouge">amp</code> to define when the crash will play,
just like with the sample playback drums above,
and we multiply the <code class="highlighter-rouge">amp</code> value by 4 to boost the volume a bit.
We also wrap the whole thing in a high-pass filter, using <code class="highlighter-rouge">HPF.ar</code>,
and set the frequency to 7040, which is a high octave of the note A.
(All of the drum sounds in this beat are tuned to A, or notes in the A minor scale.)</p>

<p>The pattern playing mechanism is similar to what we’ve already looked at above for the sample playback drums.
If you want to take a deeper look, <a href="https://github.com/gilesbowkett/basic-beat">the code is on GitHub</a>.
For now, let’s look instead at a very similar drum: the synth hi-hat.
Above, we saw the code which plays a sampled open hi-hat.
But this beat also contains a synthesized hi-hat, and the code will look very familiar.</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// basic synth hat</span>
<span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">hat</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">startPan</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="nx">endPan</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">pitchVariation</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">release</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">whiteNoise</span> <span class="o">=</span> <span class="nx">WhiteNoise</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">mul</span><span class="p">:</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="na">releaseTime</span><span class="p">:</span> <span class="nx">release</span><span class="p">,</span> <span class="na">curve</span><span class="p">:</span> <span class="o">-</span><span class="mi">7</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">));</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">Pan2</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">BBandPass</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">whiteNoise</span><span class="p">,</span> <span class="na">freq</span><span class="p">:</span> <span class="nx">pitchVariation</span><span class="p">,</span> <span class="na">bw</span><span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="na">pos</span><span class="p">:</span> <span class="nx">Line</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">endPan</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span> <span class="o">*</span> <span class="nx">amp</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>This is almost the same drum.
The code uses a much shorter default release time of 0.1,
accepts <code class="highlighter-rouge">release</code> as an argument, and accepts some other new arguments as well:
<code class="highlighter-rouge">startPan</code>, <code class="highlighter-rouge">endPan</code>, and <code class="highlighter-rouge">pitchVariation</code>.
Instead of always setting a high-pass filter at 7040,
it instead sets a band-pass filter to whatever frequency <code class="highlighter-rouge">pitchVariation</code> represents.
It also sets the pan position using <a href="http://depts.washington.edu/dxscdoc/Help/Classes/Line.html">a linear control rate</a>
“drawn” between its start and end points:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">pos</span><span class="p">:</span> <span class="nx">Line</span><span class="p">.</span><span class="nx">kr</span><span class="p">(</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">endPan</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span></code></pre></figure>

<p>One of the weirdest things about the syntax of SuperCollider’s language
is that, when you use keyword arguments, the names are optional.
(It’s not optimized for clarity, but for live-coding.)
The “4” in the above code could also be written as <code class="highlighter-rouge">dur: 4</code>, and specifies a duration of 4 seconds for the panning.</p>

<p>You might be wondering where <code class="highlighter-rouge">startPan</code>, <code class="highlighter-rouge">endPan</code>, <code class="highlighter-rouge">release</code>, and <code class="highlighter-rouge">pitchVariation</code> come from.
They’re here:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// set up when to play the hats</span>
<span class="o">~</span><span class="nx">hatAmps</span> <span class="o">=</span> <span class="p">[</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">];</span> <span class="c1">// 16 beats</span>
<span class="o">~</span><span class="nx">hatStarts</span> <span class="o">=</span> <span class="p">[</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.7</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.7</span> <span class="p">];</span> <span class="c1">// hat pan timing</span>
<span class="o">~</span><span class="nx">hatEnds</span> <span class="o">=</span> <span class="p">[</span> <span class="o">-</span><span class="mf">0.7</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.7</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="o">-</span><span class="mf">0.5</span> <span class="p">];</span> <span class="c1">// hat pan timing</span>
<span class="o">~</span><span class="nx">hatReleases</span> <span class="o">=</span> <span class="p">[</span>
  <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">,</span>
  <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span>
  <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span>
  <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span>
  <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span>
  <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span>
  <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.4</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">,</span> <span class="mf">0.3</span>
<span class="p">];</span> <span class="c1">// hat release times</span>

<span class="nx">Pbind</span><span class="p">(</span>
  <span class="err">\</span><span class="nx">instrument</span><span class="p">,</span> <span class="err">\</span><span class="nx">hat</span><span class="p">,</span>
  <span class="err">\</span><span class="nx">dur</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span> <span class="c1">// 16th note is one quarter of a beat!</span>
  <span class="err">\</span><span class="nx">amp</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatAmps</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">startPan</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatStarts</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">endPan</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatEnds</span><span class="p">,</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">pitchVariation</span><span class="p">,</span> <span class="nx">Prand</span><span class="p">([</span><span class="mi">3520</span><span class="p">,</span> <span class="mi">2637</span><span class="p">,</span> <span class="mi">7040</span><span class="p">],</span> <span class="nx">inf</span><span class="p">),</span>
  <span class="err">\</span><span class="nx">release</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">hatReleases</span><span class="p">,</span> <span class="nx">inf</span><span class="p">)</span>
<span class="p">).</span><span class="nx">play</span><span class="p">(</span><span class="nx">mainClock</span><span class="p">);</span></code></pre></figure>

<p>The <code class="highlighter-rouge">pitchVariation</code> comes from a <code class="highlighter-rouge">Prand</code>, which returns an infinite sequence of random values
selected from the <code class="highlighter-rouge">[3520, 2637, 7040]</code> array.
In other words, the band-pass filter lets frequencies through at two octaves of A, plus one octave of E.
The other values come from ordered infinite sequences via <code class="highlighter-rouge">Pseq</code>,
which simply repeat their arrays forever.
In practice, this means that the panning follows a six-step pattern where each step takes four seconds.
The releases follow a 56-step pattern, and the amps follow a 16-step pattern.</p>

<p>This means that just the combination of the release and amp configuration needs to play for 112 beats,
or 28 bars, before it repeats.
However, if you factor in the 6-step sequence of 4-second panning patterns,
and consider that the changes in pitch are entirely random,
you have a hi-hat rhythm which is never the same thing twice.
It never repeats.
Instead, there’s a lot of variety and polyrhythm in these hats.
Their pitch changes, their pan position changes, their release time changes, and their volume changes.
It’s just a subtle variation in a background sound, but I’m pretty happy with it.
Here’s what it sounds like.</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/554150994&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>That’s it for the subtractive drums in this beat,
except to note that I took the <a href="http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1">kick</a>
and the <a href="http://blog.rumblesan.com/post/53271713909/drum-sounds-in-supercollider-part-2">snare</a>
from an excellent blog called Rumblesan.
Check out those posts if you want to understand how those drums work.</p>

<p>Now, let’s move on to the most complex drum in the beat.</p>

<h2 id="complex-synthesis-drum">Complex Synthesis Drum</h2>

<p>This is the ride, aka “zaps.”
I explained this briefly in
<a href="/supercollider/2019/01/01/supercollider-house-beat.html">the previous post</a>,
but I’ll get into more detail about the synthesis here.
Here’s how it sounds:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/552890046&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<p>Here’s the code:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">zaps</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">modFreq</span> <span class="o">=</span> <span class="mi">15</span><span class="p">,</span> <span class="nx">carFreq</span> <span class="o">=</span> <span class="mi">880</span><span class="p">,</span> <span class="nx">modDepth</span> <span class="o">=</span> <span class="mi">3250</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">car</span><span class="p">,</span> <span class="nx">mod</span><span class="p">,</span> <span class="nx">env</span><span class="p">;</span>

  <span class="nx">env</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="na">releaseTime</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">);</span>
  <span class="nx">mod</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">modFreq</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.14</span><span class="p">,</span> <span class="mf">0.97</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">],</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">modDepth</span><span class="p">);</span>
  <span class="nx">car</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">carFreq</span> <span class="o">+</span> <span class="nx">mod</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.41</span><span class="p">,</span> <span class="mf">0.99</span><span class="p">,</span> <span class="mf">2.4921</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mf">1.397</span><span class="p">],</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">env</span><span class="p">);</span>
  <span class="nx">car</span> <span class="o">=</span> <span class="nx">Splay</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">car</span><span class="p">);</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">FreeVerb</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">HPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="na">freq</span><span class="p">:</span> <span class="mi">5274</span><span class="p">),</span> <span class="na">mix</span><span class="p">:</span> <span class="mf">0.05</span><span class="p">,</span> <span class="na">room</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span> <span class="na">damp</span><span class="p">:</span> <span class="mf">0.9</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">amp</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">));</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>Beyond the usual <code class="highlighter-rouge">amp</code>, this synth’s callback function has three arguments we haven’t seen before:
<code class="highlighter-rouge">modFreq</code>, <code class="highlighter-rouge">carFreq</code>, and <code class="highlighter-rouge">modDepth</code>.
Likewise, although you probably recognize the <code class="highlighter-rouge">Env.perc</code> and <code class="highlighter-rouge">HPF.ar</code> from the subtractive examples,
<code class="highlighter-rouge">Splay</code> and <code class="highlighter-rouge">Pulse</code> are new.</p>

<p>Let’s start with a little context.
Although I think it didn’t quite happen, I originally intended to produce this sound via frequency modulation (FM) synthesis.
Where subtractive synthesis works by establishing a sound and then filtering frequencies out of it,
FM synthesis works instead of by taking one sound and then using another sound to modulate it.
Another way to think of it, in comparison to subtractive synthesis, might be to consider it multiplicative synthesis,
because when you modulate one frequency with another, you are basically multiplying the two frequencies.</p>

<p>As I mentioned before, I wrote this beat during a summer workshop at CCRMA,
the computer music research department at Stanford.
For decades, the most profitable patent to come out of Stanford was an FM synthesis patent developed at CCRMA.
This patent was the foundation of the Yamaha DX7,
an incredibly popular synthesizer during the 1980s.
At a party near the end of the workshop,
one of the CCRMA researchers played a playlist of non-stop 80s hits
powered by the DX7.
There was also a DX7 in the lobby.
Here it is.</p>

<p><img src="/assets/dx7.jpg" style="width: 200px; height: 200px;" />
<img src="/assets/dx7-2.jpg" style="width: 200px; height: 200px;" /></p>

<p>Anyway, in FM synthesis, you have a minimum of two frequencies.
The base frequency is called the carrier, and the modulating frequency is the modulator.
That’s what <code class="highlighter-rouge">car</code> and <code class="highlighter-rouge">mod</code> are in this code.
Likewise, <code class="highlighter-rouge">carFreq</code> and <code class="highlighter-rouge">modFreq</code> are the frequencies of these two sounds.
We produce each sound using a square wave,
which is what <code class="highlighter-rouge">Pulse.ar</code> produces.
That’s roughly what these two lines of code are doing:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">mod</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">modFreq</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.14</span><span class="p">,</span> <span class="mf">0.97</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">],</span> <span class="nx">mul</span><span class="p">:</span> <span class="nx">modDepth</span><span class="p">);</span>
<span class="nx">car</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">carFreq</span> <span class="o">+</span> <span class="nx">mod</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.41</span><span class="p">,</span> <span class="mf">0.99</span><span class="p">,</span> <span class="mf">2.4921</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mf">1.397</span><span class="p">],</span> <span class="nx">mul</span><span class="p">:</span> <span class="nx">env</span><span class="p">);</span></code></pre></figure>

<p>But these two lines of code aren’t just producing square waves.
This is what that simpler case would look like:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">mod</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">modFreq</span><span class="p">);</span>
<span class="nx">car</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">freq</span><span class="p">:</span> <span class="nx">carFreq</span><span class="p">);</span></code></pre></figure>

<p>So we’re doing a few additional things:</p>

<ul>
  <li>passing <code class="highlighter-rouge">mul: modDepth</code></li>
  <li>passing <code class="highlighter-rouge">mul: env</code></li>
  <li>combining <code class="highlighter-rouge">carFreq</code> and <code class="highlighter-rouge">mod</code> with addition</li>
  <li>multiplying each frequency value by an array</li>
</ul>

<p>First, we’ve seen code like <code class="highlighter-rouge">mul: env</code> before, so let’s get that one out of the way.
SuperCollider multiplies the volume of a given audio source by whatever argument you pass to <code class="highlighter-rouge">mul</code>.
With <code class="highlighter-rouge">mul: env</code>, we’re passing our <code class="highlighter-rouge">Env.perc</code> to <code class="highlighter-rouge">mul</code>, so we’re applying a percussive envelope to the sound’s volume.
The other use of <code class="highlighter-rouge">mul</code> is a little more exotic.
In this case, we’re multiplying it by <code class="highlighter-rouge">modDepth</code> to specify how weak or strong the modulator waveform will be.
The code uses 3250 because it produces a very intense modulator wave,
and because 3250 is an octave of the note A.
There’s no real reason to expect 3250 to produce a properly tuned sound here;
frequency modulation is notoriously chaotic in its output.
I just used this frequency because I’d been using it for other things,
and I kept it because it worked.</p>

<p>Anyway, combining <code class="highlighter-rouge">carFreq</code> and <code class="highlighter-rouge">mod</code> with addition
gets us a combination of sounds which I think is maybe more additive synthesis than FM.
I did this in a hurry towards the end of the workshop.
However, it sounded pretty good.
This is kind of how SuperCollider works sometimes.
You start with a cool idea, get it slightly wrong, but keep it because it sounds good.
Moving on, multiplying each sound by an array means creating many slightly modified copies of the same sound.
This gives us a lot of polyphony for very little effort,
with the consequence that there’s a lot of different frequencies in the “zaps” sound,
and it has the kind of noisy high end that a ride should have.
Finally, our call to <a href="http://depts.washington.edu/dxscdoc/Help/Classes/Splay.html"><code class="highlighter-rouge">Splay</code></a>
just pans these many ride voices across the stereo space.</p>

<h2 id="conclusion">Conclusion</h2>

<p>So there you have it:
a tour of the drum sounds (and, to a lesser extent, sequencing) in a SuperCollider house beat.
We saw how SuperCollider can do simple, typical subtractive drum sounds,
how it can automate parameters like release, pan, and band-pass filter frequency to create patterns with a lot of organic variation,
and how its algorithmic approach to sound definition can cause an attempt at FM synthesis
to take an interesting detour into additive synthesis instead.
It’s a quirky beast, but it offers unique expressive opportunities,
and although it can be a challenge to work with, it can also be very rewarding.</p>

<p>The <a href="/supercollider/2019/01/05/supercollider-riser.html">next post</a>
explains how the riser works in this beat,
and there’s some more music in SuperCollider which I hope to explain after that.
Stay tuned!</p>]]></content><author><name>giles bowkett</name></author><category term="supercollider" /><summary type="html"><![CDATA[In the first post on this blog, I started an introduction to a GitHub repo which defines a house beat. In this followup post, I’m going to look at how the drums in this beat work.]]></summary></entry><entry><title type="html">A House Beat in SuperCollider</title><link href="https://truthindustri.es/supercollider/2019/01/01/supercollider-house-beat.html" rel="alternate" type="text/html" title="A House Beat in SuperCollider" /><published>2019-01-01T15:24:10-08:00</published><updated>2019-01-01T15:24:10-08:00</updated><id>https://truthindustri.es/supercollider/2019/01/01/supercollider-house-beat</id><content type="html" xml:base="https://truthindustri.es/supercollider/2019/01/01/supercollider-house-beat.html"><![CDATA[<p>There are at least three open source live-coding systems in popular languages —
Sonic Pi (Ruby), Overtone (Clojure), and Tidal Cycles (Haskell) —
which all share the same foundation:
a system called SuperCollider.
I’m going to show you how to build a basic house beat in SuperCollider.</p>

<h2 id="getting-started">Getting Started</h2>

<p>You can grab the code from GitHub here:</p>

<p><a href="https://github.com/gilesbowkett/basic-beat" target="_blank">https://github.com/gilesbowkett/basic-beat</a></p>

<p>You’ll need to <a href="https://supercollider.github.io/download">install SuperCollider</a> to use it.
Once you have it, playing the beat becomes super easy, as shown in this video:</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/iIuwFDPMndo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>

<p>In the video, I kick off the beat by opening a file called <code class="highlighter-rouge">loader.scd</code>.
As you probably guessed, it loads other files.
Here’s the code:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="p">(</span>
<span class="s2">"/Users/personal/code/ccrma-2018/supercollider-2018/project/synths.scd"</span><span class="p">.</span><span class="nf">load</span><span class="p">;</span>
<span class="s2">"/Users/personal/code/ccrma-2018/supercollider-2018/project/timing.scd"</span><span class="p">.</span><span class="nf">load</span><span class="p">;</span>
<span class="s2">"/Users/personal/code/ccrma-2018/supercollider-2018/project/pbinds.scd"</span><span class="p">.</span><span class="nf">load</span><span class="p">;</span>
<span class="p">)</span></code></pre></figure>

<p>Of course, you won’t see this same code when you first download or fork the project.
Instead of a SuperCollider file called <code class="highlighter-rouge">loader.scd</code>,
you’ll have an <a href="https://ruby-doc.org/stdlib-2.6/libdoc/erb/rdoc/ERB.html">ERB</a> template called <code class="highlighter-rouge">loader.scd.erb</code>:</p>

<figure class="highlight"><pre><code class="language-eruby" data-lang="eruby">(
"<span class="cp">&lt;%=</span> <span class="n">this_directory</span> <span class="cp">%&gt;</span>/synths.scd".load;
"<span class="cp">&lt;%=</span> <span class="n">this_directory</span> <span class="cp">%&gt;</span>/timing.scd".load;
"<span class="cp">&lt;%=</span> <span class="n">this_directory</span> <span class="cp">%&gt;</span>/pbinds.scd".load;
)</code></pre></figure>

<p>To turn this template into a SuperCollider file with the name of the appropriate directory,
just run the Ruby installer:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="o">&gt;</span> ruby installer.rb</code></pre></figure>

<p>This runs using the Ruby standard library on any Unix-like operating system.
So the good news is that it doesn’t need a Gemfile on OS X,
but the bad news is it won’t run on Windows.
Sorry Windows users.
Pull requests welcome!</p>

<p>Anyway, if you’re on OS X, you’ll see that this installer took a file called <code class="highlighter-rouge">loader.scd.erb</code>
and created a new file called <code class="highlighter-rouge">loader.scd</code>.
There’s a <code class="highlighter-rouge">synths.scd.erb</code> template as well, which the installer used the same way.
At this point, you can either <code class="highlighter-rouge">open loader.scd</code>, or, in the worst-case scenario, <code class="highlighter-rouge">open loader.scd -a SuperCollider</code>.</p>

<h2 id="common-issue-sample-rate-mismatch">Common Issue: Sample Rate Mismatch</h2>

<p>If you see an error message from SuperCollider about sample rate mismatch,
you can fix it (on OS X) by opening up the Audio MIDI Setup app —
a standard utility included with every Mac —
and ensuring that both your input and output devices are set to the same sample rate.</p>

<p><img src="/assets/watch-out-for-this-shit.png" /></p>

<h2 id="pbinds--timing">Pbinds &amp; Timing</h2>

<p><code class="highlighter-rouge">loader.scd</code> loads three files:</p>

<ul>
  <li><code class="highlighter-rouge">synths.scd</code> — SuperCollider evaluates this file to create a set of SynthDefs, which are basically functions that have the ability to create sound. Each SynthDef has a name also. The names are very useful for live-coding or testing, since for any given name, the command <code class="highlighter-rouge">Synth(name)</code> will play the synth immediately.</li>
  <li><code class="highlighter-rouge">pbinds.scd</code> — this file defines Pbinds, which are pattern binding objects.</li>
  <li><code class="highlighter-rouge">timing.scd</code> — this file defines beat-by-beat timing patterns for the Pbinds to use. These are simply arrays.</li>
</ul>

<p>To understand Pbinds and timing, consider this UI from Ableton Live,
which defines a drum pattern visually.
(In fact, it defines the same drum pattern as the SuperCollider files.)</p>

<p><img src="/assets/ableton.png" /></p>

<p>This is a very common UI for drum programming.
Each row represents a drum sound, and each box represents a beat when that drum will play.
There are four measures in the drum pattern,
and each measure is broken up into 16 beats.
(Or a more proper phrasing, in terms of music theory,
might be to say that each measure has four beats, and each beat has four subdivisions.)</p>

<p>In this color-coded version of the Ableton image,
you could say that the blue area represents a set of drum sounds,
each of which is mapped to a set of beats in the green area.</p>

<p><img src="/assets/ableton-color-coded.png" /></p>

<p>The blue area is like SuperCollider’s pattern bindings in <code class="highlighter-rouge">pbinds.scd</code>,
and the green area is like the arrays in <code class="highlighter-rouge">timing.scd</code>.</p>

<p>Let’s zero in on these two bars of ride cymbal rhythm:</p>

<p><img src="/assets/ride.png" /></p>

<p>It’s not hard to translate that into an array.
The pattern repeats every 32 subdivisions,
so our array will need 32 elements.
The entire first bar is empty,
so the first 16 elements can just be zeros.
Since this drum pattern sequence only specifies
if a drum is on or off, the array can just hold zeros and ones.</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">ride</span> <span class="o">=</span> <span class="p">[</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
         <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
         <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
         <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>

         <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
         <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
         <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
         <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span> <span class="p">]</span></code></pre></figure>

<p>The actual SuperCollider code in <code class="highlighter-rouge">timing.scd</code> looks only slightly different:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="c1">// ride timing</span>
<span class="o">~</span><span class="nx">rideAmps</span> <span class="o">=</span> <span class="p">[</span>
  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>

  <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
  <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span>
  <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
  <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span>
<span class="p">];</span></code></pre></figure>

<p>SuperCollider uses JavaScript-style <code class="highlighter-rouge">//</code> comments,
and the <code class="highlighter-rouge">~</code> prefix indicates that a variable is global.
Global variables are used extensively in native SuperCollider,
mainly because when you’re live-coding music,
you have different namespacing priorities than you would in most other types of programming.</p>

<p>The timing file uses the “amps” term (meaning “amplitudes,” or loudnesses)
because of how <code class="highlighter-rouge">pbinds.scd</code> consumes this data:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Pbind</span><span class="p">(</span>
  <span class="err">\</span><span class="nx">instrument</span><span class="p">,</span> <span class="err">\</span><span class="nx">zaps</span><span class="p">,</span>
  <span class="err">\</span><span class="nx">dur</span><span class="p">,</span> <span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span>
  <span class="err">\</span><span class="nx">amp</span><span class="p">,</span> <span class="nx">Pseq</span><span class="p">(</span><span class="o">~</span><span class="nx">rideAmps</span><span class="p">,</span> <span class="nx">inf</span><span class="p">)</span>
<span class="p">).</span><span class="nx">play</span><span class="p">(</span><span class="nx">mainClock</span><span class="p">);</span></code></pre></figure>

<p>The <code class="highlighter-rouge">\</code> plays the same role in SuperCollider syntax that the <code class="highlighter-rouge">:</code> does in Ruby and Clojure,
so <code class="highlighter-rouge">\instrument</code> in SuperCollider means what <code class="highlighter-rouge">:instrument</code> would in Ruby or Clojure.
This is an extended example of passing keyword arguments in the classic Smalltalk or Objective-C style,
which Ruby popularized by faking it with hashes, and which Python now fully supports.
If we had been writing Ruby, the above code would have looked like this:</p>

<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">p_bind</span> <span class="o">=</span> <span class="no">PatternBinding</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span>
           <span class="ss">instrument: :zaps</span><span class="p">,</span>
           <span class="ss">dur: </span><span class="mi">1</span><span class="o">/</span><span class="mi">4</span><span class="p">,</span>
           <span class="ss">amp: </span><span class="no">PatternSequence</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">ride_amps</span><span class="p">,</span> <span class="no">INFINITY</span><span class="p">)</span>
         <span class="p">)</span>
<span class="n">p_bind</span><span class="p">.</span><span class="nf">play</span><span class="p">(</span><span class="n">main_clock</span><span class="p">)</span></code></pre></figure>

<p>In other words, the code sets up a pattern binding with the “zaps” instrument,
passes it a sequence of amplitudes based on repeating our <code class="highlighter-rouge">~rideAmps</code> array an infinite number of times,
and sets a duration of one quarter note —
which brings in music theory issues that are unfortunately a bit outside the scope of this blog post.
The good news: in practice, you can scrape by for a very long time with the assumption that the duration should always be a quarter note.
It’s not exactly true, but it’s close enough.</p>

<p>Instead of stressing out about that, let’s look at what this “zaps” thing is.
That’s defined in <code class="highlighter-rouge">synths.scd</code>:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">SynthDef</span><span class="p">(</span><span class="dl">"</span><span class="s2">zaps</span><span class="dl">"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">arg</span> <span class="nx">amp</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">modFreq</span> <span class="o">=</span> <span class="mi">15</span><span class="p">,</span> <span class="nx">carFreq</span> <span class="o">=</span> <span class="mi">880</span><span class="p">,</span> <span class="nx">modDepth</span> <span class="o">=</span> <span class="mi">3250</span><span class="p">;</span>
  <span class="kd">var</span> <span class="nx">car</span><span class="p">,</span> <span class="nx">mod</span><span class="p">,</span> <span class="nx">env</span><span class="p">;</span>

  <span class="nx">env</span> <span class="o">=</span> <span class="nx">Env</span><span class="p">.</span><span class="nx">perc</span><span class="p">(</span><span class="na">releaseTime</span><span class="p">:</span> <span class="mf">0.3</span><span class="p">).</span><span class="nx">kr</span><span class="p">(</span><span class="na">doneAction</span><span class="p">:</span> <span class="mi">2</span><span class="p">);</span>
  <span class="nx">mod</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">modFreq</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.14</span><span class="p">,</span> <span class="mf">0.97</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mf">1.04</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">],</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">modDepth</span><span class="p">);</span>
  <span class="nx">car</span> <span class="o">=</span> <span class="nx">Pulse</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="na">freq</span><span class="p">:</span> <span class="nx">carFreq</span> <span class="o">+</span> <span class="nx">mod</span> <span class="o">*</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">1.41</span><span class="p">,</span> <span class="mf">0.99</span><span class="p">,</span> <span class="mf">2.4921</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mf">1.397</span><span class="p">],</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">env</span><span class="p">);</span>
  <span class="nx">car</span> <span class="o">=</span> <span class="nx">Splay</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">car</span><span class="p">);</span>
  <span class="nx">Out</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">FreeVerb</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">HPF</span><span class="p">.</span><span class="nx">ar</span><span class="p">(</span><span class="nx">car</span><span class="p">,</span> <span class="na">freq</span><span class="p">:</span> <span class="mi">5274</span><span class="p">),</span> <span class="na">mix</span><span class="p">:</span> <span class="mf">0.05</span><span class="p">,</span> <span class="na">room</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span> <span class="na">damp</span><span class="p">:</span> <span class="mf">0.9</span><span class="p">,</span> <span class="na">mul</span><span class="p">:</span> <span class="nx">amp</span> <span class="o">*</span> <span class="mf">0.5</span><span class="p">));</span>
<span class="p">}).</span><span class="nx">add</span><span class="p">;</span></code></pre></figure>

<p>Everything passed in via the curly braces at the beginning is basically a function.
The <code class="highlighter-rouge">arg amp = 1, modFreq = 15</code> section sets up a list of named keyword arguments to the function,
along with their default values.
The name “zaps” and the <code class="highlighter-rouge">.add</code> at the end ensure that SuperCollider adds them to some kind of in-memory synth registry,
which means you can audition the sound later just by evaluating the following code:</p>

<figure class="highlight"><pre><code class="language-javascript" data-lang="javascript"><span class="nx">Synth</span><span class="p">(</span><span class="dl">"</span><span class="s2">zaps</span><span class="dl">"</span><span class="p">)</span></code></pre></figure>

<p>In practice, this is very useful.</p>

<p>I created the “zaps” sound while attempting to copy the synthesis of ride cymbals in the classic TR-808 drum machine.
I used <a href="https://www.soundonsound.com/techniques/synthesizing-realistic-cymbals">two</a>
<a href="https://www.soundonsound.com/techniques/practical-cymbal-synthesis">articles</a>
from <em>Sound On Sound</em>, the British audio engineering magazine, as my guides.
It didn’t really work, but it still sounds cool.
The two Pulse objects are supposed to function as modulator and carrier for FM synthesis.
There’s also a high-pass filter and some reverb.</p>

<p>Here’s what the zaps instrument sounds like,
playing this pattern:</p>

<iframe width="100%" height="100" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/552890046&amp;color=%23ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false&amp;show_teaser=true&amp;visual=true"></iframe>

<h2 id="to-be-continued">To Be Continued</h2>

<p>This seems like a decent stopping point for now.
In <a href="/supercollider/2019/01/04/supercollider-house-drums.html">the next post</a>, 
I explain more about how the “zaps” sound works,
but I start with an explanation of the simplest drum in the beat,
and build towards the zap sound’s complexity from there.</p>]]></content><author><name>giles bowkett</name></author><category term="supercollider" /><summary type="html"><![CDATA[There are at least three open source live-coding systems in popular languages — Sonic Pi (Ruby), Overtone (Clojure), and Tidal Cycles (Haskell) — which all share the same foundation: a system called SuperCollider. I’m going to show you how to build a basic house beat in SuperCollider.]]></summary></entry></feed>