# A recipe for 8 beats

**URL:** <https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639>\
**Category:** Creations & Ideas\
**Created:** [March 27, 2022, 3:15pm UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639 "2022-03-27T15:15:26Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![notb](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/notb/32/2143_2.png) [@notb](https://in-thread.sonic-pi.net/u/notb)\
**Post date:** [March 27, 2022, 3:15pm UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639/1 "2022-03-27T15:15:26Z")

</div>

trying to boil my method down further. hardly feels like composing music anymore, just kind of describe a vague structure and the rest falls in place. hopefully the comments help explain the process better.

```ruby
# arbitrary settings, sounds nice to me
use_bpm 99
r = :f1 # root note

# drums n bass in the same loop
# doing an 8 beat pattern
live_loop :dnb do
  
  # first 4 beats are basic
  use_synth :tri
  play r, release: 2.1
  sample :bd_tek
  sleep 2
  sample :sn_dolf, amp: 0.5
  sleep 2
  
  # downbeat of 2nd bar
  play r, release: 0.5
  sample :bd_tek
  
  # next 4 are random snare fills and bass runs using one_in
  sleep 0.5
  14.times do
    play (chord r, :major7).pick, release: 0.3, on: (one_in 5)
    sample :sn_dolf, amp: 0.3, beat_stretch: 0.2 + rand(0.8), on: (one_in 5)
    sleep 0.25
  end
end

# slicer on everything else to cut a hole on the downbeat for a bigger bass and kick
with_fx :slicer, phase: 4, pulse_width: 0.01, smooth_down: 0.02, smooth_up: 3.5, invert_wave: 1 do
  with_fx :reverb, room: 0.9, mix: 0.8 do
    # air is the very slow atttack, harmonic element that fills space
    live_loop :air do
      use_synth :mod_tri
      use_synth_defaults mod_range: 0.4, mod_phase: 1/9.0, mod_phase_slide: 8, mod_wave: 2
      # pick a random note from the scale, turn it into a big chord
      n = play (chord (scale r+24, :major_pentatonic, num_octaves: 2).pick[0], :major, num_octaves: 2), attack: 6, amp: 0.5
      sleep 1
      # gradually slows the vibrato down
      control n, mod_phase: 1
      sleep 7
    end
  end
  
  # a smaller reverb space than air
  with_fx :reverb, room: 0.7, mix: 0.5 do
    # arp is the melodic element, an arppeggio that occasionally reaches higher octaves
    live_loop :arp do
      32.times do
        use_synth :mod_fm
        # random params for weird modulations
        use_synth_defaults divisor: 0.1+rand(0.6), release: 0.4, mod_phase: 1/(1.0+rand_i(3)), mod_wave: 2, mod_range: 0.5
        # the random octave range is the melodic variation
        play (chord r+24, :major7, num_octaves: 1+rand(3)).tick, amp: 0.01 + rand(0.5)
        sleep 0.5
      end
      # reset to root note on downbeat
      tick_reset
    end
    
    # splash on the downbeat to give it some sparkle
    live_loop :splash do
      sample :drum_splash_soft, amp: 0.3
      sleep 8
    end
    # a hat to bring out a little syncopation
    live_loop :hat do
      sleep 1
      sample :drum_cymbal_closed, amp: 0.7
      sleep 1
    end
  end
end

```

---

<div class="post-metadata">

**Author:** ![Loopiloop](https://dub1.discourse-cdn.com/flex017/user_avatar/in-thread.sonic-pi.net/loopiloop/32/2094_2.png) [@Loopiloop](https://in-thread.sonic-pi.net/u/Loopiloop)\
**Post date:** [March 28, 2022, 7:08am UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639/2 "2022-03-28T07:08:32Z")

</div>

This sounds amazing. Keep up the good work.

---

<div class="post-metadata">

**Author:** ![shemp](https://avatars.discourse-cdn.com/v4/letter/s/ba8739/32.png) [@shemp](https://in-thread.sonic-pi.net/u/shemp)\
**Post date:** [March 28, 2022, 12:35pm UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639/3 "2022-03-28T12:35:24Z")

</div>

One old idea is to generate notes (or chords, rhythms, etc.) using a combinatorial constraint solver. For instance, let’s “compose” some notes:

```ruby
N = [40, 52, 50, 47, 54, 47, 50, 52, 40, 52, 50, 47, 54, 47, 50, 52]

```

To make it more interesting, we “tell” the computer to automatically add a couple of voices (this is a quickly coded stupid example, but you get the philosophy, namely to give the computer instructions rather than specific notes):

```ruby
require 'winston'

use_bpm 80

define :myplay do |n, t|
  a = 0.95
  use_synth :dsaw
  use_synth_defaults amp: 0.6, cutoff: 100
  play n, sustain: a*t, release: (1.0-a)*t
  sleep t
end

NNN = [:e2, :e3, :d3, :b2, :fs3, :b2, :d3, :e3].map {|n| note(n)}*2

CONS = [3,4,7,8,9,12,15,16]

define :sol1 do
  output = Array.new
  
  csp = Winston::CSP.new
  
  D = (scale :e2, :minor, num_octaves: 3).to_a.map { |x| note(x) }
  
  (0..NNN.size-1).each do |i|
    csp.add_variable({ n: i}, domain: D)
    csp.add_variable({ m: i}, domain: D)
  end
  variables = csp.variables.keys
  NNN.each_with_index do |n,i|
    the_note = variables.select { |x| x[:n] == i }
    the_note2 = variables.select { |x| x[:m] == i }
    
    csp.add_constraint(the_note) { |x| CONS.include?((x-n)) }
    csp.add_constraint(the_note2) { |x| (CONS+CONS.map {|n| n+12}).include?((x-n)) }
    csp.add_constraint(the_note, the_note2) { |x,y| CONS.include?((y-x)) }
  end
  
  (1..NNN.size-1).each do |i|
    prev_note = variables.select { |x| x[:n] == i-1 }
    next_note = variables.select { |x| x[:n] == i }
    prev_note2 = variables.select { |x| x[:m] == i-1 }
    next_note2 = variables.select { |x| x[:m] == i }
    csp.add_constraint(prev_note, next_note) { |x,y| [1,2,3,4,5,7,12].include?((x-y).abs) }
    csp.add_constraint(prev_note2, next_note2) { |x,y| [1,2,3,4,5,7,12].include?((x-y).abs) }
    
    csp.add_constraint(prev_note, next_note, prev_note2, next_note2) { |x,y,z,w|
    !(((x-y)%12==7)&&((z-w)%12==7)) }
    csp.add_constraint(prev_note, next_note, prev_note2, next_note2) { |x,y,z,w|
    !(((x-y)%12==0)&&((z-w)%12==0)) }
    csp.add_constraint(prev_note, next_note) { |z,w| x = NNN[i-1]; y = NNN[i]; !(((x-y)%12==7)&&((z-w)%12==7)) }
    csp.add_constraint(prev_note2, next_note2) { |z,w| x = NNN[i-1]; y = NNN[i]; !(((x-y)%12==7)&&((z-w)%12==7)) }
    csp.add_constraint(prev_note, next_note) { |z,w| x = NNN[i-1]; y = NNN[i]; !(((x-y)%12==0)&&((z-w)%12==0)) }
    csp.add_constraint(prev_note2, next_note2) { |z,w| x = NNN[i-1]; y = NNN[i]; !(((x-y)%12==0)&&((z-w)%12==0)) }
    
  end
  sol = csp.solve
  output = Array.new
  output2 = Array.new
  (0..NNN.size-1).each do |i|
    a_note = variables.select { |x| x[:n] == i }
    b_note = variables.select { |x| x[:m] == i }
    output.append sol[a_note[0]]
    output2.append sol[b_note[0]]
  end
  return [output, output2]
end
ss = sol1
NNN.each { |n| myplay n, 0.25 }
in_thread { NNN.each { |n| myplay n, 0.25 }}
ss[0].each { |n| myplay n,0.25 }

in_thread { NNN.each { |n| myplay n, 0.25 }}
in_thread { ss[0].each { |n| myplay n,0.25 }}
ss[1].each { |n| myplay n,0.25 }
stop

```

---

<div class="post-metadata">

**Author:** ![Omphaloskeptic](https://avatars.discourse-cdn.com/v4/letter/o/bcef8e/32.png) [@Omphaloskeptic](https://in-thread.sonic-pi.net/u/Omphaloskeptic)\
**Post date:** [April 3, 2022, 4:28pm UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639/4 "2022-04-03T16:28:40Z")

</div>

What is ‘winston’? I get an error and thread death on line 1. I tried doing ‘gem install winston’ in Terminal and then restarting Sonic Pi, but, same result

---

<div class="post-metadata">

**Author:** ![shemp](https://avatars.discourse-cdn.com/v4/letter/s/ba8739/32.png) [@shemp](https://in-thread.sonic-pi.net/u/shemp)\
**Post date:** [April 3, 2022, 6:34pm UTC](https://in-thread.sonic-pi.net/t/a-recipe-for-8-beats/6639/5 "2022-04-03T18:34:38Z")

</div>

It is a random gem I grabbed when looking for a constraint solver for the purposes of creating a quick example. There is probably a much better gem to use, but we get some sounds 🙂 You need to make sure it shows up in your gem path, e.g. try starting Sonic Pi from the same terminal where the gem is installed and shows up in `gem list`.

For a concrete example, I gave it the original notes

```ruby
 [40, 42, 43, 45, 43, 42, 40, 40, 40, 42, 43, 45, 43, 42, 40, 40]

```

and, with the above sample constraints (E minor scale, consonant intervals between voices, no parallel fifths…) it comes up with the (slightly unfortunate, in fact I see a number of bugs in the code I posted before) solution

```ruby
 ├─ [40, 42, 43, 45, 43, 42, 40, 40, 40, 42, 43, 45, 43, 42, 40, 40]
 ├─ [43, 45, 47, 48, 47, 45, 43, 47, 43, 45, 47, 48, 47, 45, 43, 47]
 ├─ [52, 57, 55, 60, 55, 57, 52, 55, 52, 57, 55, 60, 55, 57, 52, 55]

```

Anyway, with some proper coding some old examples could be adapted into Ruby, e.g. see here: [Strasheela Examples](http://strasheela.sourceforge.net/strasheela/doc/StrasheelaExamples.html)

This is all merely supposed to be in the original poster’s philosophy of “describe a structure” and let the computer fill in the notes
