rsc3/doc-schelp/HelpSource/Classes/AmpComp.schelp

170 lines
3.1 KiB
Text
Raw Normal View History

2022-08-24 13:53:18 +00:00
class:: AmpComp
summary:: Basic psychoacoustic amplitude compensation.
related:: Classes/AmpCompA
categories:: UGens>Analysis>Amplitude
Description::
Implements the (optimized) formula:
code::
compensationFactor = (root / freq) ** exp
::
Higher frequencies are normally perceived as louder, which AmpComp
compensates.
classmethods::
method::ar, kr, ir
argument::freq
Input frequency value. For freq == root, the output is 1.0.
argument::root
Root freq relative to which the curve is calculated
(usually lowest freq).
argument::exp
Exponent: how steep the curve decreases for increasing freq.
discussion::
Note that for frequencies very much smaller than root the amplitudes can become very high.
In this case limit the freq with code::freq.max(minval)::, or use AmpCompA.
Examples::
code::
// compare a sine without compensation
{ SinOsc.ar(MouseX.kr(300, 15000, 1)) * 0.1 }.play;
// with one that uses amplitude compensation
(
{
var freq;
freq = MouseX.kr(300, 15000, 1);
SinOsc.ar(freq) * 0.1 * AmpComp.kr(freq, 300)
}.play;
)
// different sounds cause quite different loudness perception,
// and the desired musical behavior can vary, so the exponent can be tuned:
(
{
var freq;
freq = MouseX.kr(300, 15000, 1);
Pulse.ar(freq) * 0.1 * AmpComp.kr(freq, 300, 1.3)
}.play;
)
// the curves:
// exp = 0.3333
(200,210..10000).collect {|freq| (200/freq) ** 0.3333 }.plot;
// nearly linear for semitone steps:
(48..72).midicps.collect {|freq| (48.midicps/freq) ** 0.3333 }.plot;
{ AmpComp.ar(Line.ar(48, 72, 1).midicps, 48.midicps) }.plot(1.0);
// exp = 1.2
(200,210..10000).collect {|freq| (200/freq) ** 1.2 }.plot;
(48..72).midicps.collect {|freq| (200/freq) ** 1.2 }.plot;
{ AmpComp.ar(Line.ar(48, 72, 1).midicps, 48.midicps, 1.2) }.plot(1.0);
// amplitude compensation in frequency modulation
(
{
var freq;
freq = MouseX.kr(300, 15000, 1);
freq = freq * SinOsc.ar(MouseY.kr(3, 200, 1), 0, 0.5, 1);
SinOsc.ar(freq) * 0.1 * AmpComp.ar(freq, 300)
}.play;
)
// without amplitude compensation
(
{
var freq;
freq = MouseX.kr(300, 15000, 1);
freq = freq * SinOsc.ar(MouseY.kr(3, 200, 1), 0, 0.5, 1);
SinOsc.ar(freq) * 0.1
}.play;
)
// in granular synthesis:
(
SynthDef("pgrain",
{ arg out = 0, sustain=0.01, amp=0.5, pan = 0;
var freq = MouseX.kr(300, 7000, 1);
var window = Env.sine(sustain, amp * AmpComp.ir(freq));
Out.ar(out,
Pan2.ar(
SinOsc.ar(freq),
pan
) * EnvGen.ar(window, doneAction: Done.freeSelf)
)
}
).add;
)
// send grains
(
fork {
loop {
s.sendBundle(0.1, [\s_new, \pgrain, -1,1,1]);
0.02.wait;
};
}
)
// try different synth defs:
// without AmpComp:
(
SynthDef("pgrain",
{ arg out = 0, sustain=0.01, amp=0.5, pan = 0;
var freq = MouseX.kr(300, 7000, 1);
var window = Env.sine(sustain, amp);
Out.ar(out,
Pan2.ar(
SinOsc.ar(freq),
pan
) * EnvGen.ar(window, doneAction: Done.freeSelf)
)
}
).add;
)
// with AmpCompA
(
SynthDef("pgrain",
{ arg out = 0, sustain=0.01, amp=0.5, pan = 0;
var freq = MouseX.kr(300, 7000, 1);
var window = Env.sine(sustain, amp * AmpCompA.ir(freq));
Out.ar(out,
Pan2.ar(
SinOsc.ar(freq),
pan
) * EnvGen.ar(window, doneAction: Done.freeSelf)
)
}
).add;
)
::