Смешивание аудиосэмплов или изменение громкости вызывает насыщение и белый шум - PullRequest
0 голосов
/ 04 августа 2020

У меня есть многоканальный вход (я использую 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());
    }
}

1 Ответ

0 голосов
/ 05 августа 2020

IDK, если проблема в том, как байты конвертируются в короткие и обратно, но, поскольку вы спросили об этом в комментарии, я опубликую его. Предположим, что буфер имеет непрерывные байты с прямым порядком байтов при 16-битной кодировке. Просто поменяйте местами байтовые индексы для прямого порядка байтов.

pcmShort = ( buffer[i] & 0xff ) | ( buffer[i+1] << 8 );

Преобразование pcm в байты, которое я использую, следующее (для обратного порядка байтов, обратные индексы для обратного порядка байтов):

outBuffer[i] = (byte)pcmShort[0];
outBuffer[i+1] = (byte)((int)pcmShort[0] >> 8); 

Может быть, вы можете использовать два метода (ваша попытка с ByteBuffer и getShort и выше) бок о бок для одних и тех же данных и проверить, содержат ли полученные массивы одинаковые значения?

Другое дело Я бы попробовал просто заставить работать единственный трек. Если это звучит нормально, проверьте микширование. Маловероятно, что сигналы настолько горячие, что выходят за пределы поля. Так что, вероятно, происходит что-то еще.

Я должен попробовать это сам, я не уверен, когда доберусь до этого. Потенциально это могло быть улучшением того, что я делал.

...