Algoritmo di sintesi di modulazione di frequenza


9

Sulla base di ciò che ho letto, ho creato un algoritmo per la sintesi sonora FM. Non sono sicuro di averlo fatto bene. Quando si crea uno strumento sintetizzatore software, viene utilizzata una funzione per generare un oscillatore e un modulatore può essere utilizzato per modulare la frequenza di questo oscillatore. Non so se la sintesi FM dovrebbe funzionare solo per la modulazione delle onde sinusoidali?

L'algoritmo utilizza la funzione d'onda degli strumenti, l'indice e il rapporto del modulatore per il modulatore di frequenza. Per ogni nota prende la frequenza e memorizza il valore di fase per gli oscillatori portatore e modulatore. Il modulatore utilizza sempre un'onda sinusoidale.

Questo è l'algoritmo in pseudocodice:

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 

Quindi se la frequenza della nota è a 100Hz, FMRatio è impostato su 0,5 e FMIndex è 0,1 dovrebbe produrre frequenze comprese tra 95Hz e 105Hz in un ciclo di 50Hz. È questo il modo corretto di farlo. I miei test dimostrano che non suona sempre bene, specialmente quando si modulano la sega e le onde quadre. È corretto modulare onde di sega e quadre in questo modo o solo per onde sinusoidali?

Questa è l'implementazione in C e 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;
}

Le risposte sono molto apprezzate.


3
Suggerirei di leggere le discussioni a seguito di questa domanda . Mentre qui non si stanno effettuando brusche transizioni in frequenza come nell'altra domanda, è molto importante mantenere la continuità di fase nel segnale FM e assicurarsi che il segnale FM sia in fase continua indipendentemente dalla forma d'onda modulante, sia sinusoidale o a dente di sega o onda quadra (c'è un brusco cambio di frequenza!), ti aiuterà ad evitare molti problemi.
Dilip Sarwate,

3
Senza leggere la tua grande pila di codice, vale la pena chiedere: qual è esattamente il problema? Dici di non essere sicuro che funzioni o meno. Cosa ti fa pensare specificamente che non funzioni?
Jason R,

Risposte:


2

Quello che stai facendo qui è la modulazione di fase. Ecco come funzionano i sintetizzatori "FM" come Yamaha DX-7. Spesso gli oscillatori di synth sono sintonizzati su una scala musicale, non su una scala lineare lineare Hz. Quindi la modulazione del pitch provoca direttamente uno spostamento del pitch indesiderato, ecco perché la modulazione di fase è più adatta. È possibile modulare qualsiasi forma d'onda, tuttavia le forme più complesse si aliaseranno più facilmente. Anche un peccato modulato può alias però, quindi non è proibito.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.