Drum transcriptions || Notation

Hi everyone,
studying the
http://doc.sccode.org/Tutorials/Streams-Patterns-Events3.html tutorial, I found a nice example showing one way to write for a monophonic instrument, specifically for drum.

(
SynthDef( \help_SPE3_Mridangam, { |out, t_amp|
    var sound;

    sound = Resonz.ar(
        WhiteNoise.ar(70) * Decay2.kr( t_amp, 0.002, 0.1 ),
        60.midicps,
        0.02,
        4
    ).distort * 0.4;

    Out.ar(out, sound);
    DetectSilence.ar(sound, doneAction: Done.freeSelf);
}).add;

SynthDef( \help_SPE3_Drone, { |out|
    var sound;
    sound = LPF.ar(
        Saw.ar([60, 60.04].midicps)
        +
        Saw.ar([67, 67.04].midicps),
        108.midicps,
        0.007
    );
    Out.ar(out, sound);
}).add;
)

    (
    // percussion solo in 10/8

    var stream, pat, amp;

    pat = Pseq([
        Pseq(#[0.0], 10),

        // intro
        Pseq(#[0.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2),
        Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0], 2),
        Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.2, 0.0, 0.2, 0.0, 0.0], 2),
        Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.2, 0.0, 0.2], 2),

        // solo
        Prand([
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.2, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.2]),
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.2, 0.2, 0.0, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.2, 0.7, 0.2, 0.0]),
            Pseq(#[0.9, 0.2, 0.2, 0.7, 0.2, 0.2, 0.2, 0.7, 0.2, 0.2]),
            Pseq(#[0.9, 0.2, 0.2, 0.7, 0.2, 0.2, 0.2, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.2, 0.2, 0.2, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.4, 0.0, 0.4, 0.0, 0.4, 0.0, 0.4, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.4, 0.0, 0.0, 0.4, 0.2, 0.4, 0.2]),
            Pseq(#[0.9, 0.0, 0.2, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.0, 0.0, 0.7, 0.0, 0.0]),
            Pseq(#[0.9, 0.7, 0.7, 0.0, 0.0, 0.2, 0.2, 0.2, 0.0, 0.0]),
            Pseq(#[0.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
        ], 30),

        // tehai : 7 beat motif 3 times sharing 1st beat with next 7x3
        // and again the third time:
        //   123456712345671234567                   123456712345671234567
        //                       123456712345671234567
        //   !                   !                   !                   !
        //   1234567890123456789012345678901234567890123456789012345678901
        Pseq(#[2.0, 0.0, 0.2, 0.5, 0.0, 0.2, 0.9,
            1.5, 0.0, 0.2, 0.5, 0.0, 0.2, 0.9,
            1.5, 0.0, 0.2, 0.5, 0.0, 0.2], 3),
        Pseq(#[5], 1),    // sam

        Pseq(#[0.0], inf)
    ]);

    stream = pat.asStream;

    Task({
        Synth(\help_SPE3_Drone);
        loop({
            if( ( amp = stream.next ) > 0,
                { Synth(\help_SPE3_Mridangam, [ \t_amp, amp ]) }
            );
            (1/8).wait;
        })
    }).play
    )

In this example is used the amplitude to write silences, notes with different dynamics and accents.
Every note lasts 1/8…

Okay, so if someone would love to transcribe a piece for snare drum like this one:

And then apply algorithmic variations, it could become extremely long and tedious to write in separate arrays the notes length and the related dynamics.
I’m pretty sure I’m not the first one facing this kind of problem, I saw that exists Panola for writing with notes c - d - e… And length of them, but not specifically dynamic values.(Or maybe it’s possible with custom functions?)

I also saw that SC supports a variation of Mikael Laurson’s rhythm list RTM-notation.1
it’s not super intuitive … even if it is very powerful and integrated using lilycollier http://bernardobarros.com/files/lilycollider-sc2013/slides.pdf

I kindly ask you if you know a nice way to write for monophonic drum specifying dynamics.
ideally like that:

Pseq(((1/16).amp(0.3)!8)++((1/9).amp(1.0)!1)++(1/9).amp(0.4)!8)),inf);

Or if there is something to write the score in a notation software and then translate the parameters in arrays.

Or if it’s better to use midi files.

Or… ?

Thanks in advance like always.

2 Likes

Disclaimer: I don’t know of any established technique or best practice + it’s not something I’m experienced in.

Anyway, I thought you could make an ad-hoc function to accommodate the way you want to write. The idea is to you write an array with as little information as you feel it’s essential to write, and get a longer array, like the ones you show at the beginning. At least you wouldn’t have to write all the zeros.
And then: what if your functions gives [dur,amp] pairs? I think it would be nice (if you don’t want to, say, keep accents’ positions and change the rhythmic divisions, then more work is needed, but again, you can make your function work for you)

~getDurAmpPairs = {|spec|
    
    spec.asArray.collect{|hit|
        // you can specify a hit as (dur:amp)
        try{ hit.asKeyValuePairs }
        // or just dur. then it uses a default amp of 0.1
        { [hit,0.1] }
    }
}

~bars = [
    [3, (2:1), 2], 
    [1,(1:0.5),(2:0.2),3],
    [(2:1),3],
    [2,(3:1),4],
].collect(~getDurAmpPairs.(_)).flatten;

Pbind(
    [\dur,\amp],Pseq(~bars)
).play

then it would be possible to make it polyrhytmic like this:

~getDurAmpPairs = {|input|
    var seq, durScale;
    if(input.respondsTo(\key)){
        seq = input.value;
        durScale = input.key;
    }{
        seq = input;
        durScale = 1;
    };
    seq.asArray.collect{|hit|
        // you can specify a hit as (dur:amp)
        if(hit.repondsTo(\asKeyValuePairs)){
            hit.asKeyValuePairs * [durScale, 1]
        }{
        // or just dur. then it uses a default amp of 0.1
        [hit*durScale,0.1] 
        }
    }
}

~bars = [
    (1/3)->[3, (2:1), 2],  // on the triplet
    (1/5)->[1,(1:0.5),(2:0.2),3], // on the quintuplet
    (1/4)->[(2:1),3], // on the sixteenth
    [2,(3:1),4], // on the quarter notes
];

I admit it doesn’t look soooo clear, but somehow we need to put information into not so much space, and without colors or shapes… or you could write a pre-processor that parses strings you put together in a language you invent.
Many people went that way too!
In both approaches, what I think it’s nice is that the language grows with you and you can tailor it to your specific needs

2 Likes

Hi,

Panola supports specifying volume to notes if you’d like to use it, e.g.
Panola(“a4_8@vol[0.6]”)

vol stands for volume normally varies between 0 and 1.

Alternatively, you could develop your own domain specific notation. An example appears here:
http://sccode.org/1-5da It uses uppercase X and lowercase x to indicate differences in dynamics, but you could add any number of symbols to your liking.

2 Likes

@jamshark70 might want to comment here. His ddwChuklib probably has something like this in compact notation. If I understood his approach correctly, there are some “hardcoded” symbols (e.g. | for bar separation) and some defined by user for each BP e.g. x could do one thing and X another etc.


Additional comment here on the slides from the original question

There are obvious ways to do that in the base SC pattern notation (Pseq, Ppar) and even at Event level (strummed notes in an array.)

Also, I thought LilyCollider (mentioned later on in the slides) is a SC fork, but apparently I’m confusing that with some other project (that I don’t recall what it’s called right now.)

Later on it gives less trivial examples from LilyCollider v2:

Lily("<c’ des’ gih’>") // chords
Lily("4. 8 8 8") // just the rhythm
Lily("3/2{ 8 8 8 }") // tuplets
Lily("fff mp f pp") // just dynamics

Alas these aren’t explained further in terms of semantics in the slides, so you’d need familiarity with LilyPond, I assume. E.g their page for rhythm notation (fairly complex). I don’t know if LilyCollider supports any of the more specialized drum notations from LiliPond though; the slides don’t mention that.

The slides then discuss SuperFomus, which is some kind of auto-quantization; related questions here on that Lilycollider or superfomus?, Tips for organising polyphonic compositions? and Time-aware merging of two Event Pattern streams. (Having a first look at FOMUS’ documentation, my first impression is that of a Csound score notation “on steroids”, including macros etc.)

Now if only someone did a Songsterr interface for SC :wink:

1 Like

Indeed, it’s quite well suited to this type of sequencing.

s.boot;

\loadCl.eval;

// set up
(
SynthDef( \help_SPE3_Mridangam, { |out, t_amp|
	var sound;
	
	sound = Resonz.ar(
		WhiteNoise.ar(70) * Decay2.kr( t_amp, 0.002, 0.1 ),
		60.midicps,
		0.02,
		4
	).distort * 0.4;
	
	Out.ar(out, sound.dup);
	DetectSilence.ar(sound, doneAction: Done.freeSelf);
}).add;

BP(\mr).free;
PR(\abstractLiveCode).chuck(BP(\mr), nil, (
	event: (eventKey: \default),
	defaultParm: \amp,
	parmMap: (
		amp: (
			alias: \t_amp,
			$X: 0.9, $x: 0.7, $-: 0.4, $.: 0.2
		)
	),
	defaults: (instrument: \help_SPE3_Mridangam)
));

TempoClock.schedAbs(TempoClock.nextBar, { TempoClock.beatsPerBar = 5 });
TempoClock.tempo = 4;
)

/mr.i1 = "X";
/mr.i2 = "X  . |  .  ";
/mr.i3 = "X  . |. .  ";
// i4 same as i2

// only doing 5 of the solo options, you can do the rest
/mr.s1 = "X  x |. x  ";
/mr.s2 = "X. x |. x  ";
/mr.s3 = "X  x |. x .";
/mr.s4 = "X  x |..x  ";
/mr.s5 = "X..x.|..x..";

/mr = (i1.i2.i3.i2.(s1|s2|s3|s4|s5)*1000000);

/mr+

// listen for awhile, then
/mr-

Or, the solo part could be written like this:

// "_" is undefined, so it acts as a true rest
// (space is only a timing placeholder, not rendered into the \seq strings)
/mr.solo = "\ins(\rand("\seq("X__x_|._x__")\seq("X._x_|._x__")\seq("X__x_|._x_.")\seq("X__x_|..x__")\seq("X..x.|..x..")"), 10, 0.5)";

/mr = (solo);

/mr+

// or algorithmically ornament the accented rhythmic backbone
/mr.solo = "[X  x |  x  ]::\ins(".", 1..3, 0.5)";

/mr-

hjh

1 Like

Really thanks to everyone,
I’m trying different ways to do it.

  • with @elgiano functions

      (
      ~getDurAmpPairs = {|spec|
    
          spec.asArray.collect{|hit|  // you can specify a hit as (dur:amp)
              try{ hit.asKeyValuePairs }
    
      		{ [hit,0.4] }.debug("~getDurAmpPairs"); // or just dur. then it uses a default amp of 0.1
          }
      }
      )
    
    
      (
      Ndef(\monitor){
          var trigs = InBus.kr(~lightsBus, 3, 0);
      	Mix(Compander.ar( Pan2.ar( SinOsc.ar(72.midicps)*Decay2.kr(trigs.linlin(0.3,1.0,0.0,1.0), 0.02,0.1),
      		1-trigs
      	),[-1,1])/40);
      }.play;
      )
    
      (
      Ndef(\monitora){
          var trigs =  InBus.kr(~lightsBus, 2, 3);
      	Mix(Compander.ar( Pan2.ar( BPF.ar(WhiteNoise.ar(),1500)*Decay2.kr(trigs.linlin(0.3,1.0,0.0,1.0), 0.02,0.1)),[-1,1])/40);
      }.play;
      )
    
      (
      Pbindef(\drumtranscript,
          \instrument, \DcOuts,
      	\stretch,4,
      	\legato,1,
      	\bus,Pseq([(0..2)],inf) + ~lightsBus.index,
          \env, Pseq([[Env.perc(0.001,0.999,1,4)]],inf),
      	[\dur,\amp],Pseq(~full,1),
          \finish, ~beatsToSeconds
      ).play(~metro.base ,quant:~metro.base.beatsPerBar);
    
    
      Pbindef(\d,
          \instrument, \DcOuts,
      	\stretch,4,
      	\legato,1,
      	\bus,Pseq((3..5),inf) + ~lightsBus.index,
          \env, Pseq([[Env.perc(0.001,0.999,1,4)]],inf),
      	[\dur,\amp],Pseq(~full,),
          \finish, ~beatsToSeconds
      ).play(~metro.nomes[4] ,quant:~metro.base.beatsPerBar);
      )
    
      (
      var flam,
      t, t_acc, t_accflam, t_flam, t_rest,
      ss, ss_acc, ss_accflam, ss_flam, ss_rest,
      n, n_acc, n_flam, n_accflam, n_rest,
      np_acc, np_inner, np_acc_inner,
      c, c_flam, c_accflam, c_acc,c_ss, c_ss_acc,
      si, si_acc, si_accflam, si_flam, si_rest,
      z, z_acc,
      o, o_acc, o_accflam, o_flam, o_rest,
      q, q_acc, q_accflam, q_flam,
      qt, qt_acc, qt_accflam, qt_flam
      ;
    
      flam  = 1/128;
      t_accflam = (((1/12 - flam):1)!1);
      t_flam = ((1/12 - flam)!1);
      ss_accflam = (((1/24 - flam):1)!1);
      ss_flam = ((1/24 - flam)!1);
    
      t = (1/12!1);
      t_acc = ((1/12:1)!1);
      t_rest =  ((1/12:0)!1);
    
      ss = (1/24!1);
      ss_acc = ((1/24:1)!1);
    
      // ninetuplet == 2 quarters
      n = (1/18!1);
      n_acc = ((1/18:1)!1);
      n_flam =  ((1/18 - flam)!1);
      n_accflam = (((1/18 - flam):1)!1);
      np_acc = ((3/18:1)!1);
    
    
      // nintuplet .dot
      np_inner = (1/36!3);
      np_acc_inner = (3/36:1);
    
      // quintuplet == 2 quarters
      c = (1/10!1);
      c_acc = ((1/10 :1)!1);
      c_flam = ((1/10 - flam)!1);
      c_accflam = (((1/10 - flam):1)!1);
      c_ss = (1/20!1);
      c_ss_acc = ((1/20 :1)!1);
    
      // 16th
      si = (1/16!1);
      si_acc = ((1/16 :1)!1);
      si_flam = ((1/16 - flam)!1);
      si_accflam = (((1/16 - flam):1)!1);
      si_rest =  ((1/16 :1)!1);
    
      // 8th
      o = (1/8!1);
      o_acc = ((1/8 :1)!1);
      o_flam = ((1/8 - flam)!1);
      o_accflam = (((1/8 - flam):1)!1);
      o_rest =  ((1/8 :1)!1);
    
    
      //Z z!32 = o
      z = (1/256!1);
      z_acc = ((1/256 :1)!1);
    
      // q
      q = (1/4!1);
      q_acc = ((1/4 : 1)!1);
      q_flam = ((1/4 - flam)!1);
      q_accflam = (((1/4 - flam):1)!1);
    
      // quarter note triplets
      qt = (1/3!1);
      qt_acc =  ((1/3 : 1)!1);
      qt_flam = ((1/3 - flam)!1);
      qt_accflam = (((1/3 - flam):1)!1);
    
      ~bars13_14 = [
    
      	[(3/4:0),(1/4:1)],
      	[(1/12:1),(1/24!2),(1/12!1)].flat,
      	[((flam : 1)!1),(((1/12 - flam):1)!1),((1/12:1)!1),(1/12!1)].flat,
      	[((flam )!1),(((1/12 - flam):1)!1),(1/12!1),((flam)!1),(((1/12 - flam):1)!1)].flat,
      	[(1/12!1),(1/12:1),(1/12!1)].flat
      ].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars15_17 = [
      	[ss!2,t!2].flat,
      	[t!9].flat,
    
      	[t_acc,ss,ss_acc,t].flat,
      	[t_acc,ss_acc,ss,t].flat,
      	[ss_acc,ss,t,flam,t_flam].flat,
      	[t!2,t_acc].flat,
    
      	[t_acc,ss!4,t_acc!2,ss!4].flat,
      	[t!3].flat
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars18_19 = [
      	[t_acc,ss!4].flat,
      	[ss!6].flat,
      	[c_acc,c_ss_acc,c_ss,c_ss_acc,c_ss,c_ss_acc,c_ss,c_ss_acc,c_ss].flat,
    
      	[np_acc,n_acc,n!2,n_acc,n!2].flat,
      	[n_acc,n!2,n_acc,n!2,np_acc_inner!2].flat
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
    
      ~bars20_21 = [
      	[n!6,n_acc!2,n].flat,
      	[n!3,n_acc!2,n!4].flat,
    
      	[n_acc,n!2,n_acc,n!2,n_acc,n!2].flat,
      	[n_acc,n!2,n_acc,n!2,np_acc_inner,np_inner].flat,
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars22_23 = [
      	[n_acc!3,n!6].flat,
      	[n!9].flat,
    
      	[n_acc,n!5,n_acc!2,n].flat,
      	[n!3,n_acc!2,n!4].flat,
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
    
      ~bars24_26 = [
      	[ss_acc,ss,ss_acc,ss!21].flat,
      	[ss!24].flat,
    
      	[si!4,si_acc,si!3,o!2,z!256].flat,
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
    
      ~bars27_34 =[
      	[1/4,(3/4 :0)],
      	[(2 :0)],
      	[(24/4 :0)]
      	].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars35_38 =[
      	[z_acc,z!63,o,o_acc,o,z_acc,z!64,o,o_acc,o].flat, //5/8 *2
      	[si_acc,si!3,si_acc,si!3,si_acc,si!3, o_acc,o].flat, // 4/4
      	[z_acc,z!63,o,si_acc,si!3].flat // 5/8
      	].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars39_41 =[
      	[si_acc,si!5,si_acc,si!3].flat, //5/8 *2
      	[si_acc,si!3,ss!12,t!3].flat, // 4/4
      	[n_acc!6,np_acc_inner!2].flat,
      	[n_acc!3,np_acc,n_acc!3].flat
      	].collect(~getDurAmpPairs.(_)).flatten;
    
    
    
      ~bars42_43 =[
      	[np_acc,n_acc!3,np_acc].flat,
      	[n_acc!3,np_acc,n_acc!3].flat,
    
      	[np_acc,n_acc!6].flat,
      	[q_acc,flam,q_accflam].flat,
    
      	].collect(~getDurAmpPairs.(_)).flatten;
    
    
      ~bars44_46 =[
      	[t_acc,t!2,t_acc,ss!4,t_acc,ss!4,t_acc,ss!4].flat,
      	[t_acc!2, si_acc, si!6, si_acc, si, ss!6, t_acc, t].flat,
      	[si_acc, si,si_acc, si, t, si!2, t, t_acc].flat,
    
      	].collect(~getDurAmpPairs.(_)).flatten;
    
    
    
      ~bars47_49 =[
      	[o_acc,ss!4].flat,
      	[o_acc,o].flat,
      	[n_acc,n!5,n_acc,n!2].flat,
    
      	[o_acc,o,o_acc,ss!4,o,si_acc!2,si!4,ss_acc,ss!5].flat, // 5/4
      	[o_acc,o,o_acc,si!2,qt_acc!3].flat,
    
      	].collect(~getDurAmpPairs.(_)).flatten;
    
      ~bars50_52 =[
      	[o_acc,o!2,o_acc,o,flam,o_accflam,o!2,flam,ss_acc!2,o].flat,
      	[flam,o_accflam,o!2,flam,si_accflam,si_acc,o,si_acc,si,o!2,o_acc,z!32].flat,
      	[o,flam,o_accflam,o,flam,o_accflam,flam,o_accflam,flam,o_accflam,o_rest,flam,o_accflam,z!32].flat,
      	].collect(~getDurAmpPairs.(_)).flatten;
    
    
      ~bars53_55 = [
      	[o,o_acc,o_rest,o_acc,o_rest,o_acc!2,o].flat,
      	[t_acc,ss!4,t_acc,ss!4,t_acc,ss!4,t_acc,ss!4].flat,
      	[o_acc!2,(3/4:0)].flat,
      	[o_acc!2,(5/4:0)].flat,
    
      ].collect(~getDurAmpPairs.(_)).flatten;
    
      )
    

for now it looks like that,

@shiihs with Panola it could be super nice because of the animations,
to control the overall amplitude, I should find a way to copy this idea, or change my project using your quark
and to be honest your tutorials on composing help!

(
Pdef(\a, Pbind(\instrument, \DcOuts,
	\midinote, ~ex.midinotePattern,
	\dur, ~ex.durationPattern,
	\amp, ~ex.volumePattern,
	\tempo, ~ex.tempoPattern,
	\lag, ~ex.lagPattern,
	\legato, 1,
	\bus,Pseq([(0..2)],inf) + ~lightsBus.index,
       \env, Pseq([[Env.perc(0.001,0.999,1,4)]],inf),
	\finish, ~beatsToSeconds
)
).play;
)


~ex = Panola.new(
	"(c4_4@vol[0.0])*3 c4@vol[1.0]"
	"c_4/3@vol[1.0] (c_4/6@vol[0.4])*2 c_4/3"
etc..
);

WIth the approach of using symbols like notations, it would be really nice,
but it’s not clear to me how to write tuplets.

http://sccode.org/1-5da

I definitely like the simplicity in writing polymeters, and drum set grooves in general…

\poly : [ ["X.X.x.X.x.X.", *\kickdrum* , *6* ],
 ["X.X.X.x.", *\hihatclosed* , *4* ],
 ["X..X....x.X..x", *\stickclick* , *7* ], ],

@jamshark70 it’s super compact, I installed and readying the manual

http://www.dewdrop-world.net/displayNews.php?src=2019-01-26-news.md&fromIndex=1

/mr.s1 = "X  x |. x  ";
/mr.s2 = "X. x |. x  ";
/mr.s3 = "X  x |. x .";
/mr.s4 = "X  x |..x  ";
/mr.s5 = "X..x.|..x..";

@RFluff some Megadeth would be appreciate :love_you_gesture:
thanks for the huge amount of things,but right now I’m becoming crazy :crazy_face: