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

316

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

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

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

Моим первым подходом было использование <audio>элемента HTML5 и определение всех звуковых эффектов на моей странице. 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>элемент - скорее потоковая функция, а не то, с чем можно играть звуковыми эффектами.

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

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

Стефан Кочен
источник
Хах! Я также портирую старую игру для Macintosh на HTML5. Хотите выяснить, кого вы клонируете?
платный ботаник
1
Это проект ARASHI, бурный клон.
Стефан Кочен
Что подразумевается под «смешением» звуков?
Мэдс Скьерн
2
Вы закончили это? Можем ли мы увидеть это?
Enyo
4
К сожалению нет. У меня есть способность не заканчивать проекты свободного времени. :( Для этого есть git-репо, но я не трогал его годами: github.com/stephank/arashi-js
Стефан Кочен

Ответы:

448

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 , который теперь поддерживается большинством браузеров .

Корнель
источник
18
Audioобъекты автоматически буферизируются. Они спроектированы аналогично Imageобъектам, поэтому методы предварительной загрузки изображений oldschool работают и со звуком.
Корнель
5
Это также работает на iOS. Обратите внимание, что вам нужно использовать какое-то действие пользователя (например, нажатие на кнопку), чтобы начать звук. Вы не можете просто сделать snd.play()на window.load ().
Хаски
1
Я все еще использую <audio>тег, потому что он более управляемый. Но все равно спасибо за информацию!
Дерек 功夫 會 功夫
2
Я бы предпочел этот метод, если бы не тот факт, что элементы <audio> html5 допускают использование нескольких источников, поэтому, если браузер не поддерживает mp3, вы можете вернуться к ogg / wav. Это потребовало бы некоторого обмана в javascript, чтобы достигнуть того же самого.
joelmdev
2
На iOS 6 поддерживается автозапуск: вы можете запускать звуки с помощью простой функции snd.play () в window.load ().
Пьетро Полсинелли
36

API WebAudio от W3C

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

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

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

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

Крис Джейнс
источник
Это лучший ответ, чем принятый, поскольку он сосредоточен на правильном решении проблемы (WebAudio API) и причинах, по которым элементы Audio не являются хорошим решением, вместо того, чтобы пытаться соединить плохое решение с элементами Audio
Аномалия
29

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, генератор эффектов или видеоигру.

d13
источник
Не могу комментировать разработку игры, но я использую это для некоторой незначительной звуковой обратной связи в интерфейсе, и для этого это работает абсолютное удовольствие. Быстро, легко и просто.
Rid Iculous
Действительно хороший фреймворк, хорошо работает и в мобильном телефоне. Вы должны запустить его с помощью Touchstart ... но как только это будет сделано, это работает из коробки :)
Филипп
9

Вы также можете использовать это для обнаружения звука 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/, ''));
}
обкрадывать
источник
Спасибо, что отметили это. Я изучил этот метод из has.js, но обнаружил, что у него есть некоторые проблемы в Firefox, и, видимо, в Opera тоже в соответствии с исходным кодом has.js. (refs: github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19 )
Стефан Кочен
5

Вот один из методов, позволяющих воспроизводить даже один и тот же звук одновременно. Объедините с 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");
F-3000
источник
Нет. Я не думаю, что создание нового объекта для каждого отдельного воспроизведения звука - это вообще решение. Это быстрый и грязный обходной путь, но это можно сделать лучше.
Павел
@Pawel Правда, это НЕ должно использоваться в качестве основного метода воспроизведения звуков, но, насколько я знаю, принцип в примере - это единственный способ воспроизводить один и тот же звук более одного раза одновременно, или, как выразился OP, "перекрывающиеся воспроизведения". (Не требуя плагинов для браузера.) Моя фактическая реализация в моем текущем проекте намного сложнее, чем пример кода, который я разместил.
F-3000
4

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

Я делал это раньше без HTML5-элемента <audio>, используя небольшой объект Flash из http://flash-mp3-player.net/ - я написал музыкальную викторину ( http://webdeavour.appspot.com/ ) и использовал его для воспроизведения музыкальных клипов, когда пользователь нажал кнопку для вопроса. Первоначально у меня было по одному проигрывателю на вопрос, и было возможно воспроизводить их поверх друг друга, поэтому я поменял его так, чтобы был только один проигрыватель, который я указывал на разные музыкальные клипы.

Ли Ковалковски
источник
Это интересная мысль, чтобы использовать & lt; audio & gt; элементы как каналы. Когда я размещаю два элемента на странице, я могу играть их одновременно. Похоже, что клонирование, которое я делаю, на самом деле не делает то, что я ожидаю, потому что в моем исходном коде воспроизведение двух примеров также работает. Просто не дважды один и тот же образец. Мне придется еще поэкспериментировать с этим, и я вернусь к результатам!
Стефан Кочен
Да, возможно, есть тонкая причина, почему она называется клоном, а не копией. Возможно, клон все еще делится чем-то с оригиналом, что мешает им играть одновременно.
Ли Ковальковски
Для справки, повторное использование одного и того же элемента <audio> не работает, по крайней мере, в Firefox. Вы можете установить атрибут 'src', но он не будет загружать другой образец.
Стефан Кочен
4

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

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

Рауль Аграйт
источник
3

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

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

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

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

adamse
источник
Это верно, мне нужно играть один и тот же семпл несколько раз в одно и то же время.
Стефан Кочен
Да, это воспроизводит один и тот же экземпляр несколько раз, но для людей, которые смотрят на этот ответ, просто отметьте, что это не вызывает «перекрывающихся воспроизведений», как сформулировал ОП.
Патрик Робертс
3

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

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

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

digitalicarus
источник
2

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

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

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

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

Ojay
источник
эта библиотека довольно крутая, я действительно копаю генератор sfx. время сделать веб- загрузку
RozzA
1

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

Эли Грей
источник
1

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

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

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

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

зернистость
источник
Это хорошее приложение для музыкальной шкатулки! У вас есть git-репозиторий? Я мог бы использовать это с нашими детьми!
icarito
0

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

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

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

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

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

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

:)

DaveAlger
источник
Почему кто-то проголосовал против? Похоже, жизнеспособный вариант для меня.
Jtrick
это довольно хакерское решение, но я использовал эту библиотеку для создания примера игры на холсте html 5, чтобы она могла работать, тем не менее ... игра с использованием этой библиотеки здесь - beepbox.net
DaveAlger
0

Выбранный ответ будет работать во всем, кроме IE. Я написал учебник о том, как заставить его работать кросс-браузер = http://www.andy-howard.com/how-to-play-sounds-cross-browser-incключ-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");
Эндрю Джуниор Ховард
источник
0

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

haelmic
источник
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
источник
0

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

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

VJAI
источник