/* test_digitar.c * Fri Jun 18 18:07:09 PDT 2010 Kevin Karplus * * Test fixture for testing digitar implementations. */ #include #include #include /* for calloc */ #include "digitar.h" #include "make_wav.h" #define A5 (440.) #define B5 (A5*SEMITONE*SEMITONE) #define C5 (B5*SEMITONE) #define D5 (C5*SEMITONE*SEMITONE) #define E5 (D5*SEMITONE*SEMITONE) #define F5 (E5*SEMITONE) #define G5 (F5*SEMITONE*SEMITONE) #define A0 (A5/ (1<<5)) #define B0 (B5/ (1<<5)) #define C0 (C5/ (1<<5)) #define D0 (D5/ (1<<5)) #define E0 (E5/ (1<<5)) #define F0 (F5/ (1<<5)) #define G0 (G5/ (1<<5)) #define A1 (A0*2) #define B1 (B0*2) #define C1 (C0*2) #define D1 (D0*2) #define E1 (E0*2) #define F1 (F0*2) #define G1 (G0*2) #define A2 (A0*4) #define B2 (B0*4) #define C2 (C0*4) #define D2 (D0*4) #define E2 (E0*4) #define F2 (F0*4) #define G2 (G0*4) #define A3 (A0*8) #define B3 (B0*8) #define C3 (C0*8) #define D3 (D0*8) #define E3 (E0*8) #define F3 (F0*8) #define G3 (G0*8) #define A4 (A0*16) #define B4 (B0*16) #define C4 (C0*16) #define D4 (D0*16) #define E4 (E0*16) #define F4 (F0*16) #define G4 (G0*16) #define A6 (A5*2) #define B6 (B5*2) #define C6 (C5*2) #define D6 (D5*2) #define E6 (E5*2) #define F6 (F5*2) #define G6 (G5*2) #define A7 (A5*4) #define B7 (B5*4) #define C7 (C5*4) #define D7 (D5*4) #define E7 (E5*4) #define F7 (F5*4) #define G7 (G5*4) #define A8 (A5*8) #define B8 (B5*8) #define C8 (C5*8) #define D8 (D5*8) #define E8 (E5*8) #define F8 (F5*8) #define G8 (G5*8) #define A9 (A5*16) #define B9 (B5*16) #define C9 (C5*16) #define D9 (D5*16) #define E9 (E5*16) #define F9 (F5*16) #define G9 (G5*16) int main(int argc, char * argv) { short int *next_buf ; /* where to start next note */ struct wavetable *wav; /* wavetable for note */ float ampl = 32000; /* amplitude */ int beats_per_min = 60; int beat_dur = (60*SAMPLE_RATE)/ beats_per_min; /* samples/beat */ float decay_rate; /* decays per sample */ float notes[] = {F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, 0}; // float notes[] = {C4, D4, E4, F4, C4, B4, A4, G3, F3, E3, G3, C4, 0}; int note_ptr; float freq; /* frequency in Hz, takend from notes table */ wav= alloc_table(8192); short int *buffer; #define BUF_SIZE (120*SAMPLE_RATE) /* 120 second buffer */ buffer = (short int *)calloc(BUF_SIZE, sizeof(short int)); next_buf = buffer; for (note_ptr=0; notes[note_ptr]; note_ptr++) { freq = notes[note_ptr]; /* Using a fixed length wave table does not have a uniform * timbre with frequency. * Low pitches are very mellow, but high pitches are very metallic. * Very high pitches have serious aliasing problems. * Using something that scales roughly with period seems to * work better. */ /* old, by-octave scaling, that ensures power of 2 lengths */ static int length_by_octave[] = {2048, 2048, 1024, 1024, 512, 512, 256, 128, 64, 32, 32}; /* scaling with period to get 512 long at 440Hz */ wav->length = (int)( (512*440.)/freq); if (wav->length <32) wav->length = 32; else if (wav->length >2048) wav->length = 2048; assert(wav->length <= wav->alloc_length); /* Using a wave table whose length is proportional to period * has a more uniform timbre, but the top octaves get rather quiet. */ /* Varying the decay rate with table length gets very short * quiet notes in the top octaves. * Varying the decay rate with the square of the table length, * produces a more uniform amplitude and decay length, but * the low notes seem a bit unnaturally short. * Varying with period^1.5 seems to be ok. */ decay_rate = pow(wav->length/512., 1.5) * 10. ; /* doing a fixed number of passes over the initial table * produces a more uniform timbre than doing * a constant number of decay steps, independent of table length */ assert(next_buf <= buffer+BUF_SIZE); // pluck(wav, ampl, 8192/wav->length); /* decay approx 8192 times */ pluck(wav, ampl, 8); decay_note(wav, freq, decay_rate, beat_dur, next_buf); pluck(wav, ampl/2, 8); decay_note(wav, freq*1.0034, decay_rate, beat_dur, next_buf); pluck(wav, ampl/2, 4); next_buf = decay_note(wav, freq*0.9983, decay_rate, beat_dur, next_buf); } write_wav("test_digitar.wav", next_buf-buffer, buffer, SAMPLE_RATE); free_table(&wav); return 0; }