【发布时间】:2015-07-29 15:01:22
【问题描述】:
我正在 Android 中制作鼓音序器...
我正在写信给MODE_STREAM 中的AudioTrack,这样我就可以实现与所有InputStreams 的同步音频播放(可通过下面代码中的“活动”输入流列表activeStreams 获得)
音频始终为:PCM (WAV),16 位立体声 44100 Hz。
显然,我无法在 UI 线程上实时合成音频,因此我使用 AsyncTask 将所有音频缓冲排队。
我的缓冲播放工作正常,但在合并两个(或更多)InputStream 的缓冲区时,互联网似乎在讨论下一步该做什么。 “将 byte[] 转换为 short[]!”,“不,即时进行位混合!”,“但是如果你不使用 short,字节字节序将被忽略!”,“它无论如何都会被忽略!” - 我什至不知道了。
如何混合两个或多个 InputStream 的缓冲区?我不明白为什么我当前的实现失败了
我已经尝试过 4 种不同的 StackOverflow 解决方案来将 byte[] 转换为 short[],这样我就可以将示例添加在一起,但是转换总是会立即使 Java 崩溃,并带有一些我无法获取的神秘错误消息转头。所以现在我放弃了。这是我实现one such StackOverflow solution的代码...
protected Long doInBackground(Object ... Object) {
int bytesWritten = 0;
InputStream inputStream;
int si = 0, i = 0;
//The combined buffers. The 'composition'
short[] cBuffer = new short[Synth.AUDIO_BUFFER_SIZE];
//The 'current buffer', the segment of inputStream audio.
byte[] bBuffer = new byte[Synth.AUDIO_BUFFER_SIZE];
//The 'current buffer', converted to short?
short[] sBuffer = new short[Synth.AUDIO_BUFFER_SIZE];
int curStreamNum;
int numStreams = activeStreams.size();
short mix;
//Start with an empty 'composition'
cBuffer = new short[Synth.AUDIO_BUFFER_SIZE];
boolean bufferEmpty = false;
try {
while(true) { // keep going forever, until stopped or paused.
for(curStreamNum = 0;curStreamNum < numStreams;curStreamNum++){
inputStream = activeStreams.get(curStreamNum);
i = inputStream.read(bBuffer);
bufferEmpty = i<=-1;
if(bufferEmpty){
//Input stream buffer was empty. It's out of audio. Close and remove the stream.
inputStream.close();
activeStreams.remove(curStreamNum);
curStreamNum--; numStreams--; continue; // hard continue.
}else{
//Take the now-read buffer, and convert to shorts.
ByteBuffer.wrap(bBuffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(sBuffer);
//Take the short buffer, merge into composition buffer.
//TODO: Optimize by making the 'first layer' of the composition the first buffer, on its own.
for(si=0;si<Synth.AUDIO_BUFFER_SIZE;si++){
mix = (short) (sBuffer[si] + cBuffer[si]);
//This part is probably completely wrong too. I'm not up to here yet to evaluate whats needed...
if(mix >= 32767){
mix = 32767;
}else if (mix <= -32768){
mix = -32768;
}
cBuffer[si] = mix;
}
}
}
track.write(sBuffer, 0, i);
//It's always full; full buffer of silence, or of composited audio.
totalBytesWritten += Synth.AUDIO_BUFFER_SIZE;
//.. queueNewInputStreams ..
publishProgress(totalBytesWritten);
if (isCancelled()) break;
}
} catch (IOException e) {e.printStackTrace();}
return Long.valueOf(totalBytesWritten);
}
我目前在这条线上收到BufferUnderflowException:ByteBuffer.wrap(bBuffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(sBuffer);。
如何可能导致缓冲区不足?我只是将 byte[] 转换为 short[]。
请帮忙!
我已经发布了我的整个函数,希望这个更完整的代码示例和相当灵活的用法可以帮助其他人。
(P.S. byte[] 到 short[] 的转换之后是一些脆弱的硬剪辑,我什至还没有调试到,但建议也将不胜感激)
【问题讨论】:
-
你检查我的答案了吗?有什么意见吗?
-
抱歉耽搁了。很快就会测试你的答案。
标签: java android audio buffer inputstream