Thank you so much for the reply, I understand it better now! I am not used to reading and modifying source code for Classes, but here is what I did after looking at the usage example you provided. If there is a simpler way, I’d love to learn.
Instead of changing the \note eventType itself, I wanted to see if I could create a \note2 eventType that includes the change you suggest, but otherwise is identical to \note.
I looked into Event.sc and found this line and this line to be the relevant ones.
For the sake of documenting the thought process, after a few unsuccessful attempts I went back to Server Command help file to understand exactly how the bundles should be formatted. Writing the following short example helped clarify it for me:
// create three nodes
(
x = Synth(\default);
y = Synth(\default, [\freq, 550]);
z = Synth(\default, [\freq, 660]);
)
// stop them
s.freeAll;
// sending only release bundles throws "node not found" error messages as expected:
s.listSendBundle(0.2, [15, [x.nodeID, y.nodeID, z.nodeID], \gate, 0].flop);
// now wrapping bundles: nodes are not found, but error messages are not shown (desired behavior)
s.listSendBundle(0.2, ([#[error, -1]] ++ [15, [x.nodeID, y.nodeID, z.nodeID], \gate, 0].flop ++ [#[error, -2]]));
Then I basically copied the entire Function for the \note type (from Event.sc) into my new \note2 in a new document, replace the two relevant lines with code that ‘wraps’ release messages with the proper \error code:
(
Event.addEventType(\note2, {|server|
var freqs, lag, strum, sustain;
var bndl, addAction, sendGate, ids;
var msgFunc, instrumentName, offset, strumOffset;
// var schedBundleArray;
freqs = ~detunedFreq.value;
// msgFunc gets the synth's control values from the Event
msgFunc = ~getMsgFunc.valueEnvir;
instrumentName = ~synthDefName.valueEnvir;
// determine how to send those commands
// sendGate == false turns off releases
sendGate = ~sendGate ? ~hasGate;
// update values in the Event that may be determined by functions
~freq = freqs;
~amp = ~amp.value;
~sustain = sustain = ~sustain.value;
lag = ~lag;
offset = ~timingOffset;
strum = ~strum;
~server = server;
~isPlaying = true;
addAction = Node.actionNumberFor(~addAction);
// compute the control values and generate OSC commands
bndl = msgFunc.valueEnvir;
bndl = [9 /* \s_new */, instrumentName, ids, addAction, ~group] ++ bndl;
if(strum == 0 and: { (sendGate and: { sustain.isArray })
or: { offset.isArray } or: { lag.isArray } }) {
bndl = flopTogether(
bndl,
[sustain, lag, offset]
);
#sustain, lag, offset = bndl[1].flop;
bndl = bndl[0];
} {
bndl = bndl.flop
};
// produce a node id for each synth
~id = ids = Array.fill(bndl.size, { server.nextNodeID });
bndl = bndl.collect { | msg, i |
msg[2] = ids[i];
msg.asOSCArgArray
};
// schedule when the bundles are sent
if (strum == 0) {
~schedBundleArray.(lag, offset, server, bndl, ~latency);
if (sendGate) {
~schedBundleArray.(
lag,
sustain + offset,
server,
// original source code:
// [15 /* \n_set */, ids, \gate, 0].flop,
// my modification:
([#[error, -1]] ++ [15, ids, \gate, 0].flop ++ [#[error, -2]]).postln,
~latency
);
}
} {
if (strum < 0) {
bndl = bndl.reverse;
ids = ids.reverse
};
strumOffset = offset + Array.series(bndl.size, 0, strum.abs);
~schedBundleArray.(
lag, strumOffset, server, bndl, ~latency
);
if (sendGate) {
if (~strumEndsTogether) {
strumOffset = sustain + offset
} {
strumOffset = sustain + strumOffset
};
~schedBundleArray.(
lag, strumOffset, server,
// my modification, same as above:
([#[error, -1]] ++ [15, ids, \gate, 0].flop ++ [#[error, -2]]).postln,
~latency
);
}
}
}
);
)
This seems to work as desired, but it breaks when strum is > 0:
// this works:
(
g = Group.new;
p = Pbind(
\type, \note2,
\dur, 5,
\degree, Pwhite(0, 10) + [0, 2],
\group, g
).play;
)
// run this before notes reach the end.
// As desired, no error message is shown.
g.release; p.stop;
// HOWEVER, it fails miserably when strum > 0 ;-)
(
g = Group.new;
p = Pbind(
\type, \note2,
\dur, 2,
\degree, Pwhite(0, 10) + [0, 2],
\group, g,
\strum, 0.1
).play;
)
// even before running the line below, we can hear that the release mechanism is now broken -- notes never stop.
g.release; p.stop;
This last issue with the \strum I haven’t been able to figure out yet. Any tips appreciated.
Bruno
EDIT: looking further into that bit of source code I am seeing that, when strum is not 0, strumOffset
, which is the second argument to ~schedBundleArray
, becomes itself an Array, as opposed to a single offset value as in the similar line earlier (when the strum==0). I am also seeing that the function ~schedBundleArray
internally calls the method schedBundleArrayOnClock
, which can work with a SimpleNumber or an Array as receiver. So the issue has to do with how to properly format the bundle array including the #[error, -1] and #[error, -2] for this case when schedBundleArrayOnClock
is being called on an Array of offsets. Have been trying a few ideas but no luck so far.