SynthDef(
\risset_bell,
{ |freq=440, dur=4.0, out=0|
var partial;
partial = { |amplitude, rel_duration, rel_freq, detune|
OffsetOut.ar(out,
EnvGen.kr(
Env.perc(0.05, dur*rel_duration, amplitude*0.1, -4),
doneAction: 0
) * SinOsc.ar(freq*rel_freq+detune)
);
};
partial.(1, 1, 0.56, 0);
partial.(0.67, 0.9, 0.56, 1);
partial.(1, 0.65, 0.92, 0);
partial.(1.8, 0.55, 0.92, 1.7);
partial.(2.67, 0.325, 1.19, 0);
partial.(1.67, 0.35, 1.7, 0);
partial.(1.46, 0.25, 2, 0);
partial.(1.33, 0.2, 2.74, 0);
partial.(1.33, 0.15, 3, 0);
partial.(1, 0.1, 3.76, 0);
partial.(1.33, 0.075, 4.07, 0);
}
).add;
a = (
type: \note,
instrument: \risset_bell,
freq: 500,
dur: 10.0
);
a.play; // play the note
</noscript>
Here’s my first take. I defined a Synth, and broke out a function to handle each partial for the additive synthesis. Env.perc makes a great envelope shape for a bell. I’m taking all the details–the tunings, relative amplitudes, and relative durations–from the Pd example.
The biggest trouble spot I ran into was the doneAction argument on EnvGen.kr. The doneAction is “an integer representing an action to be executed when the env is finished playing.” The common choice here would be 2, which means that the server should free the enclosing Synth as soon as the envelope has completed.
When I used a 2 I observed that the sound would cut off abruptly while still playing. It took me a bit to realize what was going wrong, but it eventually dawned on me that once the shortest partial had finished (remember, they each have different durations), it was triggering the doneAction and the server was freeing the entire Synth including all the other partials that I wanted to be still sounding.
To prove my hunch, I changed the doneAction argument to 0, or “do nothing”. Sure enough, the bell played all the way to completion. But that also left a Synth and a bunch of UGens sitting around on the server. These would continue to build up with every strike of the bell. Obviously this wasn’t acceptable.
<script src="https://gist.github.com/5937242.js"></script><noscript>```
<code class="language- ">SynthDef(
\risset_bell,
{ |freq=440, dur=4.0, out=0|
var partials, addPartial;
partials = Array.new(11);
addPartial = { |amplitude, rel_duration, rel_freq, detune|
partials.add(
EnvGen.kr(
Env.perc(0.05, dur*rel_duration, amplitude*0.1, -4),
doneAction: 0
) * SinOsc.ar(freq*rel_freq+detune)
);
};
addPartial.(1, 1, 0.56, 0);
addPartial.(0.67, 0.9, 0.56, 1);
addPartial.(1, 0.65, 0.92, 0);
addPartial.(1.8, 0.55, 0.92, 1.7);
addPartial.(2.67, 0.325, 1.19, 0);
addPartial.(1.67, 0.35, 1.7, 0);
addPartial.(1.46, 0.25, 2, 0);
addPartial.(1.33, 0.2, 2.74, 0);
addPartial.(1.33, 0.15, 3, 0);
addPartial.(1, 0.1, 3.76, 0);
addPartial.(1.33, 0.075, 4.07, 0);
OffsetOut.ar(out,
EnvGen.kr(
Env.perc(0.05, dur, curve: -4),
doneAction: 2
) * Mix.new(partials)
);
}
).add;
a = (
type: \note,
instrument: \risset_bell,
freq: 500,
dur: 10.0
);
a.play; // play the note