Генерация сигналов с ограниченной полосой пропускания [закрыто]

StackOverflow https://stackoverflow.com/questions/175312

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

http://www.musicdsp.org/

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

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

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

Другие советы

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

введите описание изображения здесь

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

введите описание изображения здесь

См. пошаговое руководство на Синтез звука с ограничением диапазона .

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

  

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

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

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

Кроме того, вот еще один хороший ресурс DSP, который я нашел, просматривая SP по похожим темам: Инструментарий синтеза на C++ (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);
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top