私が読んだ内容に基づいて、FMサウンド合成のアルゴリズムを作成しました。正しくできたかどうかはわかりません。ソフトウェアシンセ楽器を作成する場合、関数を使用して発振器を生成し、変調器を使用してこの発振器の周波数をモジュール化できます。FM合成が正弦波の変調にのみ機能すると想定されているかどうかはわかりませんか?
アルゴリズムは、計測器の波動関数と、周波数変調器の変調器インデックスおよび比率を使用します。各ノートでは、周波数を受け取り、キャリアと変調器の発振器の位相値を保存します。変調器は常に正弦波を使用します。
これは疑似コードのアルゴリズムです:
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
したがって、ノートの周波数が100Hzで、FMRatioが0.5に設定され、FMIndexが0.1の場合、50Hzサイクルで95Hzと105Hzの間の周波数が生成されます。これは正しい方法ですか。私のテストでは、特にのこぎり波と方形波を変調する場合、常に正しく聞こえるとは限らないことがわかりました。このようにのこぎり波と方形波を変調してもいいですか、それとも正弦波のみですか?
これは、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;
}
回答は大歓迎です。
3
この質問に続く議論を読むことをお勧めします。ここでは、他の質問のように周波数を急激に変化させていませんが、FM信号の位相連続性を維持することは非常に重要であり、正弦波、のこぎり波、方形波などの変調波形に関係なく、FM信号が位相連続である ことを確認します(頻度の急激な変化があります!)、多くの問題を回避するのに役立ちます。
—
Dilip Sarwate、2011
大量のコードを読まなくても、質問する価値があります。何が問題なのでしょうか。あなたはそれが機能するかどうかわからない、と言います。具体的に何が機能していないと思いますか?
—
Jason R