a munch adventure
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

234 satır
4.5 KiB

  1. let playing = [];
  2. let looping = {};
  3. let audioContext;
  4. let gainControl;
  5. const audioBaseUrl = "./media/audio/";
  6. let audioDict = {};
  7. function setVolume(vol) {
  8. gainControl.gain.value = vol;
  9. }
  10. // play some sound
  11. function playSfx(name) {
  12. if (audioDict[name] == undefined) {
  13. console.error(name + " is not loaded yet, dingus");
  14. return;
  15. }
  16. let src = audioContext.createBufferSource();
  17. src.buffer = audioDict[name];
  18. src.connect(gainControl);
  19. playing.push(src);
  20. src.name = name;
  21. src.onended = (event) => src.done = true;
  22. src.start(0);
  23. }
  24. function playLoop(name) {
  25. if (audioDict[name] == undefined) {
  26. console.error(name + " is not loaded yet, dingus");
  27. return;
  28. }
  29. // if already playing, just keep going
  30. if (looping[name] && !looping[name].done) {
  31. console.warn(name + " is already looping");
  32. return;
  33. }
  34. let src = audioContext.createBufferSource();
  35. src.buffer = audioDict[name];
  36. src.connect(audioContext.destination);
  37. looping[name] = src;
  38. src.name = name;
  39. src.onended = (event) => src.done = true;
  40. src.loop = true;
  41. src.start(0);
  42. }
  43. function stopSfx(name) {
  44. playing.map(item => {
  45. if (item.name == name)
  46. item.stop();
  47. } );
  48. cleanPlaying();
  49. }
  50. function stopAllSfx() {
  51. playing.map(item => item.stop());
  52. cleanPlaying();
  53. }
  54. function stopLoop(name) {
  55. if (looping[name]) {
  56. looping[name].stop();
  57. delete looping[name];
  58. }
  59. }
  60. function stopAllLoops() {
  61. Object.entries(looping).forEach(([key, val]) => {
  62. val.stop();
  63. delete looping[key];
  64. });
  65. }
  66. function stopAllSound() {
  67. stopAllSfx();
  68. stopAllLoops();
  69. }
  70. function cleanPlaying() {
  71. playing = playing.filter(item => !item.done);
  72. }
  73. // asynchronously load an audio file
  74. function loadAudio(name, flush=false) {
  75. // do we already have the audio?
  76. if (audioDict[name] && !flush) {
  77. return;
  78. }
  79. // is the audio already stored locally?
  80. if (!flush) {
  81. checkCache(
  82. "audio",
  83. name,
  84. (data) => parseAudioData(name, data),
  85. () => loadRemoteAudio(name)
  86. );
  87. } else {
  88. loadRemoteAudio(name);
  89. }
  90. }
  91. function cacheAndParse(name, data) {
  92. storeCache("audio", name, data.slice(0));
  93. parseAudioData(name, data);
  94. }
  95. function parseAudioData(name, data) {
  96. console.log(data);
  97. audioContext.decodeAudioData(data, function(buffer) {
  98. audioDict[name] = buffer;
  99. }, function(e){ console.log("Error with decoding audio data" + e.err);});
  100. }
  101. function loadRemoteAudio(name) {
  102. let xhr = new XMLHttpRequest();
  103. xhr.open("GET", audioBaseUrl + name, true);
  104. xhr.responseType = "arraybuffer";
  105. xhr.onload = (res) => {
  106. if (xhr.status == 200)
  107. cacheAndParse(name, xhr.response);
  108. else
  109. console.log("Couldn't load " + name);
  110. }
  111. xhr.onerror = (xhr) => console.log("Couldn't load " + name);
  112. xhr.send();
  113. }
  114. // check if the content is cached
  115. function checkCache(type, name, hit, miss) {
  116. const req = window.indexedDB.open("cache", 1);
  117. req.onsuccess = () => {
  118. const db = req.result;
  119. const tx = db.transaction([type], "readonly");
  120. const audio = tx.objectStore(type);
  121. const read = audio.get(name);
  122. read.onsuccess = (event) => {
  123. const res = event.target.result;
  124. if (res) {
  125. console.log("cache hit on " + name);
  126. hit(res.content);
  127. } else {
  128. console.log("cache miss on " + name);
  129. miss();
  130. }
  131. }
  132. tx.oncomplete = () => {
  133. db.close();
  134. }
  135. }
  136. }
  137. function initAudio(story, state) {
  138. if (!audioContext)
  139. audioContext = new (window.AudioContext || window.webkitAudioContext)();
  140. if (!gainControl) {
  141. gainControl = audioContext.createGain();
  142. gainControl.gain.value = 0.5;
  143. gainControl.connect(audioContext.destination);
  144. }
  145. createCache();
  146. story.sounds.forEach(sound => {
  147. loadAudio(sound);
  148. });
  149. }
  150. // caching stuff here
  151. function storeCache(type, name, blob) {
  152. const req = window.indexedDB.open("cache", 1);
  153. req.onsuccess = () => {
  154. const db = req.result;
  155. const tx = db.transaction([type], "readwrite");
  156. const audio = tx.objectStore(type);
  157. const update = audio.put({
  158. name: name,
  159. content: blob
  160. });
  161. tx.oncomplete = () => {
  162. db.close();
  163. }
  164. }
  165. }
  166. // if the indexedDB table doesn't exist at all, make it
  167. function createCache() {
  168. let idb = window.indexedDB;
  169. let req = idb.open("cache", 1);
  170. req.onupgradeneeded = event => {
  171. const db = event.target.result;
  172. const audio = db.createObjectStore("audio", { keyPath: "name" });
  173. }
  174. req.onerror = event => {
  175. alert("Couldn't open the database?");
  176. }
  177. }