a munch adventure
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

218 строки
4.2 KiB

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