У меня есть многоканальный вход (я использую Soundflower 64ch на ma c), и я пытаюсь микшировать 4 канала из 64 на стереовыход.
Что я делаю это чтение блоков из 1024 кадров с 64 каналами в каждом кадре с последующим преобразованием байтового буфера в массив Short (значения между -32,768 <-> 32,767, потому что выборки 16 бит).
Таким образом я добавляю, например, channel1[sample] + channel2[sample]
и я получаю микс обоих каналов. Но вот проблема, сумма может выходить за пределы диапазона Short (16 бит), внося в звук насыщенность. Итак, я делаю (channel1[sample] + channel2[sample]) / 2
, но когда я делю на 2, я слышу много белого звука.
Также, если я пытаюсь уменьшить громкость канала, выполняя channel1[sample] * 0.5
, появляется много насыщенности. Почему это происходит?
Вот мой полный код, обратите внимание, что я конвертирую байты в короткие для лучшей обработки, а затем конвертирую обратно в байты для записи микса на стерео выход:
public static void main(String[] args) throws LineUnavailableException {
int inputChannels = 64;
AudioFormat inputFormat = new AudioFormat(48000, 16, inputChannels, true, false);
AudioFormat outputFormat = new AudioFormat(48000, 16, 2, true, false);
TargetDataLine mic = AudioSystem.getTargetDataLine(inputFormat);
SourceDataLine speaker = AudioSystem.getSourceDataLine(outputFormat);
mic.open(inputFormat);
speaker.open(outputFormat);
mic.start();
speaker.start();
AudioInputStream audioInputStream = new AudioInputStream(mic);
int bytesPerFrame = audioInputStream.getFormat().getFrameSize();
// Set an arbitrary buffer size of 1024 frames.
int CHUNK = 1024 ;
int numBytes = CHUNK * bytesPerFrame;
byte[] audioBytes = new byte[numBytes];
try {
byte[][] frames = new byte[CHUNK][bytesPerFrame];
int i = 0, j = 0
;
while (true) {
// read to audioBytes.
audioInputStream.read(audioBytes);
// split audioBytes in _CHUNK_ frames (1024 frames)
for(j=0; j<CHUNK; j++) {
frames[j] = Arrays.copyOfRange(audioBytes, j * bytesPerFrame, j * bytesPerFrame + bytesPerFrame);
}
// convert bytearray to shortarray
short[][] shortFrames = new short[CHUNK][inputChannels];
for(i=0; i < frames.length; i++) {
ByteBuffer.wrap(frames[i]).order(ByteOrder.BIG_ENDIAN).asShortBuffer().get(shortFrames[i]);
}
short[] leftOutput = new short[CHUNK*2];
short[] rightOutput = new short[CHUNK*2];
for (i=0; i<CHUNK; i++) {
short channel1 = shortFrames[i][0];
short channel2 = shortFrames[i][1];
short channel3 = shortFrames[i][2];
short channel4 = shortFrames[i][3];
leftOutput[i] = (short)(channel4);
rightOutput[i] = (short)(channel4);;
}
//convert shortarray in byte buffer
ByteBuffer byteBuf = ByteBuffer.allocate(CHUNK * 2 * 2); // 2 bytes * 2 output channels
for (i=0; i<CHUNK; i++) {
byteBuf.putShort(leftOutput[i]);
byteBuf.putShort(rightOutput[i]);
}
speaker.write(byteBuf.array(),0,byteBuf.array().length);
}
} catch (Exception ex) {
// Handle the error...
System.out.println("exception");
System.out.println(ex.toString());
}
}