Digitális hangminták
Gaga
|
Egyszerű 10-15-soros C programokat írunk, melyek hangtechnikai effekteket valósítanak meg. Az effekteket csővezetékbe kapcsoljuk, mint a gitáros az effektpedálokat. A bináris fájlokon (és bináris standard input/outputon) kívül a hangfájlok rendszertechnikáját ismerjük meg.
A hang a fület érő hangnyomás időbeli váltakozása: \(p(t)\), ahol \(t\) az idő, \(p\) pedig a hangnyomás.
A digitális hangminta a hangnyomás értékének rögzítése \(\Delta t\) időközönként egy tömbben \(p[k] = p(k\Delta t)\) . Ezt a digitális tárolási technikát Pulse Code Modulation (PCM) néven szoktuk emlegetni. Az alábbi ábra egy sztereó hangmintát ábrázol. A vízszintes tengely az idő, a függőleges a normalizált hangnyomás.
Az egyes hangminta-adatokat különböző módon tárolhatjuk.
A mintavételezést sokszor inkább a \(\Delta t\) időlépés reciprokával, a mintavételi frekvenciával (sample rate) jellemezzük.
signed int
típussal tárol. Ekkor a hangminta adatait a \(-2^{15}\) és \(2^{15}-1\) közötti egész értékekkel reprezentáljuk, vagyis a legkisebb hangnyomásérték a -32768 és a legnagyobb a +32767. Az audió CD-k mintavételi frekvenciája 44100 Hz. Egy CD-ről leszedett 10 másodperces egycsatornás (monaurális, mono) hangminta egy 441 000 elemű tömbben tárolható.Egy sztereó hangminta külön tartalmazza a bal és a jobb fület érő hangjeleket. Kezelhetjük akár 2D tömbként is, melynek egyik dimenziója 2 méretű, de tipikusan összefésülve (interlace), 1D tömbként ábrázoljuk. Sztereó minta esetén az összefésült tömb az alábbi formátumú:
+--------+---------+--------+---------+--------+---------+---- | 0. bal | 0. jobb | 1. bal | 1. jobb | 2. bal | 2. jobb | ... +--------+---------+--------+---------+--------+---------+----
A hangfájlok digitális hangminták tárolására valóak. Rengeteg különböző hangfájl-formátum létezik.
lady_gaga_telephone_s16le_44100_2ch.raw
).Egy jó hanglejátszó szoftver számos hangformátumot ismer. A szoftver feladata a különböző tömörített formátumok felismerése, kitömörítése (nyers PCM adatfolyammá alakítása), és az adatfolyam hangkártyára küldése:
Az igazán jól használható hanglejátszó szoftver ezen kívül
Vannak ilyen programok. A két legismertebb és legszélesebb körben használt talán az mplayer és a vlc media player
Az alábbiakban a vlc media player használatát ismertetjük. Minden itt leírt funkció megvalósítható az mplayerrel is.
Az alábbi paranccsal a vlc megnyílik, és lejátssza a guns.mp3 fájlt:
vlc guns.mp3
Ha azt akarjuk, hogy a lejátszás után a vlc automatikusan bezáruljon,
vlc guns.mp3 vlc://quit
Igazából teljesen fölösleges a lejátszáshoz megnyitni a player GUI-ját (graphical user interface):
cvlc guns.mp3 vlc://quit
Itt a cvlc
a console vlc-re utal.
vlc -I dummyahol a
-I dummy
a (korántsem) buta parancssoros interfészt jelenti.Ha azt akarjuk, hogy a vlc a hang kimenetet ne a hangkártyára, hanem fájlba küldje, akkor fel kell paramétereznünk a stream outputot (sout
)
cvlc guns.mp3 --sout "#transcode{acodec=fl32,channels=2,samplerate=44100}:std{access=file,mux=raw,dst=guns.pcm}" vlc://quit
Itt a --sout
kapcsolót követően egy sztringet adtunk meg, mely a transzkóder (mp3-ból nyers PCM) paramétereit adja meg:
float
).Ekkor létrejött a guns.pcm
, melyben a guns.mp3
kitömörített PCM adatfolyama van a megadott paraméterekkel kódolva.
Már csak egyetlen dolog van hátra. Ha a vlc-vel nyers PCM adatot akarunk lejátszani, akkor tudatnunk kell vele annak formátumát:
cvlc guns.pcm --demux=rawaud --rawaud-fourcc=fl32 --rawaud-channels=2 --rawaud-samplerate=44100 vlc://quit
Itt a fourcc (four character code) paraméter adja meg a mintaadatok formátumát, a többi paraméter magáért beszél.
Összefoglalva képesek vagyunk
Kihasználva továbbá, hogy a VLC a kitölörített PCM-et nemcsak fájlba, hanem a standard outputra is tudja küldeni, továbbá a VLC nemcsak fájlból, hanem a standard inputról is képes olvasni, az alábbi blokkdiagram megvalósítására is képesek vagyunk:
Itt két VLC példányt indítunk el párhuzamosan, melyek egyszerre futnak. Az első kitömöríti a hangfájlt, és a nyers PCM-et kiküldi a standard outputra. A második a nyers PCM-et standard inputján kapja meg, és lejátssza.
Ehhez a megfelelő VLC-hívás az alábbi:
cvlc guns.mp3 --sout "#transcode{acodec=fl32,channels=2,samplerate=44100}:std{access=file,mux=raw,dst=-}" | cvlc - --demux=rawaud --rawaud-channels=2 --rawaud-fourcc=fl32 --rawaud-samplerate=44100
A két programot a pipe operátorral kapcsoltuk össze (|
). Az első parancsban a dst=-
felelős a fájl helyett standard otputra küldésért, a másodikban a bemenő fájl helyén a -
paraméter utal a standard inputról való lejátszásra.
Ezek után már csak a két nyers PCM fájl közé kell C programokat (effekteket) írnunk. A kibővített blokkdiagramunk tehát
Egy megfelelő (és első körben semmit nem csináló) effektprogram a sztereó drót, mely a wire.c fájlban van megvalósítva. Ez a program kettesével olvas hangmintákat a bemenetről, amíg csak jönnek, és kiírja őket a kimenetre. Ahhoz, hogy jól lefusson, fontos, hogy a standard streameket (stdin és stdout) binárisra állítsuk. A standard inputról és outputról a 7. előadáson azt tanultuk, hogy "szöveges fájlok", melyek automatikusan megnyílnak a program indulásakor. A binary_streams függvény újranyitja őket bináris módban, mert a PCM adatok nem szövegesen, hanem float
értékek formájában érkeznek.
Nagyon egyszerű az erősítő effekt, melyet az amplify.c valósít meg. Ez a sztereó drót minimális módosításával megvalósítható. A bejövő hangmintákat egy konstanssal szorozzuk, mely a program parancssori paramétereként adható meg. Ezek értelmében a program lehetséges használata
amplify 10.0 < input.pcm > output.pcm
A legegyszerűbb torzító úgy működik, hogy a bemenő \(x\) jelet felerősítjük \(d\)-szeresre (ez a drive), majd \(\pm 1\) szinten levágjuk (limiter). A distort.c fájlban megtalálható torzító algoritmusa az erősítő minmális továbbfejlesztésével kódolható. Hogy ne legyen túl hangos a kimenet, a torzító mögé kacsolhatunk egy erősítőt, mellyel csillapítunk az alábbi módon:
distort 20 < input.pcm | amplify .1 > output.pcm
Az effekt nyers bemenete: queen. az effekt kimenete: queen_dist
A delay.c fájlban megvalósított zengető egyszerű szabályos visszaverődésekből álló végtelen visszhangot valósít meg. Megvalósítása végtelenített (cirkuláris) tárolóval történik. A cirkuláris tároló egyszerű tömb, melyet 0-tól N-1-ig indexelünk, de az N-1. elem után ismét a nulladikat írjuk felül. A tároló kezdetben üres, mi pedig feltöltjük a beérkező mintaelemekkel. Mikor már létező elemét írnánk felül, annak értékét megszorozzuk az \(\alpha < 1\) csillapítással (ez a visszhang csillapítása), majd hozzáadjuk az éppen beérkező mintaelemet. A visszhang késleltetését a tároló hossza határozza meg.
Az aktuális kimenet az éppen módosított tárolóelem lesz.
A cirkuláris puffer sztereó minta esetén egy 2D tömb, ahol az N érték természetesen konstans.
A feldolgozási fázis pedig az alábbi módon algoritmizálható (a k számláló értéke kezdetben 0):
Az effekt alkalmazása:
delay .2 .3 < input.pcm > output.pcm
ahol az első paraméter a 0.2 másodperces visszahngkésleltetésre, a második pedig a 0.3 értékű csillapításra utal.
A nyers hangbemenete: living. Az effektezett kimenete: living_delay
A vibrátó a hangmagasság periodikus, gyors (pár hertzes) változtatását jelenti. A vibrátó algoritmusának megértéséhez először egy egyszerű késleltetőt valósítsunk meg:
A késleltető egy tömb, melyet cirkulárisan feltöltünk a beérkező elemekkel. A cirkuláris feltöltés ugyanúgy történik, mint az előző példában, csak itt a korábbi elemeket egyszerűen felülírjuk. Ezáltal a tároló mindig az N megelőző mintaelemet tartalmazza. A késleletetés megvalósításához az aktuális kimenetet a tárolóból a beírás ütemével szinkronban, de lemaradva olvassuk ki:
A fenti példában az algoritmus N/2 elemnyi késleltetéssel dolgozik.
A vibrátó azt jelenti, hogy az olvasófej pozícióját periodikusan elmozdítjuk. Az alábbi példában az olvasófej kitérése
\( d \cdot \sin(2\pi f_{vib} k \Delta t)\)
vagyis maximum \( d \) mintaelemnyivel tér ki a szinkron pozícióhoz képest, és ezt \(f_{vib}\) frekvencián teszi.
A nyers hangbemenet: billie. Az effektezett kimenet: billie_vib
A kórus effekt legegyszerűbb verziója egy vibrátóval megeffektezett hangjel, melyhez hozzákeverjük (hozzáadjuk) az eredeti nyers hangot is. A vibrátó ismeretében igen könnyen leprogramozható, érdekes hangzása van:
A nyers hangbemenet: guns. Az effektezett kimenet: guns_chorus
Az összes program innen tölthető le. Egyszerűen fordulnak. VS alatt
cl amplify.c cl distort.c cl delay.c cl vibrato.c cl chorus.c
gcc-vel
gcc amplify.c -o amplify gcc distort.c -o distort gcc delay.c -o delay gcc vibrato.c -o vibrato -lm gcc chorus.c -o chorus -lm
ahol a -lm
a math.h
beillesztése miatt kell.