2011-12-23 8 views
7

Basado en lo que he leído, he creado un algoritmo para la síntesis de sonido FM. No estoy seguro si lo hice bien. Al crear un instrumento de sintetizador de software, se utiliza una función para generar un oscilador y se puede usar un modulador para modular la frecuencia de este oscilador. No sé si se supone que la síntesis de FM solo funciona para la modulación de ondas sinusoidales.Algoritmo de síntesis de modulación de frecuencia

El algoritmo toma la función de onda de los instrumentos y el índice y la relación del modulador para el modulador de frecuencia. Para cada nota toma la frecuencia y almacena el valor de fase para los osciladores portador y modulador. El modulador siempre usa una onda sinusoidal.

Este es el algoritmo en pseudocódigo:

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 

lo tanto, si la frecuencia de la nota es a 100Hz, el FMRatio se ha fijado en 0,5 y la FMIndex es 0,1 se debe producir frecuencias que van entre 95Hz y 105Hz en un 50Hz ciclo. ¿Es esta la forma correcta de hacerlo? Mis pruebas muestran que no siempre suena bien, especialmente cuando se modula la sierra y las ondas cuadradas. ¿Está bien modular las ondas de sierra y cuadradas como esta o solo para ondas sinusoidales?

Esta es la implementación en C y 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; 
} 

respuestas son muy apreciados.

+1

Esta podría ser una buena pregunta para http://dsp.stackexchange.com (o tal vez http://avp.stackexchange.com). – mtrw

+0

Bien, lo intentaré. ¡Gracias! –

Respuesta

2

Al final decidí usar la modulación de fase. Descubrí que muchos sintetizadores usan modulación de fase incluso cuando están etiquetados con FM.

Fue fácil de implementar:

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

¿Estaría dispuesto a citar los recursos que le parecieron más útiles? Estoy teniendo un buen éxito con la síntesis de FM de 2 operadores, pero obtuve resultados extravagantes cuando trato de conectar en cascada 3 operadores en serie. ¿Has usado FM de esa manera? He usado la ecuación que citas y su primo FM, ¡pero los resultados son idénticos! –

3

Buena pregunta, voy a tratar de ofrecer algunos pensamientos/ideas ...

Para responder a su pregunta principal, sí es absolutamente bien para modular las formas de onda diferentes de ondas sinusoidales. De hecho, eso es lo que FM es mejor. La modulación de las ondas sinusoidales proporciona una salida de sonido muy aburrida, pero cuando ingresas formas de onda más complejas con la misma modulación, obtienes resultados mucho más interesantes. FYI (en caso de que no lo sepas), el sintetizador FM más famoso es probablemente el Yamaha DX7 que fue revolucionario en su día (y también uno de los primeros sintetizadores con MIDI).

La otra cosa que mencionar es que la síntesis de FM fue el comienzo de la era digital, por lo que las formas de onda se generaron digitalmente y por lo tanto utilizaron formas de onda más sofisticadas que las ondas sinusoidales/cuadradas para crear sonidos interesantes. Esto podría ser lo que necesita hacer para obtener un mejor sonido: en lugar de generar una onda sinusoidal para modular, use formas de onda complejas.

Mirando a través de su código, parece que está haciendo la FM correctamente. Sin embargo, creo que la frecuencia de modulación es normalmente fija en lugar de una fracción de la frecuencia de la nota como lo es en tu código. Puede valer la pena intentar esto y ver si suena más como lo que estás buscando.

Espero que ayude un poco.

+0

Gracias por la respuesta. Decidí ir por una modulación de fase al final. –

6

de ojos rojos:

Para responder a su pregunta principal, sí es absolutamente bien para modular las formas de onda diferentes de ondas sinusoidales. De hecho, eso es lo que FM es mejor. La modulación de las ondas sinusoidales proporciona una salida de sonido muy aburrida, pero cuando ingresas formas de onda más complejas con la misma modulación, obtienes resultados mucho más interesantes.

Esto es, en el mejor de los casos, una simplificación excesiva y posiblemente totalmente falsa. La modulación de ondas sinusoidales con ondas sinusoidales es perfectamente capaz de crear una amplia gama de sonidos complejos y no "aburridos".

En contraste, las formas de onda complejas multiplican el número de bandas laterales resultantes de forma masiva y hacen que los resultados predecibles sean mucho más difíciles de lograr. La mayoría de la documentación sobre FM, que en realidad es la modulación PHASE casi equivalente (PM) en muchos casos comunes, incluido "el" "FM" de Yamaha, solo se refiere a ondas sinusoidales.

FYI (en caso de que no lo sabe ya), el más famoso sintetizador de FM es, probablemente, el Yamaha DX7 que fue revolucionario en su día (y también uno de los primeros sintetizadores cada vez con MIDI).

La otra cosa a mencionar es que la síntesis FM fue el comienzo de la era digital por lo que las formas de onda se generaron digitalmente y por lo tanto utilizan formas de onda más sofisticadas que las ondas/cuadrado/triángulo sinusoidales para crear los sonidos interesantes."

Esto es totalmente falso sin lugar a dudas. El DX7 y muchos primeros FM - en realidad, los sintetizadores PM de Yamaha ofrecen SOLO ondas sinusoidales, y sin embargo, como indiqué anteriormente, todavía son capaces de muchos, muchos "aburridos" "sonidos." No hubo "formas de onda más sofisticadas".

Solo después, Yamaha agregó otras formas de onda, y su utilidad es algo que discutible en comparación con la predictibilidad de las bandas laterales creadas por las ondas sinusoidales, como dije anteriormente.

Esto podría ser lo que necesita hacer para obtener un mejor sonido -. En lugar de generar una onda sinusoidal para modular, utiliza formas de onda complejas"

o simplemente utilizar ondas sinusoidales con buenos arreglos y combinaciones de parámetros (relación, índice, etc.)

El hecho de que FM/PM con ondas sinusoidales no produzca inmediatamente resultados de calidad de estudio, o tal vez simplemente analógicos, para muchos usuarios no indica en absoluto que sea incapaz de hacerlo.

Cuestiones relacionadas