2011-12-23 3 views
7

내가 읽은 것을 토대로 FM 사운드 합성 알고리즘을 만들었습니다. 내가 제대로했는지 확실하지 않습니다. 소프트웨어 신스 악기를 만들 때 함수는 발진기를 생성하는 데 사용되고 변조기는이 발진기의 주파수를 모듈화하는 데 사용될 수 있습니다. FM 합성이 사인파를 변조하는 데만 사용된다면 나는 모르겠다.주파수 변조 합성 알고리즘

알고리즘은 악기 파동 함수와 주파수 변조를위한 변조 지수 비율 걸린다. 각 음표에 대해 주파수를 취하고 반송파 및 변조기 오실레이터의 위상 값을 저장합니다. 변조기는 항상 사인파를 사용합니다. 음의 주파수는 100Hz로이면

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 

그래서 FMRatio 0.5로 설정하고 FMIndex 그것이는 50Hz에서 95Hz와 105Hz 사이가는 주파수를 생성한다 0.1 :

의사 코드의 알고리즘 주기. 이것이 올바른 방법일까요? 내 테스트에 따르면 항상 톱 소리와 구형파를 조절할 때 항상 소리가 나지 않는 것으로 나타났습니다. 이런 톱과 구형파를 변조해도 괜찮습니까? 아니면 사인파 만입니까?

이 C와의 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; 
} 

답변 대단히 감사합니다.

+1

이것은 http://dsp.stackexchange.com (또는 http://avp.stackexchange.com)에 좋은 질문 일 수 있습니다. – mtrw

+0

좋아요, 시도해 보겠습니다. 감사! –

답변

2

결국 나는 위상 변조를 사용하기로 결정했습니다. 많은 합성기가 FM으로 라벨을 붙이더라도 위상 변조를 사용한다는 것을 알았습니다.

구현하기 간단했다 :

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

가장 도움이되는 자료를 인용 하시겠습니까? 나는 2 명의 연산자 FM 합성으로 좋은 성공을 거두고 있지만 3 명의 연산자를 직렬로 연결할 때 엉뚱한 결과를 얻습니다. 그런 방식으로 FM을 사용 해본 적이 있습니까? 나는 당신이 인용 한 방정식과 그것의 FM 사촌을 사용했지만 그 결과는 동일합니다! –

3

좋은 질문, 나는 몇 가지 생각/아이디어 ...

이 주요 질문에 대한 답을 제공하려고합니다, 그래 그것은 사인파 이외의 파형을 변조하기 위해 절대적으로 괜찮습니다. 사실 FM이 가장 좋습니다. 사인파를 변조하면 매우 지루한 출력이 나오지만 동일한 변조로 복잡한 파형을 입력하면 더욱 흥미로운 결과를 얻을 수 있습니다. FYI (당신이 아직 모르는 경우를 위해), 가장 유명한 FM 신디사이저는 아마도 그날 혁명적이었던 Yamaha DX7 일 것입니다 (또한 MIDI를 가진 최초의 신스 중 하나입니다).

다른 언급 할 점은 FM 합성이 디지털 시대의 시작이므로 파형이 디지털로 생성되어 사인파/정사각형/삼각형파보다 정교한 파형을 사용하여 흥미로운 사운드를 생성한다는 것입니다. 복잡한 파형을 사용하여 변조하기 위해 사인파를 생성하는 것보다 더 나은 사운드를 얻기 위해해야 ​​할 일이 될 수 있습니다.

코드를 살펴보면 FM이 올바르게 작동하는 것처럼 보입니다. 그러나, 나는 변조 주파수가 코드에서와 같이 노트 주파수의 일부분보다는 일반적으로 고정되어 있다고 생각합니다. 이것을 시도하고 찾고있는 것보다 더 소리가 나는지 볼 가치가 있습니다.

조금 도움이 되었기를 바랍니다.

+0

답변 해 주셔서 감사합니다. 나는 결국 위상 변조를하기로 결정했다. –

6

적목 :

이 주요 질문에 대답하기 위해, 예는 사인파 이외의 파형을 변조하기 위해 절대적으로 괜찮습니다. 사실 FM이 가장 좋습니다. 사인파를 변조하면 매우 지루한 출력이 나오지만 동일한 변조로 복잡한 파형을 입력하면 더욱 흥미로운 결과를 얻을 수 있습니다.

이것은 극도의 단순화이며 아마도 완전히 거짓입니다. 정현파로 사인파를 변조하는 것은 복잡하고 다양한 "지루한"사운드를 완벽하게 생성 할 수 있습니다.

반면에 복잡한 파형은 생성 된 측 대역의 수를 크게 늘리고 예측 가능한 결과를 훨씬 더 어렵게 만듭니다. Yamaha의 "the" "FM"을 비롯한 많은 일반적인 경우에 실제로 거의 동등한 PHASE 변조 (PM) 인 FM에 대한 대부분의 문서는 사인파에만 해당됩니다.

FYI (경우에 당신이 아직없는 알이), 가장 유명한 FM 신디사이저 아마 그 일에 혁명적 야마하 DX7 (그리고 또한 최초의 어느 누구도 MIDI와 신디사이저). 언급

다른 것은 FM 합성이 파형을 디지털로 생성 따라서 흥미로운 소리를 만들 사인/사각/삼각 파도보다 더 복잡한 파형을 사용 하였다 있도록 디지털 시대의 시작이라고합니다. "

DX7과 많은 초기 FM (실제로 Yamaha의 PM 신디사이저는 오직 사인파를 제공했지만 아직 위에서 언급했듯이 많은 사람들이 여전히 지루하지 않음) "더 정교한 파형"이 포함되지 않았습니다.

나중에 야마하는 다른 파형을 추가했으며 유틸리티는 다소 복잡합니다. 위에서 언급했듯이 사인 파에 의해 생성 된 측 대역의 예측 가능성과 비교할 때 stionable입니다.

또는 단지 좋은 준비와 사인파를 사용하여 "단지 조절하는 사인파를 생성하기보다는 복잡한 파형을 사용하고 -.

이것은 당신이 더 좋은 소리를 얻기 위해 수행해야 할 수 있습니다 (비율, 인덱스 등)

사인파가있는 FM/PM이 많은 사용자를 위해 스튜디오 품질 또는 아날로그와 비슷한 결과를 즉시 생성하지 않는다는 사실은 그것이 무엇인지 나타내지 않습니다. 그렇게 할 수 없습니다.