Vowel
Inherits from: Object
a Vowel contains and manipulates the Formants of a vowel sound.
Implememted jointly by Florian Grond and Till Bovermann, June 2011
This class implementation was supported by:
the Ambient Intelligence Group, CITEC ( http://www.techfak.uni-bielefeld.de/ags/ami ) Bielefeld University, and
the TAI Studio ( http://TAI-Studio.org ), Department of Media, Aalto University, Helsinki.
Many thanks to Alberto de Campo and and Julian Rohrhuber.
the vowel class contains and handles data to describe the 5 Formants that allow to distinguish the vowel sounds \a, \e, \i, \o, \u for the registers \bass, \tenor, \counterTenor, \alto, \soprano.
The centre frequency, width and gain of these formants are taken from the C-soundmanual:
http://www.csounds.com/manual/html/MiscFormants.html
The vowel class and ugens
the vowel class is meant to be used together with the two pseudo ugen classes Formants.ar and BPFStack.ar (see below).
// Start internal server
s = Server.internal.boot;
Server.default = Server.internal;
// Create analyzer in a window you might want to see the spectrum of your vowels
(
w = Window("Frequency Spectrum", Rect(0, 0, 300, 200)); // width should be 511
f = FreqScopeView(w, w.view.bounds);
f.active_(true); // turn it on the first time;
f.dbRange_(100); // turn it on the first time;
w.onClose_({ f.kill }); // you must have this
w.front;
)
Creation / Class Methods
*new (vowel, register)
creates a new instance of Vowel
vowel - selecty a vowel by the symbols \a, \e, \i, \o, \u. default value is 'a'.
register - select a register by the symbols \bass, \tenor, \counterTenor, \alto, \soprano. Default value is 'bass'.
Vowel(); // defaults to A bass
Vowel(\a, \bass);
Vowel(\e, \tenor);
Vowel(\i, \counterTenor);
Vowel(\o, \alto);
Vowel(\u, \soprano);
{Formants.ar(100, Vowel(\e, \bass)) * 0.1 }.play
{Formants.ar(200, Vowel(\o, \alto)) * 0.1 }.play
{Formants.ar(300, Vowel(\i, \soprano)) * 0.1 }.play
The class exhibits multichannel expansion behaviour
{Formants.ar(100, Vowel([\e, \o], [\bass])) * 0.1 }.play
{Formants.ar(100, Vowel(\e, [\bass,\alto])) * 0.1 }.play
{Formants.ar(100, Vowel([\e, \o], [\bass,\alto])) * 0.1 }.play
*basicNew (freqs, dBs, widths)
You can also explicitly set the formants
freqs - an array of 5 freqs. Default value is nil.
dBs - an array of 5 dBs. Default value is nil.
widths - an array of 5 widths in Hz. Default value is nil.
Vowel.basicNew([ 300, 400, 2700, 3800, 4950 ], [ 0, -16, -35, -40, -6 ], [ 50, 10, 170, 180, 200 ])
*compose (vowels, registers, weights)
compose your own vowel out of the formTable filled with the initClass method, the arguments are arrays that do not need to be of the same size
vowels - vowels is an array of symbols \a, \e, \i, \o, \u. Default value is nil.
registers - registers is an array of symbols \bass, \tenor, \counter, \alt, \sopran. Default value is nil.
weights - registers is an array of weights Default value is nil, for reasonable values it should be a normalized sum.
Vowel.compose([\a,\e,\i], [\bass,\soprano,\alto], [0.2, 0.3, 0.5]);
Vowel.compose([\a,\e], [\soprano], [9, 4].normalizeSum);
Vowel.compose([\a], [\tenor, \counterTenor, \soprano], [1, 4, 2].normalizeSum);
Vowel() + Vowel()
(
{ var v = Vowel.compose([\a, \e, \i], [\soprano, \bass, \tenor, \counterTenor, \alto], ({10.rand}!5).normalizeSum);
Formants.ar(50 + 300.rand, v) * 0.1
}.play
)
*formLib
formLib is a Library and holds the formants freqs, widths, and dBs. of formTable and a link to its help file.
Vowel.formLib.at(\a)
Vowel.formLib.at(\a, \bass)
Vowel.formLib.at(\a, \bass, \freq)
Vowel.formLib.postTree;
save(path, timbre, register)
v = Vowel.compose([\a,\e], [\bass, \tenor], [1,1].normalizeSum )
v.save(Platform.userAppSupportDir++"/myVowelLibrary.scd", \timbre0, \register0)
*load(path)
Vowel.load(Platform.userAppSupportDir++"/myVowelLibrary.scd")
Vowel( \timbre0, \register0)
Accessing Instance variables
freqs_(arg1)
freqs
array of freqs for each vowel of a certain register
v = Vowel(\e, \tenor)
v.freqs
v.freqs_({|i| 100 * (i+1) }!5)
v.freqs
dBs_(arg1)
dBs
array of dBs for each vowel of a certain register
v = Vowel(\u, \counterTenor)
v.dBs
v.dBs_({|i| -10 * (i) }!5)
v.dBs
widths_(arg1)
widths
array of widths in Hz for each vowel of a certain register
v = Vowel(\o, \soprano)
v.widths
v.widths_({ 500.rand }!5)
v.widths
asArray
asArray is a method used internally but aslo for the controlling the pseudo ugens Formants and BPFStack.
It returns an arrays of [ freqs, dBs, widths ] of a vowel instance.
v = Vowel(\i, \soprano)
v.asArray
addFormants (freq, dB, width)
removeFormants (index)
v = Vowel()
v.addFormants([3000,4000], -6, [200, 200])
{Formants.ar(100, v) * 0.1 }.play
{Formants.ar(100, Vowel()) * 0.1}.play
{[Formants.ar(100, Vowel()) * 0.1, Formants.ar(100, v) * 0.1 ]}.play
v.removeFormants([5,6])
ampAt (freq, filterOrder)
Vowel(\u).ampAt(100);
~range = {|i|i*2}!2000;
Vowel(\u).ampAt(~range ).plot;
Vowel(\u).ampAt(~range ).ampdb.plot(minval: -100, maxval: 0);
Vowel(\u).ampAt(~range, 0.5 ).plot;
Vowel(\u).ampAt(~range, 0.5 ).ampdb.plot(minval: -100, maxval: 0);
Vowel(\u).ampAt(~range, 3 ).plot;
Vowel(\u).ampAt(~range, 3 ).ampdb.plot(minval: -100, maxval: 0);
Vowel(\u).ampAt(~range, [3,1,0.5,2] ).plot
Vowel(\u).ampAt(~range, [3,1,0.5,2] ).ampdb.plot(minval: -100, maxval: 0)
blend (that, blendFrac)
blends two vowels with the coefficient blendFrac. The blending is a linear interpolation between midinotes, widths and dBs.
that - Vowel
blendFrac - coefficient. Default value is 0.5. range from 0.0 to 1.0
~v1 = Vowel(\i, \soprano)
~v2 = Vowel(\o, \alto)
~v1.blend(~v2, 0)
~v1.blend(~v2, 0.5)
~v1.blend(~v2, 1)
~v3 = Vowel(\a, \bass)
{ Formants.ar(150, ~v1.blend(~v2, MouseX.kr(0,1)).blend(~v3, MouseY.kr(0,1)) ) * 0.1 }.play
blend also allows you to blend two vowels with individual coefficients for freq, amp, and width.
freqFrac - frequency coefficient. Default value is 0.5. range from 0.0 to 1.0
ampFrac - amplitude coefficient. Default value is 0.5. range from 0.0 to 1.0
widthFrac - bandwidth coefficient. Default value is 0.5. range from 0.0 to 1.0
v = Vowel(\a, \bass)
v = Vowel(\i, \soprano)
v.blend(w, 0)
v.blend(w, 0.5)
v.blend(w, [0.1, 0.5, 0.8])
in the following example you''l notice the biggest contributioin to the recognizability of a vowel are the frequencies (MouseX) and the amplitudes (MouseY).
The bandwidths do not contribute much (modulated by a sinewave):
{ Formants.ar(150, Vowel(\a, \bass).blend(Vowel(\u, \bass), MouseX.kr(0,1), MouseY.kr(0,1), SinOsc.kr(0.5, 0, 0.5, 0.5) ) ) * 0.1 }.play
{ Formants.ar(150, Vowel(\e, \bass).blend(Vowel(\i, \bass), MouseX.kr(0,1), MouseY.kr(0,1), SinOsc.kr(0.5, 0, 0.5, 0.5) ) ) * 0.1 }.play
{ Formants.ar(150, Vowel(\i, \bass).blend(Vowel(\o, \bass), MouseX.kr(0,1), MouseY.kr(0,1), SinOsc.kr(0.5, 0, 0.5, 0.5) ) ) * 0.1 }.play
brightenRel (bright , refFormant)
allows to lift the upper formants by multiplying their dBs. The sum of all dBs remains fixed.
bright - coefficient to brighten the vowel. Default value is 1 (no change). Values > 3 cause strange behaviour (should be between 0 and 3).
refFormant - reference formant, whose amplitude remains unchanged. Default value is 0 (first formant)
NOTE: If the coefficient bright is > 1 and the refFormant is > 0, the resulting signal may raise to a very big amplitude
Vowel().brightenRel(1 ).dBs.postln;
Vowel().brightenRel(0.1).dBs.postln;
Vowel().brightenRel(1.5).dBs.postln;
// refFormant = 0 loud on the left
{Formants.ar(100, Vowel().brightenRel(MouseX.kr(0, 2), 0 )) * 0.1}.play
// refFormant = 1
{Formants.ar(100, Vowel().brightenRel(MouseX.kr(0, 2), 1 )) * 0.1}.play
// refFormant = 2
{Formants.ar(100, Vowel().brightenRel(MouseX.kr(0, 2), 2 )) * 0.1}.play
// refFormant = 3
{Formants.ar(100, Vowel().brightenRel(MouseX.kr(0, 2), 3 )) * 0.1}.play
// refFormant = 4 loud on the right
{Formants.ar(100, Vowel().brightenRel(MouseX.kr(0, 2), 4 )) * 0.1}.play
brightenLin (bright , refFormant )
allows to lift the upper formants by multiplying their dBs. the sum of all dBs remains constant.
bright - coefficient to brighten the vowel. Default value is 1 (no change). do not use very big values (typically between 0 and 3).
refFormant - reference formant, whose amplitude remains unchanged. Default value is 0 (first formant)
NOTE: If the coefficient bright is > 1 and the refFormant is > 0, the resulting signal may raise to a very big amplitude
Vowel().brightenLin(-1).dBs.postln;
Vowel().brightenLin( 0).dBs.postln;
Vowel().brightenLin( 1).dBs.postln;
// refFormant = 0 loud on the left
{Formants.ar(100, Vowel().brightenLin(MouseX.kr(0, 20), 0 )) * 0.1}.play
// refFormant = 1
{Formants.ar(100, Vowel().brightenLin(MouseX.kr(0, 20), 1 )) * 0.1}.play
// refFormant = 2
{Formants.ar(100, Vowel().brightenLin(MouseX.kr(0, 20), 2 )) * 0.1}.play
// refFormant = 3
{Formants.ar(100, Vowel().brightenLin(MouseX.kr(0, 20), 3 )) * 0.1}.play
// refFormant = 4 loud on the right
{Formants.ar(100, Vowel().brightenLin(MouseX.kr(0, 20), 4 )) * 0.1}.play
brightenExp (bright)
allows to relatively lift the upper formants by keeping the sum of gains of all formants constant.
bright - coefficient to brighten the vowel. Default value is 1 (no change). you can use very small and very big values (typically between 0 and 5).
Vowel().brightenExp(1).dBs.postln;
Vowel().brightenExp(0.1).dBs.postln;
Vowel().brightenExp(1.5).dBs.postln;
{Formants.ar(100, Vowel(\a, \bass).brightenExp(MouseX.kr(0,5))) * 0.1 }.play
addControls(id, rate, lag)
creates controls in the wrapping synth such that the vowel's parameters can be controlled seamlessly
from the language.
id - an id to identify one of possibly several vowels to control. Optional.
rate - either kr or ar.
lag - lagtimes
(
x = SynthDef(\vowel, {|freq = 420|
Out.ar(0,
Formants.ar(freq.lag(0.1), Vowel(\a).addControls(lag: 1)) * 0.01
)
}).play
)
x.setn(*([\freq, exprand(100, 1000)] ++ Vowel(\u, \soprano).asKeyValuePairs));
x.setn(*([\freq, exprand(100, 500)] ++ Vowel(\e, \bass).asKeyValuePairs));
x.setn(*([\freq, exprand(400, 1000)] ++ Vowel(\a, \soprano).asKeyValuePairs));
PseudoUgens to be used with Vowel:
Formants.ar(baseFreq, vowel, freqMods, ampMods, widthMods, unfold )
Formants is a Stack of the Formant ugens it needs a baseFreq and either an arrays of #freqs, #dBs and #widths or a Vowel.
baseFreq - base frequency. Default value is 100.
vowel - an instamnce of Vowel, has no Default value.
freqMods - frequency modulation. Default value is 1.
ampMods - amplitude modulation. Default value is 1.
widthMods - bandwidth modulation. Default value is 1.
unfold - whether to apply channel expansion or not. Default value is false.
on how "Formants" works internally:
since Formants are PseudoUgens, they return a BinaryOpUGen
Formants.ar(400, Vowel(\a))
// -> a BinaryOpUGen
if you set unfold to true: you see a Formant plus 4 BinaryOpUGen
Formants.ar(400, Vowel(\a), unfold: true)
// [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ]
this gives the same as unfold: false
Formants.ar(400, Vowel(\a), unfold: true).sum
// a BinaryOpUGen
here you get an array of two unfolded Formants the first with 200 hz the second with 400 Hz
Formants.ar([400, 200], Vowel(\a), unfold: true)
// [ [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ], [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ] ]
this gives two folded Formants the first with 200 hz the second with 400 Hz
Formants.ar([400, 200], Vowel(\a), unfold: false)
// [ a BinaryOpUGen, a BinaryOpUGen ]
the same applies if you have one basefrequency and several Vowels
Formants.ar(200, [Vowel(\a), Vowel(\a)], unfold: true)
// [ [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ], [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ] ]
Formants.ar(200, [Vowel(\a), Vowel(\a)], unfold: false)
// [ a BinaryOpUGen, a BinaryOpUGen ]
or several basefrequencies and several Vowels
Formants.ar([400, 200], [Vowel(\a), Vowel(\a)], unfold: false)
// [ a BinaryOpUGen, a BinaryOpUGen ]
Formants.ar([400, 200], [Vowel(\a), Vowel(\a)], unfold: true)
// [ [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ], [ a Formant, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ] ]
Note the difference:
Formants.ar([400, 200], Vowel(\a), unfold: true).sum // which is summing the first two formants (400, 200) Hz pairwise till the fifth formant
// [ a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen, a BinaryOpUGen ]
Formants.ar([400, 200], Vowel(\a), unfold: true).collect({|vow| vow.sum}) // only this equals to unfold: false
// [ a BinaryOpUGen, a BinaryOpUGen ]
listening section:
{Formants.ar(150, Vowel(\a))}.play // is equal to
{Formants.ar(150, Vowel(\a), unfold: true).sum }.play
{Formants.ar(150, Vowel(\a), unfold: true)}.play // on headphones you'll ony hear formant1 in chan1 and formant2 in chan2 the rest is in chan 3..5
{Formants.ar([100, 200], Vowel(\u), unfold: false)}.play // you hear 100 Hz U on chan1 and 200 Hz on chan2
{Formants.ar(100, [Vowel(\a), Vowel(\e)], unfold: true)}.play // \a on chan1 and \e on chan2
{Formants.ar([150, 200], [Vowel(\a, \bass), Vowel(\i, \counterTenor)], unfold: true)}.play // \a 150 Hz chan1 \i 200 Hz chan2
using freqMods, ampMods, widthMods:
{Formants.ar(70, Vowel(\e), freqMods: SinOsc.kr(1,0,0.1,1) )}.play;
{Formants.ar(70, Vowel(\e), freqMods: [SinOsc.kr(1,0,0.2,1), SinOsc.kr(1.1,0,0.2,1), SinOsc.kr(1.2,0,0.2,1), SinOsc.kr(1.3,0,0.2,1), SinOsc.kr(1.4,0,0.2,1) ] )}.play;
{Formants.ar(70, Vowel(\e), ampMods: SinOsc.kr(1,0,0.5,1) )}.play;
{Formants.ar(70, Vowel(\e), ampMods: [SinOsc.kr(1,0,0.5,1), SinOsc.kr(1.1,0,0.5,1), SinOsc.kr(1.2,0,0.5,1), SinOsc.kr(1.3,0,0.5,1), SinOsc.kr(1.4,0,0.5,1) ] )}.play;
{Formants.ar(70, Vowel(\e), widthMods: SinOsc.kr(1,0,0.99,1) )}.play;
{Formants.ar(70, Vowel(\e), widthMods: [SinOsc.kr(1,0,0.99,1), SinOsc.kr(1.1,0,0.99,1), SinOsc.kr(1.2,0,0.99,1), SinOsc.kr(1.3,0,0.99,1), SinOsc.kr(1.4,0,0.99,1) ] )}.play;
all together now:
{Formants.ar(70, Vowel(\e), freqMods: SinOsc.kr(1,0,0.1,1), ampMods: SinOsc.kr(1.1,0,0.5,1), widthMods: SinOsc.kr(1.2,0,0.999,1) )}.play;
(
{Formants.ar(70, Vowel(\u),
freqMods: [SinOsc.kr(1,0,0.2,1), SinOsc.kr(1.1,0,0.2,1), SinOsc.kr(1.2,0,0.2,1), SinOsc.kr(1.3,0,0.2,1), SinOsc.kr(1.4,0,0.2,1) ],
ampMods: [SinOsc.kr(1,0,0.5,1), SinOsc.kr(1.1,0,0.5,1), SinOsc.kr(1.2,0,0.5,1), SinOsc.kr(1.3,0,0.5,1), SinOsc.kr(1.4,0,0.5,1) ],
widthMods: [SinOsc.kr(1,0,0.99,1), SinOsc.kr(1.1,0,0.99,1), SinOsc.kr(1.2,0,0.99,1), SinOsc.kr(1.3,0,0.99,1), SinOsc.kr(1.4,0,0.99,1) ])
}.play;
)
(
{Formants.ar(SinOsc.ar(5, 0, 10, 80), Vowel(\i),
freqMods: [SinOsc.kr(1,0,0.2,1), SinOsc.kr(1.1,0,0.2,1), SinOsc.kr(1.2,0,0.2,1), SinOsc.kr(1.3,0,0.2,1), SinOsc.kr(1.4,0,0.2,1) ],
ampMods: [SinOsc.kr(1,0,0.5,1), SinOsc.kr(1.1,0,0.5,1), SinOsc.kr(1.2,0,0.5,1), SinOsc.kr(1.3,0,0.5,1), SinOsc.kr(1.4,0,0.5,1) ],
widthMods: [SinOsc.kr(1,0,0.99,1), SinOsc.kr(1.1,0,0.99,1), SinOsc.kr(1.2,0,0.99,1), SinOsc.kr(1.3,0,0.99,1), SinOsc.kr(1.4,0,0.99,1) ])
}.play;
)
use unfolding for independently spatialized formants of one vowel (use Mouse)
{ [Formants.ar(100, Vowel(\o), unfold: true), {|i| SinOsc.ar(MouseY.kr(0.2,1), ((i*MouseX.kr(0,pi*0.5))) )}!5 ].flop.collect({|args| Pan2.ar( args[0], args[1] ) }).sum }.play
and more complex with the modulation from above (use Mouse)
(
{ [Formants.ar(60, Vowel(\o).brightenRel(MouseY.kr(0,2), 1),
freqMods: [SinOsc.kr(1,0,0.2,1), SinOsc.kr(1.1,0,0.2,1), SinOsc.kr(1.2,0,0.2,1), SinOsc.kr(1.3,0,0.2,1), SinOsc.kr(1.4,0,0.2,1) ],
ampMods: [SinOsc.kr(1,0,0.5,1), SinOsc.kr(1.1,0,0.5,1), SinOsc.kr(1.2,0,0.5,1), SinOsc.kr(1.3,0,0.5,1), SinOsc.kr(1.4,0,0.5,1) ],
widthMods: [SinOsc.kr(1,0,0.99,1), SinOsc.kr(1.1,0,0.99,1), SinOsc.kr(1.2,0,0.99,1), SinOsc.kr(1.3,0,0.99,1), SinOsc.kr(1.4,0,0.99,1) ]),
{|i| SinOsc.ar((i+1)/MouseX.kr(0.2,1), ((i*pi)/10) )}!5 ]
.flop.collect({|args| Pan2.ar( args[0], args[1] ) }).sum }.play
)
BPFStack.ar(in, vowel, freqMods, ampMods, widthMods, unfold )
Formants is a Stack of the BPF filters it needs an in to chew on and either an arrays of #freqs, #dBs and #widths or a Vowel.
in - exciting Signal. Default value is nil.
BPFStack.ar(Impulse.ar(1), Vowel(\a))
~freq = 100;
{BPFStack.ar(Decay.ar(Saw.ar(~freq, 0.1), ~freq.reciprocal), Vowel(\a)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(Decay.ar(Saw.ar(~freq, 0.1), ~freq.reciprocal), Vowel(\e)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(Decay.ar(Saw.ar(~freq, 0.1), ~freq.reciprocal), Vowel(\i)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(Decay.ar(Saw.ar(~freq, 0.1), ~freq.reciprocal), Vowel(\o)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(Decay.ar(Saw.ar(~freq, 0.1), ~freq.reciprocal), Vowel(\u)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(ClipNoise.ar(0.3), Vowel(\a)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(ClipNoise.ar(0.3), Vowel(\e)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(ClipNoise.ar(0.3), Vowel(\i)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(ClipNoise.ar(0.3), Vowel(\o)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
{BPFStack.ar(ClipNoise.ar(0.3), Vowel(\u)) * EnvGen.kr(Env.perc, 2.0, doneAction: 2)}.play
and more complex with the modulation from above (use Mouse)
(
{ [BPFStack.ar(ClipNoise.ar(0.1), Vowel(\i).brightenExp(MouseY.kr(0,2), 1),
freqMods: [SinOsc.kr(1,0,0.2,1), SinOsc.kr(1.1,0,0.2,1), SinOsc.kr(1.2,0,0.2,1), SinOsc.kr(1.3,0,0.2,1), SinOsc.kr(1.4,0,0.2,1) ],
ampMods: [SinOsc.kr(1,0,0.5,1), SinOsc.kr(1.1,0,0.5,1), SinOsc.kr(1.2,0,0.5,1), SinOsc.kr(1.3,0,0.5,1), SinOsc.kr(1.4,0,0.5,1) ],
widthMods: [SinOsc.kr(1,0,0.99,1), SinOsc.kr(1.1,0,0.99,1), SinOsc.kr(1.2,0,0.99,1), SinOsc.kr(1.3,0,0.99,1), SinOsc.kr(1.4,0,0.99,1) ]),
{|i| SinOsc.ar((i+1)/MouseX.kr(0.2,1), ((i*pi)/10) )}!5 ]
.flop.collect({|args| Pan2.ar( args[0], args[1] ) }).sum }.play
)
Examples
the following example show how Vowels can be used within a SynthDef:
(
SynthDef(\vowblend,{|freq = 100, b1 = 0.5, b2 = 0.5, b3 = 0.5, b4 = 0.5 bright = 0, pan = 0|
var va = Vowel(\a, \bass),
ve = Vowel(\e, \tenor),
vi = Vowel(\i, \counterTenor),
vo = Vowel(\o, \alto),
vu = Vowel(\u, \soprano),
sig;
sig = Formants.ar(
freq,
va
.blend(ve, b1)
.blend(vi, b2)
.blend(vo, b3)
.blend(vu, b4)
.brightenExp(bright, 1)
)
* EnvGen.kr(Env.perc, 3.0, doneAction: 2);
Out.ar(0, Pan2.ar(sig, pan, 0.1));
}).add
)
(
Task({ 32.do({ arg i;
Synth(\vowblend, [
\pan, i.linlin(0,32, -1, 1 ),
\freq, i.linlin(0,32, 30, 66 ).midicps,
\b1, 2.rand,
\b2, 2.rand,
\b3, 2.rand,
\b4, 2.rand,
\bright, 1.5.rand
]);
0.25.wait
});}).play
)
using addControls to create buses
(
x = SynthDef(\test, {
Out.ar(0,
Formants.ar(420, Vowel(\a).addControls(3)) * 0.01
)
}).play
)
x.inspect
x.setn(*Vowel(\i).asKeyValuePairs(3));
the following example show how Vowels can be used within JITLib style:
NdefMixer(s);
Ndef(\vowel, {Formants.ar(200, Vowel(\a, \soprano)) * 0.01 }).play
(
Ndef(\vowel, {
Formants.ar(200,
Vowel(\o, \soprano)
.blend(Vowel(\i, \tenor), SinOsc.kr(10).range(0,1))) * 0.01
}).play
)
(
Ndef(\vowel, {
Formants.ar(LFNoise0.kr(10).exprange(100, 400),
Vowel(\o, \soprano)
.brightenExp(SinOsc.kr(2).range(0,1), 1),
unfold: true
).mean * 0.01
}).play
)
Ndef(\vowel, {
Formants.ar(200, Vowel(\a, \soprano).addControls(4)) * 0.01
}).play
Ndef(\vowel).setn(*Vowel(\e, \bass).asKeyValuePairs(4).flatten)
Ndef(\vowel).setn(*Vowel(\u).asKeyValuePairs(4).flatten)
Ndef(\vowel, {
Formants.ar(200, Vowel(\a, \soprano), unfold: true).scramble.keep(2) * 0.1
}).play
Ndef(\vowel).free(2)
Ndef(\vowel).fadeTime = 4;
(
Ndef(\vowel, {
Formants.ar([1, 2, 4] * 240 * {LFNoise1.kr(5, 0.003, 1)}!3, Vowel(\a, [\bass, \tenor, \soprano]),
freqMods: LFNoise1.ar(4*[0.1, 0.2, 0.3, 0.4, 0.5].scramble, 0.1, ampMods: [1, 1, 1, 0]
)).sum * 0.1
}).play
)
// FUN:
( // CPU demanding
~freqs = {|i| 50 * 1.5.pow(i) }!9;
~numChan = 2;
r = Routine{
var sustain = 8, transition = 3, overlap = 4;
var period = 1.5 * 2.sqrt;
var harms, amps;
0.5.wait;
inf.do{
harms = {|i| (i+1) * ~freqs.choose }!60;
amps = Vowel([\a,\e,\i,\o,\u].choose,[\bass,\tenor,\counterTenor,\alto,\soprano].choose).ampAt(harms);
{ PanAz.ar(~numChan, DynKlank.ar( `[~freqs,amps,amps],
Decay.ar(Impulse.ar( exp(1)/5.0 ), SinOsc.kr( pi/9.0, 1.0.rand ).range(0.05,0.7) ) ) *
EnvGen.kr(Env.new([-40,-20, -30,-40].dbamp, [2/5.0, 1/5.0,2/5.0],'exponential'), 1.0, timeScale: 35, levelScale: 0.1, doneAction: 2) ,SinOsc.kr(0.5, 1.0.rand) )}.play;
period.wait;
}
};
r.play;
)
r.stop; //stop spawning new synths
(
Ndef(\vowel).fadeTime = 5;
Ndef(\vowel, {
var freqs, dBs, widths, out;
var baseFreq = LFNoise0.kr([5, 10] * 0.1).round(0.1).exprange(50, 200) * [2, 1.01];
#freqs, dBs, widths = (Vowel(\i, \soprano).blend(Vowel(\o, \bass), LFNoise1.kr(0.1265))).blend(Vowel(\e, \bass), LFNoise1.kr(10)).asArray;
//freqs = freqs * SinOsc.ar([0.1, 0.2, 0.3, 0.4].scramble, Rand(), 0.1, 1);
freqs = freqs * LFNoise1.ar([0.1, 0.2, 0.3, 0.4].scramble, 0.1, 1);
out = [freqs, widths, dBs.dbamp].flop.collect{ |args|
Formant.ar(baseFreq, *args);
}.flop;
out = out.collect{|vocal|
Splay.ar(vocal)
}.sum.postln;
out
* LFPulse.ar([9, 9.01], 0, 0.4).range(0, 1).lag(0.01, 0.5)
* LFPulse.ar(0.1, [0, 0.35], [0.9, 0.8]).lag(0.01)
* 0.1
}).play
)