Algoritma Sintesis Modulasi Frekuensi

9

Berdasarkan apa yang saya baca, saya telah membuat algoritma untuk sintesis suara FM. Saya tidak yakin apakah saya melakukannya dengan benar. Saat membuat instrumen synth perangkat lunak fungsi digunakan untuk menghasilkan osilator dan modulator dapat digunakan untuk memodulasi frekuensi osilator ini. Saya tidak tahu apakah sintesis FM seharusnya hanya berfungsi untuk memodulasi gelombang sinus?

Algoritma mengambil fungsi gelombang instrumen dan indeks modulator dan rasio untuk modulator frekuensi. Untuk setiap catatan dibutuhkan frekuensi dan menyimpan nilai fase untuk osilator pembawa dan modulator. Modulator selalu menggunakan gelombang sinus.

Ini adalah algoritma dalam 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 

Jadi jika frekuensi note berada pada 100Hz, FMRatio diatur pada 0,5 dan FMIndex 0,1 harus menghasilkan frekuensi antara 95Hz dan 105Hz dalam siklus 50Hz. Apakah ini cara yang benar untuk melakukannya. Tes saya menunjukkan bahwa itu tidak selalu terdengar benar, terutama ketika memodulasi gelombang gergaji dan persegi. Apakah boleh memodulasi gergaji dan gelombang persegi seperti ini atau hanya untuk gelombang sinus?

Ini adalah implementasi di C dan 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;
}

Jawaban sangat kami hargai.

Matthew Mitchell
sumber
3
Saya sarankan agar Anda membaca diskusi berikut pertanyaan ini . Sementara di sini Anda tidak membuat transisi frekuensi secara tiba-tiba seperti pada pertanyaan lain, mempertahankan kontinuitas fase dalam sinyal FM sangat penting, dan memastikan bahwa sinyal FM adalah fase-kontinu terlepas dari bentuk gelombang modulasi, apakah gelombang sinusoidal atau gigi gergaji atau gelombang persegi. (ada perubahan frekuensi yang tiba-tiba!), akan membantu Anda menghindari banyak masalah.
Dilip Sarwate
3
Tanpa membaca tumpukan besar kode Anda, ada baiknya bertanya: apa sebenarnya masalahnya? Anda mengatakan Anda tidak yakin apakah itu berfungsi atau tidak. Apa yang secara spesifik membuat Anda berpikir itu tidak berfungsi?
Jason R

Jawaban:

2

Apa yang Anda lakukan di sini adalah modulasi fase. Beginilah cara synth 'FM' seperti Yamaha DX-7 beroperasi. Seringkali osilator synth disetel pada skala musik, bukan skala Hz linier lurus. Jadi memodulasi pitch secara langsung menghasilkan perubahan pitch yang tidak diinginkan, itu sebabnya modulasi fase lebih cocok. Anda dapat memodulasi bentuk gelombang apa pun, namun bentuk yang lebih kompleks alias lebih mudah. Bahkan dosa modulasi bisa alias, jadi tidak dilarang.

Jeff McClintock
sumber