Dựa trên những gì tôi đọc, tôi đã thực hiện thuật toán tổng hợp âm thanh FM. Tôi không chắc liệu tôi có làm đúng không. Khi tạo một công cụ phần mềm synth, một hàm được sử dụng để tạo ra một bộ dao động và một bộ điều biến có thể được sử dụng để mô-đun tần số của bộ dao động này. Tôi không biết nếu tổng hợp FM được cho là chỉ hoạt động để điều chỉnh sóng sin?Thuật toán tổng hợp điều chế tần số
Thuật toán lấy hàm sóng của công cụ và chỉ số và tỷ số điều biến cho bộ điều biến tần số. Đối với mỗi lưu ý phải mất tần số và lưu trữ các giá trị pha cho các sóng mang và bộ điều biến dao động. Bộ điều biến luôn sử dụng sóng sin.
Đây là thuật toán trong giả:
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
Vì vậy, nếu tần số của lưu ý là tại 100Hz, các FMRatio được thiết lập ở mức 0,5 và FMIndex là 0,1 nó nên sản xuất tần số đi giữa 95Hz và 105Hz trong một 50Hz chu kỳ. Đây có phải là cách làm đúng hay không. Các thử nghiệm của tôi cho thấy rằng nó không phải lúc nào cũng đúng, đặc biệt là khi điều chỉnh cưa và sóng vuông. Liệu có thể điều chỉnh các sóng cưa và sóng vuông như thế này hay chỉ là sóng sin?
này là việc thực hiện trong C và 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;
}
Answers được rất nhiều đánh giá cao.
Đây có thể là một câu hỏi hay cho http://dsp.stackexchange.com (hoặc có thể http://avp.stackexchange.com). – mtrw
Được rồi, tôi sẽ thử. Cảm ơn! –