5

質問: AudioTrack と setLoopPoints() を使用して、ミリ秒あたりのサンプル/フレーム数に基づいた精度でループを構成する方法はありますか?

編集:ほとんどの Android デバイスが持つ処理能力からは完全な精度が期待できないことを理解しています。ただし、平均ループ時間をミリ秒単位のテンポの「実際の」間隔に近づけたいと思います。これは、テンポと同期する必要がある「アニメーション」に基づいているためです (アニメーションは、再描画する SurfaceView です)テンポの間隔中の線の座標)。

詳細: setLoopPoints で AudioTrack を使用して、正確なメトロノームを作成しようとしています。これを行うために、2 つの wav ファイル (Tick と Tock) を使用して byte[] 配列を埋め、AudioTrack にフィードします。4/4 時間で byte[] を埋める例を考えてみましょう。1 回は [0] から始まる Tick で、3 回は (arrayCopy() を使用して) Tock で [length/4]、[length/2]、および[3*長さ/4] とし、wav データが重ならないようにします。

私のコードが行うことの大まかな例:

// read each wav file's header into its own ByteBuffer (with LITTLE_ENDIAN order)
// ... then get the size of the audio data
tickDataSize = tickHeaderBuffer.getInt(40); 
tockDataSize = tockHeaderBuffer.getInt(40); 

// allocate space for one loop at the current tempo into a byte[] array (to be given to    AudioTrack) 
// e.g. 22050hz * 2 Bytes (1 per channel) * 2 Bytes (1 per 8 bit PCM sample) = 22050*4 Bytes/second
//      If my tempo were 60 BPM I'd have 88200 Bytes/second (where 1 second is the whole loop interval);
// 110 BPM = 48109.0909091 Bytes per loop interval (where 1 loop interval is 0.54545 seconds)

int tempo = 110;
int bytesPerSecond  = sampleRate * 2 * 2;
int bytesPerInterval = (int)((((float)bytesPerSecond * 60.0F)/(float)tempo) * 4); 

byte[] wavData = new byte[bytesPerInterval];

// ... then fill wavData[] as mentioned above with 1*wavOne and 3*wavTwo

// Then feed to an instance of AudioTrack and set loop points
audioTrack.write(wavData, 0, bytesPerInterval);
int numSamples = bytesPerInterval/4;
audioTrack.setLoopPoints(0, numSamples, -1);
audioTrack.play();

問題が見えてきたと思います。特定のテンポでは、ループで静的な再生しか得られません(ただし、1 番目と 3 番目の Tock [ループの 2 番目と 4 番目のサンプル] の間のみ)。

次の場合、スタティックは停止します。

  • byte[] に wav データを入力しないで、bytesPerInterval と numSamples を同じにします (正しい持続時間のサイレント ループ)。
  • bytesPerInterval = bytesPerInterval % 4 に設定します (したがって、テンポの精度が失われます)

機能する (静的ではない) テンポと機能しない (静的) テンポの例と必要なフレーム数 (1 秒 = 88200 フレームと考えてください):

tempo: 110 (static)
wavData.length: 192436 
numFrames: 48109

tempo: 120 (no static)
wavData.length: 176400 
numFrames: 44100

tempo: 130 (static)
wavData.length: 162828 
numFrames: 40707

tempo: 140 (no static)
wavData.length: 151200 
numFrames: 37800

tempo: 150 (no static)
wavData.length: 141120 
numFrames: 35280

tempo: 160 (static)
wavData.length: 132300 
numFrames: 33075

tempo: 170 (static)
wavData.length: 124516 
numFrames: 31129

tempo: 180 (no static)
wavData.length: 117600 
numFrames: 29400

質問に対する答えが「いいえ、setLoopPoints() を使用してミリ秒単位で正確なループを構成することはできません」という場合は、他のオプションについて知りたいと思います。NDK、SoundPool、または MediaPlayer の OpenSL ES は、正確なループを生成するのに適していますか?

編集 2:静的な問題の原因となっている場所を絞り込みました:

// Assume a tempo of 160 BPM which requires byte[132300]
wavStream1 = this.context.getResources().openRawResource(R.raw.tick);
wavStream2 = this.context.getResources().openRawResource(R.raw.tock);

ByteBuffer headerBuffer1 = ByteBuffer.allocate(44);
ByteBuffer headerBuffer2 = ByteBuffer.allocate(44);
headerBuffer1.order(ByteOrder.LITTLE_ENDIAN);
headerBuffer2.order(ByteOrder.LITTLE_ENDIAN);
wavStream1.read(headerBuffer1.array(), 0, 44);   
wavStream2.read(headerBuffer2.array(), 0, 44);
int tickDataSize = headerBuffer1.getInt(40); 
int tockDataSize = headerBuffer2.getInt(40);    

byte[] wavData = new byte[bytesPerInterval * 4];

byte[] tickWavData = new byte[bytesPerInterval];
byte[] tockWavData = new byte[bytesPerInterval];

wavStream1.read(accentWavData, 0, tickDataSize);
wavStream2.read(normalWavData, 0, tockDataSize);

System.arraycopy(tickWavData, 0, wavData, 0, bytesPerInterval);
System.arraycopy(tockWavData, 0, wavData, 33075, bytesPerInterval);
System.arraycopy(tockWavData, 0, wavData, 66150, bytesPerInterval);
System.arraycopy(tockWavData, 0, wavData, 99225, bytesPerInterval);
// bytesPerInterval of 33075 and 99225 (or any odd number) will be 
// static when wavData is played 

AudioTrack audioTrack = new AudioTrack(3, 22050, 12, 2, wavData.length, 0);
audioTrack.write(wavData, 0, wavData.length);
audioTrack.setLoopPoints(0, bytesPerInterval, -1);
audioTrack.play();  

最も重要なことは、wavData の奇数インデックスで始まるオーディオ データが、予想されるサウンドではなくスタティックを生成する理由と、これに対する救済策があるかどうかを理解したいことです。

4

1 に答える 1

1

あなたの編集を読んだ後、奇数インデックスが問題を引き起こす理由は、AudioTrackwith ENCODING_PCM_16BIT(コンストラクターに渡す "2") を作成しているためだと思います。つまり、すべてのサンプルが 16 ビットである必要があります。"3" を使用するENCODING_PCM_8BITか、サンプルが 8 ビットの場合に試してください。

于 2013-12-20T09:53:25.643 に答える