| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
ADSR-ääniZtane 23.08.07 22:44 Esittelee eri python-ominaisuuksia - luokat, binaaritiedostot, struct.pack, generaattorit, klosuurit, lambda-funktiot, ja tekee samalla myös ääntä
# kaytto: python adsr.py aani.raw # # vaatii varmaankin python 2.4:n # # soita aani vaikka komennolla aplay -f cd aani.raw import math import struct import sys class ADSR: # luokan konstruktori. # parametrit a, d, r, on # atakin, dekayn, releasen pituus sekunneissa, # s on sustaintaso 0 .. 1 # length on koko nuotin mitta eli # sustainin pituus on length - a - d - r. # siistimmankin saa tehda jos osaa. # (vahan quick'n'dirty) def __init__(self, a, d, s, r, length): if a == 0 or r == 0 or d == 0 or length == 0: raise ValueError("Keston pitaa olla != 0") self.a = a self.d = d self.s = s self.r = r self.suslength = length - self.a - self.d - self.r self.length = length # laskee adsr-ampin kohdassa time (sekunteja) # ihan peisik lineaarinen, vahan rumasti tehty # vois ehka kayttaa jotain eksponenttifunktiota # tms lisamaan pehmeytta (tietyt atakit napsuu pahasti!) def get_amp(self, time): # attack? if (time < self.a): return time / self.a time -= self.a # decay? if (time < self.d): return 1.0 - (time / self.d) \ * (1 - self.s) time -= self.d # sustain? if (time < self.suslength): return self.s # release.. return self.s * (1 - (time - self.suslength) / self.r) # applyttaa adsr:aa sampleratella rate funkkariin wavefunk, # palauttaa yksittaisia amplitudeja valilla -1 .. 1 (eli siis # sampleja annetulla ratella). Wavefunkin PITAA antaa # amplitudit valilla -1..1, kompuraa ei ole, eika limitteria # (koodi kaatuu sitten poikkeukseen struct.packissa ;) # # wavefuncia evaluoidaan diskreeteissa ajankohdissa t # missa t on aika sekunteina. # # metodi on generaattori, ts yield-lause palauttaa arvoja # toiseen saikeeseen def apply(self, wavefunc, rate): # tama vain siksi etta jakolasku pakottuisi floateiksi # koska kyseessa on loop invariant, otin sen ulos... rate = float(rate) # kesto s, kertaa samplet per minuutti samples = int(self.length * rate) # eli 0..samples - 1 silmukkaa for i in xrange(samples): # i:nnen samplen ajankohta t = i / rate # evaloidaan wavefunkki ja verhokappyra # ja kerrotaan keskinnaan yield wavefunc(t) * self.get_amp(t) # aanta! palauttaa lambdafunktion: perusaanes # @f hz, harmonisina yla-aanina vaimeampana # kvintti ylospain (* 1.5) ja oktaavi (* 2). # Amplitudien sopivalla skaalauksella ~ -1...1 def aani(f): # 2 pi f m = 2 * 3.14159 * f # lambdafunktio, klosuuri (m-muuttujaa # ulkopuolelta kaytetaan palautetussa funktiossa...) # palauttaa siis funktio-olion, joka palauttaa # diskreetin amplitudin ajanhetkella t [s] ;) return lambda t: \ .75 * math.sin(m * t) + \ .17 * math.sin(m * 1.5 * t) + \ .07 * math.sin(m * 2 * t) # tarkista etta tiedostonnimi annettu if len(sys.argv) != 2: print "Anna tiedostonimi!" sys.exit(1) # ja ala paukuttaa binaaritiedostoon f = file(sys.argv[1], 'w') # tee verhokappyra # # attack 1ms, # decay 1ms # sustaintaso 0,4 # release 200ms, # koko kesto 250ms adsr = ADSR(.001, .001, .4, .2, .25); # ok... c - c1-oktaavi, 44100 samplea / s, stereosamplet 16 bit for freq in [ 261.63, 293.66, 329.63, 349.23, 392.00, 440.0, 493.88, 523.25 ]: # heh, iteroi sample kerrallaan aanifunktiota, johon on # applytetty adsr, @ 44100 hz samplaystaajuus for i in adsr.apply(aani(freq), 44100): # kerro -1 ... 1 32767:lla (tuloksena siis # signed shortin alue (-32768 ... 32767) s = int(i * 32767); # tallenna molemmille kanaville shortteina (h)... # eli 16 bittia kanava, vasen ja oikea... # silmukan joka kierros siis tallettaa nelja tavua. f.write(struct.pack('hh', s, s)) f.close() Entropia 08:38 24.8.07 Saatan ehkä aistia mikä on kirvoittanut tämän pätkän. :) Hyvää oppimateriaalia, vaikkakaan ihan kaikkea ei ole ruohonjuuritasolta selitetty. Ztane 11:02 24.8.07 selitin enämpi |
![]() Haku
|