Effets sonores en JavaScript / HTML5

316

J'utilise HTML5 pour programmer des jeux; l'obstacle que j'ai rencontré maintenant est de savoir comment jouer des effets sonores.

Les exigences spécifiques sont peu nombreuses:

  • Jouez et mixez plusieurs sons,
  • Jouez le même échantillon plusieurs fois, éventuellement des chevauchements de lectures,
  • Interrompez la lecture d'un échantillon à tout moment,
  • Jouez de préférence des fichiers WAV contenant du PCM brut (de faible qualité), mais je peux les convertir, bien sûr.

Ma première approche a été d'utiliser l' <audio>élément HTML5 et de définir tous les effets sonores de ma page. Firefox lit les fichiers WAV simplement pêche, mais appeler #playplusieurs fois ne joue pas vraiment l'échantillon plusieurs fois. D'après ma compréhension de la spécification HTML5, l' <audio>élément suit également l'état de la lecture, ce qui explique pourquoi.

Ma pensée immédiate était de cloner les éléments audio, j'ai donc créé la petite bibliothèque JavaScript suivante pour le faire pour moi (cela dépend de 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;
      };
    });
  }
};

Alors maintenant, je peux le faire à Snd.boom();partir de la console Firebug et jouer snd/boom.wav, mais je ne peux toujours pas jouer le même échantillon plusieurs fois. Il semble que l' <audio>élément soit plus une fonctionnalité de streaming que quelque chose avec lequel jouer des effets sonores.

Existe-t-il un moyen intelligent de faire en sorte que cela me manque, en utilisant de préférence uniquement HTML5 et JavaScript?

Je dois également mentionner que mon environnement de test est Firefox 3.5 sur Ubuntu 9.10. Les autres navigateurs que j'ai essayés - Opera, Midori, Chromium, Epiphany - ont produit des résultats variables. Certains ne jouent rien, et certains lèvent des exceptions.

Stéphan Kochen
la source
Hah! Je porte également un ancien jeu Macintosh en HTML5. Voulez-vous révéler lequel vous clonez?
un nerd payé le
1
C'est le projet ARASHI, un clone de la tempête.
Stéphan Kochen
Qu'entend-on par "mixage" de sons?
Mads Skjern
2
Tu l'as fini? Pouvons-nous le voir?
enyo
4
Malheureusement non. J'ai le don de ne pas terminer les projets de temps libre. :( Il y a un dépôt git pour cela, mais je n'y ai pas touché depuis des années: github.com/stephank/arashi-js
Stéphan Kochen

Réponses:

448

AudioObjets HTML5

Vous n'avez pas besoin de vous soucier des <audio>éléments. HTML 5 vous permet d'accéder directement aux Audioobjets :

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

Il n'y a pas de support pour le mixage dans la version actuelle de la spécification.

Pour lire plusieurs fois le même son, créez plusieurs instances de l' Audioobjet. Vous pouvez également définir snd.currentTime=0l'objet après qu'il ait fini de jouer.


Étant donné que le constructeur JS ne prend pas en charge les <source>éléments de secours , vous devez utiliser

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

pour tester si le navigateur prend en charge Ogg Vorbis.


Si vous écrivez un jeu ou une application musicale (plus qu'un simple lecteur), vous souhaiterez utiliser une API Web Audio plus avancée , désormais prise en charge par la plupart des navigateurs .

Kornel
la source
18
Audioles objets sont tamponnés automatiquement. Ils sont conçus de manière analogue aux Imageobjets, de sorte que les techniques de préchargement d'image oldschool fonctionnent également avec l'audio.
Kornel
5
Cela fonctionne également sur iOS. Notez cependant que vous devez utiliser une sorte d'action utilisateur (par exemple, un clic sur un bouton) pour lancer le son. Vous ne pouvez pas simplement faire un snd.play()sur window.load ().
Husky
1
J'utilise toujours le <audio>tag car il est plus contrôlable. Mais de toute façon merci pour l'info!
Derek 朕 會 功夫
2
Je préférerais cette méthode sans le fait que les éléments <audio> html5 autorisent plusieurs sources, donc si un navigateur ne prend pas en charge le mp3, vous pouvez revenir à ogg / wav. Cela nécessiterait une supercherie en javascript pour accomplir la même chose.
joelmdev
2
Sur iOS 6, la lecture automatique est prise en charge: vous pouvez lancer des sons avec un simple snd.play () sur window.load ().
Pietro Polsinelli
36

API WebAudio par W3C

Depuis juillet 2012, l' API WebAudio est désormais prise en charge dans Chrome, et au moins en partie dans Firefox, et devrait être ajoutée à IOS à partir de la version 6.

Bien qu'il soit suffisamment robuste pour être utilisé par programme pour les tâches de base, l'élément audio n'a jamais été conçu pour fournir un support audio complet pour les jeux, etc. Il a été conçu pour permettre à un seul élément multimédia d'être intégré dans une page, semblable à un img marque. Il y a beaucoup de problèmes à essayer d'utiliser la balise audio pour les jeux:

  • Les feuillets de synchronisation sont courants avec les éléments audio
  • Vous avez besoin d'un élément audio pour chaque instance d'un son
  • Les événements de chargement ne sont pas encore totalement fiables
  • Pas de contrôles de volume communs, pas de décoloration, pas de filtres / effets

J'ai utilisé cet article Mise en route avec WebAudio pour commencer avec l'API WebAudio. L' étude de cas FieldRunners WebAudio est également une bonne lecture.

Chris Jaynes
la source
C'est une meilleure réponse que celle acceptée, car elle se concentre sur la bonne solution au problème (API WebAudio), et les raisons pour lesquelles les éléments audio ne sont pas une bonne solution, plutôt que d'essayer de pirater ensemble une mauvaise solution avec des éléments audio
Anomalie
29

howler.js

Pour la création de jeux, l'une des meilleures solutions consiste à utiliser une bibliothèque qui résout les nombreux problèmes auxquels nous sommes confrontés lors de l'écriture de code pour le Web, comme howler.js . howler.js résume la grande (mais de bas niveau) API Web Audio dans un cadre facile à utiliser. Il tentera de revenir à l' élément audio HTML5 si l'API Web Audio n'est pas disponible.

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

Une autre grande bibliothèque est wad.js , qui est particulièrement utile pour produire du son de synthé, comme de la musique et des effets. Par exemple:

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}
})

Sound for Games

Une autre bibliothèque similaire à Wad.js est " Sound for Games ", elle se concentre davantage sur la production d'effets, tout en fournissant un ensemble similaire de fonctionnalités via une API relativement distincte (et peut-être plus concise):

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?]
  );
}

Résumé

Chacune de ces bibliothèques vaut le coup d'œil, que vous ayez besoin de lire un seul fichier audio ou de créer votre propre éditeur de musique html, générateur d'effets ou jeu vidéo.

d13
la source
Je ne peux pas commenter le développement du jeu, mais je l'utilise pour certains commentaires audio mineurs dans une interface et pour cela, cela fonctionne un régal absolu. Rapide, facile et simple.
Rid Iculous
Cadre vraiment sympa, fonctionne aussi bien sur mobile. Vous devez le déclencher avec touchstart ... mais une fois cela fait, cela fonctionne hors de la boîte :)
Philip
9

Vous pouvez également utiliser ceci pour détecter l'audio HTML 5 dans certains cas:

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

Fonction de détection HTML 5 JS

function supportsAudio()
{
    var a = document.createElement('audio'); 
    return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
}
Rob
la source
Merci de l'avoir noté. J'ai appris cette méthode de has.js, mais je trouve qu'elle a quelques problèmes avec Firefox, et apparemment aussi avec Opera selon le code source de has.js. ( réfs : github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19 )
Stéphan Kochen
5

Voici une méthode permettant de jouer même le même son simultanément. Combinez avec le préchargeur et vous êtes prêt. Cela fonctionne avec Firefox 17.0.1 au moins, je ne l'ai pas encore testé avec autre chose.

// 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();
}

Associez-le à une touche du clavier et profitez:

player("step");
F-3000
la source
Non. Je ne pense pas que la création d'un nouvel objet pour chaque lecture de son individuelle soit une solution. C'est une solution rapide et sale, mais cela peut être mieux fait.
Pawel
@Pawel Il est vrai que cela ne devrait PAS être utilisé comme méthode principale de lecture des sons, mais pour autant que je sache, le principe de l'exemple est la seule façon de jouer le même son plusieurs fois simultanément, ou comme OP l'a exprimé, msgstr "lectures qui se chevauchent". (Sans nécessiter de plugins de navigateur.) Mon implémentation réelle dans mon projet actuel est beaucoup plus sophistiquée que l'exemple de code que j'ai publié.
F-3000
4

Des sons comme ce que vous voulez sont des sons multicanaux. Supposons que vous ayez 4 canaux (comme sur les très vieux jeux 16 bits), je n'ai pas encore commencé à jouer avec la fonctionnalité audio HTML5, mais n'avez-vous pas simplement besoin de 4 éléments <audio> et du cycle qui est utilisé jouer le prochain effet sonore? As-tu essayé ça? Ce qui se produit? Si cela fonctionne: Pour jouer plus de sons simultanément, ajoutez simplement plus d'éléments <audio>.

J'ai déjà fait cela sans l'élément HTML5 <audio>, en utilisant un petit objet Flash de http://flash-mp3-player.net/ - j'ai écrit un quiz musical ( http://webdeavour.appspot.com/ ) et l'a utilisé pour lire des clips de musique lorsque l'utilisateur a cliqué sur le bouton de la question. Au départ, j'avais un joueur par question, et il était possible de les jouer les uns sur les autres, alors je l'ai changé pour qu'il n'y ait qu'un seul joueur, que j'ai pointé sur différents clips musicaux.

Lee Kowalkowski
la source
C'est une pensée intéressante, pour utiliser & lt; audio & gt; éléments comme canaux. Lorsque je mets deux éléments sur une page, je peux les jouer simultanément. Il semble que le clonage que je fais ne fait pas vraiment ce que j'attends, car dans mon code d'origine, jouer deux échantillons fonctionne également. Pas deux fois le même échantillon. Je vais devoir expérimenter cela un peu plus et je reviendrai sur les résultats!
Stéphan Kochen
Oui, il y a peut-être une raison subtile pour laquelle on l'appelle cloner et non copier. Peut-être que le clone partage toujours quelque chose avec l'original qui les empêche de jouer simultanément.
Lee Kowalkowski
Pour référence, réutiliser le même élément <audio> ne fonctionne pas, du moins dans Firefox. Vous pouvez définir l'attribut 'src', mais il ne chargera pas réellement un échantillon différent.
Stéphan Kochen
4

Jetez un œil au site jai (-> miroir ) (interface audio javascript). En regardant leur source, ils semblent appeler à play()plusieurs reprises, et ils mentionnent que leur bibliothèque pourrait être appropriée pour une utilisation dans des jeux basés sur HTML5.

Vous pouvez déclencher plusieurs événements audio simultanément, ce qui pourrait être utilisé pour créer des jeux Javascript ou avoir une voix parlant sur une musique de fond

Raul Agrait
la source
3

Pour lire le même échantillon plusieurs fois, ne serait-il pas possible de faire quelque chose comme ceci:

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

(e est l'élément audio)

Peut-être que j'ai complètement mal compris votre problème, voulez-vous que l'effet sonore soit lu plusieurs fois en même temps? Alors c'est complètement faux.

admirer
la source
C'est vrai, je dois jouer le même échantillon plusieurs fois en même temps.
Stéphan Kochen
Oui, cela joue plusieurs fois la même instance, mais pour les personnes qui consultent cette réponse, notez simplement que cela ne provoque pas de "lectures qui se chevauchent", comme le dit l'OP.
Patrick Roberts
3

Voici une idée. Chargez tout votre audio pour une certaine classe de sons dans un seul élément audio individuel où les données src sont tous vos échantillons dans un fichier audio contigu (vous voulez probablement un peu de silence entre les deux afin de pouvoir capturer et couper les échantillons avec un délai d'attente avec moins risque de saignement à l'échantillon suivant). Ensuite, recherchez l'échantillon et jouez-le si nécessaire.

Si vous avez besoin de plusieurs d'entre eux pour jouer, vous pouvez créer un élément audio supplémentaire avec le même src afin qu'il soit mis en cache. Maintenant, vous avez effectivement plusieurs "pistes". Vous pouvez utiliser des groupes de pistes avec votre schéma d'allocation de ressources préféré comme Round Robin, etc.

Vous pouvez également spécifier d'autres options comme la mise en file d'attente des sons dans une piste à lire lorsque cette ressource devient disponible ou la découpe d'un échantillon en cours de lecture.

digitalicarus
la source
2

Je recommanderais d'utiliser SoundJS , une bibliothèque que j'ai aidé à développer. Il vous permet d'écrire une base de code unique qui fonctionne partout, avec SoundJS choisissant l'audio Web, l'audio html ou l'audio flash selon le cas.

Cela vous permettra de faire tout ce que vous voulez:

  • Jouez et mixez plusieurs sons,
  • Lire le même échantillon plusieurs fois, chevauchant éventuellement des lectures
  • Interrompre la lecture d'un échantillon à tout moment
  • lire des fichiers WAV contenant (selon le support du navigateur)

J'espère que cela pourra aider.

OJay
la source
cette bibliothèque est plutôt géniale, je creuse vraiment le générateur sfx. il est temps de faire un téléchargement
RozzA
1

Il n'est pas possible de jouer à plusieurs coups avec un seul <audio>élément. Vous devez utiliser plusieurs éléments pour cela.

Eli Grey
la source
1

Je suis tombé sur cela lors de la programmation d'un générateur de cartes Musicbox. Commencé avec différentes bibliothèques mais à chaque fois il y avait un problème. Le retard sur l'implémentation audio normale était mauvais, pas de lecture multiple ... a finalement fini par utiliser la bibliothèque lowlag + soundmanager:

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

Vous pouvez consulter la mise en œuvre ici: http://musicbox.grit.it/

J'ai généré des fichiers wav + ogg pour des jeux multi-navigateurs. Ce lecteur de boîte à musique fonctionne réactif sur iPad, iPhone, Nexus, Mac, PC, ... fonctionne pour moi.

Grincer
la source
C'est une belle application de boîte à musique! Avez-vous un référentiel git? Je pourrais l'utiliser avec nos enfants!
icarito
0

Je sais que c'est un hack total mais j'ai pensé que je devrais ajouter cet exemple de bibliothèque audio open source que j'ai mise sur github il y a un moment ...

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

Après avoir cliqué sur le lien ci-dessous, tapez sur les touches de la ligne d'accueil pour jouer un riff de blues (tapez également plusieurs touches en même temps, etc.)

Exemple d'utilisation de la bibliothèque jThump >> http://davealger.com/apps/jthump/

Il fonctionne essentiellement en créant des <iframe>éléments invisibles qui chargent une page qui lit un son sur Ready ().

Ce n'est certainement pas idéal mais vous pourriez attribuer +1 à cette solution uniquement sur la base de la créativité (et du fait qu'elle est open source et fonctionne dans n'importe quel navigateur sur lequel j'ai essayé). J'espère que cela donnera à quelqu'un d'autre au moins quelques idées.

:)

DaveAlger
la source
Pourquoi quelqu'un a-t-il voté contre cela? Cela me semble une option viable.
jtrick
c'est une solution assez hacky mais j'ai utilisé cette bibliothèque pour faire un exemple de jeu de toile html 5 afin qu'il puisse quand même fonctionner
DaveAlger
0

La réponse sélectionnée fonctionnera dans tout sauf IE. J'ai écrit un tutoriel sur la façon de le faire fonctionner cross browser = http://www.andy-howard.com/how-to-play-sounds-cross-browser-including-ie/index.html

Voici la fonction que j'ai écrite;

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();
 }
 };

Vous devez également ajouter la balise suivante à la page html:

<bgsound id="sound">

Enfin, vous pouvez appeler la fonction et simplement passer par le chemin ici:

playSomeSounds("sounds/welcome.wav");
Andrew Junior Howard
la source
0

Vous pouvez toujours l'essayer AudioContextavec un support limité, mais cela fait partie du brouillon de travail de l' API audio Web . Cela pourrait valoir la peine si vous prévoyez de sortir quelque chose à l'avenir. Et si vous ne programmez que pour Chrome et Firefox, vous êtes en or.

haelmique
la source
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>

user1024
la source
0

L'API Web Audio est l'outil idéal pour ce travail. Il y a peu de travail impliqué dans le chargement des fichiers sons et leur lecture. Heureusement, il existe de nombreuses bibliothèques qui simplifient le travail. Étant intéressé par les sons, j'ai également créé une bibliothèque appelée musquito vous pouvez également consulter.

Actuellement, il ne prend en charge que les effets sonores atténués et je travaille sur d'autres choses comme la spatialisation 3D.

VJAI
la source