Звуковые эффекты в JavaScript / HTML5

Я использую HTML5 для программирования игр; препятствие, с которым я столкнулся сейчас, состоит в том, как играть звуковые эффекты.

Конкретные требования немногочисленны:

  • Играть и смешивать несколько звуков,
  • Проиграть один и тот же семпл несколько раз, возможно, с перекрывающимся воспроизведением,
  • Прервать воспроизведение сэмпла в любой точке,
  • Предпочтительно воспроизводить файлы WAV, содержащие (низкокачественные) необработанные PCM, но я, конечно, могу их конвертировать.

Мой первый подход состоял в том, чтобы использовать HTML5 <audio> элемент и определить все звуковые эффекты на моей странице. Firefox проигрывает файлы WAV просто замечательно, но #play Несколько раз на самом деле не воспроизводит семпл несколько раз. Из моего понимания спецификации HTML5, <audio> Элемент также отслеживает состояние воспроизведения, поэтому это объясняет, почему.

Моей первой мыслью было клонирование аудио элементов, поэтому я создал для этого следующую крошечную библиотеку JavaScript (зависит от 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;
      };
    });
  }
};

Так что теперь я могу сделать Snd.boom(); из консоли Firebug и играйте snd/boom.wav, но я все еще не могу воспроизвести один и тот же семпл несколько раз. Кажется, что <audio> element - это скорее функция потоковой передачи, а не то, с чем можно играть звуковыми эффектами.

Есть ли какой-нибудь умный способ заставить это случиться, что я пропускаю, предпочтительно используя только HTML5 и JavaScript?

Я должен также упомянуть, что моей тестовой средой является Firefox 3.5 на Ubuntu 9.10. Другие браузеры, которые я пробовал - Opera, Midori, Chromium, Epiphany - дали разные результаты. Некоторые ничего не играют, а некоторые бросают исключения.

16 ответов

Решение

HTML5 Audio объекты

Вам не нужно беспокоиться с <audio> элементы. HTML 5 позволяет вам получить доступ Audio объекты напрямую:

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

В текущей версии спецификации поддержки микширования нет.

Чтобы воспроизвести один и тот же звук несколько раз, создайте несколько экземпляров Audio объект. Вы также можете установить snd.currentTime=0 на объекте после того, как он заканчивает играть.


Поскольку конструктор JS не поддерживает запасной вариант <source> элементы, вы должны использовать

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

проверить, поддерживает ли браузер Ogg Vorbis.


Если вы пишете игру или музыкальное приложение (больше, чем просто плеер), вам нужно использовать более продвинутый Web Audio API, который теперь поддерживается большинством браузеров.

APIWebAudio от W3C

По состоянию на июль 2012 года API WebAudio теперь поддерживается в Chrome и, по крайней мере, частично поддерживается в Firefox, и планируется добавить в IOS начиная с версии 6.

Несмотря на то, что он достаточно надежен, чтобы его можно было использовать программно для выполнения основных задач, элемент Audio никогда не предназначался для обеспечения полной поддержки звука для игр и т. Д. Он был разработан для того, чтобы позволить одной части мультимедиа быть встроенной в страницу, аналогично img тег. Существует много проблем с использованием тега Audio для игр:

  • Сроки синхронизации являются общими для аудио элементов
  • Вам нужен элемент Audio для каждого экземпляра звука
  • События загрузки еще не совсем надежны
  • Нет общих регуляторов громкости, нет затухания, нет фильтров / эффектов

Я использовал эту статью Начало работы с WebAudio, чтобы начать работу с API WebAudio. Пример использования FieldRunners WebAudio также хорошо читается.

howler.js

Для разработки игр одним из лучших решений является использование библиотеки, которая решает многие проблемы, с которыми мы сталкиваемся при написании кода для Интернета, например, howler.js. howler.js абстрагирует великолепный (но низкоуровневый) API-интерфейс Web Audio в простой в использовании фреймворк. Он попытается использовать HTML5 Audio Element, если Web Audio API недоступен.

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

Еще одна отличная библиотека - wad.js, которая особенно полезна для создания синтезированного звука, такого как музыка и эффекты. Например:

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

Звук для игр

Еще одна библиотека, похожая на Wad.js, - это " Звук для игр", она в большей степени ориентирована на создание эффектов, обеспечивая при этом аналогичный набор функциональных возможностей посредством относительно отличного (и, возможно, более лаконичного) интерфейса API:

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

Резюме

Каждую из этих библиотек стоит посмотреть, нужно ли вам воспроизвести один звуковой файл или, возможно, создать свой собственный музыкальный редактор на основе html, генератор эффектов или видеоигру.

Вы также можете использовать это для обнаружения звука HTML 5 в некоторых случаях:

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

HTML 5 JS функция обнаружения

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

Вот один из методов, позволяющих воспроизводить даже один и тот же звук одновременно. Объедините с preloader, и все готово. Это работает с Firefox 17.0.1 по крайней мере, еще не проверял его ни с чем.

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

Свяжите это с клавишей клавиатуры и наслаждайтесь:

player("step");

Взгляните на сайт jai (-> mirror) (аудио интерфейс javascript). Глядя на их источник, они, кажется, зовут play() неоднократно, и они упоминают, что их библиотека может быть подходящей для использования в играх на основе HTML5.

Вы можете запустить несколько аудио событий одновременно, которые могут быть использованы для создания игр Javascript или иметь голос, говорящий поверх некоторой фоновой музыки.

Чтобы воспроизвести один и тот же семпл несколько раз, нельзя было бы сделать что-то вроде этого:

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

(e это аудио элемент)

Возможно, я полностью неправильно понял вашу проблему, вы хотите, чтобы звуковой эффект воспроизводился несколько раз одновременно? Тогда это совершенно неправильно.

Похоже, что вы хотите многоканальные звуки. Предположим, у вас есть 4 канала (как в действительно старых 16-битных играх), я еще не дошел до игры с аудио-функцией HTML5, но вам не нужны только 4 элемента

Я делал это раньше без HTML5-элемента

Вот идея. Загрузите все ваши аудио для определенного класса звуков в один отдельный аудиоэлемент, где данные src - это все ваши сэмплы в непрерывном аудиофайле (вероятно, требуется некоторое молчание между ними, чтобы вы могли ловить и вырезать сэмплы с тайм-аутом с меньшими затратами риск кровотечения до следующего образца). Затем найдите образец и воспроизведите его при необходимости.

Если вам нужно более одного из них для воспроизведения, вы можете создать дополнительный аудиоэлемент с тем же src, чтобы он кэшировался. Теперь у вас есть несколько "треков". Вы можете использовать группы треков с вашей любимой схемой распределения ресурсов, такой как Round Robin и т. Д.

Вы также можете указать другие параметры, такие как постановка в очередь звуков в дорожку для воспроизведения, когда этот ресурс станет доступным, или вырезание воспроизводимого в данный момент семпла.

http://robert.ocallahan.org/2011/11/latency-of-html5-sounds.html

http://people.mozilla.org/~roc/audio-latency-repeating.html

Работает нормально в Firefox и Chrome для меня.

Чтобы остановить звук, который вы начали, выполните var sound = document.getElementById("shot"). CloneNode(true); sound.play(); и позже sound.pause();

Я бы порекомендовал использовать SoundJS, библиотеку, которую я помогаю в разработке. Он позволяет вам написать единую кодовую базу, которая работает везде, при этом SoundJS выбирает веб-аудио, HTML-аудио или флэш-аудио в зависимости от ситуации.

Это позволит вам делать все, что вы хотите:

  • Играть и смешивать несколько звуков,
  • Проигрывайте один и тот же семпл несколько раз, возможно, перекрывая воспроизведение
  • Прервать воспроизведение сэмпла в любой точке
  • воспроизводить WAV файлы, содержащие (в зависимости от поддержки браузера)

Надеюсь, это поможет.

Я столкнулся с этим при программировании генератора карт музыкальной шкатулки. Начал с разных библиотек, но каждый раз как-то возникал глюк. Отставание в реализации обычного звука было плохим, многократных воспроизведений... в конечном итоге использовалась библиотека lowlag + soundmanager:

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

Вы можете проверить реализацию здесь: http://musicbox.grit.it/

Я сгенерировал файлы wav + ogg для мультибраузерной игры. Этот музыкальный плеер работает на Ipad, Iphone, Nexus, Mac, ПК,... работает для меня.

Невозможно играть несколькими выстрелами с одним <audio> элемент. Вам нужно использовать несколько элементов для этого.

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>

Я знаю, что это полный взлом, но подумал, что мне следует добавить этот пример аудио библиотеки с открытым исходным кодом, которую я недавно поставил на github...

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

После нажатия на ссылку ниже, введите клавиши домашнего ряда для воспроизведения блюзового риффа (также введите несколько клавиш одновременно и т. Д.)

Пример использования библиотеки jThump >> http://davealger.com/apps/jthump/

Это в основном работает, делая невидимым <iframe> элементы, которые загружают страницу, которая воспроизводит звук onReady().

Это, конечно, не идеально, но вы могли бы +1 это решение, основанное только на творчестве (и на том факте, что оно с открытым исходным кодом и работает в любом браузере, на котором я его пробовал), я надеюсь, что это даст кому-то другому хотя бы некоторые идеи.

:)

Web Audio API - правильный инструмент для этой работы. Существует небольшая работа, связанная с загрузкой звуковых файлов и их воспроизведением. К счастью, существует множество библиотек, которые упрощают работу. Заинтересовавшись звуками, я также создал библиотеку musquito, которую вы также можете проверить.

В настоящее время он поддерживает только эффект затухания звука, и я работаю над другими вещами, такими как трехмерное пространственное размещение.

Вы всегда можете попробовать AudioContext он имеет ограниченную поддержку, но является частью рабочего проекта web audio api. Это может стоить того, если вы планируете выпустить что-то в будущем. И если вы программируете только для Chrome и Firefox, то вы великолепны.

Выбранный ответ будет работать во всем, кроме IE. Я написал учебник о том, как заставить его работать кросс-браузер = http://www.andy-howard.com/how-to-play-sounds-cross-browser-including-ie/index.html

Вот функция, которую я написал;

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

Вам также необходимо добавить следующий тег на HTML-страницу:

<bgsound id="sound">

Наконец, вы можете вызвать функцию и просто пройти по пути здесь:

playSomeSounds("sounds/welcome.wav");
Другие вопросы по тегам