Генератор тонов генерирует второй тон - PullRequest
0 голосов
/ 10 июня 2018

Я пытаюсь сделать простой генератор сигналов для изохронных пульсирующих звуков.

По сути, «beatFrequency» управляет изменением амплитуды основной (основной) частоты.

Это работает довольно хорошо, за исключением того, что для некоторых частот основного тона выше 4-5 кГц, есть второй тон, генерируемый с более низкой частотой.
Это не для всех частот, но для многих я определенно могу услышатьвторой тон.

Что это может быть?Какой-то резонанс?Я пытался увеличить частоту дискретизации, но ничего не изменилось, и использования 44100 должно быть достаточно примерно до 20 кГц, если я правильно понимаю?

Я действительно не могу понять это самостоятельно, так благодаренза помощь!

Вот пример кода с частотой ударов 1 Гц, частотой тона 5000 Гц и частотой дискретизации 44100.

public void playSound() {

double beatFreq = 1;
double pitch = 5000;
int mSampleRate = 44100;

    AudioTrack mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,   mSampleRate,
        AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
        256, AudioTrack.MODE_STREAM);

int loopLength = 2 * this.mSampleRate;

while (isPlaying) {
    double[] mSound = new double[loopLength];

    for (int i = 0; i < loopLength; i = i + 1) {
       mSound[i] = beatFreq*Math.sin((1.0*Math.PI * i/(this.mSampleRate/pitch)));
       mBuffer[i] = (short) (mSound[i] * Short.MAX_VALUE);
    }

    mAudioTrack.play();
    mAudioTrack.write(mBuffer, 0, loopLength);

}
}

Вот (добавлено) изображение частот, когда я играютон 4734 Гц .. И, например, есть довольно большой пик на частоте около 1100 Гц, а также много выше.

enter image description here

Код теперь простоиспользуя поле, я удалил частоту ударов:

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

Переписав ответ, после лучшего понимания вопроса, ОП хочет сделать амплитудную модуляцию.

Да, Java может выполнять амплитудную модуляцию.Я сделал сносный звук крикета, например, взяв тон 4,9 кГц и модулируя громкость на 66 Гц, и придав результирующему тону огибающую AR.

В вашем коде переменная beatFreq остается постоянной в течениецелый цикл.Разве вы не намерены изменить это с течением времени?

Я думаю, вам следует одновременно вычислить волновое значение beatFreq в его собственной функции (но также с использованием переменной i) и умножить этот результат (масштабируется в диапазоне от 0 до 1) в зависимости от значения, рассчитанного для более быстрого тона.


** РЕДАКТИРОВАТЬ


Для перемещения избыточных вычислений из внутреннего цикла возможна следующая ситуация:

В качестве переменных экземпляра должны иметь следующие значения:

private double incr;
private double incrSum;
private final double TWO_PI = Math.PI * 2;

Выполните следующие вычисления в конструкторе только один раз:

    incr = pitch / audioFmt.getSampleRate();
    incr *= TWO_PI;

Это предполагает, что pitch - это значение, указанное в герцах, а audioFormat - это Java AudioFormat.использовался.С Android я не знаю, как сохраняется частота дискретизации аудиоформата или как к ней осуществляется доступ.

С этим у вас может быть метод, который возвращает следующее двойное значение PCM с некоторым очень простым кодом:

private double getNextSinePCM()
{
    incrSum += incr;
    if (incrSum > TWO_PI)
    {
        incrSum -= TWO_PI;
    }
    return Math.sin(incrSum);
}

Примечание: не сбрасывайте incrSum в ноль, как вы указали в своем комментарии.Это может привести к разрыву.

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

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

Просто комментарий: мне кажется, что вы увлечены работой со звуком, но, возможно, самоучка или немного отстает в основных приемах программирования.Перемещение избыточных вычислений за пределы цикла является своего рода фундаментальным.Так же как и способность делать простые тестовые случаи для проверки предположений и устранения неполадок.В дальнейшем я хочу призвать вас посвятить некоторое время разработке этих основ, а также интересу к звуку!Вы можете проверить группу чтения кода StackOverflow в качестве ресурса для получения дополнительных советов.Я также самоучка и многому научился там, а также читал курс на JavaRanch под названием "CattleDrive".

0 голосов
/ 10 июня 2018

В вашем коде вы используете beatFreq*Math.sin((1.0*Math.PI * i/(this.mSampleRate/pitch))); для определения частоты (здесь отсутствует какое-либо присвоение)

Однако, mSampleRate и pitch являются значениями типа int, что приводит к целочисленному делению вместо двойного деления,В особых случаях для высоты тона и частоты дискретизации это приведет к более низким частотам, чем предполагалось.Для больших значений высоты эффект должен ухудшаться.

Попробуйте использовать double вместо int, что должно избавить от проблемы.

...