用gcc FILE.c -lm -o FILE编译
程序生成单声道 16 位“扫频”正弦波。作为奖励,它还展示了扫描幅度。
// http://www.purplemath.com/modules/grphtrig.htm
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <string.h>
const double
radians = (M_PI * 2);
typedef struct SineWave {
double
rate, // sample rate
frequency, // oscillation Hz.
amplitude, // amplitude
phase, // current phase
phaseStep; // phase step
struct transition {
double
amplitude,
amplitudeStep,
frequency,
frequencyStep;
} transition;
} SineWave;
SineWave * sine_wave(double frequency, double amplitude, double rate) {
SineWave * sw = calloc(1, sizeof(SineWave));
sw->frequency = frequency, sw->amplitude = amplitude, sw->rate = rate;
return sw;
}
// close enough comparison..
// http://stackoverflow.com/a/18975072
int double_equals(double a, double b)
{
return abs(a - b) < 0.001;
}
double sine_wave_sample(SineWave * sw) {
double sample = sw->amplitude * sin(sw->phase);
sw->phase += sw->phaseStep;
if (sw->transition.frequencyStep) {
sw->frequency += sw->transition.frequencyStep;
sw->phaseStep = radians * sw->frequency / sw->rate;
if (double_equals(sw->frequency, sw->transition.frequency)){
sw->transition.frequencyStep = 0;
sw->frequency = sw->transition.frequency;
}
}
if (sw->transition.amplitudeStep) {
sw->amplitude += sw->transition.amplitudeStep;
if (double_equals(sw->amplitude, sw->transition.amplitude)) {
sw->transition.amplitudeStep = 0;
sw->amplitude = sw->transition.amplitude;
}
}
return sample;
}
void sine_wave_frequency_transition(SineWave * sw, double frequency, double duration) {
sw->transition.frequency = frequency;
sw->transition.frequencyStep = (frequency - sw->frequency) / (sw->rate * duration);
}
void sine_wave_amplitude_transition(SineWave * sw, double amplitude, double duration) {
sw->transition.amplitude = amplitude;
sw->transition.amplitudeStep = (amplitude - sw->amplitude) / (sw->rate * duration);
}
// test
int main(int argc, char ** argv) {
SineWave * mono = sine_wave(0, 0, 44100); // start with "nothing"
// transition to 500 Hz by .5 seconds.
sine_wave_frequency_transition(mono, 500, .5);
// transition to 50% amplitude by 1 second
sine_wave_amplitude_transition(mono, SHRT_MAX * .5, 1);
// 1 second of samples total
long long samples = mono->rate * 1;
short sample;
while (samples--) {
sample = sine_wave_sample(mono);
fwrite(&sample, sizeof(sample), 1, stdout);
}
return 0;
}