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

189 lines
3.3 KiB
Racket

#lang scribble/manual
@(require (for-label racket))
@title{AmpComp}
Basic psychoacoustic amplitude compensation.@section{related}
Classes/AmpCompA
@section{categories}
UGens>Analysis>Amplitude
@section{description}
Implements the (optimized) formula:
@racketblock[
compensationFactor = (root / freq) ** exp
::
Higher frequencies are normally perceived as louder, which AmpComp
compensates.
]
@section{classmethods}
@section{method}
ar, kr, ir
@section{argument}
freq
Input frequency value. For freq == root, the output is 1.0.
@section{argument}
root
Root freq relative to which the curve is calculated
(usually lowest freq).
@section{argument}
exp
Exponent: how steep the curve decreases for increasing freq.
@section{discussion}
Note that for frequencies very much smaller than root the amplitudes can become very high.
In this case limit the freq with
@racketblock[freq.max(minval)::, or use AmpCompA.
]
@section{Examples}
@racketblock[
// 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;
)
::
]