LoginSignup
3
2

More than 5 years have passed since last update.

AudioBufferに追加されるcopyFromChannelについて調べたのですが、この理解であっていますか?

Last updated at Posted at 2015-02-23

Web Audio API のドラフト仕様で AudioBuffer に追加されている copyFromChannelcopyToChannel メソッドについて、今の API でも容易に同等の操作が可能なのに何故こういうAPIが必要なのか気になったので調べたメモ。

参照: http://webaudio.github.io/web-audio-api/#acquire-the-content

interface AudioBuffer {
  readonly attribute float  sampleRate;
  readonly attribute long   length;
  readonly attribute double duration;
  readonly attribute long   numberOfChannels;

  // いままでこれだけだったのが
  Float32Array getChannelData(unsigned long channel);

  // この2つのメソッドが追加される
  void copyFromChannel(Float32Array destination, long channelNumber, optional unsigned long startInChannel = 0);
  void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
};

以下翻訳が目的ではないので、大まかな解釈を書いています。
間違っていたらコメント or 編集リクエストください!!!

NOTE

The methods copyToChannel and copyFromChannel can be used to fill part of an array by passing in a Float32Array that's a view onto the larger array. When reading data from an AudioBuffer's channels, and the data can be processed in chunks, copyFromChannel should be preferred to calling getChannelData and accessing the resulting array, because it may avoid unnecessary memory allocation and copying.

copyToChannelcopyFromChannel はデータの部分的な操作ができる。
AudioBuffer から部分的にデータを読み込むときは getChannelData より copyFromChannel を使うべき。なぜなら copyFromChannel はメモリの確保やコピーを発生させないから。

:pencil: getChannelData を使うとメモリの確保やコピーが行われる場合がある?


An internal operation acquire the contents of an AudioBuffer is invoked when the contents of an AudioBuffer are needed by some API implementation. This operation returns immutable channel data to the invoker.

operation acquire the contents of an AudioBuffer (AudioBufferのデータ取得) は API の必要に応じて内部で実行される。この操作は不変のチャネルデータを返す。

:pencil: 内部の実装の話であって、外部 (JavaScript側) からは観測できない。知っておかないと対応できない類のはなしっぽい。


When an acquire the content operation occurs on an AudioBuffer, run the following steps:

  1. If any of the AudioBuffer's ArrayBuffer have been neutered, abort these steps, and return a zero-length channel data buffers to the invoker.
  2. Neuter all ArrayBuffers for arrays previously returned by getChannelData on this AudioBuffer.
  3. Retain the underlying data buffers from those ArrayBuffers and return references to them to the invoker.
  4. Attach ArrayBuffers containing copies of the data to the AudioBuffer, to be returned by the next call to getChannelData.

acquire the content operation は、以下の手順に従う:

  1. いずれかの ArrayBuffer が無力化 (neutered) されているときこの手順は行わず、空のデータを返す。
  2. ArrayBuffer のデータを無力化する (JavaScript側から見えなくなる)
  3. ArrayBuffer のデータを保持し、参照を返します (C++で見えるようにする)
  4. (C++側で) 保持しているデータは、(JS側の) getChannelData によって返される

:pencil: たぶん 4 の時に ArrayBuffer の再確保 (アロケートとコピー) が行われる。


The acquire the contents of an AudioBuffer operation is invoked in the following cases:

  • When AudioBufferSourceNode.start is called, it acquires the contents of the node's buffer. If the operation fails, nothing is played.
  • When a ConvolverNode's buffer is set to an AudioBuffer while the node is connected to an output node, or a ConvolverNode is connected to an output node while the ConvolverNode's buffer is set to an AudioBuffer, it acquires the content of the AudioBuffer.
  • When the dispatch of an AudioProcessingEvent completes, it acquires the contents of its outputBuffer.

acquire the contents は以下の場合に起こる

  • AudioBufferSourceNode.start が呼ばれたとき
  • 他のノードに接続されている ConvolverNode の buffer がセットされたとき
  • buffer がセットされている ConvolverNode が他のノードに接続されたとき
  • AudioProcessingEvent が完了したとき

:pencil: 上記のときに AudioBuffer の内容が実装側に転送されて、JavaScript 側から触れなくなる。


たぶんこういうことだと思う。

var audioContext = new AudioContext();
var audioBuffer = audioContext.createBuffer(1, 10000, 44100);
var convolver = audioContext.createConvolver();

audioBuffer.getChannelData(0).set([ 0, 1, 2, 3, 4, 5, 6, 7 ]);

var savedBuffer = audioBuffer.getChannelData(0);

console.log(savedBuffer); // [ 0, 1, 2, 3, 4, 5, 6, 7, 0 ... 0 ]

convolver.buffer = audioBuffer;
convolver.connect(audioContext.destination); // ここで acquire the contents 

// acquire the contents により JavaScript側から参照できなくなる
console.log(savedBuffer); // []

// getChannelData をすればデータを見ることはできる
// このときに ArrayBuffer の再確保 (アロケートとコピー) が行われる
var tempBuffer = audioBuffer.getChannelData(0);
console.log(tempBuffer); // [ 0, 1, 2, 3, 4, 5, 6, 7, 0 ... 0 ]
console.log(tempBuffer.buffer.byteLength); // 10000 * 4
// getChannelData だと呼ばれるたびに 40000バイトの ArrayBuffer が生成される(場合がある)

// 新しい API を使う場合
var tempBuffer = new Float32Array(8);
audioBuffer.copyFromChannel(tempBuffer, 0);
console.log(tempBuffer); // [ 0, 1, 2, 3, 4, 5, 6, 7 ]
console.log(tempBuffer.buffer.byteLength); // 8 * 4
// copyFromChannel だとあらかじめ確保している領域に書き込むだけなので、メモリ確保等は起こらない
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2