Strike Tones for Bell Synthesis

I was curious if anyone had experience working with strike tones in SC? I have been working with synthesizer bell sounds and would love to figure out how to implement a proper sounding strike tone.

Thanks

1 Like

Hi there…
… would you please be more explicit or include some example?

Thank you :slight_smile:

Many (most? all?) physical musical instruments produce pitch through natural resonance. An input of noisy energy drives the resonance. For example, air turbulence on the edge of a flute mouthpiece produces noise; the resonances in the tube emphasize harmonic frequencies (producing pitch) and give the instrument its color.

If you hit a marimba or vibraphone bar, or a bell, this is also a noisy input.

The final color depends on the characteristics of the noise input and on the resonances.

You can get a reasonable bell approximation by feeding a short burst of decaying noise into resonators (Ringz and Formlet are my favorites in SC).

You might be able to get a better bell approximation by matching the characteristics of the noise to the characteristics of a mallet striking a body of some material.

I think this is what me91 is asking about.

I have used noise --> resonators before (https://soundcloud.com/dewdrop_world/jupiter-chimes) but I haven’t gone as far as simulating better exciters. So I don’t have an answer to the original question.

hjh

Hi me91

I’m not sure if you mean literally the strike of the bell? If so, I wonder, if you think more of a bass drum sound (the hit, followed by the low frequency), you could adapt that idea. If it’s any help here’s an adapted synth, originally a bass drum kick, and which I’ve quickly added a PMOsc to get a bell like tone for you to hear the effect - you can do much better as James suggested using noise and Formlet etc, or even browsing the https://sccode.org/tag/category/bell page.

Anyhow, try this to see if it’s of any help, as you can see the bell tone and the hit are two different things which when combined give a reasonable approximation:

   (
SynthDef(\bell, {
	arg out = 0, vol=0.5, carr = 420, mod=580.6, modIndex=0.1, bellAmp=0.5, att=0.01, susT=0.5, relT=0.9;
	var bell, env, bdFreq, popFreq, popAmp, pop, kPos, sig;
	bdFreq = EnvGen.ar(Env([220,151,60], [0.038, 0.08], -5));
	bell = PMOsc.ar(carr, mod, modIndex, mul:bellAmp);
	env = EnvGen.kr(Env.linen(att, susT, relT), doneAction:2);
	sig = bell*env;
	popFreq = Line.ar(700,220, 0.02);
	popAmp = EnvGen.ar(Env.linen(0.001, 0.02, 0.001))*0.2;
	pop = SinOsc.ar(popFreq)*popAmp;
	sig = sig+pop*vol;
	kPos = SinOsc.kr(0.01).range(-0.9, 0.5);
	Out.ar(out, Pan2.ar(sig));
}).add;
)


(
Pbindef(
	\bells,
	\instrument, \bell,
	\dur, Pshuf([Pseq([2/2, 1/2, 1/2], 3),Pseq([1/2, 1/4, 1/4], 2)], inf),
	\bellAmp, 0.8,
	\modIndex, Pwhite(0.6, 2.2, inf),
	\relT, Pwhite(0.4, 0.9, inf),
	\vol, Pwhite(0.1, 0.3, inf),
	\out, 0,
).play;
)

I hope that’s of some help - joesh

Hey,

I guess I am really interested in how this patch (found online) does such a good job of making a realistic hit sound. Could anyone break the mallet and input parts down? The rest of the patch makes sense to me.

(
SynthDef(\prayer_bell, { |outbus, t_trig = 1, sing_switch = 0, freq = 2434, amp = 0.5, decayscale = 1, lag = 10, i_doneAction = 0|
var sig, input, first, freqscale, mallet, sing;
freqscale = freq / 2434;
freqscale = Lag3.kr(freqscale, lag);
decayscale = Lag3.kr(decayscale, lag);

mallet = LPF.ar(Trig.ar(t_trig, SampleDur.ir)!2, 10000 * freqscale);
sing = LPF.ar(
LPF.ar(
{
PinkNoise.ar * Integrator.kr(sing_switch * 0.001, 0.999).linexp(0, 1, 0.01, 1) * amp
} ! 2,
2434 * freqscale
) + Dust.ar(10.1), 10000 * freqscale
) * LFNoise1.kr(0.5).range(-45, -30).dbamp;
input = mallet + (sing_switch.clip(0, 1) * sing);

sig = DynKlank.ar(`[
[
(first = LFNoise1.kr(0.5).range(2424, 2444)) + Line.kr(20, 0, 0.5),
first + LFNoise1.kr(0.5).range(1,3),
LFNoise1.kr(1.5).range(5435, 5440) - Line.kr(35, 0, 1),
LFNoise1.kr(1.5).range(5480, 5485) - Line.kr(10, 0, 0.5),
LFNoise1.kr(2).range(8435, 8445) + Line.kr(15, 0, 0.05),
LFNoise1.kr(2).range(8665, 8670),
LFNoise1.kr(2).range(8704, 8709),
LFNoise1.kr(2).range(8807, 8817),
LFNoise1.kr(2).range(9570, 9607),
LFNoise1.kr(2).range(10567, 10572) - Line.kr(20, 0, 0.05),
LFNoise1.kr(2).range(10627, 10636) + Line.kr(35, 0, 0.05),
LFNoise1.kr(2).range(14689, 14697) - Line.kr(10, 0, 0.05)
],
[
LFNoise1.kr(1).range(-10, -5).dbamp,
LFNoise1.kr(1).range(-20, -10).dbamp,
LFNoise1.kr(1).range(-12, -6).dbamp,
LFNoise1.kr(1).range(-12, -6).dbamp,
-20.dbamp,
-20.dbamp,
-20.dbamp,
-25.dbamp,
-10.dbamp,
-20.dbamp,
-20.dbamp,
-25.dbamp
],
Array.interpolation(11,0.01,0.3).reverse
* freqscale.reciprocal.pow(0.5)
], input, freqscale, 0, decayscale);
DetectSilence.ar(sig, doneAction: i_doneAction);
Out.ar(outbus, sig);
}).add;
)

[
0.9,4.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,4.1
]
(
Pdef(\bell_1,
Pmono(\prayer_bell,
\dur, Pseq([8, 20], inf),
\freq, Pseq([2500, 500], inf),
\amp, 0.5,
\lag, 0,
\trig, Pseq([0.1], inf) * Pwhite(0.5, 1, inf) * Pwrand([0, 1], [1, 5].normalizeSum, inf),
\sing_switch, Pseq((0!4) ++ (1!4), inf)
)
);

Pdef(\bell_2,
Pmono(\prayer_bell,
\dur, Pwhite(8, 20, inf),
\trig, Pwhite(0.05, 0.09),
\sing_switch, Pwrand([0, 1], [5, 3].normalizeSum, inf),
\freq, Prand((240, 360 … 2000), inf),
\amp, 0.5
)
);

Pdef(\bell_3,
Ppar([
Pmono(\prayer_bell,
\freq, 100,
\dur, 1,
\trig, 0,
\sing_switch, Pwrand([0, 1], [10, 3].normalizeSum, inf),
\amp, Pwhite(0.1, 0.5)
),
Pmono(\prayer_bell,
\freq, 200,
\dur, 1,
\trig, 0,
\sing_switch, Pwrand([0, 1], [10, 3].normalizeSum, inf),
\amp, Pwhite(0.1, 0.5)
),
Pmono(\prayer_bell,
\freq, 300,
\dur, 1,
\trig, 0,
\sing_switch, Pwrand([0, 1], [10, 3].normalizeSum, inf),
\amp, Pwhite(0.1, 0.5)
)
])
);

Pdef(\bell_1).play;
Pdef(\bell_2).play;
Pdef(\bell_3).play;
)

wow, just got around to trying this out
the original appears to be here: https://doc.sccode.org/1-4VL

what a beauty!

can’t help with the reverse engineering, sorry. but you’ve got the code, just mess around with it and integrate into your own stuff, that’s what we all do : )

cheers,
eddi

Doesn’t quite answer the OP but have you seen Bill Hibbert’s research on the acoustics of bells? His PhD paper is refreshingly easy to read and his other research is fantastic.

I used to lecture at the University of Surrey (gave a 24-week course on SC, among other things) and created the following as an example of how to create the resonant part of a bell’s sound:

(
SynthDef(\bell, {arg
nominal = 750,
decayTime = 10,
decayShape = -5,
decayFalloff = -2;
var hum = nominal / 4;
var prime = nominal / 2;
var tierce = prime * (2**(3/12));
var quint = prime * (2**(7/12));
var superquint = nominal * (2**(7/12));
var octaveNominal = nominal * 2;
var i7 = nominal * (2**(17/12));
var i8 = nominal * (2**(21/12));
var i9 = nominal * 4;
var delta = nominal * 2 / 3;
var i10 = i9 + delta;
var i11 = i10 + delta;
var i12 = i11 + delta;
var i13 = i12 + delta;
var freqs =
[hum, prime, tierce, quint, nominal, superquint, octaveNominal] ++
[i7, i8, i9, i10, i11, i12, i13];
var amps = [-20, -7, -11, -20, -8, 0, -3, -9, -10, -16, -28, -31, -38, -43].dbamp;
var decayShapes = Array.series(freqs.size, decayShape, decayFalloff);
var env = Env([0, amps, 0], [0.01, decayTime], [0, decayShapes]);
var envGen = EnvGen.ar(env, doneAction: 2);
var mix = Splay.ar(SinOsc.ar(freqs, 0, envGen));
Out.ar(0, mix);
}).play;
)

Hello! This was originally my code, nice to see it still kicking around :slight_smile:

The “mallet” is just a single-sample impulse with slight lowpass filtering (t_trig is a control-rate trigger, and Trig.ar(t_trig, SampleDur.ir) turns it into an audio-rate impulse.

The “sing” part is only active when sing_switch is on, it was my attempt to replicate the sound of a singing bowl when the mallet is run around the rim, basically just some filtered noise with a few Dust impulses here and there. But if you just want to understand the initial hit, don’t worry about it.

Most of the realism comes actually from the DynKlank parameters, as you can see here,

Same mallet impulse, much simplified DynKlank:

(
{
  arg t_trig = 1, freq = 2434, amp = 0.5, decayscale = 1;
  var sig, input, freqscale, mallet, sing;
  freqscale = freq / 2434;

  mallet = LPF.ar(Trig.ar(t_trig, SampleDur.ir)!2, 10000 * freqscale);
  input = mallet;

  sig = DynKlank.ar(`[[2434, 5435, 5480], [0.3, 0.1, 0.2], [20, 5, 5]], input, freqscale, 0, decayscale);  
  
  sig;
}.play(fadeTime: 0);
)

And here’s the full version:

(
{
  arg t_trig = 1, freq = 2434, amp = 0.5, decayscale = 1;
  var sig, input, first, freqscale, mallet, sing;
  freqscale = freq / 2434;

  mallet = LPF.ar(Trig.ar(t_trig, SampleDur.ir)!2, 10000 * freqscale);
  input = mallet;
  
  sig = DynKlank.ar(`[
    [
      (first = LFNoise1.kr(0.5).range(2424, 2444)) + Line.kr(20, 0, 0.5),
      first + LFNoise1.kr(0.5).range(1,3),
      LFNoise1.kr(1.5).range(5435, 5440) - Line.kr(35, 0, 1),
      LFNoise1.kr(1.5).range(5480, 5485) - Line.kr(10, 0, 0.5),
      LFNoise1.kr(2).range(8435, 8445) + Line.kr(15, 0, 0.05),
      LFNoise1.kr(2).range(8665, 8670),
      LFNoise1.kr(2).range(8704, 8709),
      LFNoise1.kr(2).range(8807, 8817),
      LFNoise1.kr(2).range(9570, 9607),
      LFNoise1.kr(2).range(10567, 10572) - Line.kr(20, 0, 0.05),
      LFNoise1.kr(2).range(10627, 10636) + Line.kr(35, 0, 0.05),
      LFNoise1.kr(2).range(14689, 14697) - Line.kr(10, 0, 0.05)
    ],
    [
      LFNoise1.kr(1).range(-10, -5).dbamp,
      LFNoise1.kr(1).range(-20, -10).dbamp,
      LFNoise1.kr(1).range(-12, -6).dbamp,
      LFNoise1.kr(1).range(-12, -6).dbamp,
      -20.dbamp,
      -20.dbamp,
      -20.dbamp,
      -25.dbamp,
      -10.dbamp,
      -20.dbamp,
      -20.dbamp,
      -25.dbamp
    ],
    [
      20 * freqscale.pow(0.2),
      20 * freqscale.pow(0.2),
      5,
      5,
      0.6,
      0.5,
      0.3,
      0.25,
      0.4,
      0.5,
      0.4,
      0.6
    ] * freqscale.reciprocal.pow(0.5)
  ], input, freqscale, 0, decayscale);
  
  sig;
}.play(fadeTime: 0);
)

To work out the DynKlank parameters, I opened a recording of a tibetan prayer bell in the analysis software SPEAR and just tried to mimic each partial’s frequency movement, amplitude, and decay time as closely as possible.

3 Likes

amazing! thanks so much! This is exactly what I want/need to read.