General Purpose Drumkit

@alexesc I agree. And there’s lots of downside to hardware besides the cost - like it can break or get stolen, which is a real issue for gigging musicians. Always getting kit nicked. For a lot of people a computer is a sunk cost.

For me, since the virus I’m really missing the physicality of playing out. Well, not lugging a drum kit round but the playing. It was time not spent at the computer, which was a plus. I’m thinking a bit of kit might be good in that regard.

Bui the ‘not too much money on kit’ vibe is one of the reasons I’d like to use Raspberry Pi as much as possible rather than a high end PC. I’ve had a start look at PureData - my question is have you got that working from SPi?

And here’s my final word on the OP (until the next final word) incorporating all the goodness I’ve picked from here last few days.

It strikes a perfect balance between a drummer’s view of the world where you carefully place hits on beats, and the electronic world of random beats :stuck_out_tongue_winking_eye: ha ha ha. I’ve put in an XOR on each instrument and each beat using the lovely one_in() function. A value of 0 means it’s as written, unchanged (my world) - a large value gives bit of random - a low value gives chaos (your world) :smile:

#General purpose drum kit

use_bpm 120

live_loop :main do
  sleep 4
  cue :bar
end

live_loop :drumkit do
  sync :bar
  
  #Instrument Probs
  p1=[0,0,0,0,0,0] #Threshold for playing bar 0=always 6=never
  p2=[6,6,6,6,6,0] #Prob on each beat 0=no change, 1=lots, 100=little
  v =[5,4,3,3,1,5] #Volume
  a =0.5
  
  perc  = "x---------------"
  open  = "---------------x"
  hihat = "xxxxxxxxxxxxxxxx"
  pedal = "----x-----------"
  snare = "------------x---"
  kick  = "x---x---x---x-x-"
  
  inst = [kick, snare, pedal, hihat, open, perc]
  
  samp  = [:bd_fat,
           :sn_zome,
           :drum_cymbal_pedal,
           :drum_cymbal_soft,
           :drum_cymbal_open,
           :perc_bell]
  
  with_fx :reverb, mix: 0.2 do
    with_fx :echo, mix: 0.1 do
      i=0
      6.times do
        if dice(6)>p1[i] then
          in_thread do
            j=i
            16.times do
              sample samp[j], amp: a*v[j] if (inst[j][tick]=="x") ^ one_in(p2[j])
              sleep 0.25
            end
          end
        end
        i+=1
      end
    end #echo
  end #verb
end #drumkit
2 Likes

Here’s a demo track, all standard samples

5 Likes

OK, this is the real final word. As usual I look back a few days later and think d’Oh.

Now available with just one thread. What was I thinking.

#General purpose drum kit

use_bpm 120

live_loop :main do
  sleep 4
  cue :bar
end

live_loop :drumkit do
  sync :bar
  
  #Instrument Probs
  p1=[0,0,0,0,0,0] #Threshold for playing bar 0=always 6=never
  p2=[0,0,0,0,0,0] #Prob on each beat 0=no change, 1=lots, 9=little
  v =[5,5,5,5,3,2] #Volume
  a =0.5
  
  perc  = "x-x--x--x--x----"
  open  = "----x-------x---"
  hihat = "x-x-x-x-x-xxxxxx"
  pedal = "-x-x-x-x-x-x-x-x"
  snare = "------------x---"
  kick  = "x---x---x---x-x-"
  
  inst = [kick, snare, pedal, hihat, open, perc]
  
  samp  = [:bd_zum,
           :elec_blip2,
           :elec_plip,
           :elec_fuzz_tom,
           :elec_mid_snare,
           :elec_bong]
  
  with_fx :reverb, mix: 0.3 do
    with_fx :echo, mix: 0.1 do
      in_thread do
        16.times do
          i=0
          tick
          6.times do
            if dice(6)>p1[i] then
              sample samp[i], amp: a*v[i] if (inst[i][look]=="x") ^ one_in(p2[i])
              i+=1
            end
          end
          sleep 0.25
        end
      end
    end
  end
end #drumkit

Or even this compact format which is bit simpler and immediate for live

#General purpose drum kit (Compact)
use_bpm 120

live_loop :main do
  sleep 4
  cue :bar
end

live_loop :drumkit do
  sync :bar
  
  s  = [:bd_zum,
        :elec_blip2,
        :elec_plip,
        :elec_fuzz_tom,
        :elec_mid_snare,
        :elec_bong]
  
  with_fx :reverb, mix: 0.3 do
    with_fx :echo, mix: 0.1 do
      in_thread do
        16.times do
          tick
          sample s[5], amp: 0.4 if ("--x---x---x---x-"[look]=="x") ^ one_in(6)
          sample s[4], amp: 1.0 if ("---x------------"[look]=="x")
          sample s[3], amp: 0.5 if ("------------x-x-"[look]=="x")
          sample s[2], amp: 0.5 if ("------------x---"[look]=="x")
          sample s[1], amp: 0.5 if ("----x-----------"[look]=="x")
          sample s[0], amp: 0.7 if ("x---x---x---x---"[look]=="x") ^ one_in(6)
          sleep 1.0/4
        end
      end
    end
  end
end

that´s sick, but what´s the difference to using bools?

Fewer commas? :smile: Functionally no difference, but I like the look of the matrix/block for editing live. More intuitive for me.

If our code is to be on show - and about time! - it’s got to look pretty. Most programmers I know are a bit obsessed with their code structures being elegant. Normally not many people get to see it though.

I mentioned @binarysweets code looked especially satisfying - you can ‘hear’ the track in the way it’s presented in the file

I can’t let this one lie. While I like the randomness injected using the one_in() function, sometimes it did feel a bit too chaotic in some pieces. So I’ve augmented my general purpose drumkit to have a ‘mask’ type of function. So I can deterministically chose where in the bar variations are to go, then optionally apply a bit of randomness to that.

I can edit the mask for live playing. It gives a nicer feel - setting up a new pattern variation that I can let run for a bit. If I hear something I like, I can let it run for a few bars before changing it.

Ideally I would like something like the ‘Turing Machine’ eurorack module, where you can let it produce patterns itself, and you can lock it when you hear a good one. Not sure I can code that in SPi because of the immutable arrays.

define :r0 do
  "1---2x--3---4-x-".ring.tick(:r0)=="x" and one_in(2)
end
#Drumkit with variations

use_bpm 120

live_loop :drumtest do
  cue :bar
  sleep 4
end

#Variation masks
define :r0 do
  "1---2x--3---4-x-".ring.tick(:r0)=="x" and one_in(2)
end

define :r1 do
  "1---2--x3---4xxx".ring.tick(:r1)=="x" and one_in(2)
end

live_loop :drums do
  sync :bar
  #stop
  a = 1.0
  n = tick(:bar)
  s = [:drum_bass_hard,
       :drum_snare_hard,
       :drum_cymbal_closed,
       :ambi_swoosh,
       :elec_filt_snare,
       :elec_blip,
       :elec_blip2]
  
  sample :ambi_swoosh if false
  
  define :p do |i|
    case i
    when 0
      sample s[i], beat_stretch: 1.5, amp: a*0.3
    when 1
      sample s[i], amp: a*0.2
    when 2
      sample s[i], beat_stretch: 1, amp: a*0.1*[2,1,1,1].ring.tick(:hat)
    when 3
      sample s[i], beat_stretch: 0.5, amp: a*0.1
    when 4
      sample s[i], beat_stretch: 2, amp: a*0.1
    when 5
      sample s[i], beat_stretch: 1.5, amp: a*0.1
    when 6
      sample s[i], beat_stretch: 1, amp: a*0.05
    else
      sample s[i], beat_stretch: 1, amp: a*0.1
    end
  end
  
  
  with_fx :echo, mix: 0.1, phase: 0.75, decay: 6 do
    with_fx :lpf, cutoff: 130 do
      in_thread do
        16.times do
          tick
          p(0) if ("x-----x-x-------"[look]=="x") ^ r0 #^ one_in(24)
          p(1) if ("----x-------x---"[look]=="x") ^ r1 #^ one_in(24)
          p(2) if ("xxxxxxxxxxxxxxxx"[look]=="x") #^ one_in(0)
          #p(3) if ("----x-------x---"[look]=="x") #^ one_in(0)
          #p(4) if ("-------x--x-----"[look]=="x") ^ one_in(24)
          #p(5) if ("------x---x-----"[look]=="x") ^ one_in(18)
          p(6) if ("-x--x--x--x-----"[look]=="x") ^ one_in(16)
          sleep 1.0/4
        end
      end
    end
  end
end

A while ago I created a simple sequencer. Finding good sequences and repeating/storing these was kind of the main idea (actually you record the sequences by storing a ring of random seeds in :rand). Maybe you can use that…

1 Like

Thank you @Martin that pushed me to do something using push. So this gives me a set of r(i) functions that I can use i the drumkit, that lock but I can vary by changing the seed and hitting alt-R.

Lots of scope for doing that manually or automating it. Very helpful, thanks!

use_random_seed 14
x=[]
for i in 0..6
  x[i]=[]
  for j in 0..15
    x[i].push(one_in(12))
  end
end
define :r do |i|
  x[i].tick(:rtick)
end

or

x=[]
live_loop :varydrums do
  use_random_seed [1,2,3,4].ring.tick
  for i in 0..6
    x[i]=[]
    for j in 0..15
      x[i].push(one_in(12))
    end
  end
  sleep 16
end
define :r do |i|
  x[i].tick(:rtick)
end
1 Like

Ah, in fact even just setting use_random_seed in loop gives some nice locking. Even easier, maybe this is better. I’ll find a use for all these things.

with_fx :echo, mix: 0.1, phase: 0.75, decay: 12 do
    in_thread do
      use_random_seed 4
      16.times do
        tick
        p(0) if ("x-------x---x---"[look]=="x") or one_in(8)
        p(1) if ("------x---x-----"[look]=="x") ^ one_in(24)
        p(2) if ("------------xxxx"[look]=="x") ^ one_in(4)
        #p(3) if ("------xx--------"[look]=="x") #^ one_in(16)
        #p(4) if ("-----------x--x-"[look]=="x") ^ one_in(16)
        #p(5) if ("--------------x-"[look]=="x") #^ one_in(0)
        #p(6) if ("--------x---x---"[look]=="x") #^ one_in(0)
        sleep 1.0/4
      end
    end
  end