在Web Audio API中,是否可以从样本数组中随机选择音频播放?

时间:2017-09-20 03:32:02

标签: javascript web-audio

我有一个包含大约100个样本的网页,其中许多是相同声音的不同版本;包含四个样本的简化版本位于http://stephenandrewtaylor.net/sample-array-test/sample-loader.html

此页面使用William Turner的优秀书籍Javascript for Sound Artists的代码,将所有样本加载到一个对象中(从var appSounds开始 - 我已经包含了特纳的代码顶部)。

// *** adapted from William Turner's "Javascript for Sound Artists" ***
"use strict";

var audioContext = new AudioContext();

function audioFileLoader(fileDirectory, callback) {
  var soundObj = {};
  var playSound = undefined;
  var getSound = new XMLHttpRequest();
  soundObj.fileDirectory = fileDirectory;
  getSound.open("GET", soundObj.fileDirectory, true); // 'true' argument enables asynchronous download
  getSound.responseType = "arraybuffer";
  getSound.onload = function() {
    audioContext.decodeAudioData(getSound.response, function(buffer) { // callback function
      soundObj.soundToPlay = buffer;  // stored as global variable
    });
};

  getSound.send(); // initiate the XMLHttpRequest

  soundObj.play = function(time, setStart, setDuration) {
    playSound = audioContext.createBufferSource();
    playSound.buffer = soundObj.soundToPlay;
    playSound.start(audioContext.currentTime + time || audioContext.currentTime, setStart || 
      0, setDuration || soundObj.soundToPlay.duration);

  if (typeof callback === "function") {
    return callback(playSound);
    } else {
      return playSound.connect(audioContext.destination);
    }
  };

  soundObj.stop = function(time) {
    playSound.stop(audioContext.currentTime + time || audioContext.currentTime);
  };
  return soundObj;
}

function audioBatchLoader(obj) {
  var callback = undefined;
  var prop = undefined;
  for (prop in obj) {
    if (typeof obj[prop] === "function") {
      callback = obj[prop];
      delete obj[prop];
    }
  }
  for (prop in obj) {
    obj[prop] = audioFileLoader(obj[prop], callback);
  }
  return obj;
}

// *** here is the code I would like to improve if possible ***
var appSounds = {
  stringPluck0: "StringA4-0.mp3",
  stringPluck1: "StringA4-1.mp3",
  stringPluck2: "StringA4-2.mp3",
  stringPluck3: "StringA4-3.mp3",
// *** how to make this an array, like stringPluck[0] etc.? ***

  nodes: function nodeGraph(sound) {
   sound.connect(audioContext.destination);
  }
};

var sounds = audioBatchLoader(appSounds);

function playback() {
  var rand = Math.floor(Math.random() * 4);
 switch (rand) {
  case 0: sounds.stringPluck0.play(); break;
  case 1: sounds.stringPluck1.play(); break;
  case 2: sounds.stringPluck2.play(); break;
  case 3: sounds.stringPluck3.play(); break;
  }
}

window.addEventListener("mousedown", playback);

我真的希望这是一个数组,在对象中:

stringPluck: ["StringA4-0.mp3", "StringA4-1.mp3", 
  "StringA4-2.mp3", "StringA4-3.mp3"]

然后我可以使用随机数来触发stringPluck[rand]。但我无法让它发挥作用;我在这里看了几个例子,并研究了威廉特纳的书。我现在所拥有的正在工作,但是当您开始加载大量样本时代码变得非常冗长。

如果您对此感兴趣,那么使用d3的主项目就在这里: http://stephenandrewtaylor.net/exo-sonification/exoplanets.html

2 个答案:

答案 0 :(得分:0)

我没有弄清楚所有细节,但你可以从定义

开始

var appSounds = { stringPluck: ["StringA4-0.mp3", "StringA4-1.mp3", "StringA4-2.mp3", "StringA4-3.mp3"]; ... };

然后将audioBatchLoader更新为

function audioBatchLoader(obj) { // Get the nodeGraph method let callback = obj.nodes; // Run through the stringPluck array and create a corresponding // soundObj for each element. return obj.stringPluck.map(mp3 => { audioFileLoader(mp3, callback); }); }

然后你可以做,我想,

function playback() { let rand = Math.floor(Math.random() * sounds.length); sounds[rand].play(); }

但是,我没有测试过这个。

答案 1 :(得分:0)

与其他人的回答类似,audioBatchLoader重写了诀窍 - 必须确保返回整个对象而不仅仅是stringPluck:)

function audioBatchLoader(obj) {
    let callback = obj.nodes;
    let mp3;
    for (mp3 in obj.stringPluck) {
        obj.stringPluck[mp3] = audioFileLoader(obj.stringPluck[mp3], callback);
    }

    return obj;
}

干杯教授!

(P.S。将" sounds.stringPluck.length"更改为" appSounds.stringPluck.length"这样可以减少错误):

        let rand = Math.floor(Math.random() * appSounds.stringPluck.length);

- 洛根