Drum Maschine in single line

Hey Guys/Girls

I just wanna share my ideas about the drum machine.
The idea is to create something like real drum machine in a single line.

And so I wrote a simple function like this

##| define :maschine do |s_name, beats, amp, humanize, stretch|
define :maschine do |var|
  ##| set default values in case they if they are not set
  _sample = !var[0].nil? ? var[0] : "bd_house"
  _beats = !var[1].nil? ? var[1].ring : [1]
  _n = _beats.length ? _beats.length : 1
  _amp = !var[2].nil? ? var[2] : 1
  _humanize = !var[3].nil? ? var[3] : 0
  _stretch = !var[4].nil? ? var[4] : 1
  
  _n.times do
    if(_beats.tick == 1)
      sample _sample, amp: _amp, start: rrand(0, _humanize), rate: rrand(1, _stretch)
    end
    sleep 1.0 / _beats.length
  end
end

this is the way how to use it

  live_loop :beat do
      maschine [ "bd_haus",  [1, 0, 0, 0 ], 0.5, 0.002, 1.1]
  end

What you do is that you call the function it self, you tell it what sample you wanna play, you give it bunch of 1 & 0 (the number depends completely on you). The next 3 numbers are: amp, random start position (which gives the groove bit of human like feel), and the rate for funky transpositions

You can even do this
maschine [ "bd_haus"]
this will play one beat per a measure

maschine [ “bd_haus”, [1, 0, 0, 0 ]]
this will play one beat on the beginning with the time/measure equally divided by number of beats in this case it is equal to this

sample :bd_house
sleep 0.25
sleep 0.25
sleep 0.25
sleep 0.25

and so this

 live_loop :beat do
          maschine [ "bd_haus",  [1, 0, 0, 0 ]]
      end
 live_loop :beat2 do
          maschine [ "elec_blip",  [0, 1, 0 ]]
      end

will create 4/3 beat
You see that it’s even more powerful than normal beat maschine as you can use as many beats per measure as you like 1, 4, 5, 6, 19876,… if you will
(yes I have not use any of other features like: amp, start, rate that are part of the function, I just wanted to simplify the example)

Although I like the what it does in a code of “one line” I feel it has flaws. Mainly the most elementary flaw is that - while I write the line it does not autocomplete for the sample type.

If you look at it… it is basically a simple extension of the sample it self… only enhanced by the repetition.

Something like we have
play_pattern [:d3, :c1, :Eb5]

But the play_pattern is able to play melodical pattern but not rhythmical.

The ideal implementation I can think of would be:
sample :bd_ada, pattern: [1,0,0,0,1,0,1,0], amp: 1, start: 0.02, …

See that?
If the sample or synth, whatever will be extended for the “pattern” option, we will be able to create a drum maschine from every sample/synth right away… I just don’t know how to patch the sample implementation it self…
Plus My question is, if you feel anything other/better approach to that?

looking forward to hear your comments.

3 Likes

I like the idea and I expanded on it a little - but you can achieve the same thing already:

E.G.

use_bpm 100

define :maschine do |var|
  _sample = !var["sample"].nil? ? var["sample"] : "bd_house"
  _pattern = !var["pattern"].nil? ? var["pattern"].ring : [1]
  _patternlength = _pattern.length ? _pattern.length : 1
  _amp = !var["amp"].nil? ? var["amp"] : 1
  _swing = !var["swing"].nil? ? var["swing"] : 0
  _rate = !var["rate"].nil? ? var["rate"] : 1
  _bars = !var["bars"].nil? ? var["bars"] : 1
  
  _patternlength.times do
    if(_pattern.tick == 1)
      with_swing rrand(0, _swing), pulse: 8 do
        sample _sample, amp: _amp, rate: _rate
      end
    end
    
    sleep 1.0 / _pattern.length * _bars
  end
end


live_loop :kicks do
  8.times do
    maschine "sample" => :bd_haus, "pattern" => [1], "bars" => 4
  end
  
  32.times do
    maschine "sample" => :bd_haus, "pattern" => [1]
  end
end

live_loop :snares do
  maschine "sample" => :sn_dub, "pattern" => [0, 1], "swing" => 0.05
end

live_loop :synths do
  with_synth :growl do
    play [:a3, :cs4], attack: 0.25, sustain: 0.1, decay: (line 0.1, 0.5, steps: 32).mirror.tick, release: 0.1, amp: 0.8
  end
  
  sleep 1
end

V.S (does the same thing):

use_bpm 100

live_loop :kicks do
  8.times do
    sample :bd_haus, amp: 0.8, rate: 0.8 if (ring 1,0,0,0).tick == 1
    sleep 1
  end
  
  32.times do
    sample :bd_haus, amp: 0.8, rate: 0.8 if (ring 1,1,1,1).tick == 1
    sleep 1
  end
end

live_loop :snares do
  sample :sn_dub, amp: 0.8, rate: 1 if (ring 0,1,0,1).tick == 1
  sleep 0.5
end


live_loop :synths do
  with_synth :growl do
    play [:a3, :cs4], attack: 0.25, sustain: 0.1, decay: (line 0.1, 0.5, steps: 32).mirror.tick, release: 0.1, amp: 0.8
  end
  
  sleep 1
end
1 Like

Thats a lot of code, really, for a drum machine…

I didn’t write this, I think it was posted elsewhere in the
forums, so I liked it, and saved it away safe…

Eli…

  use_bpm 120
  
  cycle = (ring 2, 4, 6,8)

  live_loop :drums do
    tick
    sample :bd_tek if 5[look%4] >0
    sample :bd_klub if 3[look%5] >0
    sample :bd_boom if cycle.look[look%4] >0
    sample :elec_cymbal, rate: 3 if 10[look%4] >0
    sleep 0.5
  end
end
2 Likes

I was thinking the same thing. Here is another derivative version from yours @Eli

live_loop :drums2 do ; tick
  sample :bd_tek if bools(1, 0, 1, 0).look
  sample :bd_klub if spread(1, 5).look
  sample :bd_boom if spread(1, 8).look
  sample :elec_cymbal, rate: 3 if bools(0, 1).look
  
  sleep 0.5
end

Using two different techniques, bools and spread.

And Ring samples ^^

live_loop :drums2 do ; tick
  sample (ring :bd_tek,:elec_cymbal).look
  sample (ring :bd_klub, :bd_boom).look if spread(4, 11).look
  sleep 0.5
end

Hmmm… you know…

@notinflight posted a nice little snippet in this post…

If you jazz it up a little and trigger it off the drums, you’ve
got the basics of a dance track…

use_bpm 120
cycle = (ring 2, 4, 6,8)

live_loop :drums do
  tick
  sample :bd_tek if 5[look%4] >0
  sample :bd_klub if 3[look%5] >0
  sample :bd_boom if cycle.look[look%4] >0
  sample :elec_cymbal, rate: 3 if 10[look%4] >0
  sleep 0.5
  
  
  live_loop :looper do
    sync :drums
    use_synth [:hoover, :blade, :piano].choose
    if rand() > 0.65 then
      with_fx :ixi_techno do
        with_fx :wobble do
          play :Gs3, attack: 0.25, sustain: 0.1, decay: 0.1, release: 0.1
          sleep 0.25
          play :Fs3, attack: 0.25, sustain: 0.1, decay: 0.1, release: 0.1
          sleep 0.25
          play :A3, attack: 0.25, sustain: 0.1, decay: 0.1, release: 0.1
          sleep 0.25
          play :B3, attack: 0.25, sustain: 0.1, decay: 0.1, release: 0.1
          sleep 0.5
        end
      end
    end
  end
end

thanks for all the tips, I’ll go thru it definitely more in depth soon.

…sure we can program machine like pattern many ways… the point here is I guess to come up with the most important features for a single line function similar to play_pattern_timed used for tone based approach but this time for rhythm.
I think the rhythm deserves a simple function for fast rhythm sketches and
I found the rhythm machines and their logic a perfect example of what to achieve.
What I’m suggesting is to come up with ideas and narrow them down to a most useful functions that can be hopefully later implemented straight to the Sonic Pi.

If you look on many kinds of music and how it is programmed MPC, Push 1-2, Maschine, and the like they all use grids of samples with more or less grove. And if that will be implemented it’ll speed up our workflow a lot. Same like the play_pattern_timed does for us in melody.

so my proposal of attributes are:

  • sample name
  • amplification
  • sample start definition
  • stretch
  • beat pattern
  • automatic or/and manual time definition connected with the beat pattern

thanks again for advices…
(It would be nice if anybody knows how to patch the Sonic Pi and hacked that in .) one day.

How about something like this? The numbers in the strings represent amplitudes so that you can easily vary each drum hit…

define :str_to_amps do |s|
  s.sub("-", "0").chars.map{ |c| c.to_f / 9 }
end

define :phrase do |inst, beat, amps|
  if amps.is_a? String then
    amps = str_to_amps amps
  end
  
  in_thread do
    beat_num = 0
    amps.each { |a|
      sample inst, amp: a
      sleep beat
      beat_num += 1
    }
  end
end

use_bpm 140

live_loop :bdrums do
  phrase :drum_bass_soft, 0.5, "7-5-6---"
  phrase :drum_cymbal_closed, 0.5, "35234336"
  phrase :drum_snare_soft, 0.5, "-1-2-8-2"
  sleep 4
  tick
end
1 Like