Разработка кода волнового типа генератора и создание новых волновых типов - PullRequest
2 голосов
/ 08 февраля 2012

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

OSStatus RenderTone(
    void *inRefCon, 
    AudioUnitRenderActionFlags  *ioActionFlags, 
    const AudioTimeStamp        *inTimeStamp, 
    UInt32                      inBusNumber, 
    UInt32                      inNumberFrames, 
    AudioBufferList             *ioData)

{
    // Fixed amplitude is good enough for our purposes
    const double amplitude = 0.25;

    // Get the tone parameters out of the view controller
    ToneGeneratorViewController *viewController =
        (ToneGeneratorViewController *)inRefCon;
    double theta = viewController->theta;
    double theta_increment = 2.0 * M_PI * viewController->frequency / viewController->sampleRate;

    // This is a mono tone generator so we only need the first buffer
    const int channel = 0;
    Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;

     // Generate the samples
     for (UInt32 frame = 0; frame < inNumberFrames; frame++) 
    {
        buffer[frame] = sin(theta) * amplitude;

        theta += theta_increment;
        if (theta > 2.0 * M_PI)
        {
             theta -= 2.0 * M_PI;
        } 
    }

    // Store the theta back in the view controller
    viewController->theta = theta;

    return noErr;

}

Ответы [ 2 ]

1 голос
/ 09 февраля 2012

Чтобы получить желаемую форму волны, вам нужно заменить функцию sin () на функцию, которая создает желаемую форму волны.

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

1 голос
/ 08 февраля 2012

Фактические образцы синусоидальной волны генерируются и заполняют буфер во фрагменте ниже

for (UInt32 frame = 0; frame < inNumberFrames; frame++) 
{
    buffer[frame] = sin(theta) * amplitude;

    theta += theta_increment;
    if (theta > 2.0 * M_PI)
    {
         theta -= 2.0 * M_PI;
    } 
}

В строке, где назначается buffer[frame], вы вызываете sin(theta) * amplitude, и для каждогоитерации цикла for, вы увеличиваете theta на некоторый конечный размер шага, основанный на вашей частоте и частоте дискретизации, через

double theta_increment = 2.0 * M_PI * viewController->frequency / viewController->sampleRate;

, который по существу делит 2.0 * PI * frequency на вашу частоту дискретизации.

Увеличение переменной theta во время цикла по циклу for в основном продвигает шаг по времени на одну выборку за раз, пока ваш буфер не заполнится (т. Е. frame == iNumberFrames).

Если выЕсли вы хотите сгенерировать что-то, кроме синусоидальной волны, вы просто замените следующую строку какой-нибудь другой функцией:

buffer[frame] = sin(theta) * amplitude;

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

buffer[frame] = (8 / pow(M_PI,2)) * (sin(theta) - sin(3*theta)/9 + sin(5*theta)/25);
...