Støy Lag en synthesizer for retro lydeffekter - lydprosessorer

Dette er den siste delen i vår serie av opplæringsprogrammer om å lage en synthesizer-basert lydmotor som kan brukes til å generere lyder for retro-stilte spill. Lydmotoren kan generere alle lydene ved kjøretid uten behov for eksterne avhengigheter som MP3-filer eller WAV-filer. I denne veiledningen legger vi til støtte for lydprosessorer, og koden a forsink prosessor som kan legge til en decaying echo effekt til våre lyder.

Hvis du ikke allerede har lest den første opplæringen eller den andre opplæringen i denne serien, bør du gjøre det før du fortsetter.

Programmeringsspråket som brukes i denne opplæringen, er ActionScript 3.0, men de teknikker og begreper som brukes kan enkelt oversettes til et hvilket som helst annet programmeringsspråk som gir en lavnivå lyd API.

Du bør sørge for at du har Flash Player 11.4 eller høyere installert for nettleseren din hvis du vil bruke de interaktive eksemplene i denne opplæringen.


Lydprosessor Demo

I denne siste opplæringen vil vi legge til lydprosessorer til kjernemotoren og skape en enkel forsinkelsesprosessor. Følgende demonstrasjon viser forsinkelsesprosessoren i aksjon:

Bare én lyd blir spilt i den demonstrasjonen, men frekvensen av lyden blir randomisert, og lydprøver generert av motoren blir presset gjennom en forsinkelsesprosessor, noe som gir den den forfallne ekko-effekten.


lydprosessor Klasse

Det første vi må gjøre er å lage en grunnklasse for lydprosessorer:

pakkestøy offentlig klasse AudioProcessor // public var aktivert: Boolean = true; // offentlig funksjon AudioProcessor () hvis (Objekt (dette) .constructor == AudioProcessor) kaste ny feil ("AudioProcessor-klassen må utvides");  // intern funksjon prosess (prøver: Vector. ):tomrom   

Som du kan se, er klassen veldig enkel; den inneholder en intern prosess() metode som påberopes av Audioengine klasse når noen prøver må behandles, og en offentlig aktivert Egenskap som kan brukes til å slå prosessoren på og av.


AudioDelay Klasse

De AudioDelay klassen er klassen som faktisk skaper lydforsinkelsen, og den strekker seg ut lydprosessor klasse. Her er den grunnleggende tomme klassen som vi skal jobbe med:

pakke støy offentlig klasse AudioDelay utvider AudioProcessor // offentlig funksjon AudioDelay (tid: Nummer = 0.5) this.time = time; 

De tid argument bestått til klassekonstruktøren er tiden (i sekunder) av forsinkelsestappen - det vil si hvor mye tid mellom hver lydforsinkelse.

La oss nå legge til de private eiendommene:

privat var m_buffer: vektor. = Ny Vector.(); private var m_bufferSize: int = 0; privat var m_bufferIndex: int = 0; privat var m_time: tall = 0,0; privat var m_gain: tall = 0,8;

De m_buffer vektor er i utgangspunktet en tilbakemelding loop: den inneholder alle lydprøver som sendes til prosess metode, og disse prøvene er modifisert (i dette tilfellet redusert i amplitude) kontinuerlig som m_bufferIndex passerer gjennom bufferen. Dette vil gi mening når vi kommer til prosess() metode.

De m_bufferSize og m_bufferIndex Egenskaper brukes til å holde oversikt over bufferens tilstand. De m_time Egenskapen er tidspunktet for forsinkelsen, i sekunder. De m_gain Egenskapen er en multiplikator som brukes til å redusere amplituden til de buffede lydprøvene over tid.

Denne klassen har bare én metode, og det er det interne prosess() metode som overstyrer prosess() metode i lydprosessor klasse:

intern overstyringsfunksjon prosess (prøver: Vector. ): void var i: int = 0; var n: int = samples.length; var v: tall = 0,0; // mens jeg < n )  v = m_buffer[m_bufferIndex]; // grab a buffered sample v *= m_gain; // reduce the amplitude v += samples[i]; // add the fresh sample // m_buffer[m_bufferIndex] = v; m_bufferIndex++; // if( m_bufferIndex == m_bufferSize )  m_bufferIndex = 0;  // samples[i] = v; i++;  

Til slutt må vi legge til getters / setters for private m_time og m_gain eiendommer:

offentlig funksjon få tid (): tall retur m_time;  Offentlig funksjon satt tid (verdi: Nummer): void // klemme tiden til rekkevidde 0.0001 - 8.0 verdi = verdi < 0.0001 ? 0.0001 : value > 8,0? 8.0: verdi; // Ikke nødvendig å endre bufferstørrelsen hvis tiden ikke har endret seg hvis (m_time == verdi) return;  // angi tiden m_time = verdi; // oppdater bufferstørrelsen m_bufferSize = Math.floor (44100 * m_time); m_buffer.length = m_bufferSize; 
offentlig funksjon få gain (): tall return m_gain;  offentlige funksjonsinnstilt gevinst (verdi: tall): void // klemme gevinsten til intervallet 0.0 - 1.0 m_gain = verdi < 0.0 ? 0.0 : value > 1,0? 1,0: verdi; 

Tro eller ikke, det er AudioDelay klasse gjennomført. Lydforsinkelser er faktisk veldig enkle når du forstår hvordan tilbakemeldingssløyfen ( m_buffer eiendom) fungerer.


Oppdaterer Audioengine Klasse

Det siste vi må gjøre er å oppdatere Audioengine klasse så lydprosessorer kan legges til det. Først og fremst la vi legge til en vektor for å lagre lydprosessorinstansene:

statisk privat var m_processorList: Vector. = Ny Vector.();

Å faktisk legge til og fjerne prosessorer til og fra Audioengine klasse vil vi bruke to offentlige metoder:

Audioengine.addProcessor ()

statisk offentlig funksjon addProcessor (prosessor: AudioProcessor): void if (m_processorList.indexOf (prosessor) == -1) m_processorList.push (prosessor); 

Audioengine.removeProcessor ()

statisk offentlig funksjon removeProcessor (prosessor: AudioProcessor): void var i: int = m_processorList.indexOf (prosessor); hvis (i! = -1) m_processorList.splice (jeg, 1); 

Enkelt nok - alle de metodene gjør er å legge til og fjerne lydprosessor forekomster til eller fra m_processorList vektor.

Den siste metoden som vi vil legge til ruller gjennom listen over lydprosessorer, og hvis prosessoren er aktivert, overfører lydprøver til prosessorens prosess() metode:

statisk privat funksjon prosessSamples (): void var i: int = 0; var n: int = m_processorList.length; // mens jeg < n )  if( m_processorList[i].enabled )  m_processorList[i].process( m_sampleList );  i++;  

Nå er det på tide å legge til den endelige koden, og dette er en enkelt linje med kode som må legges til den private onSampleData () metode i Audioengine klasse:

hvis (m_soundChannel == null) mens (i < n )  b.writeFloat( 0.0 ); b.writeFloat( 0.0 ); i++;  return;  // generateSamples(); processSamples(); // while( i < n )  s = m_sampleList[i] * m_amplitude; b.writeFloat( s ); b.writeFloat( s ); m_sampleList[i] = 0.0; i++; 

Den uthevede koden er den som må legges til klassen; det påkaller bare processSamples () metode som vi tidligere har lagt til.


Konklusjon

Det, som de sier, er det. I den første opplæringen tok vi en titt på ulike bølgeformer og hvordan lydbølger lagres digitalt, da konstruerte vi kjerne lydmotorkoden i den andre opplæringen, og nå har vi pakket inn ting med tillegg av lydprosessorer.

Det er mye mer som kan gjøres med denne koden, eller til en variant av denne koden, men det viktige å huske på er hvor mye arbeid en lydmotor har å gjøre ved kjøring. Hvis du skyver en lydmotor for langt (og det er lett å gjøre), kan det hende at spillets generelle ytelse kan lide som en konsekvens - selv om du flytter en lydmotor til en egen tråd (eller ActionScript 3.0-arbeider), vil det fortsatt lykkelig bite biter ut av CPUen hvis du ikke er forsiktig.

Men mange profesjonelle og ikke-så-profesjonelle spill gjør mye lydbehandling ved kjøring, fordi det å ha dynamiske lydeffekter og musikk i et spill kan legge mye til den generelle opplevelsen, og den kan trekke spilleren dypere inn i spillet verden. Lydmotor vi legger sammen i denne serien av opplæringsprogrammer, kan like enkelt arbeide med vanlige (ikke-genererte) lydeffektprøver lastet fra filer: i hovedsak er all digital lyd en sekvens av prøver i sin mest grunnleggende form.

En siste ting å tenke på: Lyd er et svært viktig aspekt av spilldesign, det er like viktig og kraftig som den visuelle siden av ting, og det er ikke noe som skal kastes sammen eller boltet på et spill i siste øyeblikk av utvikling hvis du virkelig bryr deg om produksjonskvaliteten til spillene dine. Ta deg tid med lyddesignen for spillene dine, og du vil høste fordelene.

Jeg håper du likte denne serien av opplæringsprogrammer og kan ta noe positivt vekk fra det: selv om du bare tenker på lyden i spillene dine litt mer fra nå av da har jeg gjort jobben min.

Alle lydkildens kildekoden er tilgjengelig i nedlasting av kilde.

Ha det gøy!