根据我的阅读,我制作了一个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;
}
非常感谢答案。
答案 0 :(得分:7)
红眼:
回答你的主要问题,是的,调制除正弦波之外的波形绝对没问题。事实上,这就是FM最擅长的。调制正弦波提供非常无聊的声音输出,但是当您使用相同的调制输入更复杂的波形时,您将获得更有趣的结果。
这充其量只是过于简单化,可能完全错误。用正弦波调制正弦波完全能够产生各种复杂而非“无聊”的声音。
相比之下,复杂波形大量增加了产生的边带数量,使得可预测的结果更难以实现。大多数关于FM的文档 - 实际上是在许多常见情况下几乎等效的PHASE调制(PM),包括Yamaha的“FM” - 仅涉及正弦波。
仅供参考(如果您还不知道),最着名的FM合成器可能是雅马哈DX7,它在当时是革命性的(也是首批使用MIDI的合成器之一)。
另一件需要提及的是,FM合成是数字时代的开始,因此波形是以数字方式生成的,因此使用比正弦/方波/三角波更复杂的波形来创建有趣的声音。“
毫无疑问,这是完全错误的。 DX7和许多早期FM - 实际上,雅马哈的PM合成器仅提供正弦波,然而,正如我上面所说,它们仍然能够发出许多很多非“无聊”的声音。没有涉及“更复杂的波形”。
正如我上面所述,雅马哈后来才添加其他波形,与正弦波产生的边带的可预测性相比,它们的实用性有些疑问。
这可能是你需要做的才能获得更好的声音 - 而不是仅仅生成一个正弦波进行调制,使用复杂的波形。“
或者只使用具有良好排列和参数组合(比率,指数等)的正弦波
对于许多用户而言,带有正弦波的FM / PM不能立即产生工作室质量 - 或者可能只是类似模拟 - 这一事实并不能表明它无法做到这一点。
答案 1 :(得分:3)
好问题,我会尝试提供一些想法/想法......
回答你的主要问题,是的,调制除正弦波之外的波形绝对没问题。事实上,这就是FM最擅长的。调制正弦波提供非常无聊的声音输出,但是当您使用相同调制输入更复杂的波形时,您将获得更有趣的结果。仅供参考(如果您还不知道),最着名的FM合成器可能是当时具有革命性的Yamaha DX7(也是首批使用MIDI的合成器之一)。
另一件需要提及的是,FM合成是数字时代的开始,因此波形是以数字方式生成的,因此使用比正弦/方波/三角波更复杂的波形来创建有趣的声音。这可能是您需要做的以获得更好的声音 - 而不是仅仅生成正弦波进行调制,使用复杂的波形。
查看您的代码,看起来您正确地进行了调频。但是,我认为调制频率通常是固定的而不是音符频率的一小部分,因为它在您的代码中。可能值得尝试这一点,看看它听起来更像你正在寻找的东西。
我希望这有点帮助。
答案 2 :(得分:3)
最后我决定使用相位调制。我发现许多合成器使用相位调制,即使它们用FM标记。
实施起来很简单:
signal += wave_function(note_phase * note_frequency / sample_rate + fm_index * sin(note_phase * fm_frequency * pi / sample_rate))*note_amplitude