Efek suara dalam JavaScript / HTML5

316

Saya menggunakan HTML5 untuk memprogram game; kendala yang saya hadapi sekarang adalah bagaimana memainkan efek suara.

Persyaratan spesifik jumlahnya sedikit:

  • Mainkan dan campur beberapa suara,
  • Putar sampel yang sama beberapa kali, mungkin tumpang tindih pemutaran,
  • Mengganggu pemutaran sampel di titik mana pun,
  • Lebih disukai memutar file WAV yang berisi PCM mentah (kualitas rendah), tetapi saya dapat mengonversinya, tentu saja.

Pendekatan pertama saya adalah menggunakan <audio>elemen HTML5 dan mendefinisikan semua efek suara di halaman saya. Firefox memainkan file WAV hanya dengan sangat bagus, tetapi memanggil #playbeberapa kali tidak benar-benar memainkan sampel beberapa kali. Dari pemahaman saya tentang spesifikasi HTML5, <audio>elemen ini juga melacak status pemutaran, sehingga menjelaskan alasannya.

Pikiran langsung saya adalah untuk mengkloning elemen audio, jadi saya membuat pustaka JavaScript kecil berikut untuk melakukannya untuk saya (tergantung pada 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;
      };
    });
  }
};

Jadi sekarang saya dapat melakukannya Snd.boom();dari Firebug console dan bermain snd/boom.wav, tetapi saya masih tidak bisa memainkan sampel yang sama beberapa kali. Tampaknya <audio>elemen tersebut lebih merupakan fitur streaming daripada memainkan efek suara.

Apakah ada cara cerdas untuk mewujudkan hal ini bahwa saya tidak ada, lebih baik hanya menggunakan HTML5 dan JavaScript?

Saya juga harus menyebutkan bahwa, lingkungan pengujian saya adalah Firefox 3.5 di Ubuntu 9.10. Browser lain yang saya coba - Opera, Midori, Chromium, Epiphany - menghasilkan hasil yang beragam. Beberapa tidak memainkan apa pun, dan beberapa melemparkan pengecualian.

Stéphan Kochen
sumber
Hah! Saya juga porting game Macintosh lama ke HTML5. Ingin mengungkapkan yang mana yang Anda kloning?
nerd yang dibayar
1
Ini Proyek ARASHI, klon prahara.
Stéphan Kochen
Apa yang dimaksud dengan suara "mixing"?
Mads Skjern
2
Apakah kamu menyelesaikannya? Bisakah kita melihatnya?
Enyo
4
Sayangnya tidak. Saya memiliki bakat untuk tidak menyelesaikan proyek waktu luang. :( Ada repo git untuk itu, tapi saya belum menyentuhnya selama bertahun-tahun: github.com/stephank/arashi-js
Stéphan Kochen

Jawaban:

448

AudioObjek HTML5

Anda tidak perlu repot dengan <audio>elemen. HTML 5 memungkinkan Anda mengakses Audioobjek secara langsung:

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

Tidak ada dukungan untuk pencampuran dalam versi spesifikasi saat ini.

Untuk memutar suara yang sama beberapa kali, buat beberapa instance Audioobjek. Anda juga bisa mengatur snd.currentTime=0objek setelah selesai diputar.


Karena konstruktor JS tidak mendukung <source>elemen fallback , Anda harus menggunakannya

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

untuk menguji apakah browser mendukung Ogg Vorbis.


Jika Anda menulis game atau aplikasi musik (lebih dari sekadar pemain), Anda akan ingin menggunakan API Audio Web yang lebih canggih , yang sekarang didukung oleh sebagian besar browser .

Kornel
sumber
18
Audioobjek autobuffered. Mereka dirancang analog dengan Imageobjek, sehingga teknik preloading gambar oldschool bekerja dengan audio juga.
Kornel
5
Ini juga berfungsi di iOS. Perhatikan bahwa Anda perlu menggunakan beberapa jenis tindakan pengguna (misalnya, klik tombol) untuk memulai suara. Anda tidak bisa hanya melakukan snd.play()di window.load ().
Husky
1
Saya masih menggunakan <audio>tag karena lebih dapat dikontrol. Tapi bagaimanapun, terima kasih atas informasinya!
Derek 朕 會 功夫
2
Saya lebih suka metode ini jika bukan karena elemen <audio> html5 memungkinkan banyak sumber, jadi jika browser tidak mendukung mp3, Anda dapat mundur ke ogg / wav. Dibutuhkan beberapa tipu daya dalam javascript untuk mencapai hal yang sama.
joelmdev
2
Di iOS 6 autoplay didukung: Anda dapat memulai suara dengan snd.play () sederhana di window.load ().
Pietro Polsinelli
36

WebAudio API oleh W3C

Pada Juli 2012, WebAudio API sekarang didukung di Chrome, dan setidaknya sebagian didukung di Firefox, dan dijadwalkan akan ditambahkan ke iOS pada versi 6.

Meskipun cukup kuat untuk digunakan secara programatis untuk tugas-tugas dasar, elemen Audio tidak pernah dimaksudkan untuk memberikan dukungan audio penuh untuk game, dll. Itu dirancang untuk memungkinkan satu bagian media untuk disematkan dalam halaman, mirip dengan gambar menandai. Ada banyak masalah dengan mencoba menggunakan tag Audio untuk game:

  • Slip pengaturan waktu sering terjadi pada elemen Audio
  • Anda membutuhkan elemen Audio untuk setiap instance suara
  • Memuat acara belum sepenuhnya dapat diandalkan
  • Tidak ada kontrol volume umum, tidak ada pemudaran, tidak ada filter / efek

Saya menggunakan artikel Memulai Dengan WebAudio ini untuk memulai dengan WebAudio API. The Fieldrunners WebAudio Studi Kasus ini juga membaca yang baik.

Chris Jaynes
sumber
Ini adalah jawaban yang lebih baik daripada yang diterima, karena berfokus pada solusi yang tepat untuk masalah (WebAudio API), dan alasan elemen Audio bukan solusi yang baik, daripada mencoba meretas bersama solusi buruk dengan elemen Audio
Anomali
29

howler.js

Untuk pembuatan game, salah satu solusi terbaik adalah menggunakan perpustakaan yang memecahkan banyak masalah yang kita hadapi saat menulis kode untuk web, seperti howler.js . howler.js mengabstraksi API Audio Web yang hebat (tapi level rendah) menjadi kerangka kerja yang mudah digunakan. Ini akan berusaha untuk kembali ke Elemen Audio HTML5 jika API Audio Web tidak tersedia.

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

Perpustakaan hebat lainnya adalah wad.js , yang sangat berguna untuk memproduksi audio synth, seperti musik dan efek. Sebagai contoh:

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

Suara untuk Game

Pustaka lain yang mirip dengan Wad.js adalah " Sound for Games ", ia lebih fokus pada produksi efek, sambil menyediakan serangkaian fungsionalitas yang serupa melalui API yang relatif berbeda (dan mungkin lebih ringkas):

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

Ringkasan

Masing-masing perpustakaan ini patut dilihat, apakah Anda perlu memutar ulang file suara tunggal, atau mungkin membuat editor musik berbasis html Anda sendiri, efek generator, atau video game.

d13
sumber
Tidak dapat mengomentari pengembangan game, tapi saya menggunakan ini untuk beberapa umpan balik audio kecil dalam sebuah antarmuka dan untuk itu berfungsi dengan sangat baik. Cepat, mudah & sederhana.
Singkirkan Iculous
Kerangka yang sangat bagus, berfungsi dengan baik di ponsel juga. Anda harus memicunya dengan touchstart ... tapi begitu selesai, ia bekerja di luar kotak :)
Philip
9

Anda mungkin juga ingin menggunakan ini untuk mendeteksi audio HTML 5 dalam beberapa kasus:

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

HTML 5 JS Detect function

function supportsAudio()
{
    var a = document.createElement('audio'); 
    return !!(a.canPlayType && a.canPlayType('audio/mpeg;').replace(/no/, ''));
}
rampok
sumber
Terima kasih telah memperhatikan ini. Saya belajar metode ini dari has.js, tetapi saya menemukan ada beberapa masalah di Firefox, dan ternyata di Opera juga sesuai dengan kode sumber has.js. (ref: github.com/phiggins42/has.js/issues/48 github.com/phiggins42/has.js/blob/master/detect/audio.js#L19 )
Stéphan Kochen
5

Inilah salah satu metode untuk memungkinkannya memainkan suara yang sama secara bersamaan. Kombinasikan dengan preloader, dan Anda siap. Ini berfungsi dengan Firefox 17.0.1 setidaknya, belum mengujinya dengan yang lain.

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

Ikat ini ke tombol keyboard, dan nikmati:

player("step");
F-3000
sumber
Tidak. Saya tidak berpikir bahwa membuat objek baru untuk setiap pemutaran suara adalah solusi sama sekali. Ini solusi cepat dan kotor, tetapi ini bisa dilakukan dengan lebih baik.
Pawel
@ Pam Benar, bahwa ini TIDAK boleh digunakan sebagai metode utama memainkan suara, tetapi sejauh yang saya ketahui, prinsip dalam contoh ini adalah satu-satunya cara memainkan suara yang sama lebih dari sekali secara bersamaan, atau seperti yang diungkapkan OP, "pemutaran yang tumpang tindih". (Tanpa memerlukan browser-plugins.) Implementasi aktual saya di proyek saya saat ini jauh lebih canggih daripada kode contoh yang saya posting.
F-3000
4

Kedengarannya seperti yang Anda inginkan adalah suara multi-saluran. Misalkan Anda memiliki 4 saluran (seperti pada game 16-bit yang benar-benar tua), saya belum sempat bermain dengan fitur audio HTML5, tapi bukankah Anda hanya perlu 4 elemen <audio>, dan siklus yang digunakan untuk memainkan efek suara selanjutnya? Sudahkah Anda mencobanya? Apa yang terjadi? Jika berhasil: Untuk memutar lebih banyak suara secara bersamaan, tambahkan saja lebih banyak elemen <audio>.

Saya telah melakukan ini sebelumnya tanpa elemen HTML5 <audio>, menggunakan objek Flash kecil dari http://flash-mp3-player.net/ - Saya menulis kuis musik ( http://webdeavour.appspot.com/ ) dan menggunakannya untuk memutar klip musik ketika pengguna mengklik tombol untuk pertanyaan. Awalnya saya punya satu pemain per pertanyaan, dan itu mungkin untuk bermain mereka di atas satu sama lain, jadi saya mengubahnya jadi hanya ada satu pemain, yang saya tunjuk klip musik yang berbeda.

Lee Kowalkowski
sumber
Itu pemikiran yang menarik, untuk menggunakan & lt; audio & gt; elemen sebagai saluran. Ketika saya meletakkan dua elemen pada halaman, saya bisa memainkannya secara bersamaan. Sepertinya kloning yang saya lakukan tidak benar-benar melakukan apa yang saya harapkan, karena dalam kode asli saya, memainkan dua sampel juga berfungsi. Hanya tidak dua kali sampel yang sama. Saya harus bereksperimen dengan ini lagi, dan akan kembali pada hasilnya!
Stéphan Kochen
Ya, mungkin ada alasan halus mengapa itu disebut clone dan bukan copy. Mungkin klon masih berbagi sesuatu dengan yang asli yang mencegah keduanya bermain secara bersamaan.
Lee Kowalkowski
Untuk referensi, menggunakan kembali elemen <audio> yang sama tidak berfungsi, setidaknya di Firefox. Anda dapat mengatur atribut 'src', tetapi sebenarnya tidak akan memuat sampel yang berbeda.
Stéphan Kochen
4

Lihatlah situs jai (-> mirror ) (antarmuka audio javascript). Dari melihat sumber mereka, mereka tampaknya menelepon play()berulang kali, dan mereka menyebutkan bahwa perpustakaan mereka mungkin cocok untuk digunakan dalam permainan berbasis HTML5.

Anda dapat menjalankan beberapa acara audio secara bersamaan, yang dapat digunakan untuk membuat game Javascript, atau memiliki suara yang berbicara di atas musik latar belakang

Raul Agrait
sumber
3

Untuk memainkan sampel yang sama beberapa kali, apakah tidak mungkin melakukan hal seperti ini:

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

( eadalah elemen audio)

Mungkin saya benar-benar salah memahami masalah Anda, apakah Anda ingin efek suara diputar beberapa kali pada saat yang sama? Maka ini sepenuhnya salah.

adamse
sumber
Itu benar, saya perlu memainkan sampel yang sama beberapa kali pada waktu yang bersamaan.
Stéphan Kochen
Ya ini memainkan contoh yang sama beberapa kali tetapi untuk orang yang melihat jawaban ini, perlu diketahui bahwa ini tidak menyebabkan "tumpang tindih pemutaran", seperti kata OP.
Patrick Roberts
3

Ini ide. Muat semua audio Anda untuk kelas suara tertentu ke dalam elemen audio tunggal di mana data src adalah semua sampel Anda dalam file audio yang bersebelahan (mungkin ingin beberapa keheningan di antaranya sehingga Anda dapat menangkap dan memotong sampel dengan timeout dengan lebih sedikit risiko perdarahan ke sampel berikutnya). Kemudian, cari sampelnya dan mainkan saat dibutuhkan.

Jika Anda membutuhkan lebih dari satu untuk memainkannya, Anda dapat membuat elemen audio tambahan dengan src yang sama sehingga di-cache. Sekarang, Anda secara efektif memiliki beberapa "trek". Anda dapat memanfaatkan grup trek dengan skema alokasi sumber daya favorit Anda seperti Round Robin dll.

Anda juga bisa menentukan opsi lain seperti mengantri suara ke trek untuk diputar ketika sumber daya itu tersedia atau memotong sampel yang sedang diputar.

digitalicarus
sumber
2

Saya akan merekomendasikan menggunakan SoundJS , perpustakaan yang saya bantu kembangkan. Ini memungkinkan Anda untuk menulis basis kode tunggal yang berfungsi di mana-mana, dengan SoundJS memilih audio web, audio html, atau audio flash yang sesuai.

Ini akan memungkinkan Anda untuk melakukan semua hal yang Anda inginkan:

  • Mainkan dan campur beberapa suara,
  • Putar sampel yang sama beberapa kali, mungkin tumpang tindih pemutaran
  • Memutus pemutaran sampel di titik mana pun
  • memutar file WAV yang mengandung (tergantung pada dukungan browser)

Semoga itu bisa membantu.

OJay
sumber
perpustakaan itu agak luar biasa, saya benar-benar menggali generator sfx. waktu untuk membuat unduhan
RozzA
1

Bermain multi-shot dengan <audio>elemen tunggal tidak dimungkinkan . Anda perlu menggunakan beberapa elemen untuk ini.

Eli Gray
sumber
1

Saya mengalami ini saat memprogram generator kartu musicbox. Dimulai dengan perpustakaan yang berbeda tetapi setiap kali ada kesalahan entah bagaimana. Kelambatan implementasi audio normal buruk, tidak ada beberapa pemutaran ... akhirnya berakhir menggunakan perpustakaan lowlag + soundmanager:

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

Anda dapat memeriksa implementasinya di sini: http://musicbox.grit.it/

Saya membuat file wav + ogg untuk memainkan multi browser. Musicbox player ini bekerja responsif di ipad, iphone, Nexus, mac, pc, ... berfungsi untuk saya.

Menggertakkan
sumber
Itu aplikasi kotak musik yang bagus! Apakah Anda memiliki repositori git? Saya mungkin menggunakannya dengan anak-anak kita!
icarito
0

Saya tahu ini adalah total hack tetapi saya pikir saya harus menambahkan sampel ini perpustakaan audio open source yang saya pakai github beberapa waktu lalu ...

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

Setelah mengklik tautan di bawah ini, ketikkan tombol baris rumah untuk memainkan riff blues (juga ketik beberapa tombol secara bersamaan, dll.)

Sampel menggunakan perpustakaan jThump >> http://davealger.com/apps/jthump/

Ini pada dasarnya bekerja dengan membuat <iframe>elemen tak terlihat yang memuat halaman yang memutar suara onReady ().

Ini tentu saja tidak ideal tetapi Anda dapat memberi +1 solusi ini hanya berdasarkan kreativitas (dan fakta bahwa itu adalah open source dan berfungsi di browser apa pun yang pernah saya coba) Saya harap ini memberi orang lain setidaknya mencari beberapa ide.

:)

DaveAlger
sumber
Mengapa seseorang memilih ini? Sepertinya pilihan yang layak untuk saya.
jtrick
ini adalah solusi yang cukup rumit tetapi saya telah menggunakan perpustakaan ini untuk membuat contoh game html 5 canvas sehingga dapat bekerja tidak lebih ... permainan menggunakan perpustakaan ini ada di sini - beepbox.net
DaveAlger
0

Jawaban yang dipilih akan bekerja dalam segala hal kecuali IE. Saya menulis tutorial tentang cara membuatnya bekerja lintas browser = http://www.andy-howard.com/how-to-play-sounds-cross-browser-includes-ie/index.html

Inilah fungsi yang saya tulis;

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

Anda juga perlu menambahkan tag berikut ke halaman html:

<bgsound id="sound">

Akhirnya Anda dapat memanggil fungsi dan cukup melewati jalur di sini:

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

Anda selalu dapat mencobanya AudioContextmemiliki dukungan terbatas tetapi merupakan bagian dari draft kerja api audio web . Mungkin bermanfaat jika Anda berencana untuk merilis sesuatu di masa depan. Dan jika Anda hanya memprogram untuk chrome dan Firefox, Anda adalah yang terbaik.

haelmic
sumber
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>

pengguna1024
sumber
0

API Audio Web adalah alat yang tepat untuk pekerjaan ini. Ada sedikit pekerjaan yang terlibat dalam memuat file suara dan memainkannya. Untungnya ada banyak perpustakaan di luar sana yang menyederhanakan pekerjaan. Karena tertarik pada suara, saya juga membuat perpustakaan bernama musquito. Anda juga bisa melihatnya .

Saat ini hanya mendukung efek suara memudar dan saya sedang mengerjakan hal-hal lain seperti spasialisasi 3D.

VJAI
sumber