Web Audio API er en modell som er helt skilt fra
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.
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.
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.
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.
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å.
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!