Slik lager du en lydoscillator med Web Audio API

Hva du skal skape

Web Audio API er en modell som er helt skilt fra

Hva vi bygger

Se Pen WebAudio API m / Oscilloskop av Dennis Gaebel (@dennisgaebel) på CodePen.

Vår demo ovenfor inneholder tre radioinnganger som når de velges, vil spille den korrelerende lyden som hver referanse. Når en kanal er valgt, vil lyden vår spille, og frekvensgrafen vil bli vist. 

Jeg vil ikke forklare hver linje i demoens kode; Jeg vil imidlertid forklare de primære bitene som bidrar til å vise lydkilden og dens frekvensdiagram. For å starte, trenger vi en liten oppskrift.

The Markup

Den viktigste delen av oppslaget er lerret, som vil være elementet som viser oscilloskopet vårt. Hvis du ikke er kjent med lerret, Jeg foreslår at du leser denne artikkelen med tittelen "En introduksjon til arbeid med lerret."

Med scenen satt for å vise grafen, må vi lage lyden.

Opprette lyden

Vi begynner med å definere et par viktige variabler for lydkonteksten og gevinsten. Disse variablene vil bli brukt til å referere til et senere punkt i koden.

la lydkontekst, mastergain;

De audioContext representerer et lydbehandlingsgraf (en komplett beskrivelse av et lydsignalbehandlingsnettverk) bygget fra lydmoduler koblet sammen. Hver er representert av en AudioNode, og når de er koblet sammen, oppretter de en lyddirigasjonsgraf. Denne lydkonteksten styrer både opprettelsen av noden (e) den inneholder og utførelsen av lydbehandling og dekoding. 

De AudioContext må skje før noe annet, som alt skjer i en kontekst.

Våre masterGain aksepterer innspilling av en eller flere lydkilder og utgir lydens volum, som er justert i forsterkning til et nivå som er spesifisert av nodens GainNode.gain a-takt-parameter. Du kan tenke på master gain som volumet. Nå skal vi opprette en funksjon for å tillate avspilling av nettleseren.

funksjon audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = new (window.AudioContext || window.webkitAudioContext) (); 

Jeg begynner med å definere en kilde variabel som vil bli brukt til å referere til lydfilen. I dette tilfellet bruker jeg en nettadresse til en streamingtjeneste, men det kan også være en lydfil. De audioContext linje definerer et lydobjekt og er sammenhengen vi diskuterte tidligere. Jeg ser også etter kompatibilitet ved hjelp av WebKit prefiks, men støtte er allment vedtatt på dette tidspunkt med unntak av IE11 og Opera Mini.

funksjon audioSetup () masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination); 

Med vårt første oppsett fullført, må vi opprette og koble til masterGain til lyddestinasjonen. For denne jobben bruker vi koble() metode, som lar deg koble en av nodens utganger til et mål.

funksjon audioSetup () la sangen = ny lyd (kilde), songSource = audioContext.createMediaElementSource (sang); songSource.connect (masterGain); song.play (); 

De sang variabel lager et nytt lydobjekt ved hjelp av Audio () konstruktør. Du trenger et lydobjekt, slik at konteksten har en kilde til avspilling for lyttere.

De songSource variabel er den magiske sausen som spiller lyden og er hvor vi skal passere i lydkilden vår. Ved bruk av createMediaElementSource (), lyden kan spilles og manipuleres etter ønske. Den endelige variabelen kobler lydkilden til master gain (volum). Den endelige linjen song.play () er samtalen å faktisk gi tillatelse til å spille av lyden.

la lydkontekst, mastergain; funksjon audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = new (window.AudioContext || window.webkitAudioContext) (); masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination); la sang = ny lyd (kilde), songSource = audioContext.createMediaElementSource (sang); songSource.connect (masterGain); song.play ();  audioSetup ();

Her er vårt endelige resultat som inneholder alle kodelinjene vi har diskutert til dette punktet. Jeg sørger også for å ringe til denne funksjonen skrevet på den siste linjen. Deretter skal vi lage lydbølgeformen.

Opprette lydbølgen

For å vise frekvensbølgen for vår valgte lydkilde, må vi lage bølgeformen.

const analyzer = audioContext.createAnalyser (); masterGain.connect (analysator);

Den første referansen til createAnalyser () utsetter lydtid og frekvensdata for å generere datavisualiseringer. Denne metoden vil produsere en AnalyserNode som overfører lydstrømmen fra inngangen til utgangen, men lar deg anskaffe de genererte dataene, behandle den og konstruere lydvisualiseringer som har nøyaktig ett inngang og en utgang. Analysator node vil bli koblet til master gain som er utgangen av signalveien vår og gir muligheten til å analysere en kilde.

const waveform = ny Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (bølgeform);

Dette Float32Array () Konstruktøren representerer en rekkevidde av et 32-biters flytende punktnummer. De frequencyBinCount eiendom av AnalyserNode grensesnittet er en usignert lang verdi halvparten av FFT (Fast Fourier Transform) -størrelsen. Dette tilsvarer generelt antall dataverdier du vil ha til bruk med visualiseringen. Vi bruker denne tilnærmingen til å samle våre frekvensdata gjentatte ganger.

Den endelige metoden getFloatTimeDomainData kopierer nåværende bølgeform- eller tidsdomenedata til en Float32Array array passert inn i den.

funksjon updateWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (bølgeform); 

Denne hele mengden data og behandling bruker requestAnimationFrame () å samle tidsdomener data gjentatte ganger og tegne en "oscilloskopstil" -utgang av gjeldende lydinngang. Jeg ringer også til getFloatTimeDomainData () siden dette må oppdateres kontinuerlig som lydkilden er dynamisk.

const analyzer = audioContext.createAnalyser (); masterGain.connect (analysator); const waveform = ny Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (bølgeform); funksjon updateWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (bølgeform); 

Kombinere all koden som er diskutert så langt, resulterer i hele funksjonen ovenfor. Anropet til denne funksjonen vil bli plassert inne i vår audioSetup fungere like nedenfor song.play (). Med bølgeformen på plass, må vi fremdeles tegne denne informasjonen på skjermen ved hjelp av vår lerret element, og dette er neste del av diskusjonen vår.

Tegne lydbølgen

Nå som vi har opprettet vår bølgeform og har dataene vi trenger, må vi tegne den på skjermen. dette er hvor lerret element er introdusert.

funksjon drawOscilloscope () requestAnimationFrame (drawOscilloscope); const scopeCanvas = document.getElementById ('oscilloskop'); const scopeContext = scopeCanvas.getContext ('2d'); 

Koden ovenfor tar bare tak i lerret element slik at vi kan referere det til vår funksjon. Anropet til requestAnimationFrame øverst på denne funksjonen planlegger neste animasjonsramme. Dette er plassert først slik at vi kan få så nær 60FPS som mulig.

funksjon drawOscilloscope () scopeCanvas.width = waveform.length; scopeCanvas.height = 200; 

Jeg har implementert grunnleggende styling som vil tegne bredden og høyden på lerret. Høyden er satt til en absolutt verdi, mens bredden vil være lengden på bølgeformen produsert av lydkilden.

funksjon drawOscilloscope () scopeContext.clearRect (0, 0, scopeCanvas.width, scopeCanvas.height); scopeContext.beginPath (); 

De clearRect (x, y, bredde, høyde) Metoden vil fjerne alt tidligere tegnet innhold, slik at vi kontinuerlig kan tegne frekvensgrafen. Du må også sørge for å ringe beginPath () før du begynner å tegne den nye rammen etter å ha ringt clearRect (). Denne metoden starter en ny bane ved å tømme listen over alle underveier. Det endelige brikke i dette puslespillet er en løkke for å løpe gjennom dataene vi har oppnådd, slik at vi kontinuerlig kan tegne denne frekvensgrafen til skjermen.

funksjon drawOscilloscope () for (la i = 0; i < waveform.length; i++)  const x = i; const y = ( 0.5 + (waveform[i] / 2) ) * scopeCanvas.height; if(i == 0)  scopeContext.moveTo(x, y);  else  scopeContext.lineTo(x, y);   scopeContext.stroke(); 

Denne sløyfen over trekker vår bølgeform til lerret element. Hvis vi logger bølgeformlengden til konsollen (mens du spiller lyden), vil den rapportere 1024 gjentatte ganger. Dette tilsvarer generelt antall dataverdier du må spille med for visualisering. Hvis du husker fra forrige seksjon for å lage bølgeformen, får vi denne verdien fra Float32Array (analyser.frequencyBinCount). Slik kan vi referere til 1024-verdien som vi skal løse gjennom.

De flytte til() Metoden vil bokstavelig talt flytte utgangspunktet for en ny undervei til den oppdaterte (x, y) koordinater. De lineTo () Metoden kobler det siste punktet i underbanen til x, y koordinater med en rett linje (men faktisk ikke tegner det). Det endelige stykket ringer slag () levert av lerret så vi kan faktisk tegne frekvenslinjen. Jeg vil forlate delen som inneholder matte som en leserutfordring, så sørg for å legge inn svaret ditt i kommentarene nedenfor.

funksjon drawOscilloscope () requestAnimationFrame (drawOscilloscope); const scopeCanvas = document.getElementById ('oscilloskop'); const scopeContext = scopeCanvas.getContext ('2d'); scopeCanvas.width = waveform.length; scopeCanvas.height = 200; scopeContext.clearRect (0, 0, scopeCanvas.width, scopeCanvas.height); scopeContext.beginPath (); for (la jeg = 0; jeg < waveform.length; i++)  const x = i; const y = ( 0.5 + (waveform[i] / 2) ) * scopeCanvas.height; if(i == 0)  scopeContext.moveTo(x, y);  else  scopeContext.lineTo(x, y);   scopeContext.stroke(); 

Dette er hele funksjonen vi har opprettet for å tegne bølgeformen som vi skal ringe etter song.play () plassert innenfor vår audioSetup funksjon, som også inkluderer vår updateWaveForm funksjonsanrop også.

Deler tanker

Jeg har bare forklart de viktige brikkene for demoen, men sørg for å lese gjennom de andre delene av demonstrasjonen min for å få bedre forståelse for hvordan radioknappene og startknappen fungerer i forhold til koden ovenfor, inkludert CSS-styling.

Web Audio API er veldig morsomt for alle som er interessert i lyd av noe slag, og jeg oppfordrer deg til å gå dypere. Jeg har også samlet noen veldig morsomme eksempler fra CodePen som bruker Web Audio API til å bygge noen veldig interessante eksempler. Nyt!

  • https://codepen.io/collection/XLYyWN
  • https://codepen.io/collection/nNqdoR
  • https://codepen.io/collection/XkNgkE
  • https://codepen.io/collection/ArxwaW

referanser

  • http://webaudioapi.com
  • https://webaudio.github.io/web-audio-api
  • http://chimera.labs.oreilly.com/books/1234000001552/ch01.html