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; ) ::