Algorithmus zur Synthese der Frequenzmodulation


9

Basierend auf dem, was ich gelesen habe, habe ich einen Algorithmus für die FM-Klangsynthese entwickelt. Ich bin mir nicht sicher, ob ich es richtig gemacht habe. Beim Erstellen eines Software-Synthesizer-Instruments wird eine Funktion zum Erzeugen eines Oszillators verwendet, und ein Modulator kann verwendet werden, um die Frequenz dieses Oszillators zu modulieren. Ich weiß nicht, ob die FM-Synthese nur zur Modulation von Sinuswellen funktionieren soll.

Der Algorithmus übernimmt die Wellenfunktion des Instruments sowie den Modulatorindex und das Verhältnis für den Frequenzmodulator. Für jede Note wird die Frequenz genommen und der Phasenwert für die Träger- und Modulatoroszillatoren gespeichert. Der Modulator verwendet immer eine Sinuswelle.

Dies ist der Algorithmus im Pseudocode:

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 

Wenn also die Frequenz der Note bei 100 Hz liegt, das FMRatio auf 0,5 und der FMIndex auf 0,1 eingestellt sind, sollten Frequenzen zwischen 95 Hz und 105 Hz in einem 50-Hz-Zyklus erzeugt werden. Ist das die richtige Art, es zu tun? Meine Tests zeigen, dass es nicht immer richtig klingt, besonders wenn Säge- und Rechteckwellen moduliert werden. Ist es in Ordnung, Säge- und Rechteckwellen wie diese zu modulieren, oder ist es nur für Sinuswellen?

Dies ist die Implementierung in C und 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;
}

Antworten werden sehr geschätzt.


3
Ich würde vorschlagen, dass Sie die Diskussionen nach dieser Frage lesen . Während hier macht nicht abrupte Übergänge in der Frequenz , wie in der Frage, Phasenkontinuität in dem FM - Signal aufrechterhalten wird , sehr wichtig, und dafür zu sorgen , dass das FM - Signal ist phasenkontinuierlichen unabhängig von der modulierenden Wellenform, ob sinus- oder sägezahnförmig oder Rechteck (Es gibt die abrupte Änderung der Frequenz!), hilft Ihnen, viele Probleme zu vermeiden.
Dilip Sarwate

3
Ohne Ihren großen Haufen Code zu lesen, lohnt es sich zu fragen: Was genau ist das Problem? Sie sagen, Sie sind sich nicht sicher, ob es funktioniert oder nicht. Was lässt Sie konkret denken, dass es nicht funktioniert?
Jason R

Antworten:


2

Was Sie hier tun, ist Phasenmodulation. So funktionieren FM-Synthesizer wie der Yamaha DX-7. Oft werden Synth-Oszillatoren auf einer Musikskala gestimmt, nicht auf einer geraden linearen Hz-Skala. Die direkte Modulation der Tonhöhe führt also zu einer unerwünschten Tonhöhenverschiebung. Deshalb ist die Phasenmodulation besser geeignet. Sie können jede Wellenform modulieren, die komplexeren Formen werden jedoch leichter aliasisiert. Sogar eine modulierte Sünde kann einen Alias ​​haben, daher ist dies nicht verboten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.