Frekans Modülasyon Sentezi Algoritması


9

Okuduğum bilgilere dayanarak, FM ses sentezi için bir algoritma yaptım. Doğru yapıp yapmadığımdan emin değilim. Bir yazılım synth aracı oluştururken bir osilatör üretmek için bir işlev kullanılır ve bu osilatörün frekansını modüle etmek için bir modülatör kullanılabilir. FM sentezinin sadece sinüs dalgalarını modüle etmek için çalışıp çalışmadığını bilmiyorum?

Algoritma, enstrüman dalga fonksiyonunu ve frekans modülatörünün modülatör indeksini ve oranını alır. Her nota için frekans alır ve taşıyıcı ve modülatör osilatörlerinin faz değerini depolar. Modülatör her zaman bir sinüs dalgası kullanır.

Sözde koddaki algoritma:

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 

Eğer note frekansı 100Hz ise, FMRatio 0,5 olarak ayarlanır ve FMIndex 0,1 ise 50Hz'lik bir döngüde 95Hz ile 105Hz arasındaki frekansları üretmelidir. Bunu yapmanın doğru yolu bu mu? Testlerim, özellikle testere ve kare dalgaları modüle ederken her zaman doğru gelmediğini gösteriyor. Testere ve kare dalgaları böyle modüle etmek uygun mu yoksa sadece sinüs dalgaları için mi?

Bu C ve CoreAudio'daki uygulama:

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;
}

Cevaplar çok takdir ediliyor.


3
Bu soruyu izleyen tartışmaları okumanızı öneririm . Burada diğer sorudaki gibi frekansta ani geçişler yapmazken, FM sinyalinde faz devamlılığını korumak çok önemlidir ve FM sinyalinin , ister sinüzoidal ister testere dişi veya kare dalga olsun , modülasyon dalga formuna bakılmaksızın faz-sürekli olmasını sağlamak (frekansta ani bir değişiklik var!), birçok problemden kaçınmanıza yardımcı olacaktır.
Dilip Sarwate

3
Büyük kod yığınınızı okumadan, sormaya değer: sorun tam olarak nedir? Çalışıp çalışmadığından emin olmadığınızı söylüyorsunuz. Sizi özellikle işe yaramadığını düşündüren nedir?
Jason R

Yanıtlar:


2

Burada yaptığınız şey faz modülasyonudur. Yamaha DX-7 gibi 'FM' synth'leri bu şekilde çalışır. Genellikle synth osilatörleri, düz doğrusal Hz ölçeğinde değil, müzikal bir ölçekte ayarlanır. Bu nedenle, perdeyi modüle etmek doğrudan istenmeyen bir perde kaymasına neden olur, bu yüzden faz modülasyonu daha uygundur. Herhangi bir dalga şeklini modüle edebilirsiniz, ancak daha karmaşık şekiller daha kolay takma ad oluşturur. Modüle edilmiş bir günah bile takma isim olabilir, bu yüzden yasak değildir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.