CC control with Patterns s612

hi
Ive got an Akai S612 sampler. I got the hideaway mods for it.

Im trying to mess with the Front panel animator with patterns. I can get it playing, but the CC messages are not getting through.
From the manual of the FPA

"5 Parameters are available for continuous control via the following MIDI CC channels: The MIDI CC channels are as follows (hard coded to MIDI channel 1):

  1. CC20 Sample Start Position / Splice
  2. CC21 Sample End Position
  3. CC22 LFO Speed
  4. CC23 Sample Decay Rate
  5. CC24 Filter Cutoff"

I left out lfo (22) for now. Here is my code. I looked around before I posted this ,believe me.

This plays and the dur works, But the CC’s do not…

(
    // substitute your own device here
var    mOut = MIDIOut.newByName("UM-ONE", "UM-ONE").latency_(Server.default.latency);
​
p = Pbind(
    \type, \midi,
        // this line is optional b/c noteOn is the default
        // just making it explicit here
    \midicmd, \noteOn,
    \midiout, mOut,    // must provide the MIDI target here
    \chan, 0,
        // degree is converted to midinote, not just frequency
    \degree, Pseq(#[3], inf),
    \dur, Pseq(#[2,0.1,0.4], inf),

    \amp, Pseq(#[1], inf),
	\ctlNum, 20,
	\control, 15,
	\ctlNum, 21,
	\control, 56,
	\ctlNum, 23,
	\control, Pexprand(5, 12, inf),
	\ctlNum, 24,
	\control, Pexprand(5, 55, inf)
).play(quant: 1);
)
​p.clear;
p.stop;

Midi monitors output is ;

20:57:14.888 To UM-ONE Note On 1 F3 127
20:57:14.968 To UM-ONE Note Off 1 F3 127
20:57:14.988 To UM-ONE Note On 1 F3 127
20:57:22.887 To UM-ONE Note On 1 D3 127
20:57:24.488 To UM-ONE Note Off 1 D3 127
20:57:24.888 To UM-ONE Note On 1 D3 127
20:57:24.968 To UM-ONE Note Off 1 D3 127
20:57:24.988 To UM-ONE Note On 1 D3 127
20:57:33.888 To UM-ONE Note On 1 F3 127
20:57:35.488 To UM-ONE Note Off 1 F3 127
20:57:35.888 To UM-ONE Note On 1 F3 127
20:57:35.968 To UM-ONE Note Off 1 F3 127
20:57:35.988 To UM-ONE Note On 1 F3 127
20:57:36.308 To UM-ONE Note Off 1 F3 127
20:57:36.388 To UM-ONE Note On 1 F3 127
20:57:43.888 To UM-ONE Note On 1 F3 127
20:57:45.488 To UM-ONE Note Off 1 F3 127
20:57:45.888 To UM-ONE Note On 1 F3 127

I haven’t tested it, but I think you could do something as follows:

  • make a pattern for each control change
  • combine all patterns to render in parallel using Ppar
    e.g.
(
var mOut;
var p = (); // an event (dictionary) to store many things in

if (MIDIClient.initialized.not) { MIDIClient.init; };
mOut = MIDIOut.new(0).latency_(Server.default.latency);

p[\notes] = Pbind(
    \type, \midi,
    \midicmd, \noteOn,
    \midiout, mOut,
    \chan, 0,
    \degree, Pseq([3], inf),
    \dur, Pseq([2,0.1,0.4], inf),

    \amp, Pseq([1], inf),
);
p[\cc20] = Pbind(
	\type, \midi,
	\midicmd, \control,
	\midiout, mOut,
	\chan, 0,
	\ctlNum, 20,
	\val, Pseq([15], inf)
);
p[\cc21] = Pbind(
	\type, \midi,
	\midicmd, \control,
	\midiout, mOut,
	\chan, 0,
	\ctlNum, 21,
	\val, Pseq([56], inf)
);
p[\cc23] = Pbind(
	\type, \midi,
	\midicmd, \control,
	\midiout, mOut,
	\chan, 0,
	\ctlNum, 23,
	\val, Pexprand(5, 12, inf)
);
p[\cc24] = Pbind(
	\type, \midi,
	\midicmd, \control,
	\midiout, mOut,
	\chan, 0,
	\ctlNum, 24,
	\val, Pexprand(5, 55, inf)
);
p[\all] = Ppar([p[\notes], p[\cc20], p[\cc21], p[\cc23], p[\cc24] ]).trace;

~player = p[\all].play(quant: 1);
)
​~player.stop;

Then in a next step, instead of typing out all the Pbind keys all the time for defining each of the p[\cc20], p[\cc21], etc, you could define a function to make a Pbind from a midiout, a control number and a pattern, e.g.

(
var mOut;
var p = ();
var makeCC;

if (MIDIClient.initialized.not) { MIDIClient.init; };
mOut = MIDIOut.new(0).latency_(Server.default.latency);

makeCC = { | mOut, ctlNum, pattern |
	Pbind(
	\type, \midi,
	\midicmd, \control,
	\midiout, mOut,
	\chan, 0,
	\ctlNum, ctlNum,
	\val, pattern
	);	
};

p[\notes] = Pbind(
    \type, \midi,
    \midicmd, \noteOn,
    \midiout, mOut,
    \chan, 0,
    \degree, Pseq([3], inf),
    \dur, Pseq([2,0.1,0.4], inf),
    \amp, Pseq([1], inf),
);
p[\cc20] = makeCC.(mOut, 20, Pseq([15], inf));
p[\cc21] = makeCC.(mOut, 21, Pseq([56], inf));
p[\cc23] = makeCC.(mOut, 23, Pexprand(5, 12, inf));
p[\cc24] = makeCC.(mOut, 24, Pexprand(5, 55, inf));

p[\all] = Ppar([p[\notes], p[\cc20], p[\cc21], p[\cc23], p[\cc24] ]).trace;

~player = p[\all].play(quant: 1);
)

​~player.stop;

1 Like

There are a couple of misconceptions here.

The code example seems to be using Pbind as a list of instructions (especially the series of \ctlNum, ..., \control, ...). It is a list of instructions, but the list populates an Event object. An Event can’t have more than one value under the same name, so for those 4 ctlNums, only the last one will “win.” The others are lost.

BUT… event type \midi expands arrays into multiple MIDI messages:

(
	type: \midi,
	midiout: m,
	midicmd: \control,
	ctlNum: [7, 10],
	control: [10, 20]
).play;

^^ This sends 2 CC messages: CC 7 value 10, CC 10 value 20.

So you could handle the 4 CCs by:

\ctlNum, [20, 21, 23, 24],
\control, Ptuple([15, 56, Pexprand(5, 12, inf), Pexprand(5, 55, inf)])

Second, the event can have only one midicmd. A \noteOn midi event will not send controls. So you have no choice but to split up the noteOn and control messages into separate patterns.

Ppar([notePattern, controlPattern])

… where notePattern is the Pbind(…, \midicmd, \noteOn, …) and controlPattern is Pbind(..., \midicmd, \control, \ctlNum, [20, 21, 23, 24], \control, Ptuple([15, 56, Pexprand(5, 12, inf), Pexprand(5, 55, inf)]).

hjh

Like this?


(


var  mOut = MIDIOut.newByName("UM-ONE", "UM-ONE").latency_(Server.default.latency);
var notePattern = Pbind(
     \type, \midi,
        // this line is optional b/c noteOn is the default
        // just making it explicit here
    \midicmd, \noteOn,
    \midiout, mOut,    // must provide the MIDI target here
    \chan, 0,
        // degree is converted to midinote, not just frequency
    \degree, Pseq(#[3], inf),
    \dur, Pseq(#[2,0.1,0.4], inf),

);

var a, b, c, controlPattern;
	a = Pseq([73, 71, 69, 69, 65, 64], inf);
	b = Pseq([22,33,55,2], inf) + a;
    c = Ptuple([a, b,a, b], inf);
    controlPattern = Pbind(
	\type, \midi,
    \midicmd, \control,
    \midiout, mOut,
	\ctlNum, [20, 21, 23, 24],
	\control, c);

	Ppar([notePattern, controlPattern]).play;


)
​p.clear;
p.stop;
m.allNotesOff(0);

Revised at home. Plays the s612,might actually be working. Im not totally sure.

Im also getting a hanging note.

Im able to turn it off with m.allNotesOff(0);

But this is a mess. This is too cool to not get right though. The Patterns can do so much cool stuff with external gear.

Like the Ptuple, Im trying to get more basic sequences in there

I think my code is working, But Im not sure if it is good enough

Thank you very much for the help

The only potential problem I see is that \dur is not controlled in your controlPattern.

Also make sure to do p = Ppar([...]).play if you want to do p.stop later.

The hanging note, I don’t see the cause in this code. SC should be generating at least 0.02 sec between note-off and the next note-on here.

Another approach would be a hybrid note/control MIDI event… which depends on some knowledge of event internals, so you wouldn’t figure it out by yourself, but it might look like this:

(
Event.addEventType(\mnotectl, {
	currentEnvironment.copy.put(\type, \midi).put(\midicmd, \noteOn).play;
	currentEnvironment.copy.put(\type, \midi).put(\midicmd, \control).play;
});
)

p = Pbind(
	\type, \mnotectl,
	\midiout, m,
	\degree, Pseq(#[3], inf),
	\dur, Pseq(#[2, 0.1, 0.4], inf),
	\ctlNum, [20, 21, 23, 24],
	\control, c
).play;

p.stop;

hjh

1 Like

Excellent. Thank you