19

私は Web Audio API をいじっており、mp3 をインポートする方法を見つけようとしています (したがって、これは Chrome のみです)、キャンバス上でその波形を生成します。リアルタイムでこれを行うことができますが、私の目標はこれをリアルタイムよりも速く行うことです。

私が見つけたすべての例は、 onaudioprocess イベントにアタッチされた関数で、アナライザー オブジェクトから周波数データを読み取ることを含みます。

processor = context.createJavascriptNode(2048,1,1);
processor.onaudioprocess = processAudio;
...
function processAudio{
    var freqByteData = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(freqByteData);
    //calculate magnitude & render to canvas
}

ただし、analyser.frequencyBinCountサウンドが再生されているときにのみ読み込まれるようです (バッファがいっぱいになっていることについての何か)。

私が望むのは、ファイルを手動/プログラムでできるだけ速くステップ実行して、キャンバス イメージを生成できるようにすることです。

私がこれまでに持っているのはこれです:

$("#files").on('change',function(e){
    var FileList = e.target.files,
        Reader = new FileReader();

    var File = FileList[0];

    Reader.onload = (function(theFile){
        return function(e){
            context.decodeAudioData(e.target.result,function(buffer){
                source.buffer = buffer;
                source.connect(analyser);
                analyser.connect(jsNode);

                var freqData = new Uint8Array(buffer.getChannelData(0));

                console.dir(analyser);
                console.dir(jsNode);

                jsNode.connect(context.destination);
                //source.noteOn(0);
            });
        };
    })(File);

    Reader.readAsArrayBuffer(File);
});

ただし、getChannelData() は常に空の型付き配列を返します。

たとえそれが不可能であることが判明したとしても、どんな洞察も高く評価されます。インターネットがリアルタイムで何かをしたくないのは私だけだと思います。

ありがとう。

4

2 に答える 2

26

Web Audio API には本当に素晴らしい「オフライン」モードがあり、オーディオ コンテキストを介してファイル全体を前処理し、その結果に対して何かを行うことができます。

var context = new webkitOfflineAudioContext();

var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.noteOn(0);

context.oncomplete = function(e) {
  var audioBuffer = e.renderedBuffer;
};

context.startRendering();

oncompleteしたがって、セットアップは、コールバックと への呼び出しをセットアップすることを除いて、リアルタイム処理モードとまったく同じに見えますstartRendering()。あなたが戻ってくるのe.redneredBufferAudioBuffer.

于 2011-11-12T00:05:53.640 に答える
5

次のコードを使用して OfflineAudioContext を使用してこれを機能させました。ここにある完全な例は、それを使用して線形チャープの FFT の大きさを計算する方法を示しています。ノードを接続するという概念が理解できたら、オフラインでほぼ何でもできるようになります。

function fsin(freq, phase, t) {
  return Math.sin(2 * Math.PI * freq * t + phase)
}

function linearChirp(startFreq, endFreq, duration, sampleRate) {
  if (duration === undefined) {
    duration = 1; // seconds
  }
  if (sampleRate === undefined) {
    sampleRate = 44100; // per second
  }
  var numSamples = Math.floor(duration * sampleRate);
  var chirp = new Array(numSamples);
  var df = (endFreq - startFreq) / numSamples;
  for (var i = 0; i < numSamples; i++) {
    chirp[i] = fsin(startFreq + df * i, 0, i / sampleRate);
  }
  return chirp;
}

function AnalyzeWithFFT() {
  var numChannels = 1; // mono
  var duration = 1; // seconds
  var sampleRate = 44100; // Any value in [22050, 96000] is allowed
  var chirp = linearChirp(10000, 20000, duration, sampleRate);
  var numSamples = chirp.length;

  // Now we create the offline context to render this with.
  var ctx = new OfflineAudioContext(numChannels, numSamples, sampleRate);
  
  // Our example wires up an analyzer node in between source and destination.
  // You may or may not want to do that, but if you can follow how things are
  // connected, it will at least give you an idea of what is possible.
  //
  // This is what computes the spectrum (FFT) information for us.
  var analyser = ctx.createAnalyser();

  // There are abundant examples of how to get audio from a URL or the
  // microphone. This one shows you how to create it programmatically (we'll
  // use the chirp array above).
  var source = ctx.createBufferSource();
  var chirpBuffer = ctx.createBuffer(numChannels, numSamples, sampleRate);
  var data = chirpBuffer.getChannelData(0); // first and only channel
  for (var i = 0; i < numSamples; i++) {
    data[i] = 128 + Math.floor(chirp[i] * 127); // quantize to [0,256)
  }
  source.buffer = chirpBuffer;

  // Now we wire things up: source (data) -> analyser -> offline destination.
  source.connect(analyser);
  analyser.connect(ctx.destination);

  // When the audio buffer has been processed, this will be called.
  ctx.oncomplete = function(event) {
    console.log("audio processed");
    // To get the spectrum data (e.g., if you want to plot it), you use this.
    var frequencyBins = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(frequencyBins);
    console.log(frequencyBins);
    // You can also get the result of any filtering or any other stage here:
    console.log(event.renderedBuffer);
  };

  // Everything is now wired up - start the source so that it produces a
  // signal, and tell the context to start rendering.
  //
  // oncomplete above will be called when it is done.
  source.start();
  ctx.startRendering();
}
于 2015-04-15T13:43:50.743 に答える