Im letzen Teil habe ich schon etwas zu Kontrollvariablen geschrieben. Ich habe gezeigt, wie man den Opcode line dazu benutzen kann, die Tonhöhe über die Zeit zu ändern. Dasselbe können wir natürlich auch mit der Lautstärke machen.
Amplitude Envelopes
instr 1
kenv line 0, p3, 10000 ;linear ramp from 0 zo 10000
aone oscil kenv, 320, 1 ;amplitude envelope (kenv)
out aone
endin
Diese line Kontrollvariable ändert die Lautstärke des Tons, indem sie einen Amplitude Envelope erzeugt. Wenn man sich schon vorher ein wenig mit Synthesizern beschäftigt hat, dann ist einem solch ein Envelope Generator sicherlich schon einmal über den Weg gelaufen. Das klassische ADSR-Modul kann dafür benutzt werden. In unserem Fall lassen wir die Lautstärke von 0 auf 10.000 ansteigen. Das wäre ein Attack (A) Wert von 3 Sekunden, wobei D, S und R auf 0 gedreht wären.
Wie das klingt kann man im kompletten Beispiel anhören:
<CsoundSynthesizer>
<CsOptions>
-odac ;realtime audio
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 10
nchnls = 1
instr 1
kenv line 0, p3, 10000 ;linear ramp from 0 zo 10000
aone oscil kenv, 320, 1 ;amplitude envelope (kenv)
out aone
endin
</CsInstruments>
<CsScore>
f1 0 4096 10 1 ;instr1 sinus
i1 0 3 ;instr1, lasts 3sec
</CsScore>
</CsoundSynthesizer>
Wir haben nun also drei verschiedene Möglichkeiten kennengelernt, wie man dem Oszillator seine Lautstärke und Frequenz vorgeben kann. Entweder direkt als Konstante in den Opcode geschrieben, oder indirekt mithilfe von p-Feldern, die wir dann im Score angeben, oder aber mithilfe von Kontrollvariablen.
Kontrollvariablen mit mehreren Segmenten
Es ist auch möglich einen Ton erst ansteigen und dann wieder abfallen zu lassen, ebenso kann man natürlich auch die Lautstärke erst zunehmen und dann wieder abfallen lassen. Das würde dann einem Attack-Decay-Envelope entsprechen. Außerdem sind auch noch komplexere Formen möglich. Erreichen kann man diese mithilfe des linseg Opcodes. Während line nur ein Liniensegment erzeugt, kann linseg gleich mehrere erzeugen – ein Segment gefolgt vom nächsten… Die allgemeine Syntax sieht so aus:
kx linseg a, dur, b, dur, c ...
Z.B. erzeugt der folgende Code einen Oszillator, dessen Frequenz erst von 300Hz nach 800Hz ansteigt und dann nach 400Hz abfällt.
instr 1
ksweep linseg 300, p3/2, 800, p3/2, 400
anew oscil 10000, ksweep, 1
out anew
endin
ksweep im oberen Beispiel hat zwei Segmente. In diesem Fall wurde die Tondauer (p3) einfach in zwei große Teile aufgeteilt (p3/2).
Um drei Segmente zu erzeugen, könnte man die Zeit bspw. einfach durch 3 teilen und dementsprechend ein Argument zu linseg dazuschreiben.
instr 1
ksweep linseg 800, p3/3, 1000, p3/3, 400, p3/3, 900
anew oscil 10000, ksweep, 1
out anew
endin
Hier wurden die Frequenzen wieder fest in den Opcode linseg geschrieben. Natürlich kann man diese auch erst beim Schreiben des Scores festlegen, somit kann man dann für jede gespielte Note entschieden, welche Tonhöhe wo und wie zu ändern ist.
instr 1
ksweep linseg p5, p3/3, p6, p3/3, p7, p3/3, p8
anew oscil 10000, ksweep, 1
out anew
endin
Im folgenden Code nutzen wir einen zweiten linseg Opcode, der einen Amplitude Envelope erzeugt, mit Attack, Sustain und Decay.
instr 1
ksweep linseg p5, p3/3, p6, p3/3, p7, p3/3, p8
kenv1 linseg 0, p3/3, 10000, p3/3, 10000, p3/3, 0
anew oscil kenv1, ksweep, 1
out anew
endin
In diesem Fall steigt die Amplitude von 0 auf 10.000 in p3/3 (attack time), hält dann den Wert für p3/3 Sekunden (sustain) und fällt wieder auf 0 in den verbleibenden p3/3 Sekunden (decay).
Falls wir Zeitsegmente nutzen, die zusammen nicht die gesamte Spieldauer der Note ergeben, dann wird der Wert des letzten Segments für den Rest der Zeit angewandt.
k1 linseg 0, p3/3, 1, p3/3, 0
Kontrollvariablen mit mehreren exponentiellen Segmenten
Zusätzlich zu linearen Segmenten kann Csound auch exponentielle Segmente erzeugen. Es ist nun mal so, das exponentielle Frequenzänderungen einfach natürlicher für’s menschliche Ohr klingen. Das exponentielle Äquivalent zu line ist expon und das exponentielle Pendant zu linseg ist expseg.
kx expon ia, idur, ib
kx expseg ia, idur1, ib, idur2, ic ...
In beiden Fällen ist die Syntax praktisch dieselbe, wie auch bei line oder linseg. Der einzige Unterschied ist der, dass exponentielle Opcodes keine 0 als Größe akzeptieren. Falls eine 0 benötigt wird, muss man einen sehr kleinen Wert wie 0.01 nehmen.
<CsoundSynthesizer>
<CsOptions>
-odac ;realtime audio
</CsOptions>
<CsInstruments>
sr = 48000
ksmps = 10
nchnls = 1
instr 1 ;instrument #1
kglis expon 220, p3, 740 ;exp segment, raising from 220 to 440
;in p3 seconds, outpit in kglis
a1 oscil p4, kglis, 1 ;oscillator, amp is p4, freq follows kglis,
;waveform function #1
out a1
endin
instr 2 ;instrument #2
ksweep expseg p5, p3/2, p6, p3/2, p7 ;2 exp. segments (freq)
kenv1 expseg .001, p3/3, 10000, p3/3, 10000, p3/3, .0001
;3 exp. segments (amp)
a2 oscil kenv1, ksweep, 1
out a2
endin
</CsInstruments>
<CsScore>
f1 0 4096 10 1 ;instr1 sinus
i1 0 3 10000
i2 0 3 10000 300 600 300
</CsScore>
</CsoundSynthesizer>
Envelopes mit linen
In Csound gibt es einen speziellen Opcode für trapezoide Envelopes: Attack-Sustain-Release.
kenv linen kamp, iatt, idur, irel
- kamp ist die Spitze der Amplitude (die höchste Lautstärke des Sounds)
- iatt ist die Dauer der Attack-Phase (attack time)
- idur ist die gesamte Dauer des Sounds (normalerweise die Dauer von p3)
- irel ist die Dauer der Release-Phase.
Ein Beispiel:
instr 1
kenv linen 1000, 0.1, p3, 0.5
a1 oscil kenv, 440, 1
out a1
endin
Wenn die Dauer der Note (p3) geändert wird, wird die Dauer des Sustain Parts dementsprechend verändert. Die Attack Time und die Release Time bleiben dabei so, wie angegeben.
Soviel erstmal zu Envelopes. Im nächsten Artikel geht es dann etwas mehr um Frequenzen und Amplituden. Außerdem zeige ich noch, wie man das Schreiben des Scores etwas angenehmer macht.
2 Pingbacks