/* * reverb.c -- mono reverberation filtration * * Written and copywritten by Philip Edelbrock, 1999 * * Code may be used for non-profit use only. This code * may not be used (in part or whole) for commercial use * without a license. Please contact the author for * more information on establishing a license at: * * Philip Edelbrock * * Custom filter designs may also be arranged. * * This program uses a full-duplex OSS inteface (such as * ALSA'a) to continuously process the recording channel * (as choosen by the mixer settings) and plays the * processed audio out the pcm channel at 44.1kHz/16bit. * * To use, make the binary (a 'make reverb' will work, * but will not be optimized for speed). Choose the * recording channel in the mixer & mute it, adjust the * recording channel's gain to about 50% (adjust as needed), * adjust the PCM channel's channel and make sure it * isn't muted. Run the program! * * On a P2-266, this program takes about 13% of the CPU * when unoptimized, and 9% optimized (gcc 2.8.1). For * testing, an OEM Soundblaster Awe-64PNP was used. * * This public version is unthreaded, so no SMP support. * * Additional features (code not public): * * - stereo processing, including adjustable * cross-channel reverb * * - 2 channel input, 4 output using two sound cards for * 'rear' channel production. * * - Using a sound card with SPDIF ins and outs provides * an all digital signal path for zero quality loss * for 'professional quality' filtering. * * * Purpose/Uses: * * - Firstly, for education and entertainment * * - Easily tweakable and adjustable real-time IIR testbed * * - Cheap and easy platform for testing/proving concepts * * - Linux (or other Unix) platform offers good platform * for code performance testing and open-source * access to various APIs, include sound cards * */ #include #include #include #include #include /* Sound card interface defs and vars */ #define BUF_SIZE 4096 int audio_fd; unsigned char audio_buffer[BUF_SIZE]; /* Filter design parameters */ #define COMB_GAIN_1 (double)-0.80 #define COMB_DELAY_1 2849 #define COMB_GAIN_2 (double)-0.7 #define COMB_DELAY_2 4556 #define COMB_GAIN_3 (double)-0.6 #define COMB_DELAY_3 6522 #define COMB_GAIN_4 (double)-0.75 #define COMB_DELAY_4 3674 /* Mixing value -- Value from 0 to 1 for the ammount of reverb */ #define AMMOUNT 0.3 /* Global vars for filters */ double mem[COMB_DELAY_1]; double mem2[COMB_DELAY_2]; double mem3[COMB_DELAY_3]; double mem4[COMB_DELAY_4]; int step=0; int step2=0; int step3=0; int step4=0; double allpassmem1=0; double allpassmem2=0; /* Fill the comb histories with silence */ void initdelays(void) { int temp; for (temp=0; temp= COMB_DELAY_1) step=0; return temp; } double comb2(double sample) { double temp; mem2[step2]=sample + (COMB_GAIN_2 * mem2[(step2 + 1) % COMB_DELAY_2]); temp= mem2[(step2 + 1) % COMB_DELAY_2]; step2++; if (step2 >= COMB_DELAY_2) step2=0; return temp; } double comb3(double sample) { double temp; mem3[step3]=sample + (COMB_GAIN_3 * mem3[(step3 + 1) % COMB_DELAY_3]); temp= mem3[(step3 + 1) % COMB_DELAY_3]; step3++; if (step3 >= COMB_DELAY_3) step3=0; return temp; } double comb4(double sample) { double temp; mem4[step4]=sample + (COMB_GAIN_4 * mem4[(step4 + 1) % COMB_DELAY_4]); temp= mem4[(step4 + 1) % COMB_DELAY_4]; step4++; if (step4 >= COMB_DELAY_4) step4=0; return temp; } /* Put the filters together here */ double reverb(double sample) { return ((1 - AMMOUNT) * sample) + (AMMOUNT * allpass2( allpass1( (comb1(sample) + comb2(sample) + comb3(sample) + comb4(sample)) / 4 ) )); } /* Sound card function(s) */ int opensound(void) { /* * Open and initialize the sound card * */ int stereo = 0; /* 0=mono, 1=stereo */ int speed = 44100; int format = AFMT_U16_LE; if ((audio_fd = open("/dev/dsp", O_RDWR, 0)) == -1) { /* Opening device failed */ perror("Blah... can't open sound device."); return 1; } if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1) { /* Fatal error */ perror("SNDCTL_DSP_STEREO"); return 2; } if (stereo != 0) { perror("Doesnt support mono"); } if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1) { /* Fatal error */ perror("SNDCTL_DSP_SPEED"); return 3; } if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1) { /* Fatal error */ perror("SNDCTL_DSP_SETFMT"); return 4; } /* if (format != AFMT_S16_LE) { printf("Format not supported."); return 5; }*/ } /* Main sampling/playback loop */ int main(void) { int i,len; unsigned char audio_buffer[64]; long c; initdelays(); if (opensound()) { return 1; } while ((len = read(audio_fd, audio_buffer, 64))!=-1) { if ((len <= 0) || (len > 64)) { printf("sampling error!"); return 1;} for (i=0;i> 8) <= 0x0FF) audio_buffer[i + 1]=(c >> 8); else audio_buffer[i + 1]=255; } if (write(audio_fd, audio_buffer, 64) == -1) { return 1; } } return 0; /* (we should never get here) */ }