2011-12-23 7 views
7

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

L'algoritmo prende la funzione d'onda dello strumento e 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 portante e modulatore. Il modulatore usa 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, il FMRatio è fissato a 0,5 e la FMIndex è 0.1 dovrebbe produrre frequenze corso tra 95Hz e 105Hz in una 50Hz ciclo. È questo il modo corretto di farlo. I miei test dimostrano che non sempre suona bene, specialmente quando si modula la sega e le onde quadre. Va bene modulare la sega e le onde quadre come questa o è solo per le 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; 
} 

risposte sono molto apprezzati.

+1

Questa potrebbe essere una buona domanda per http://dsp.stackexchange.com (o forse http://avp.stackexchange.com). – mtrw

+0

Ok, ci proverò. Grazie! –

risposta

2

Alla fine ho deciso di utilizzare la modulazione di fase. Ho scoperto che molti sintetizzatori usano la modulazione di fase anche quando sono etichettati con FM.

era semplice da implementare:

signal += wave_function(note_phase * note_frequency/sample_rate + fm_index * sin(note_phase * fm_frequency * pi/sample_rate))*note_amplitude 
+0

Saresti disposto a citare tutte le risorse che hai trovato più utili? Sto ottenendo un discreto successo con la sintesi FM a 2 operatori, ma ottenendo risultati stravaganti quando provo a mettere in cascata 3 operatori in serie. Hai usato FM in quel modo? Ho usato l'equazione che citi e il suo cugino FM, ma i risultati sono identici! –

3

Buona domanda, cercherò di offrire un paio di pensieri/idee ...

Per rispondere alla tua domanda principale, sì, è assolutamente bene per modulare le forme d'onda diverse da onde sinusoidali. In effetti, questo è ciò che FM è il migliore. Le onde sinusoidali modulanti producono un suono molto noioso, ma quando si introducono forme d'onda più complesse con la stessa modulazione, si ottengono risultati molto più interessanti. FYI (nel caso non lo sapessi già), il synth FM più famoso è probabilmente lo Yamaha DX7 che era rivoluzionario ai suoi tempi (e anche uno dei primi synth con MIDI).

L'altra cosa da ricordare è che la sintesi FM fu l'inizio dell'era digitale in modo che le forme d'onda sono stati generati digitalmente e quindi utilizzate forme d'onda più sofisticati rispetto alle onde/piazza/triangolo sinusoidali per creare i suoni interessanti. Questo potrebbe essere ciò che devi fare per ottenere un suono migliore - piuttosto che generare un'onda sinusoidale per modulare, utilizzare forme d'onda complesse.

Guardando attraverso il tuo codice, sembra che tu stia facendo l'FM correttamente. Tuttavia, penso che la frequenza di modulazione sia normalmente fissa piuttosto che una frazione della frequenza della nota come nel codice. Potrebbe valere la pena provare questo e vedere se suona più come quello che stai cercando.

Spero che questo aiuti un po '.

+0

Grazie per la risposta. Alla fine ho deciso di optare per una modulazione di fase. –

6

Redeye:

Per rispondere alla tua domanda principale, sì, è assolutamente bene per modulare le forme d'onda diverse da onde sinusoidali. In effetti, questo è ciò che FM è il migliore. Le onde sinusoidali modulanti producono un suono molto noioso, ma quando si introducono forme d'onda più complesse con la stessa modulazione, si ottengono risultati molto più interessanti.

Questa è tutt'al più una semplificazione eccessiva e probabilmente totalmente falsa. Modulare le onde sinusoidali con onde sinusoidali è perfettamente in grado di creare una vasta gamma di suoni complessi e non "noiosi".

Al contrario, forme d'onda complesse moltiplicano il numero di bande laterali risultanti in modo massiccio e rendono molto più difficile ottenere risultati prevedibili. La maggior parte della documentazione su FM - che è in realtà la modulazione PHASE quasi equivalente (PM) in molti casi comuni incluso "il" "FM" di Yamaha - riguarda solo le onde sinusoidali.

FYI (nel caso non lo sapessi già), il più famoso sintetizzatore FM è probabilmente il DX7 Yamaha che è stato rivoluzionario ai suoi tempi (e anche uno dei primi synth con MIDI in assoluto).

L'altra cosa da ricordare è che la sintesi FM fu l'inizio dell'era digitale in modo che le forme d'onda sono stati generati digitalmente e quindi utilizzate forme d'onda più sofisticati rispetto alle onde/piazza/triangolo sinusoidali per creare i suoni interessanti."

Questo è totalmente falso: il DX7 e molti primi FM - in realtà, i PM - synth di Yamaha offrivano SOLO onde sinusoidali, eppure, come ho detto sopra, sono ancora capaci di molti, molti non "noiosi" "suoni." Non sono state coinvolte "forme d'onda più sofisticate"

Solo più tardi Yamaha ha aggiunto altre forme d'onda e la loro utilità è in qualche modo stionable rispetto alla prevedibilità delle bande laterali create da onde sinusoidali, come ho affermato sopra.

Questo potrebbe essere ciò che è necessario fare per ottenere un suono migliore -. E non solo generare un'onda sinusoidale di modulare, utilizzare forme d'onda complesse"

o semplicemente usare onde sinusoidali con buoni arrangiamenti e combinazioni di parametri (rapporto, indice, ecc.)

Il fatto che FM/PM con onde sinusoidali non produca immediatamente risultati di qualità studio - o forse solo analogici - per molti utenti non indica affatto che sia incapace di farlo