Efekty dźwiękowe w JavaScript / HTML5


316

Używam HTML5 do programowania gier; przeszkodą, na którą się teraz natknąłem, jest sposób odtwarzania efektów dźwiękowych.

Szczegółowe wymagania są nieliczne:

  • Graj i miksuj wiele dźwięków,
  • Odtwórz tę samą próbkę wiele razy, być może nakładające się na siebie odtworzenia,
  • Przerywać odtwarzanie próbki w dowolnym momencie,
  • Najlepiej odtwarzaj pliki WAV zawierające (niskiej jakości) surowe PCM, ale oczywiście mogę je przekonwertować.

Moje pierwsze podejście polegało na użyciu <audio>elementu HTML5 i zdefiniowaniu wszystkich efektów dźwiękowych na mojej stronie. Firefox odtwarza pliki WAV po prostu brzoskwiniowe, ale #playwielokrotne wywoływanie tak naprawdę nie odtwarza próbki wielokrotnie. Z mojego zrozumienia specyfikacji HTML5 <audio>element śledzi również stan odtwarzania, więc to wyjaśnia dlaczego.

Moją bezpośrednią myślą było sklonowanie elementów audio, dlatego stworzyłem następującą małą bibliotekę JavaScript, aby to dla mnie zrobić (zależy od 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;
      };
    });
  }
};

Teraz mogę to zrobić Snd.boom();z konsoli Firebug i grać snd/boom.wav, ale wciąż nie mogę grać tej samej próbki wiele razy. Wygląda na to, że <audio>element ten jest raczej funkcją przesyłania strumieniowego, niż czymś do odtwarzania efektów dźwiękowych.

Czy istnieje sprytny sposób, aby tak się stało, czego mi brakuje, najlepiej używając tylko HTML5 i JavaScript?

Powinienem również wspomnieć, że moim środowiskiem testowym jest Firefox 3.5 na Ubuntu 9.10. Inne przeglądarki, których wypróbowałem - Opera, Midori, Chromium, Objawienie Pańskie - przynosiły różne wyniki. Niektórzy nic nie grają, a niektórzy zgłaszają wyjątki.


Hah! Przenoszę też starą grę Macintosh na HTML5. Chcesz ujawnić, który klonujesz?
płatny frajer

1
To Project ARASHI, klon burzy.
Stéphan Kochen

Co należy rozumieć przez „miksowanie” dźwięków?
Mads Skjern

2
Skończyłeś to? Czy możemy to zobaczyć?
enyo

4
Niestety nie. Mam talent do nie kończenia projektów w wolnym czasie. :( Jest za to repozytorium git, ale nie zmieniłem
Stéphan Kochen

Odpowiedzi:


448

AudioObiekty HTML5

Nie musisz zawracać sobie głowy <audio>elementami. HTML 5 umożliwia bezpośredni dostęp do Audioobiektów :

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

W obecnej wersji specyfikacji nie ma obsługi miksowania.

Aby odtworzyć ten sam dźwięk wiele razy, utwórz wiele instancji Audioobiektu. Możesz także ustawić snd.currentTime=0obiekt po zakończeniu odtwarzania.


Ponieważ konstruktor JS nie obsługuje <source>elementów zastępczych , należy go użyć

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

aby sprawdzić, czy przeglądarka obsługuje Ogg Vorbis.


Jeśli piszesz grę lub aplikację muzyczną (więcej niż tylko odtwarzacz), możesz użyć bardziej zaawansowanego interfejsu Web Audio API , który jest teraz obsługiwany przez większość przeglądarek .


18
Audioobiekty są automatycznie buforowane. Są zaprojektowane analogicznie do Imageobiektów, więc techniki ładowania obrazu oldschool również działają z dźwiękiem.
Kornel,

5
Działa to również na iOS. Zwróć jednak uwagę, że musisz zainicjować jakiś dźwięk użytkownika (np. Kliknięcie przycisku). Nie możesz po prostu wykonać polecenia snd.play()na window.load ().
Husky

1
Nadal używam <audio>tagu, ponieważ jest on bardziej kontrolowany. Ale i tak dziękuję za informację!
Derek 朕 會 功夫

2
Wolałbym tę metodę, gdyby nie fakt, że elementy <audio> html5 pozwalają na wiele źródeł, więc jeśli przeglądarka nie obsługuje formatu mp3, możesz wrócić do ogg / wav. Osiągnięcie tego samego wymagałoby pewnych sztuczek w javascript.
joelmdev

2
W iOS 6 obsługiwana jest gra automatyczna: możesz inicjować dźwięki za pomocą prostej snd.play () na window.load ().
Pietro Polsinelli

36

WebAudio API firmy W3C

Od lipca 2012 r. Interfejs API WebAudio jest teraz obsługiwany w Chrome, a przynajmniej częściowo obsługiwany w Firefoksie, i ma zostać dodany do IOS od wersji 6.

Chociaż jest wystarczająco solidny, aby można go było używać programowo do wykonywania podstawowych zadań, element Audio nigdy nie miał zapewniać pełnego wsparcia audio dla gier itp. Został zaprojektowany tak, aby umożliwić osadzenie jednego elementu multimediów na stronie, podobnie jak na img etykietka. Istnieje wiele problemów z próbą użycia znacznika audio w grach:

  • Pasy czasowe są wspólne dla elementów audio
  • Potrzebujesz elementu audio dla każdej instancji dźwięku
  • Zdarzenia ładowania nie są jeszcze całkowicie niezawodne
  • Bez wspólnych regulacji głośności, bez zanikania, bez filtrów / efektów

Użyłem tego artykułu Pierwsze kroki z WebAudio, aby rozpocząć pracę z interfejsem API WebAudio. Fieldrunners WebAudio Case Study to również dobra lektura.


To lepsza odpowiedź niż zaakceptowana, ponieważ koncentruje się na poprawnym rozwiązaniu problemu (interfejs API WebAudio), a także na przyczynach, dla których elementy audio nie są dobrym rozwiązaniem, zamiast próbować zhakować złe rozwiązanie za pomocą elementów audio
Anomalia

29

howler.js

Do tworzenia gier jednym z najlepszych rozwiązań jest użycie biblioteki, która rozwiązuje wiele problemów napotykanych podczas pisania kodu dla Internetu, takich jak howler.js . howler.js wyodrębnia świetny (ale niskiego poziomu) interfejs API Web Audio do łatwego w użyciu frameworka. Spróbuje wrócić do HTML5 Audio Element, jeśli interfejs API Web Audio jest niedostępny.

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

Inną świetną biblioteką jest plik wad.js , który jest szczególnie przydatny do tworzenia audio syntezatora, takiego jak muzyka i efekty. Na przykład:

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

Dźwięk dla gier

Inną biblioteką podobną do Wad.js jest „ Sound for Games ”, która bardziej skupia się na tworzeniu efektów, zapewniając jednocześnie podobny zestaw funkcji dzięki stosunkowo odrębnemu (i być może bardziej zwięzłemu) interfejsowi 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?]
  );
}

Podsumowanie

Każda z tych bibliotek jest warta obejrzenia, bez względu na to, czy chcesz odtworzyć pojedynczy plik dźwiękowy, czy może utworzyć własny edytor muzyki oparty na HTML, generator efektów lub grę wideo.


Nie mogę komentować rozwoju gier, ale używam tego do drobnych sprzężeń audio w interfejsie i do tego działa to absolutna przyjemność. Szybki, łatwy i prosty.
Rid Iculous

Naprawdę fajny framework, działa również dobrze na urządzeniach mobilnych. Musisz uruchomić go za pomocą touchstartu ... ale kiedy to zrobisz, działa od razu po wyjęciu z pudełka :)
Philip

9

Możesz także użyć tego do wykrywania audio HTML 5 w niektórych przypadkach:

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

Funkcja wykrywania JS HTML 5

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

Dzięki, że to zauważyłeś. Nauczyłem się tej metody od has.js, ale okazuje się, że ma pewne problemy w Firefoksie i najwyraźniej także w Operze, zgodnie z kodem źródłowym has.js. (refs: github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19 )
Stéphan Kochen

5

Oto jedna z metod umożliwiająca jednoczesne odtwarzanie nawet tego samego dźwięku. Połącz z preloaderem i wszystko gotowe. Działa to przynajmniej z Firefoksem 17.0.1, jeszcze go nie testowałem.

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

Powiąż to z klawiszem na klawiaturze i ciesz się:

player("step");

Nie. Nie wydaje mi się, aby tworzenie nowego obiektu dla każdego odtwarzanego dźwięku było w ogóle rozwiązaniem. Jest to szybkie i brudne obejście, ale można to zrobić lepiej.
Paweł

@Pawel Prawda, że ​​NIE należy tego używać jako głównej metody odtwarzania dźwięków, ale o ile mi wiadomo, zasada w tym przykładzie jest jedynym sposobem odtwarzania tego samego dźwięku więcej niż raz jednocześnie lub w sposób, w jaki wyraził to OP, „nakładające się odtworzenia”. (Nie wymagając wtyczek do przeglądarki). Moje rzeczywiste narzędzie w moim bieżącym projekcie jest znacznie bardziej wyrafinowane niż przykładowy kod, który opublikowałem.
F-3000

4

Brzmi tak, jakbyś chciał brzmieć wielokanałowych. Załóżmy, że masz 4 kanały (jak w naprawdę starych 16-bitowych grach), nie miałem jeszcze ochoty grać z funkcją audio HTML5, ale nie potrzebujesz tylko 4 elementów <audio> i cyklu, który jest używany odtworzyć następny efekt dźwiękowy? Próbowałeś tego? Co się dzieje? Jeśli to działa: Aby jednocześnie odtwarzać więcej dźwięków, po prostu dodaj więcej elementów <audio>.

Zrobiłem to wcześniej bez elementu HTML5 <audio>, używając małego obiektu Flash z http://flash-mp3-player.net/ - napisałem quiz muzyczny ( http://webdeavour.appspot.com/ ) i używał go do odtwarzania klipów muzycznych, gdy użytkownik kliknął przycisk pytania. Początkowo miałem jednego odtwarzacza na pytanie i można było odtwarzać je jeden nad drugim, więc zmieniłem to, aby był tylko jeden odtwarzacz, na który wskazywałem różne klipy muzyczne.


To interesująca myśl, aby użyć & lt; audio & gt; elementy jako kanały. Kiedy umieścić dwa elementy na stronie, że można odtwarzać je jednocześnie. Wygląda na to, że klonowanie, które wykonuję, nie robi właściwie tego, czego oczekuję, ponieważ w moim oryginalnym kodzie działa również odtwarzanie dwóch próbek. Po prostu nie dwa razy ta sama próbka. Będę musiał z tym jeszcze trochę poeksperymentować i powrócę do wyników!
Stéphan Kochen

Tak, istnieje prawdopodobnie subtelny powód, dla którego nazywa się to klonowaniem, a nie kopiowaniem. Być może klon nadal udostępnia coś z oryginałem, co uniemożliwia im jednoczesne granie.
Lee Kowalkowski,

Dla porównania, ponowne użycie tego samego elementu <audio> nie działa, przynajmniej w Firefoksie. Możesz ustawić atrybut „src”, ale tak naprawdę nie załaduje innej próbki.
Stéphan Kochen,

4

Zajrzyj na stronę jai (-> mirror ) (interfejs audio javascript). Patrząc na źródło, wydają się dzwonić play()wielokrotnie i wspominają, że ich biblioteka może być odpowiednia do użytku w grach opartych na HTML5.

Możesz uruchamiać wiele zdarzeń audio jednocześnie, które mogą być używane do tworzenia gier JavaScript lub głosu w tle muzyki


3

Aby odtworzyć tę samą próbkę wiele razy, czy nie byłoby możliwe zrobienie czegoś takiego:

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

( ejest elementem audio)

Być może całkowicie źle zrozumiałem twój problem, czy chcesz, aby efekt dźwiękowy był odtwarzany wiele razy w tym samym czasie? To jest całkowicie błędne.


Zgadza się, muszę grać tę samą próbkę wiele razy w tym samym czasie.
Stéphan Kochen

Tak, gra ta sama instancja wiele razy, ale dla osób patrzących na tę odpowiedź, pamiętaj, że nie powoduje to „nakładających się odtworzeń”, jak sformułowano OP.
Patrick Roberts,

3

Oto pomysł. Załaduj wszystkie swoje audio dla określonej klasy dźwięków do pojedynczego pojedynczego elementu audio, w którym dane src to wszystkie twoje próbki w ciągłym pliku audio (prawdopodobnie potrzebujesz ciszy między nimi, abyś mógł złapać i wyciąć próbki z limitem czasu przy mniejszym czasie ryzyko krwawienia do następnej próbki). Następnie poszukaj próbki i zagraj w razie potrzeby.

Jeśli potrzebujesz więcej niż jednego z nich do odtworzenia, możesz utworzyć dodatkowy element audio z tym samym kodem SR, aby był buforowany. Teraz skutecznie masz wiele „ścieżek”. Możesz wykorzystywać grupy ścieżek w swoim ulubionym schemacie alokacji zasobów, takim jak Round Robin itp.

Możesz również określić inne opcje, takie jak kolejkowanie dźwięków na ścieżce, aby odtworzyć ją, gdy ten zasób stanie się dostępny, lub wyciąć aktualnie odtwarzaną próbkę.



2

Polecam korzystanie z SoundJS , biblioteki, którą opracować. Pozwala napisać jedną bazę kodu, która działa wszędzie, z SoundJS wybierającym audio internetowe, audio HTML lub audio Flash, odpowiednio.

Pozwoli ci to zrobić wszystko, co chcesz:

  • Graj i miksuj wiele dźwięków,
  • Odtwórz tę samą próbkę wiele razy, być może nakładające się na siebie odtworzenia
  • Przerywanie odtwarzania próbki w dowolnym momencie
  • odtwarzać pliki WAV zawierające (w zależności od obsługi przeglądarki)

Mam nadzieję, że to pomaga.


ta biblioteka jest raczej niesamowita, naprawdę kopie generator sfx. czas zrobić web Saiko do pobrania dla wszystkich zainteresowanych
RozzA,

1

Nie można grać w wiele ujęć za pomocą jednego <audio>elementu. W tym celu musisz użyć wielu elementów.


1

Wpadłem na to podczas programowania generatora kart Musicbox. Zacząłem od różnych bibliotek, ale za każdym razem była jakaś usterka. Opóźnienie w normalnej implementacji audio było złe, brak wielokrotnych odtworzeń ... ostatecznie użyto biblioteki lowlag + soundmanagera:

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

Możesz sprawdzić wdrożenie tutaj: http://musicbox.grit.it/

Wygenerowałem pliki wav + ogg do odtwarzania w wielu przeglądarkach. Ten odtwarzacz muzyki działa responsywnie na iPadzie, iPhonie, Nexusie, Macu, PC, ... działa dla mnie.


To fajna aplikacja pozytywki! Czy masz repozytorium git? Mogę go używać z naszymi dziećmi!
icarito

0

Wiem, że to totalny hack, ale pomyślałem, że powinienem dodać tę przykładową bibliotekę audio open source, którą jakiś czas temu włączyłem na github ...

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

Po kliknięciu poniższego linku wpisz klawisze w wierszu głównym, aby zagrać w riff bluesowy (jednocześnie wpisz kilka klawiszy jednocześnie itp.)

Przykład za pomocą biblioteki jThump >> http://davealger.com/apps/jthump/

Zasadniczo działa, tworząc niewidoczne <iframe>elementy, które ładują stronę odtwarzającą dźwięk w funkcjiReady ().

Z pewnością nie jest to idealne rozwiązanie, ale możesz dać +1 temu rozwiązaniu w oparciu o samą kreatywność (i fakt, że jest to oprogramowanie typu open source i działa w dowolnej przeglądarce, w której wypróbowałem). Mam nadzieję, że dzięki temu ktoś inny przeszuka jakieś pomysły.

:)


Dlaczego ktoś głosował za tym? Wydaje mi się realną opcją.
jtrick

jest to dość hacky rozwiązanie, ale wykorzystałem tę bibliotekę do stworzenia przykładowej gry HTML 5 na płótnie, dzięki czemu może ona mimo wszystko działać ... gra korzystająca z tej biblioteki jest już dostępna - beepbox.net
DaveAlger

0

Wybrana odpowiedź będzie działać we wszystkim oprócz IE. Napisałem samouczek na temat tego, jak to działa w różnych przeglądarkach = http://www.andy-howard.com/how-to-play-sounds-cross-browser-incellation-ie/index.html

Oto funkcja, którą napisałem;

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

Musisz także dodać następujący tag do strony HTML:

<bgsound id="sound">

Na koniec możesz wywołać funkcję i po prostu przejść przez ścieżkę tutaj:

playSomeSounds("sounds/welcome.wav");

0

Zawsze możesz spróbować, AudioContextponieważ ma ograniczone wsparcie, ale jest to część roboczego projektu interfejsu API audio . Może warto, jeśli planujesz wydać coś w przyszłości. A jeśli programujesz tylko dla Chrome i Firefox, jesteś złoty.


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

Web Audio API to odpowiednie narzędzie do tego zadania. Załadowanie plików dźwiękowych i ich odtwarzanie wymaga trochę pracy. Na szczęście istnieje wiele bibliotek, które upraszczają pracę. Zainteresowany dźwiękami stworzyłem także bibliotekę o nazwie musquito którą również możesz sprawdzić.

Obecnie obsługuje tylko zanikający efekt dźwiękowy, a ja pracuję nad innymi rzeczami, takimi jak przestrzenna przestrzenność.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.