Subsystem Search

Shaping a sound on the way out

By the end of this chapter, your kick is compressed, your hi-hat filtered, and a knob on your controller darkens the snare as you play.

The project so far

The project from Your first MIDI map: your own map, watched as it plays, with a kick by name, a snare by likeness and a hi-hat by rule.

$ mkdir kitchen-kit
$ cd kitchen-kit
$ subsample --init
…
recorder:
  enabled: true
player:
  midi_map: midi-map.yaml
  watch_midi_map: true
  enabled: true
similarity:
  weight_timbre_onset: 2
detection:
  release_threshold_db: 4
  retrigger_threshold_db: 15
  min_peak_db: -45
assignments:
  - name: My kick
    channel: 10
    notes: 36
    select:
      where:
        name: hits_1
  - name: My snare
    channel: 10
    notes: drum.snare_1
    select:
      where:
        reference: GM38_AcousticSnare
  - name: My hi-hat
    channel: 10
    notes: drum.hi_hat_closed
    select:
      where:
        duration: { lte: 0.5 }
      order: [{ by: level, dir: desc }]
      pick: velocity

A chain of processors

An assignment can change its sound before it plays: process is a list of processors, and the sound passes through them from the top down. Give the kick one:

- name: My kick
  channel: 10
  notes: 36
  select:
    where:
      name: hits_1
  process:
    - compress: true

true gives a processor its own settings. The compressor takes them from the sound it is given, as gate, distort, transient and reshape do, while the rest, such as the filters and saturate, start from fixed settings, each given on the processing page. The compressor reads each sample's level, how fast it starts and how it decays, and sets itself from those, so a kick's strike keeps its punch. Save the map and play the kick, and listen for the quieter part of its sound coming up to meet the strike: evening the two out is what compression does.

A value where you want one

true is the place to start, and a value is for when you know the one you want. A tick recorded on a worktop can carry some low thud with it, and a filter that lets through only what is above 300 Hz, as the General MIDI kit filters its hi-hats, takes it out:

- name: My hi-hat
  channel: 10
  notes: drum.hi_hat_closed
  select:
    where:
      duration: { lte: 0.5 }
    order: [{ by: level, dir: desc }]
    pick: velocity
  process:
    - filter_high: { freq: 300 }

Listen for the hi-hat losing its body and keeping its tick. The processing reference lists each processor, what it does, and every value it takes.

A knob on any setting

Wherever a processor takes a number, a controller can set it instead. Give the snare a filter that darkens it as its cutoff comes down, and put the cutoff on controller 74, which MIDI calls brightness and General MIDI 2 uses for a filter's cutoff. Set a knob on your controller to send it, if none does already:

- name: My snare
  channel: 10
  notes: drum.snare_1
  select:
    where:
      reference: GM38_AcousticSnare
  process:
    - filter_low: { freq: { cc: 74, min: 200, max: 8000 } }

The knob's travel runs from 200 Hz at the bottom to 8000 Hz at the top: cc says which controller, and min and max where its ends fall. Play the snare and turn the knob: it goes from muffled to open.

Why a change arrives a moment late

Subsample does not process a sound as each note plays. It prepares each processed version in the background, as soon as it knows it will need it, and keeps it on disk, in samples/variant-cache/, so a note plays it with nothing left to compute. Until a version is ready, a note plays the one it played last, or the sound unprocessed. So the first notes after Subsample starts, or after you change a setting or turn the knob, can come out without the change, and the notes after it have it.

With the kit shaped, the next chapter turns from drums to a keyboard played by one held sound, and a loop that stays on the beat.