Arhn - архитектура программирования

Андроид. Генерируемая синусоида производит стук каждую секунду

Я хочу генерировать синусоиду с комбинированными частотами. Я иду таким образом:

public static byte[] combineSineWave(Collection<Double> frequencies) {
    double[] sample = new double[SAMPLE_RATE];
    byte[] result = new byte[2 * SAMPLE_RATE];

    double coefficient = 2 * Math.PI;

    for (int i = 0; i < SAMPLE_RATE; i++) {
        double sum = 0;

        for (double frequency : frequencies) {
            sum += Math.sin(coefficient * i * frequency / SAMPLE_RATE);
        }

        sample[i] = sum / frequencies.size();
    }

    convertToPCM16Bit(sample, result);

    return result;
}

private static void convertToPCM16Bit(double[] sample, byte[] result) {
    int idx = 0;
    for (final double dVal : sample) {
        // scale to maximum amplitude
        final short val = (short) ((dVal * 32767));
        // in 16 bit wav PCM, first byte is the low order byte
        result[idx++] = (byte) (val & 0x00ff);
        result[idx++] = (byte) ((val & 0xff00) >>> 8);
    }
}

И воспроизведение сгенерированных байтов по этому коду:

AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SoundWaveGenerator.SAMPLE_RATE,
            AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, 2 * SoundWaveGenerator.SAMPLE_RATE,
            AudioTrack.MODE_STREAM);

    audioTrack.play();

    while (true) {
        byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies);
        audioTrack.write(bytes, 0, bytes.length);
    }

Но проблема в том, что я слышу щелчок примерно каждую секунду. Что случилось?


Ответы:


1

Щелчок, который вы слышите, является разрывом между каждым вызовом combSineWave. При каждом вызове combSineWave каждая частота будет начинаться с нуля градусов фазы. Но, в зависимости от частоты, может не давать четного числа циклов к концу 1-секундного интервала. Скажем, одна из частот такова, что последний образец второй находится на 90 градусов (1,0), тогда возникает разрыв при генерации следующего интервала.

Чтобы решить эту проблему, вам нужно отслеживать некоторое состояние между последовательными вызовами. Я закодировал пример ниже, но я не знаю, как передать по ссылке в Java. Кроме того, вам нужно иметь дело с возможностью перевернуться.

int i = 0;
while (true) {
    byte[] bytes = SoundWaveGenerator.combineSineWave(frequencies, ref i);
    audioTrack.write(bytes, 0, bytes.length);
}


public static byte[] combineSineWave(Collection<Double> frequencies, ref int i) {
    double[] sample = new double[SAMPLE_RATE];
    byte[] result = new byte[2 * SAMPLE_RATE];

    double coefficient = 2 * Math.PI;

    for (int j = 0; j < SAMPLE_RATE; j++) {
        double sum = 0;

        for (double frequency : frequencies) {
            sum += Math.sin(coefficient * i++ * frequency / SAMPLE_RATE);
        }
        sample[i] = sum / frequencies.size();
    }

    convertToPCM16Bit(sample, result);

    return result;
}

P.S. вы можете разделить на SAMPLE_RATE вне цикла.

double coefficient = 2 * Math.PI / SAMPLE_RATE;
29.10.2014
  • хорошо, так что я должен продолжить волну. Но в этом случае я получу переполнение индекса i. Также я вижу, что в вашем коде saple[0] == sample[SAMPLE_RATE + 1] проблема все еще существует, верно? Можно ли рассчитать правильную длину звука, где у меня будет четное количество циклов? Я думал, что 2 * Math.PI правильный период синусоиды, не так ли? 29.10.2014
  • Кроме того, не рекомендуется предварительно вычислять длину, когда у вас будет четное количество циклов. Представьте себе синусоиду на частоте 1 кГц в сочетании с синусоидой на частоте 1,00001 кГц. 30.10.2014
  • поэтому решение состоит в том, что мы можем отбросить только шум щелчков. Мы слышим его не каждую секунду, а каждый час (например). Это правда? 30.10.2014
  • Нет, есть лучшее решение, но оно требует небольшого рефакторинга. Вместо того, чтобы передавать частоты, вы предварительно вычисляете приращение фазы, передаете его, а затем вам нужно отслеживать текущую фазу каждого тона. Это разрешено, потому что счетчик фаз масштабируется между 0 и 2*pi. Я обновлю свой ответ, как только у меня будет шанс. 31.10.2014
  • написал некоторый код pastebin.com/KwRZ0jZy с этим примером basicsynth.com/ и с вашей помощью. И это работает. 31.10.2014
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..