Алгоритм синтеза частотной модуляции

9

Основываясь на том, что я прочитал, я создал алгоритм синтеза звука FM. Я не уверен, правильно ли я это сделал. При создании программного синтезатора используется функция для генерации генератора, а модулятор - для модуляции частоты этого генератора. Я не знаю, должен ли синтез FM работать только для модуляции синусоидальных волн?

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

Это алгоритм в псевдокоде:

function ProduceSample(instrument, notes_playing)
    for each note in notes_playing
        if note.isPlaying()
            # Calculate signal
            if instrument.FMIndex != 0 # Apply FM
                FMFrequency = note.frequency*instrument.FMRatio; # FM frequency is factor of note frequency.
                note.FMPhase = note.FMPhase + FMFrequency / kGraphSampleRate # Phase of modulator.
                frequencyDeviation = sin(note.FMPhase * PI)*instrument.FMIndex*FMFrequency # Frequency deviation. Max deviation is a factor of the FM frequency. Modulation is done by a sine wave. 
                note.phase = note.phase + (note.frequency + frequencyDeviation) / kGraphSampleRate # Adjust phase with deviation
                # Reset the phase value to prevent the float from overflowing
                if note.FMPhase >= 1
                    note.FMPhase = note.FMPhase - 1
                end if
            else # No FM applied
                note.phase = note.phase + note.frequency / kGraphSampleRate # Adjust phase without deviation
            end if
            # Calculate the next sample
            signal = signal + instrument.waveFunction(note.phase,instrument.waveParameter)*note.amplitude
            # Reset the phase value to prevent the float from overflowing
            if note.phase >= 1
                note.phase = note.phase - 1
            end if
        end if
    end loop
    return signal
end function 

Таким образом, если частота ноты равна 100 Гц, FMRatio установлен на 0,5, а FMIndex равен 0,1, он должен производить частоты, идущие между 95 Гц и 105 Гц в цикле 50 Гц. Это правильный способ сделать это. Мои тесты показывают, что он не всегда звучит правильно, особенно при модуляции пилы и прямоугольных волн. Можно ли модулировать пильные и прямоугольные волны, как это, или это только для синусоидальных волн?

Это реализация в C и CoreAudio:

static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData){
    AudioSynthesiser * audioController = (AudioSynthesiser *)inRefCon;
    // Get a pointer to the dataBuffer of the AudioBufferList
    AudioSampleType * outA = (AudioSampleType *) ioData->mBuffers[0].mData;
    if(!audioController->playing){
        for (UInt32 i = 0; i < inNumberFrames; ++i){
            outA[i] = (SInt16)0;
        }
        return noErr;
    }
    Track * track = &audioController->tracks[inBusNumber];
    SynthInstrument * instrument = (SynthInstrument *)track;
    float frequency_deviation;
    float FMFrequency;
    // Loop through the callback buffer, generating samples
    for (UInt32 i = 0; i < inNumberFrames; ++i){
        float signal = 0;
        for (int x = 0; x < 10; x++) {
            Note * note = track->notes_playing[x];
            if(note){
                //Envelope code removed
                //Calculate signal
                if (instrument->FMIndex) { //Apply FM
                    FMFrequency = note->frequency*instrument->FMRatio; //FM frequency is factor of note frequency.
                    note->FMPhase += FMFrequency / kGraphSampleRate; //Phase of modulator.
                    frequency_deviation = sinf(note->FMPhase * M_PI)*instrument->FMIndex*FMFrequency; //Frequency deviation. Max deviation is a factor of the FM frequency. Modulation is done by a sine wave. 
                    note->phase += (note->frequency + frequency_deviation) / kGraphSampleRate; //Adjust phase with deviation
                    // Reset the phase value to prevent the float from overflowing
                    if (note->FMPhase >= 1){
                        note->FMPhase--;
                    }
                }else{
                    note->phase += note->frequency/ kGraphSampleRate; //Adjust phase without deviation
                }
                // Calculate the next sample
                signal += instrument->wave_function(note->phase,instrument->wave_parameter)*track->note_amplitude[x];
                // Reset the phase value to prevent the float from overflowing
                if (note->phase >= 1){
                    note->phase--;
                }
            } //Else nothing added
        }
        if(signal > 1.0){
            signal = 1;
        }else if(signal < -1.0){
            signal = -1.0;
        }
        audioController->wave[audioController->wave_last] = signal;
        if (audioController->wave_last == 499) {
            audioController->wave_last = 0;
        }else{
            audioController->wave_last++;
        }
        outA[i] = (SInt16)(signal * 32767.0f);
    }
    return noErr;
}

Ответы очень ценятся.

Мэтью Митчелл
источник
3
Я хотел бы предложить вам прочитать обсуждения после этого вопроса . Хотя здесь вы не делаете резких переходов по частоте, как в другом вопросе, поддержание непрерывности фазы в FM-сигнале очень важно, и обеспечение того, чтобы FM-сигнал был непрерывным по фазе независимо от модулирующего сигнала, будь то синусоидальный или пилообразный или прямоугольный сигнал (есть резкое изменение частоты!), поможет вам избежать множества проблем.
Дилип Сарватэ
3
Не читая большую кучу кода, стоит спросить: в чем именно проблема? Вы говорите, что не уверены, работает ли это или нет. Что конкретно заставляет вас думать, что это не работает?
Джейсон Р

Ответы:

2

То, что вы делаете здесь, это фазовая модуляция. Вот как работают такие FM-синтезаторы, как Yamaha DX-7. Часто генераторы синтезатора настроены на музыкальную шкалу, а не на прямую линейную шкалу Гц. Таким образом, модуляция высоты тона напрямую приводит к нежелательному сдвигу высоты тона, поэтому фазовая модуляция является более подходящей. Вы можете модулировать любую форму волны, однако более сложные формы будут более легко использовать псевдоним. Даже модулированный грех может быть псевдонимом, поэтому это не запрещено.

Джефф МакКлинток
источник