Web Audio API är en modell som är helt skild från
Se Penna WebAudio API w / Oscilloskop av Dennis Gaebel (@dennisgaebel) på CodePen.
Vår demo ovan innehåller tre radioingångar som när de väljs kommer att spela det korrelerande ljudet som var och en refererar till. När en kanal väljs kommer vårt ljud att spelas och frekvensgrafen visas.
Jag kommer inte att förklara varje rad i demo-koden; Jag kommer dock att förklara de primära bitarna som hjälper till att visa ljudkällan och dess frekvensdiagram. För att börja, behöver vi en liten bit av uppmärkning.
Den viktigaste delen av markeringen är duk
, vilket kommer att vara det element som visar vårt oscilloskop. Om du inte är bekant med duk
, Jag föreslår att du läser den här artikeln med titeln "En introduktion till arbete med kanfas".
Med scenen som anges för att visa grafen måste vi skapa ljudet.
Vi börjar med att definiera några viktiga variabler för ljudkontext och förstärkning. Dessa variabler kommer att användas för att hänvisa vid en senare punkt i koden.
låt audioContext, masterGain;
De audioContext
representerar ett ljudbehandlingsdiagram (en komplett beskrivning av ett ljudsignalbehandlingsnätverk) byggt från ljudmoduler kopplade ihop. Var och en representeras av en AudioNode
, och när de är anslutna tillsammans skapar de ett ljuddirigeringsdiagram. Detta ljudkontext kontrollerar både skapandet av noden (erna) som den innehåller och utförandet av ljudbehandlingen och avkodningen.
De AudioContext
måste skapas före något annat, eftersom allt händer inom ett sammanhang.
Vår masterGain
accepterar en ingång av en eller flera ljudkällor och matar ut ljudets volym, som har justerats i förstärkningen till en nivå som anges av nodens GainNode.gain
en-rate parameter. Du kan tänka på huvudförstärkningen som volymen. Nu skapar vi en funktion för att tillåta uppspelning av webbläsaren.
funktionen audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = nytt (window.AudioContext || window.webkitAudioContext) ();
Jag börjar med att definiera en källa
variabel som används för att referera till ljudfilen. I det här fallet använder jag en webbadress till en streamingtjänst, men det kan också vara en ljudfil. De audioContext
rad definierar ett ljudobjekt och är det sammanhang vi diskuterade tidigare. Jag kontrollerar också för kompatibilitet med hjälp av WebKit
prefix, men stöd är allmänt antaget vid denna tidpunkt med undantag för IE11 och Opera Mini.
funktion audioSetup () masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination);
Med vår första installationen måste vi skapa och ansluta masterGain
till ljuddestinationen. För det här jobbet använder vi ansluta()
metod som låter dig ansluta en av nodens utgångar till ett mål.
funktion audioSetup () låt låt = ny ljud (source), songSource = audioContext.createMediaElementSource (låt); songSource.connect (masterGain); song.play ();
De låt
variabel skapar ett nytt ljudobjekt med hjälp av Audio()
konstruktör. Du behöver ett ljudobjekt så att kontexten har en källa att spela upp för lyssnare.
De songSource
variabel är den magiska såsen som spelar ljudet och är där vi kommer att passera i vår ljudkälla. Genom att använda createMediaElementSource ()
, ljudet kan spelas och manipuleras efter önskemål. Den slutliga variabeln kopplar vår ljudkälla till huvudförstärkningen (volym). Slutlinjen song.play ()
är uppmaningen att faktiskt ge tillstånd att spela ljudet.
låt audioContext, masterGain; funktionen audioSetup () let source = 'http://ice1.somafm.com/seventies-128-aac'; audioContext = nytt (window.AudioContext || window.webkitAudioContext) (); masterGain = audioContext.createGain (); masterGain.connect (audioContext.destination); låt låt = ny ljud (source), songSource = audioContext.createMediaElementSource (låt); songSource.connect (masterGain); song.play (); audioSetup ();
Här är vårt slutresultat med alla koden vi har diskuterat fram till den här tiden. Jag är också säker på att ringa till den här funktionen på den sista raden. Därefter skapar vi ljudvågformen.
För att kunna visa frekvensvåg för vår valda ljudkälla behöver vi skapa vågformen.
const analyzer = audioContext.createAnalyser (); masterGain.connect (analysator);
Den första hänvisningen till createAnalyser ()
exponerar ljudtid och frekvensdata för att generera datavisualiseringar. Denna metod kommer att producera en AnalyserNode som överför ljudströmmen från ingången till utgången, men låter dig förvärva genererade data, bearbeta den och konstruera ljudvisningar som har exakt en ingång och en utgång. Analysernoden kommer att kopplas till mastergin som är utgången från vår signalväg och ger möjlighet att analysera en källa.
const waveform = ny Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (vågform);
Detta Float32Array ()
konstruktorn representerar en uppsättning av ett 32-bitars flytpunktsnummer. De frequencyBinCount
egenskapen hos AnalyserNode
gränssnittet är ett osignerat långt värde som är halva det för FFT (Fast Fourier Transform) -storleken. Detta motsvarar i allmänhet det antal datavärden du kommer att använda för visualisering. Vi använder denna metod för att samla våra frekvensdata upprepade gånger.
Den slutliga metoden getFloatTimeDomainData
kopierar nuvarande vågforms- eller tidsdomändata till en Float32Array
array passerade in i den.
funktionuppdateringWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (vågform);
Hela denna mängd data och bearbetning använder requestAnimationFrame ()
att samla in tidsdomändata upprepat och dra en "oscilloskopstil" -utgång från den nuvarande ljudingången. Jag gör också ett nytt samtal till getFloatTimeDomainData ()
eftersom det måste uppdateras kontinuerligt eftersom ljudkällan är dynamisk.
const analyzer = audioContext.createAnalyser (); masterGain.connect (analysator); const waveform = ny Float32Array (analyser.frequencyBinCount); analyser.getFloatTimeDomainData (vågform); funktionuppdateringWaveform () requestAnimationFrame (updateWaveform); analyser.getFloatTimeDomainData (vågform);
Genom att kombinera all kod som diskuterats hittills resulterar hela funktionen ovan. Samtalet till denna funktion kommer att placeras inuti vårt audioSetup
funktionen nedanför song.play ()
. Med vågformen på plats behöver vi fortfarande dra denna information till skärmen med vår duk
element, och det här är nästa del av vår diskussion.
Nu när vi har skapat vår vågform och har de data vi behöver, måste vi dra den till skärmen. det här är där duk
element införs.
funktion drawOscilloscope () requestAnimationFrame (drawOscilloscope); const scopeCanvas = document.getElementById ("oscilloskop"); const scopeContext = scopeCanvas.getContext ('2d');
Koden ovan klarar bara duk
element så vi kan referera det till vår funktion. Samtalet till requestAnimationFrame
högst upp i denna funktion schemalägger nästa animationsram. Detta placeras först så att vi kan få så nära 60FPS som möjligt.
funktion drawOscilloscope () scopeCanvas.width = waveform.length; scopeCanvas.height = 200;
Jag har implementerat grundläggande styling som kommer att dra bredden och höjden på duk
. Höjden är inställd på ett absolut värde, medan bredden blir längden på den vågform som produceras av ljudkällan.
funktion drawOscilloscope () scopeContext.clearRect (0, 0, scopeCanvas.width, scopeCanvas.height); scopeContext.beginPath ();
De clearRect (x, y, bredd, höjd)
Metoden kommer att rensa eventuellt tidigare ritat innehåll så att vi kontinuerligt kan rita frekvensdiagrammet. Du måste också se till att ringa beginPath ()
innan du börjar rita den nya ramen efter att du har ringt clearRect ()
. Den här metoden startar en ny sökväg genom att tömma listan över alla undervägar. Slutstycket i detta pussel är en slinga för att springa igenom de data vi har erhållit så att vi kontinuerligt kan dra denna frekvensgraf till skärmen.
funktion drawOscilloscope () for (låt 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();
Denna slinga ovan drar vår vågform till duk
element. Om vi loggar in vågformens längd till konsolen (medan du spelar ljudet) kommer det att rapportera 1024 upprepade gånger. Detta motsvarar i allmänhet det antal datavärden du måste spela med för visualiseringen. Om du kommer ihåg från föregående avsnitt för att skapa vågformen får vi det här värdet Float32Array (analyser.frequencyBinCount)
. Så här kan vi hänvisa till 1024-värdet som vi ska gå igenom.
De flytta till()
Metoden kommer bokstavligen att flytta utgångspunkten för en ny delväg till den uppdaterade (x, y)
koordinater. De lineTo ()
Metoden kopplar den sista punkten i undervägen till x, y
koordinater med en rak linje (men faktiskt inte ritar den). Slutstycket ringer stroke()
tillhandahålls av duk
så vi kan faktiskt dra frekvenslinjen. Jag lämnar den del som innehåller matte som en läsareutmaning, så se till att du skickar ditt svar i kommentarerna nedan.
funktion 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 (); för (låt jag = 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();
Det här är hela funktionen som vi skapat för att rita den vågform som vi ska ringa efter song.play ()
placeras inom vårt audioSetup
funktion, som också inkluderar vår updateWaveForm
funktionssamtal också.
Jag har bara förklarat de viktiga bitarna för demo, men se till att läsa igenom andra delar av min demo för att få en bättre förståelse för hur radioknapparna och startknappen fungerar i förhållande till koden ovan, inklusive CSS-styling.
Web Audio API är verkligen kul för alla som är intresserade av ljud av något slag, och jag uppmuntrar dig att gå djupare. Jag har också samlat några riktigt roliga exempel från CodePen som använder Web Audio API för att bygga några riktigt intressanta exempel. Njut av!