Алгоритм синтеза частотной модуляции - PullRequest
7 голосов
/ 23 декабря 2011

На основании прочитанного я разработал алгоритм синтеза 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 ]

7 голосов
/ 07 сентября 2013

Redeye:

Чтобы ответить на ваш главный вопрос, да, абсолютно нормально модулировать сигналы, отличные от синусоидальных. На самом деле, это то, что FM лучше всего. Модуляция синусоидальных волн дает очень скучное звучание, но когда вы вводите более сложные осциллограммы с той же модуляцией, вы получаете гораздо более интересные результаты.

В лучшем случае это упрощение и, возможно, совершенно неверное. Модулирование синусоидальных волн синусоидальными волнами вполне способно создавать широкий спектр сложных, а не «скучных» звуков.

Напротив, сложные формы сигналов значительно увеличивают количество получаемых боковых полос и значительно затрудняют достижение предсказуемых результатов. Большая часть документации о FM - которая фактически является почти эквивалентной PHASE модуляцией (PM) во многих распространенных случаях, включая «FM» от Yamaha, - касается только синусоидальных волн.

К вашему сведению (если вы еще не знаете), самым известным FM-синтезатором, вероятно, является Yamaha DX7, который был революционным в свое время (а также одним из первых в мире синтезаторов с MIDI).

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

Это абсолютно неверно, без сомнения. DX7 и многие ранние FM - на самом деле, PM - синтезаторы Yamaha предлагали ТОЛЬКО синусоидальные волны, и, тем не менее, как я уже говорил выше, они по-прежнему способны на множество, не «скучных» звуков. Никаких «более сложных форм волны» не было.

Лишь позже Yamaha добавила другие формы волны, и их полезность несколько сомнительна по сравнению с предсказуемостью боковых полос, создаваемых синусоидальными волнами, как я уже говорил выше.

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

Или просто используйте синусоиды с хорошим расположением и комбинацией параметров (отношение, индекс и т. Д.)

Тот факт, что FM / PM с синусоидальными волнами не дает сразу студийного качества - или, может быть, просто аналогичных результатов - для многих пользователей, не указывает на то, что он не способен это сделать.

3 голосов
/ 21 января 2012

В итоге я решил использовать фазовую модуляцию. Я обнаружил, что многие синтезаторы используют фазовую модуляцию, даже если они помечены с помощью FM.

Это было просто реализовать:

signal += wave_function(note_phase * note_frequency / sample_rate + fm_index * sin(note_phase * fm_frequency * pi / sample_rate))*note_amplitude
3 голосов
/ 24 декабря 2011

Хороший вопрос, я постараюсь предложить несколько мыслей / идей ...

Чтобы ответить на ваш главный вопрос, да, абсолютно нормально модулировать сигналы, отличные от синусоидальных.На самом деле, это то, что FM лучше всего.Модуляция синусоидальных волн дает очень скучное звучание, но когда вы вводите более сложные осциллограммы с той же модуляцией, вы получаете гораздо более интересные результаты.К вашему сведению (если вы еще не знаете), самым известным FM-синтезатором, вероятно, является Yamaha DX7 , который был революционным в свое время (а также одним из первых в мире синтезаторов с MIDI).

Еще одна вещь, которую стоит упомянуть, это то, что FM-синтез стал началом цифровой эры, поэтому сигналы были сгенерированы цифровым способом и, следовательно, для создания интересных звуков использовались более сложные сигналы, чем волны синус / квадрат / треугольник.Это может быть то, что вам нужно сделать, чтобы получить лучший звук - вместо того, чтобы просто генерировать синусоидальную волну для модуляции, использовать сложные осциллограммы.

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

Надеюсь, это немного поможет.

...