SerbianEnglish (United Kingdom)
Flash 10 Аудио, FFT (Fast Fourier Transform) ПДФ Штампа Eл. пошта
Написао Саша Рудан   
недеља, 07 децембар 2008 03:41
Често нам технологија помаже да учинимо ствари једноставнијима. То је наравно лијепо ;), али када нам помогне да учинимо немогуће ствари могућим, то је онда узбућујућа ствар. То се десило са новом аудио подршком у Флешу 10. У овом посту причам о имплементирању FFT (Fast Fourier Transform) са Flash-ом.

Увод

Задњих пар година Флешери су покушавали да извуку више из Флеша што се тиче звука. Flash 9 је омогућио рачунање спектра за аудио сигнал (SoundMixer.computeSpectrum(). Ово је омогућило прављење елегантих визуелизација звука у Флешу 9 са AS3. Међутим, велики проблем је остао са

  • генерисањем звука у реалном времену из Флеша
  • преузимање аудио спектра у реалном времену (computeSpectrum(), омогућава само асинхроно позивање и очитавање тренутног узорка, вођеног нпр. тајмером илидогађајом уласка на фрејм)
  • манипулисање аудио спектром аудио сигнала у реалном времену
  • снимање аудио сигнала са микрофона

Међутим са појавом ActionScript 3 брзина извршавања Флеш апликација се драматично повечала омогућујући разне трикове са динамичким генерисањем звука. Један од најфасцинантнијих је везан за динамичко креирање свиф (SWF) фајла који садржи аудио сигнал "спуштен" на Timeline (погледајте popforge библиотеку). Овим се фактичи генерисао аудио сигнал кроз његово паковање у свиф фајл и накнадно учитавање у извршујући свиф и тиме његово репродуковање. Ово је можда прљав, али фасцинантан начин проширивања могућности једнога окружења.

Други начин је био коришћење Јава аплета за манипулисање звуком и прослеђивање резултата преко јаваскрипта флешу на накнадну обраду и визуелизацију.

Flash 10

Flash 10 је унио најзначајније новости везано за рад са звуком у задњих пар верзија.

Креирање аудио записа

Најкраће речено, сада можемо да из наше AS3 апликације пунимо Sound објекат са аудио сигналом који представља обичан низ аудио семплова. Најузбудљивија ствар је да овај низ ми можемо сами креирати.

Исчитавање аудио семплова из аудио записа

Ово је друга узбудљива могућност која нам даје шансу да у реалном времену очитавамо аудио семплове некога mp3 фајла и нпр. миксујемо га са неким другим mp3 фајлом и тиме направимо једноставну миксету :)

Примјери

Примјери везани за ове нове могућности Flash-a 10 заиста није тешко наћи. Занимљив примјер је у самој Flash 10 документацији. Око овога у принципу неа ста даље да се пише, сем да се играјте колико са тим до миле воље :)

FFT (Fast Fourier Transform)

Увод

Временски и спектрални сигнал

Временски сигнал је запис неког сигналакроз вријеме, у случају дигитално семплованог сигнала, то је низ очитаних интензитета сигнала кроз вријеме у равномјерним временским размацима.

Спектрални сигнал се математички не разликује много :), међутим концептуално он представља скуп свих фреквенција садржаних у датом сигналу као и њихових интензитета и фаза. Као што је у дигиталном одабирању временски сигнал не садржи све временске вриједности, већ само оне узете у одређеним временским тренуцима, тј постоји Tdelta, тако је и за спектрални домен, у коме постоје само одређене фреквенције са истим размацима међу њима, Fdelta.Одавде је битно закључити да ако желимо да сазнамо заиста која фреквенција је у датом сигналу, ми ћемо оперисати увјек са грешком од Fdelta, мада за предвидив сигнал можемо је смањити интерполацијом.

FT (Fourier Transform)

FT (Fourier Transform) је најкраће речено, математички апарат који нам омогућава добијање спектралног сигнала из временског сигнала и обрнуто. Дакле, ако сте у могућности да приступите времнском сигналу (у флешу вам је то могућа кроз extract() методу), тада помоћу FT сте у могућности да добијете спектрални сигнал. Мало прецизније, користићете DFT (Discret Fourier Transform).

FT је у ствари полиномисање функције, слично Њутновим полиномима, с тим да FT пребацује сигнал у други домен и тиме даје интересантне могућности:

  • пичовање (pitch) сигнала
  • филтрирање сигнала (Lowpass, Highpass, bandpass филтери), редукција шума
  • детектовање главне фреквенције (гитар тјунер нпр :)
  • итд

За неке од ових ефеката потребна је и IFT (Inverse Fourier Transform). Она нам омогућава добијање пребацивање сигнала из спектралног домена у временски домен.

FFT & IFFT

FFT (Fast Fourier Transform) јe FT која је оптимизована и прилагођена рачунарском процесирању. Оптимизација је драматична и без ње многи данашњи алгоритми у реалном времену не би били могући.

Inverse FFT нам омогућава да се из спектралног домена вратимо натраг у временски домен.

Дакле сценарио је слиједећи:

  • сигнал се преузме у дигиталном облику
  • извршише иницијална обрада у временском домену (нпр. нормализовање сигнала, ...)
  • сигнал се пребаци у спекрални домен помоћу FFT
  • изврши се обрада у спектралном домену (нпр. lowpass филтерисање, ...)
  • сигнал се врати у временски домен помоћу IFFT
  • изврши се финална обрада сигнала у временском домен
  • сигнал се пошаље на излазу или слиједећи степен обраде

Један проблем при таквој обради сигнала је тај да ће на граничним зонама доћи до пуцкетања. Одакле ово пуцкетање? Оно је посљедица операција у спектралном домену. Ако сте пребацивање у спектрални домен користили само за очитавање сигнала а не и за модификовање, онда је наравно све у реду. Међутим ако сте га мјењали, тада су се у генералном случају пореметиле фазе. Оне су унутар интервала и непримјетне, али на ивицама нису, и тако помјерене фазе сигнала у једном интервалу и исто тако помјерене у другом интервалу ће изазвати пикове на "зашивеним" спојевима :).

Постоје начини да се то отклони, али о томе касније.

Примјер - Bandpass филтер

Увод

Овај примјер је релативно једноставан. Ипак у систему постоји више компоненти.

  1. Sound Dispatcher - Глобална инфраструктура која омогућава дистрибуирање аудио сигнала између различитих аудио пророцесирајућих компоненти
  2. SourceMP3 - Компонента која ектсракује аудио сигнал из mp3 фајла
  3. SourceOscillation - Компонента која генерише синусиодални сигнал
  4. Mixer - Компонента која миксује 2 аудио сигнала
  5. Output - Компонента која "пушта" аудио сигнал
  6. FourierTransformation - Компонента која врши фуријеову трансформацију
  7. Spectrum - Компонента која визуелизује спектар сигнала
  8. KnobSlider - визелни knob који омогућава промјену фреквенције осцилатора

Компоненте које ћу анализирати су компонента 1, 6 и 7. Остале су овдје само зарад тога да би примјер радио, и оне нису довршене нити тема овога поста, већ неког каснијег. Наравно, слободни сте да истражујете и да их користите :)



>>> Сорс код

Опис

Слиједећа слика описује ток сигнала у овом примјеру:

Bandpass audio flow

Свака од компоненти је довољно дескриптивна, једино се не види једна компонента а то је компонента која интегрише све друге компоненте. То је компонента која виртуелно повезујсе све компоненте и прослијеђује захтјеве и сигнал из једне у другу компоненту.

Ова компонента је садржана у Мain.as фајлу и за сада није најелегантније ријешена и вјероватно је превише комплексна, али разлог за то је што ће се касније развити AudioHeads систем који ће бити скуп Fash компоненти за обраду аудио сигнала и у ту сврху је потребна комплекснија дистрибуција сигнала.

Основни начин рада

Основни начин рада је представљен слиједећим процесом: излазна аудио компонента шаље захтјеве за аудио узорцима sоund distribution компоненти:

	var num: int = parent.RequestData(this, this.inputBuffer, length, startPosition);

Ова компонента води евиденцију о везама свих компоненти и прослеђује захтјев пријетходној компоненти у току аудио сигнала и враћа резултат излазној аудио компоненти.

	public function RequestData(requester:AudioComponent, target:ByteArray, 
length:Number, startPosition:Number = -1, channel:int=0):Number{
var sourceID:int = this.connectionsComponents[requester.id + channel*(LAST_COMPONENT+1)];
var sourceComponent:AudioComponent = this.components[sourceID];
return sourceComponent.RequestData(requester, target, length, startPosition);
}

Ова метода сазнаје из connectionsComponents матрице ID пријетходне компененте, референцира је из низа компоненти components, и прослијеђује захтјев тој компоненти, а резултат тога захтјева враћа компоненти која је послала захтјев (у овом случају излазној аудио компоненти).

Наравно пријетходна компонента ће тражити аудио сигнал од компоненте која њој пријетходи ;) и тако све докомпоненте која је извор звука и тада ће се резултовани звук пропагирати натраг до излазне компоненте.

FFT/IFFT компонента

Component name: FourierTransformation

Package: SoundProcessors

Ово је најважнија компонента а уједно готово и најједноставнија компонента :)

Битне су слиједеће функције:

RequestData()

Ово је метода коју имају све AudioProvider класе. Она је одговорна за прослијеђивање података аудио компоненти која јој слиједи у аудио ланцу, у овом случају аудио излазу.

Као што је већ речено ова метода прво тражи аудио одабирке од аудио компоненте која јој пријетходи у аудио ланцу (у овом случају аудио миксер) и за то се обраћа родитељској компоненти која је у ствари sound dispatcher.

У првој петљи, ова метода припрема податке за FFT обраду; пуни реалне и имагинарне одабирке. За случај реалног сигнала, имагинарни одабирци су 0. Такође пуни и излазне аудио одабирке за слиједећу компоненту у низу (у слућају да нема обраде сигнала у фреквентном домену).

Након тога се позива DirectFFT метода која израчунава фреквентни спектар из временског.За објашњавање ове методе је потребан не један нови пост већ бар једно поглавље, а основни концепт је објашњен у уводу, тако да овдје нећу ићи у детаље. За вас је вјероватно довољно да знате да она ради :).

Интересантно је да она као излаз даје фреквентни спектар у истим низовима који је напуњен са временским спектром, у овом случају inputs_real, inputs_imag. Ипак за кориснике је много битнија метода processOutput која из спектралног домену проналази локалне максимуме тј. носеће фреквенције. Код комплексног сигнала ово може дати пуно хитова, тако да је потребно урадити или налажење глобалног максимума, или поставити праг минималног интензитета. За одређене апликације (као у овом примјеру), позив ове функције није ни потребан. Такође треба размислити о оптималнијем складиштењулокалних максимума, јер се овако "малтретира" Garbage Collector.

Након тога у случају да се захтјева филтрирање у фреквентном опсегу, тада се спектрални домен филтрира а затим позива функција за инверзну фуријеову трансформацију.

 

	for( i= 0 ; i < num ; ++i )
{
// bandwidth filtering
if(! ((i>=this.indexLow1 && i<=this.indexHigh1) || (i>=this.indexLow2 && i<=this.indexHigh2)) ){
this.inversed_real[i] = 0;
this.inversed_imag[i] = 0;
}else{
this.inversed_real[i] = this.inputs_real[i];
this.inversed_imag[i] = this.inputs_imag[i];
}
}

this.InverseFFT(true, this.samplesNoLog2, this.samplesNo, this.inversed_real, this.inversed_imag);

Пошто је добијени фреквентни спектар симетричан око Никвистове фреквенције, то се требају очистити и доњи (Low) дио и горњи (High) дио спектра. ОБјашњење за ово је мало математички комплексније.

На крају се временски спектар (добијен IFFT-ом) пребацује у низ који представља аудио излаз овог аудио блока.

GetIndexForFrequency(frequency:Number, roundToHigher:Boolean)

Ова функција израчунава индекс у фреквентном спектру који одговара датој фреквенцији. Као што је речено, семплови у фреквентном спектру су еквидистантни. У случају да фреквенција не одговара тачно фреквенцији одабирка, параметрном roundToHigher се инсистира да се заокружи на вишем индексу (true), или на нижем (false).

SetFilter(frequencyLow:Number, frequencyHigh:Number)

Ова метода служи за постављање филтер. Она позива функцију GetIndexForFrequency како би нашла одговарајуће индексе, док законима симетрије налази индекс за горњи симетрични дио спектра.

GetSamples(spectrum:Vector.<Number>, indexLow:int, indexHigh:int, samplesNo:int)

Ова функција враћа скуп одабирака у датом фреквентном интервалу и то задати број семплова. Ова функција би се требала преправити да рачуна усредњену вриједност свих семплова који се пресликавају у један семпл у резултату, а не само да се узме онај који "пада" на датој позицији.

DirectFFT(dir:Boolean, m:int, n:int, re:Vector.<Number>, im:Vector.<Number>)
Ова метода је већ објашњена у тексту
InverseFFT(dir:Boolean, m:int, n:int, re:Vector.<Number>, im:Vector.<Number>)

Ова метода се заснива на позиву методе за директну FFT, засновано на симетричности израчунавања FFT и IFFT.

createTestInput(input_signals:Vector.<Signal>)

Ова метода служи у тестирању и креира тест улазни аудио сигнал у временском спектру

DirectDFT()

Ово је имплементација класичне FT чијим се позивом може тестирати наша FFT имплементациј и уочити огромна разлика у времену процесирања сигнала у односу на FFT.

Spectrum компонента

Spectrum компонента служи за визуелизацију фреквентног спектра.У сваком новом фрејму компонента позива FFT компоненту да би преузела нове вриједности семплова и визуелизовала их као мали правоугаонике којима висина одговара интензитету.

Могућа унапређења

Основни проблем овога приступа филтрирању је пуцкетање. Оно се може ријешити интерполирањем. Наиме, идеја је једноставна али захтјева више процесирања: израчунавају се фреквентни спектруми на половини интервала (N/2). У том случају тај спектар ће преузети доминацију на "шавовима" док ће на осталом дијелу спектра бити доминантнији нормали спектри.

Друго побољшање је као што смо рекли у складиштењу детектованих семплвова.

Слиједеће побољшање је у начину процесирања сигнала и непотребности копирања сигнала у свакој компоненти (сем у случају миксете или компоненти за кашњење, итд). Тиме временски и меморијски оптимизујемо систем.

Последње ажурирано понедељак, 19 јануар 2009 12:12
 
Comments (5)
5 понедељак, 01 фебруар 2010 12:00
Find cheap Nike shoes for sale. Gigantic selection of Nike Shox shoes and Nike Dunks shoes for your choice - www.123nikeshoes.com .
4 петак, 23 октобар 2009 08:28
hey i am currently working on a multi touch project where i have defined the sound where user puts the finger on the screen it generates sound what i would like to know if it is possible to give real time spectrum to the visuals in the amplitude of the sound ?
PB
3 уторак, 14 април 2009 11:28
jkozniewski
In case you've missed this:
http://www.kaourantin.net/2008/10/audio-mixing-with-pixel-bender.html

Note that PB Toolkit has been updater recently
so maybe they solved a bug that Tinic refered to in
his post.
:)
2 уторак, 14 април 2009 10:23
Hi, thanks a lot :)
I'm in process of building kind of "sound game" in which
accessing sound spectrum data for particular sounds separately (instead of built-in global SoundSpectrum) is essential.

Regarding PB i think that with few hacks it's possible
to force it to process arbitrary data - in form of bytearray or even vector... Main problem may be it's inability of computing more complexed algorithms ( lack of loops, arrays etc ).

I'll post any progress I'll made in this subject :)
Hope to stay in touch :)
code :) ?
1 уторак, 14 април 2009 00:30
Hi,
Quite informative article on not so well explored
subject :) It's very hard to find any examples
in this subject... Could you be so nice and post
some code you've mentioned in the article ?

BTW. Do you think that's possible to calculate FFT
via PixelBender in favour of performance gain ?
уторак, 14 април 2009 01:11
Sasha Rudan
Hi,

I just put code and working example.

Sorry for missing this out :)

If you want to try it, you need to set correct path to your mp3 file in Main.as (line 125).

If there is any problem just ask.

Sasha

P.S. I hope, it would be possible to speed up with PixelBender. I just started investigating on it. It mainly depends what PB can accept as input. I think it is addressing only few pixels in image, so it seems it cannot work with big arrays that represents audio samples :(

We can play with it together and see if it works :)
In source code you have FFT algorithm

Add your comment

Very HappySmileWinkSadSurprisedShockedConfusedCoolLaughingMadRazzEmbarrassedCrying or Very SadEvil or Very MadTwisted EvilRolling EyesExclamationQuestionIdeaArrowNeutralMr. GreenGeekUber Geek
Your name:
Your website:
Наслов:
Comment (you may use HTML tags here):