Effetti sonori in JavaScript / HTML5


316

Sto usando HTML5 per programmare giochi; l'ostacolo che ho incontrato ora è come riprodurre effetti sonori.

I requisiti specifici sono pochi:

  • Riproduci e mixa più suoni,
  • Riproduci lo stesso campione più volte, possibilmente sovrapponendo le riproduzioni,
  • Interrompere la riproduzione di un campione in qualsiasi momento,
  • Preferibilmente riprodurre file WAV contenenti PCM non elaborati (di bassa qualità), ma ovviamente li posso convertire.

Il mio primo approccio è stato quello di utilizzare l' <audio>elemento HTML5 e definire tutti gli effetti sonori nella mia pagina. Firefox riproduce i file WAV in modo semplice, ma chiamare #playpiù volte non riproduce realmente il campione più volte. Dalla mia comprensione delle specifiche HTML5, l' <audio>elemento traccia anche lo stato di riproduzione, quindi questo spiega perché.

Il mio pensiero immediato è stato quello di clonare gli elementi audio, quindi ho creato la seguente piccola libreria JavaScript per farlo (dipende da jQuery):

var Snd = {
  init: function() {
    $("audio").each(function() {
      var src = this.getAttribute('src');
      if (src.substring(0, 4) !== "snd/") { return; }
      // Cut out the basename (strip directory and extension)
      var name = src.substring(4, src.length - 4);
      // Create the helper function, which clones the audio object and plays it
      var Constructor = function() {};
      Constructor.prototype = this;
      Snd[name] = function() {
        var clone = new Constructor();
        clone.play();
        // Return the cloned element, so the caller can interrupt the sound effect
        return clone;
      };
    });
  }
};

Quindi ora posso fare Snd.boom();dalla console Firebug e giocare snd/boom.wav, ma non riesco ancora a riprodurre lo stesso campione più volte. Sembra che l' <audio>elemento sia più una funzionalità di streaming piuttosto che qualcosa con cui riprodurre effetti sonori.

C'è un modo intelligente per farlo accadere che mi manca, preferibilmente usando solo HTML5 e JavaScript?

Dovrei anche menzionarlo, il mio ambiente di test è Firefox 3.5 su Ubuntu 9.10. Gli altri browser che ho provato - Opera, Midori, Chromium, Epiphany - hanno prodotto risultati diversi. Alcuni non giocano nulla e alcuni generano eccezioni.


Hah! Sto anche eseguendo il porting di un vecchio gioco per Macintosh su HTML5. Vuoi rivelare quale stai clonando?
un secchione pagato

1
È Project ARASHI, un clone di tempesta.
Stéphan Kochen,

Cosa si intende per "missaggio" dei suoni?
Mads Skjern,

2
L'hai finito? Possiamo vederlo?
enyo,

4
Purtroppo no. Ho un talento per non finire i progetti per il tempo libero. :( C'è un repository git per questo, ma non lo tocco da anni: github.com/stephank/arashi-js
Stéphan Kochen,

Risposte:


448

AudioOggetti HTML5

Non devi preoccuparti degli <audio>elementi. HTML 5 ti consente di accedere direttamente agli Audiooggetti :

var snd = new Audio("file.wav"); // buffers automatically when created
snd.play();

Non è supportato il missaggio nella versione corrente delle specifiche.

Per riprodurre lo stesso suono più volte, creare più istanze Audiodell'oggetto. È inoltre possibile impostare snd.currentTime=0l'oggetto al termine della riproduzione.


Poiché il costruttore JS non supporta gli <source>elementi di fallback , è necessario utilizzare

(new Audio()).canPlayType("audio/ogg; codecs=vorbis")

per verificare se il browser supporta Ogg Vorbis.


Se stai scrivendo un gioco o un'app musicale (più di un semplice lettore), ti consigliamo di utilizzare l' API Web Audio più avanzata , che ora è supportata dalla maggior parte dei browser .


18
Audiogli oggetti sono autobuffer. Sono progettati in modo analogo agli Imageoggetti, quindi anche le tecniche di precaricamento delle immagini della vecchia scuola funzionano con l'audio.
Kornel,

5
Questo funziona anche su iOS. Si noti tuttavia che è necessario utilizzare un tipo di azione dell'utente (ad esempio, un clic su un pulsante) per avviare il suono. Non puoi semplicemente fare un snd.play()on window.load ().
Husky,

1
Sto ancora usando il <audio>tag perché è più controllabile. Ma comunque grazie per le informazioni!
Derek 朕 會 功夫

2
Preferirei questo metodo se non fosse per il fatto che gli elementi <audio> html5 consentono più fonti, quindi se un browser non supporta mp3, è possibile eseguire il fallback su ogg / wav. Richiederebbe qualche trucco in javascript per ottenere lo stesso risultato.
Joelmdev,

2
Su iOS 6 è supportata la riproduzione automatica: puoi avviare i suoni con un semplice snd.play () su window.load ().
Pietro Polsinelli,

36

API WebAudio di W3C

A partire da luglio 2012, l' API WebAudio è ora supportata in Chrome, e almeno in parte supportata in Firefox, e dovrebbe essere aggiunta a IOS dalla versione 6.

Sebbene sia abbastanza robusto da essere utilizzato in modo programmatico per le attività di base, l'elemento Audio non è mai stato pensato per fornire un supporto audio completo per i giochi, ecc. È stato progettato per consentire l'incorporazione di un singolo elemento multimediale in una pagina, simile a un img etichetta. Esistono molti problemi con il tentativo di utilizzare il tag Audio per i giochi:

  • I tempi sono comuni con gli elementi audio
  • È necessario un elemento audio per ogni istanza di un suono
  • Gli eventi di caricamento non sono ancora completamente affidabili
  • Nessun controllo di volume comune, nessuna dissolvenza, nessun filtro / effetto

Ho usato questo articolo Introduzione a WebAudio per iniziare con l'API WebAudio. Anche il Case Study WebAudio di FieldRunners è una buona lettura.


Questa è una risposta migliore di quella accettata, poiché si concentra sulla soluzione corretta al problema (API WebAudio) e i motivi per cui gli elementi audio non sono una buona soluzione, piuttosto che cercare di hackerare insieme una cattiva soluzione con elementi audio
Anomalia

29

howler.js

Per la creazione di giochi, una delle migliori soluzioni è quella di utilizzare una libreria che risolva i numerosi problemi che dobbiamo affrontare durante la scrittura di codice per il Web, come howler.js . howler.js estrae l'eccezionale (ma di basso livello) API audio Web in un framework facile da usare. Tenterà di tornare a HTML5 Audio Element se l'API Web Audio non è disponibile.

var sound = new Howl({
  urls: ['sound.mp3', 'sound.ogg']
}).play();
// it also provides calls for spatial/3d audio effects (most browsers)
sound.pos3d(0.1,0.3,0.5);

wad.js

Un'altra grande libreria è wad.js , che è particolarmente utile per la produzione di audio synth, come musica ed effetti. Per esempio:

var saw = new Wad({source : 'sawtooth'})
saw.play({
    volume  : 0.8,
    wait    : 0,     // Time in seconds between calling play() and actually triggering the note.
    loop    : false, // This overrides the value for loop on the constructor, if it was set. 
    pitch   : 'A4',  // A4 is 440 hertz.
    label   : 'A',   // A label that identifies this note.
    env     : {hold : 9001},
    panning : [1, -1, 10],
    filter  : {frequency : 900},
    delay   : {delayTime : .8}
})

Suono per giochi

Un'altra libreria simile a Wad.js è " Sound for Games ", che si concentra maggiormente sulla produzione di effetti, fornendo allo stesso tempo un insieme simile di funzionalità attraverso un'API relativamente distinta (e forse più concisa):

function shootSound() {
  soundEffect(
    1046.5,           //frequency
    0,                //attack
    0.3,              //decay
    "sawtooth",       //waveform
    1,                //Volume
    -0.8,             //pan
    0,                //wait before playing
    1200,             //pitch bend amount
    false,            //reverse bend
    0,                //random pitch range
    25,               //dissonance
    [0.2, 0.2, 2000], //echo array: [delay, feedback, filter]
    undefined         //reverb array: [duration, decay, reverse?]
  );
}

Sommario

Ognuna di queste librerie vale la pena dare un'occhiata, sia che tu abbia bisogno di riprodurre un singolo file audio, o magari di creare il tuo editor musicale, generatore di effetti o videogioco basato su HTML.


Non posso commentare lo sviluppo del gioco, ma lo sto usando per alcuni piccoli feedback audio in un'interfaccia e per questo funziona in modo assoluto. Veloce, facile e semplice.
Elimina Iculous l'

Quadro davvero bello, funziona bene anche su dispositivi mobili. Devi attivarlo con il touchstart ... ma una volta fatto funziona fuori dagli schemi :)
Philip,

9

È inoltre possibile utilizzare questo per rilevare l'audio HTML 5 in alcuni casi:

http://diveintohtml5.ep.io/everything.html

HTML 5 Funzione JS Detect

function supportsAudio()
{
    var a = document.createElement('audio'); 
    return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
}

Grazie per averlo notato. Ho imparato questo metodo da has.js, ma trovo che abbia alcuni problemi in Firefox, e apparentemente anche in Opera secondo il codice sorgente has.js. (rif: github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19 )
Stéphan Kochen

5

Ecco un metodo per rendere possibile riprodurre anche lo stesso suono contemporaneamente. Combina con il preloader e sei pronto. Funziona almeno con Firefox 17.0.1, non l'ho ancora provato con nient'altro.

// collection of sounds that are playing
var playing={};
// collection of sounds
var sounds={step:"knock.ogg",throw:"swing.ogg"};

// function that is used to play sounds
function player(x)
{
    var a,b;
    b=new Date();
    a=x+b.getTime();
    playing[a]=new Audio(sounds[x]);
    // with this we prevent playing-object from becoming a memory-monster:
    playing[a].onended=function(){delete playing[a]};
    playing[a].play();
}

Associa questo a un tasto della tastiera e goditi:

player("step");

No. Non credo che la creazione di un nuovo oggetto per ogni singola riproduzione audio sia una soluzione. È una soluzione rapida e sporca, ma questo può essere fatto meglio.
Pawel,

@Pawel Vero, che questo NON dovrebbe essere usato come metodo principale di riproduzione dei suoni, ma per quanto ne so, il principio nell'esempio è l'unico modo per riprodurre lo stesso suono più di una volta contemporaneamente, o come espresso da OP, "riproduzioni sovrapposte". (Senza richiedere plug-in per browser.) La mia effettiva attrezzatura nel mio progetto attuale è molto più sofisticata del codice di esempio che ho pubblicato.
F-3000,

4

Suona come quello che vuoi sono i suoni multicanale. Supponiamo che tu abbia 4 canali (come su giochi a 16 bit davvero vecchi), non ho ancora avuto modo di giocare con la funzione audio HTML5, ma non hai solo bisogno di 4 elementi <audio> e ciclo che viene utilizzato suonare il prossimo effetto sonoro? Ci hai provato? Che succede? Se funziona: per riprodurre più suoni contemporaneamente, basta aggiungere più elementi <audio>.

L'ho già fatto senza l'elemento <audio> HTML5, usando un piccolo oggetto Flash da http://flash-mp3-player.net/ - Ho scritto un quiz musicale ( http://webdeavour.appspot.com/ ) e lo utilizzava per riprodurre clip musicali quando l'utente faceva clic sul pulsante per la domanda. Inizialmente avevo un giocatore per domanda, ed era possibile giocarli uno sopra l'altro, quindi l'ho cambiato in modo che ci fosse un solo giocatore, che ho indicato diversi clip musicali.


È un pensiero interessante, usare & lt; audio & gt; elementi come canali. Quando inserisco due elementi in una pagina, posso riprodurli contemporaneamente. Sembra che la clonazione che sto facendo in realtà non faccia quello che mi aspetto, perché nel mio codice originale funziona anche la riproduzione di due campioni. Solo il doppio dello stesso campione. Dovrò sperimentare ancora un po 'e tornerò sui risultati!
Stéphan Kochen,

Sì, c'è forse una ragione sottile per cui si chiama clone e non copia. Forse il clone sta ancora condividendo qualcosa con l'originale che impedisce loro di giocare contemporaneamente.
Lee Kowalkowski il

Per riferimento, il riutilizzo dello stesso elemento <audio> non funziona, almeno in Firefox. È possibile impostare l'attributo 'src', ma in realtà non caricherà un campione diverso.
Stéphan Kochen,

4

Dai un'occhiata al sito jai (-> mirror ) (interfaccia audio javascript). Osservando la loro fonte, sembrano chiamare play()ripetutamente e menzionano che la loro libreria potrebbe essere appropriata per l'uso in giochi basati su HTML5.

Puoi attivare più eventi audio contemporaneamente, che potrebbero essere utilizzati per creare giochi Javascript o avere una voce che parla su musica di sottofondo


3

Per riprodurre lo stesso campione più volte, non sarebbe possibile fare qualcosa del genere:

e.pause(); // Perhaps optional
e.currentTime = 0;
e.play();

( eè l'elemento audio)

Forse ho completamente frainteso il tuo problema, vuoi che l'effetto sonoro venga riprodotto più volte contemporaneamente? Quindi questo è completamente sbagliato.


Esatto, devo suonare lo stesso campione più volte contemporaneamente.
Stéphan Kochen,

Sì, questo riproduce la stessa istanza più volte, ma per le persone che guardano questa risposta, basta notare che ciò non causa "riproduzioni sovrapposte", come indicato dall'OP.
Patrick Roberts,

3

Ecco un'idea. Carica tutto il tuo audio per una determinata classe di suoni in un singolo elemento audio in cui i dati src sono tutti i tuoi campioni in un file audio contiguo (probabilmente vuoi un po 'di silenzio tra di loro in modo da poter catturare e tagliare i campioni con un timeout con meno rischio di sanguinamento al prossimo campione). Quindi, cerca l'esempio e riproducilo quando necessario.

Se hai bisogno di più di uno di questi per giocare, puoi creare un elemento audio aggiuntivo con lo stesso src in modo che sia memorizzato nella cache. Ora, hai effettivamente più "tracce". Puoi utilizzare gruppi di tracce con il tuo schema di allocazione delle risorse preferito come Round Robin ecc.

È inoltre possibile specificare altre opzioni come mettere in coda i suoni in una traccia da riprodurre quando tale risorsa diventa disponibile o tagliare un campione attualmente in riproduzione.



2

Consiglierei di usare SoundJS , una libreria che ho aiutato a sviluppare. Ti consente di scrivere una singola base di codice che funziona ovunque, con SoundJS che seleziona audio web, audio html o audio flash come appropriato.

Ti permetterà di fare tutto ciò che vuoi:

  • Riproduci e mixa più suoni,
  • Riproduci lo stesso campione più volte, possibilmente sovrapponendo le riproduzioni
  • Interrompere la riproduzione di un campione in qualsiasi momento
  • riprodurre file WAV contenenti (a seconda del supporto del browser)

Spero che aiuti.


quella libreria è piuttosto fantastica, ho davvero scavato il generatore sfx. tempo di fare un download
RozzA

1

Non è possibile eseguire la riproduzione multi-shot con un singolo <audio>elemento. È necessario utilizzare più elementi per questo.


1

Mi sono imbattuto in questo durante la programmazione di un generatore di schede musicbox. Iniziato con diverse librerie ma ogni volta c'era un problema tecnico in qualche modo. Il ritardo nella normale implementazione audio è stato negativo, nessuna riproduzione multipla ... alla fine è finito con la libreria lowlag + soundmanager:

http://lowlag.alienbill.com/ e http://www.schillmania.com/projects/soundmanager2/

Puoi controllare l'implementazione qui: http://musicbox.grit.it/

Ho generato file wav + ogg per riproduzioni multi-browser. Questo lettore di musicbox funziona in modo reattivo su iPad, iPhone, Nexus, Mac, PC, ... funziona per me.


È una bella app per musicbox! Hai un repository git? Potrei usarlo con i nostri bambini!
Icarito,

0

So che questo è un trucco totale ma ho pensato di aggiungere questo esempio di libreria audio open source che ho messo su github qualche tempo fa ...

https://github.com/run-time/jThump

Dopo aver fatto clic sul collegamento di seguito, digita i tasti della riga home per riprodurre un riff blues (digita anche più tasti contemporaneamente, ecc.)

Esempio usando la libreria jThump >> http://davealger.com/apps/jthump/

Funziona fondamentalmente creando <iframe>elementi invisibili che caricano una pagina che riproduce un suono suReady ().

Questo non è certamente l'ideale, ma potresti fare +1 su questa soluzione basata solo sulla creatività (e sul fatto che sia open source e funzioni in qualsiasi browser su cui l'ho provato) Spero che questo dia almeno qualcun altro alla ricerca di idee.

:)


Perché qualcuno ha votato in negativo? Mi sembra un'opzione praticabile.
jtrick,

è una soluzione piuttosto confusa ma ho usato questa libreria per creare un esempio di gioco HTML 5 su tela in modo che possa funzionare comunque ... il gioco che utilizza questa libreria è qui - beepbox.net
DaveAlger

0

La risposta selezionata funzionerà in tutto tranne IE. Ho scritto un tutorial su come farlo funzionare cross browser = http://www.andy-howard.com/how-to-play-sounds-cross-browser-including-ie/index.html

Ecco la funzione che ho scritto;

function playSomeSounds(soundPath)
 {

 var trident = !!navigator.userAgent.match(/Trident\/7.0/);
 var net = !!navigator.userAgent.match(/.NET4.0E/);
 var IE11 = trident && net
 var IEold = ( navigator.userAgent.match(/MSIE/i) ? true : false );
 if(IE11 || IEold){
 document.all.sound.src = soundPath;
 }
 else
 {
 var snd = new Audio(soundPath); // buffers automatically when created
 snd.play();
 }
 };

È inoltre necessario aggiungere il seguente tag alla pagina HTML:

<bgsound id="sound">

Finalmente puoi chiamare la funzione e passare semplicemente attraverso il percorso qui:

playSomeSounds("sounds/welcome.wav");

0

Puoi sempre provare AudioContextche ha un supporto limitato ma fa parte della bozza di lavoro dell'API audio Web . Potrebbe valerne la pena se stai pianificando di rilasciare qualcosa in futuro. E se stai programmando solo per Chrome e Firefox sei d'oro.


0

var AudioContextFunc = window.AudioContext || window.webkitAudioContext;
var audioContext = new AudioContextFunc();
var player=new WebAudioFontPlayer();
var instrumVox,instrumApplause;
var drumClap,drumLowTom,drumHighTom,drumSnare,drumKick,drumCrash;
loadDrum(21,function(s){drumClap=s;});
loadDrum(30,function(s){drumLowTom=s;});
loadDrum(50,function(s){drumHighTom=s;});
loadDrum(15,function(s){drumSnare=s;});
loadDrum(5,function(s){drumKick=s;});
loadDrum(70,function(s){drumCrash=s;});
loadInstrument(594,function(s){instrumVox=s;});
loadInstrument(1367,function(s){instrumApplause=s;});
function loadDrum(n,callback){
  var info=player.loader.drumInfo(n);
  player.loader.startLoad(audioContext, info.url, info.variable);
  player.loader.waitLoad(function () {callback(window[info.variable])});
}
function loadInstrument(n,callback){
  var info=player.loader.instrumentInfo(n);
  player.loader.startLoad(audioContext, info.url, info.variable);
  player.loader.waitLoad(function () {callback(window[info.variable])});
}
function uhoh(){
  var when=audioContext.currentTime;
  var b=0.1;
  player.queueWaveTable(audioContext, audioContext.destination, instrumVox, when+b*0, 60, b*1);
  player.queueWaveTable(audioContext, audioContext.destination, instrumVox, when+b*3, 56, b*4);
}
function applause(){
  player.queueWaveTable(audioContext, audioContext.destination, instrumApplause, audioContext.currentTime, 54, 3);
}
function badumtss(){
  var when=audioContext.currentTime;
  var b=0.11;
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*0, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumLowTom, when+b*0, drumLowTom.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*1, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumHighTom, when+b*1, drumHighTom.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumSnare, when+b*3, drumSnare.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumKick, when+b*3, drumKick.zones[0].keyRangeLow, 3.5);
  player.queueWaveTable(audioContext, audioContext.destination, drumCrash, when+b*3, drumCrash.zones[0].keyRangeLow, 3.5);
}
<script src='https://surikov.github.io/webaudiofont/npm/dist/WebAudioFontPlayer.js'></script>
<button onclick='badumtss();'>badumtss</button>
<button onclick='uhoh();'>uhoh</button>
<button onclick='applause();'>applause</button>
<br/><a href='https://github.com/surikov/webaudiofont'>More sounds</a>


0

L'API Web Audio è lo strumento giusto per questo lavoro. C'è poco lavoro da fare per caricare i file audio e riprodurlo. Fortunatamente ci sono molte librerie là fuori che semplificano il lavoro. Essendo interessato ai suoni, ho anche creato una libreria chiamata musquito, che puoi anche controllare.

Attualmente supporta solo effetti sonori di dissolvenza e sto lavorando su altre cose come la spazializzazione 3D.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.