Шум в фоновом режиме при генерации синусоиды в Java - PullRequest
5 голосов
/ 11 апреля 2009

Я получаю небольшое искажение (звучит как жужжание) на заднем плане, когда я запускаю следующий код. Из-за своей тонкой природы он полагает, что с передачей байтов происходит какое-то сглаживание.

AudioFormat = PCM_SIGNED 44100,0 Гц, 16 бит, стерео, 4 байта / кадр, big-endian

Примечание : код предполагает (на данный момент), что данные находятся в порядке с прямым порядком байтов.

public static void playFreq(AudioFormat audioFormat, double frequency, SourceDataLine sourceDataLine)
{
    System.out.println(audioFormat);
    double sampleRate = audioFormat.getSampleRate();
    int sampleSizeInBytes = audioFormat.getSampleSizeInBits() / 8;
    int channels = audioFormat.getChannels();

    byte audioBuffer[] = new byte[(int)Math.pow(2.0, 19.0) * channels * sampleSizeInBytes];

    for ( int i = 0; i < audioBuffer.length; i+=sampleSizeInBytes*channels )
    {
        int wave = (int) (127.0 * Math.sin( 2.0 * Math.PI * frequency * i / (sampleRate * sampleSizeInBytes * channels) )  );

        //wave = (wave > 0 ? 127 : -127);

        if ( channels == 1 )
        {
            if ( sampleSizeInBytes == 1 )
            {
                audioBuffer[i] = (byte) (wave);
            }

            else if ( sampleSizeInBytes == 2 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte)(wave >>> 8);
            }
        }

        else if ( channels == 2 )
        {
            if ( sampleSizeInBytes == 1 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte) (wave);
            }

            else if ( sampleSizeInBytes == 2 )
            {
                audioBuffer[i] = (byte) (wave);
                audioBuffer[i+1] = (byte)(wave >>> 8);

                audioBuffer[i+2] = (byte) (wave);
                audioBuffer[i+3] = (byte)(wave >>> 8);
            }
        }
    }

    sourceDataLine.write(audioBuffer, 0, audioBuffer.length);
}

Ответы [ 2 ]

7 голосов
/ 11 апреля 2009

В ваших комментариях говорится, что в коде подразумевается порядок байтов.

Технически вы на самом деле выводите в порядке с прямым порядком байтов, однако это не имеет значения, потому что благодаря счастливой причуде ваш самый значимый байт всегда равен 0.

РЕДАКТИРОВАТЬ: чтобы объяснить это далее - когда ваше значение имеет максимальное значение 127, вы должны писать (0x00, 0x7f), но фактический вывод из вашего кода (0x7f, 0x00), который равен 32512. Это происходит быть около правильного 16 бит максимальное значение 32767, но с младшими 8 битами все ноль. Было бы лучше всегда использовать 32767 в качестве максимального значения, а затем отбросить 8 младших битов, если требуется.

Это означает, что даже если вы выводите 16-битные данные, эффективное разрешение составляет всего 8 бит. Это, кажется, объясняет отсутствие качества звука.

Я сделал версию вашего кода, которая просто выгружает необработанные данные в файл и не видит ничего плохого в самом сдвиге битов. Там нет неожиданных изменений знака или пропущенных битов, но есть шум в соответствии с качеством 8-битной выборки.

Кроме того, математика будет проще, если вы вычислите волновое уравнение на основе отсчетов выборок, а затем отдельно позаботитесь о смещении байтов:

int samples = 2 << 19;
byte audioBuffer[] = new byte[samples * channels * sampleSizeInBytes];

for ( int i = 0, j = 0; i < samples; ++i )
{
    int wave = (int)(32767.0 * Math.sin(2.0 * Math.PI * frequency * i / sampleRate));
    byte msb = (byte)(wave >>> 8);
    byte lsb = (byte) wave;

    for (int c = 0; c < channels; ++c) {
        audioBuffer[j++] = msb;
        if (sampleSizeInBytes > 1) {
            audioBuffer[j++] = lsb;
        }
    }
 }
2 голосов
/ 11 апреля 2009

Полагаю, вы повторно вызываете этот код для воспроизведения длинного звука.

Есть ли вероятность, что генерируемая вами волна не может завершить полный период до того, как она будет написана?

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

Например:

        /-------\              /-------\              /-------\
  -----/         \       -----/         \       -----/         \
                  \                      \                      \
                   \-----                 \-----                 \-----

Обратите внимание на разрыв между частями этой волны. Это может быть причиной жужжания.

...