«Re: midified arpeggiator/auto-accompaniment using patterns» by elgiano

on 11 Jan'20 12:03 in patternarpeggiomidicode forkarpeggiatorautoaccompaniment

Re: Let me know if you have ideas for improvement! (code-wise or feature-wise) -> I used an object prototype to streamline the process of registering notes and getting sequences of them. Code looks simpler to me and easier to further develop :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(
s.waitForBoot({
	var right, left;

	MIDIdef.freeAll;
	if (~midi_initilized.isNil) {
		MIDIClient.init;
		MIDIIn.connectAll;
		~midi_initialized = 1;
	};

	~n = (
		table: Order(),
		noteOn: {|n,note| n.table[note] = 1},
		noteOff: {|n,note| n.table.removeAt(note)},
		get: {|n,i| 
			n.table.indices[i] ?? n.table.indices.first ?? Rest(1)
		},
		seq: {|n,notes|
			notes.asArray.collect{|i| Plazy{n.get(i)}}
		}
	);
	
	MIDIdef.noteOn(
		\mynoteonhandler, // just a name for this handler
		{
			|val, num, chan, src|
			~n.noteOn(num)
		}
	);

	MIDIdef.noteOff(
		\mynoteoffhandler, // just a name for this handler
		{
			|val, num, chan, src|
			~n.noteOff(num) // update note table and update ~n
			/*
			// only enable the following lines if you want the arpeggio to stop as soon as you release the keys
			~n.table.clear
			*/
		}
	);

	right = Pbind(
		\instrument, \default,
		\midinote, Pseq(~n.seq(
			[ 0, 2, 1, 2] ++ (([ 0, 2, 1, 2] + 12)!2).flatten
		)),
		\dur, 2*Pseq([1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 ].normalizeSum)
	);
	left = Pbind(
		\instrument, \default,
		\midinote, Pseq(~n.seq([ 0, 2, 0, 2, 0, 2, 0, 2] - 12)),
		\dur, 2*Pseq([1, 1, 1, 1, 1, 1, 1, 1].normalizeSum)
	);
	if (~player.notNil) { ~player.stop; };
	~player = Pn(Ppar([right,left])).play;
});
)
raw 1354 chars (focus & ctrl+a+c to copy)
reception
comments
56228375 user 15 Jan'20 16:55

It looks much cleaner indeed. Great work! Thanks!!

56228375 user 15 Jan'20 17:01

hmm, on second thought your code produces a very different musical result from mine even though you didn't edit the pattern; it also stops the arpeggio when the notes are released. I'll need to examine in more detail why it's so different.

56228375 user 15 Jan'20 17:12

I see... you remove the notes from the table on noteOff. In my approach, I had an ~n which more or less corresponded to the "last active chord" and which remained intact even after the note off had come (this is more how autoaccompaniment works, and less how arpeggiators work). Anyway, it's a detail that should be fairly easy to adjust. I'm still a bit confused why your approach results in other notes being used than in my approach.

56228375 user 15 Jan'20 17:34

Ah I understand why your approach gives different notes now. In my approach I can do calculations on the "degrees" (e.g. I have a [ 0, 2, 1, 2] + 12 term in the "right" pattern). Since you rely on the indices in the Order object, it will return nil for a calculated degree. I guess the solution here would be not to use Order. (I had never heard about that class before your input :) )

56228375 user 15 Jan'20 17:37

(to clarify: the "nil" for a calculated degree eventually results in the first note of the chord being used instead of the expected degrees with transposition)

56228375 user 15 Jan'20 17:41

(How I wish I could edit my comments...) I used [ n0, n2, n1, n2 ] + 12, with n0-n2 functions, which allows for applying intuitive, arbitrarily complex transformations on the chord degrees. In your approach I'm not sure how that would best be done.