Генерирование генерируемых сигналов

Я пишу программный синтезатор и нуждаюсь в генерации bandlimited, alias free waveforms в реальном времени с частотой 44,1 кГц. Звуковая форма пилот-сигнала будет делать сейчас, так как я могу генерировать импульсную волну, смешивая два пилообразных пилы вместе, один перевернутый и сдвинутый по фазе.

До сих пор я пробовал следующие подходы:

  • Предварительно вычитая однотактные идеально диапазонные образцы осциллограмм на разных диапазонах частот при запуске, затем воспроизводя два наиболее близких друг друга. Работы хорошо, я думаю, но не чувствую себя очень элегантно. Требуется много образцов, или будут слышны "промежутки" между ними. Интерполяция и микширование также очень интенсивные.

  • Интеграция поезда DC с компенсацией импульсов sinc для получения пилообразной волны. Звучит здорово, за исключением того, что волна дрейфует от нуля, если вы не получите компенсацию DC точно вправо (что я считаю очень сложным). Проблема постоянного тока может быть уменьшена путем добавления небольшого количества утечек к интегратору, но затем вы теряете низкие частоты.

Итак, мой вопрос: каким образом это делается? Любое предлагаемое решение должно быть эффективным с точки зрения процессора, поскольку оно должно выполняться в реальном времени для многих голосов одновременно.

Ответ 1

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

Я предлагаю вам ознакомиться с этим сайтом здесь:

http://www.musicdsp.org/

Посмотрите архив! Он полон хорошего материала. Я просто выполнил поиск по ключевому слову "bandlimited". Материал, который появляется, должен оставаться занятым хотя бы на неделю.

Btw - Не знаю, что вы ищете, но пару лет назад я сделал псевдоним (например, не очень ограниченный группой). Я только что вычислил интеграл между последней и текущей позицией образца. Для традиционных synth-waveforms вы можете сделать это довольно легко, если вы разделите интервал интеграции на особенности (например, когда пилочка получит его reset). Нагрузка процессора была низкой и качество было приемлемым для моих потребностей.

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

Ответ 2

Одним быстрым способом генерации сигналов с ограничением по диапазону является использование ограниченных диапазоном шагов (BLEPs). Вы сами генерируете сам диапазон:

enter image description here

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

enter image description here

См. прохождение через Band-Limited Sound Synthesis.

Поскольку этот BLEP не является причинно-следственным (что означает, что он распространяется в будущее), для генерации сигналов в реальном времени лучше использовать минимально-фазовый шаг с ограничением полосы, называемый MinBLEP, который имеет тот же частотный спектр, но только распространяется на прошлое:

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

Ответ 3

Это то, что я придумал, вдохновленный идеями Нилса. Вставка этого здесь, если это полезно для кого-то другого. Я просто коробку фильтрую пилообразную волну аналитически, используя изменение фазы из последнего образца в качестве размера ядра (или обрезания). Он работает достаточно хорошо, есть несколько слышимых псевдонимов на самых высоких нотах, но для нормального использования он звучит великолепно.

Чтобы еще больше уменьшить наложение, размер ядра может быть увеличен, что делает его 2 * phaseChange, например, хорошим и хорошим, хотя вы теряете бит самых высоких частот.

Кроме того, вот еще один хороший ресурс DSP, который я нашел при просмотре SP для похожих тем: The Synthesis ToolKit в С++ (STK). Это библиотека классов, в которой есть много полезных инструментов DSP. Он даже готов использовать генераторы генераторов с полосой пропускания. Метод, который они используют, - это интегрировать sinc, как я описал в своем первом сообщении (хотя, я думаю, они делают это лучше, чем меня...).

float getSaw(float phaseChange)
{
    static float phase = 0.0f;
    phase = fmod(phase + phaseChange, 1.0f);
    return getBoxFilteredSaw(phase, phaseChange);
}

float getPulse(float phaseChange, float pulseWidth)
{
    static float phase = 0.0f;
    phase = fmod(phase + phaseChange, 1.0f);
    return getBoxFilteredSaw(phase, phaseChange) - getBoxFilteredSaw(fmod(phase + pulseWidth, 1.0f), phaseChange);
}

float getBoxFilteredSaw(float phase, float kernelSize)
{
    float a, b;

    // Check if kernel is longer that one cycle
    if (kernelSize >= 1.0f) {
        return 0.0f;
    }

    // Remap phase and kernelSize from [0.0, 1.0] to [-1.0, 1.0]
    kernelSize *= 2.0f;
    phase = phase * 2.0f - 1.0f;

    if (phase + kernelSize > 1.0f)
    {
        // Kernel wraps around edge of [-1.0, 1.0]
        a = phase;
        b = phase + kernelSize - 2.0f;
    }
    else
    {
        // Kernel fits nicely in [-1.0, 1.0]
        a = phase;
        b = phase + kernelSize;
    }

    // Integrate and divide with kernelSize
    return (b * b - a * a) / (2.0f * kernelSize);
}

Ответ 4

Смещение DC от blit - может быть уменьшено с помощью простого фильтра высоких частот! - очень похоже на реальную аналоговую схему, где они используют блокировочную крышку постоянного тока!