Synth Jam 6 | bitstream hymn

Friday, June 26th 2020, 12:47:07 am

Recording Notes

For this episode of the synth jam series, I brought the laptop back into the mix. Specifically, to use SonicPi as my AI drummer. SonicPi sends a generative stream of drum hits to the Digitakt via usb+midi. I then played over it for a bit. Eventually, I let the digitakt record the inputs from sonicpi events as midi tracks. once I had two measures-worth of events, I stopped sonicpi and let the digitakt repeat the last 2 measures of beat. I then layered a few synth parts on top.

Programming Notes

This AI autodrummer script for SonicPi and Digitakt can be used to control your digitakt automatically via USB+MIDI. This will send generative “beats” to your Digitakt hence the name “autodrummer”.

It assumes that your sample pads 1-8 are mapped to MIDI channels 1-8.

This is the instrument to channel mapping and can be re-configured accordingly:

DTAKT = {
  bd: 1,
  sn: 2,
  lo_tom: 3,
  clap: 4,
  cb: 5,
  hat: 6,
  open_hat: 7,
  cymb: 8,
}

The USE_MIDI boolean can be set to false to debug using the SonicPi instruments. On first run, I recommend setting USE_MIDI=false in order to ensure the script runs as expected.

Code

# sonicpi_autodrummer_for_digitakt.rb

use_bpm 75

T = 4.0

# MIDI clock
live_loop :m_clock do
  midi_clock_beat
  sleep T/4.0
end

### AI Drummer

M = 4.0

# velocity adjustments
kick_vel_scaling = 1.75
snare_vel_scaling = 1.5

# determines whether hihats ignore level changes
persist_hihats = false

# Toggle Using SonicPI synths or external MIDI instruments
USE_MIDI = true

# DIGITAKT mappings
DTAKT = {
  bd: 1,
  sn: 2,
  lo_tom: 3,
  clap: 4,
  cb: 5,
  hat: 6,
  open_hat: 7,
  cymb: 8,
}

# Initial States
set :ch, 1

# Level Transitions
LV = {
  0 => [1,1,1,0],
  1 => [0,0,1,1]
}

LEVELS = {
  hats: 1,
  kicks: 1,
  snares: 1,
  claps: 1
}

# Update Levels
live_loop :levels do
  LEVELS.each {|k,v| LEVELS[k] = LV[v].sample }
  sleep M/1
end

rhythm = range(0,16).ring
durations = (ring, 16)
##| melody = make_melody(48)
set :rh, 0

### Utility Functions

define :tr do |inst, dur = (T/4), vel = 5.0, n = 0|
  vel /= 10.0
  n_chan = DTAKT[inst] # send to a particular midi channel, assumes pads 1-8 are mapped to channels 1-8
  port_a = 'elektron_digitakt_digitakt_out_1' # main port

  n = :C2 # assumes middle C is the "default" pitch, but this can be adapted for different tunings
  if vel > 0.1 # assumes velocity gt 0.1 is a "hit"
    (midi n, vel_f: vel, port: port_a, sustain: dur, channel: n_chan) if n_chan
  end
end

### STATE TRANSITIONS -- these are tuples of each note's possible frequency of occurence
kick_dur = [
  [4, 1],
  [8, 2],
  [3, 2],
  [12, 3],
]

kicks = [
  ringify('1000 0000 1000 0000')
]

hats = [
  [16, 4],
  [16, 4],
  [16, 4],
  [32, 8],
  [48, 12],
  [12, 3]
].ring

snare_dur = [
  [4, 1],
  [4, 1],
  [4, 1],
  [4, 1],
  [8, 2],
  [12, 3],
  [24, 3],
  [64, 4],
  [128, 8],
].ring

snares = [
  ringify('0000 1000 0000 1000')
]


live_loop :ht do
  h = hats.tick
  h[1].times do
    if persist_hihats
      l = 3.0
    else
      l = 3.0 * LEVELS[:hats]
    end
    ##| (sample :elec_tick, amp: l) if not USE_MIDI
    (tr :hat, M/16, l) if USE_MIDI
    sleep M/h[0]
  end
end

live_loop :bt do
  r = rhythm.tick

  # Kicks
  in_thread do
    s = kicks[0][r]
    if s == 1
      d = kick_dur.choose
      d[1].times do |n|
        l = ((8.0 / ((n*2)+1)) * LEVELS[:kicks]) * kick_vel_scaling
        (sample :bd_fat, amp: l) if not USE_MIDI
        (tr :bd, M/d[0], l) if USE_MIDI
        sleep M/(d[0])
      end
    end
  end

  # Snares
  in_thread do
    s = snares[0][r]
    if s == 1
      d = snare_dur.choose
      d[1].times do |n|
        l = (4.0 / ((n*2)+1) * LEVELS[:snares]) * snare_vel_scaling
        dur = M/d[0]
        (sample :sn_dolf, amp: l) if not USE_MIDI
        (tr :sn, dur, l) if USE_MIDI
        sleep dur
      end
    end
  end

  ##| Claps
  in_thread do
    s = snares[0][r]
    if s == 1
      l = 4.0 * LEVELS[:claps]
      (sample :sn_dolf, amp: l) if not USE_MIDI
      (tr :clap, M/16, l) if USE_MIDI
    end
  end
  sleep M/16
end

Omar Delarosa avatar

Written by Omar Delarosa who lives in Brooklyn and builds things using computers.

Add me on LinedInFollow me on GithubFollow me on TumblrFollow me on Twitter