#include #include #include #include #include int dobreak = 0; void *brkhndl = NULL; void handlesigint(int sig) { dobreak++; if (brkhndl) { snd_pcm_t *apcm = (snd_pcm_t *) brkhndl; snd_pcm_drop(apcm); } } int main(int argc, char **argv) { //PCM handle snd_pcm_t *pcm_handle; //playback stream snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; //Struct for Info about hardware & config for stream snd_pcm_hw_params_t *hwparams; //PCM Device Name, eg "plughw:0,0" or "hw:0,0". Can also use "default"? char *pcm_name; //Assignments & Allocations if (argc>1) pcm_name = strdup(argv[1]); else pcm_name = strdup("default"); snd_pcm_hw_params_alloca(&hwparams); //Open PCM if (snd_pcm_open(&pcm_handle, pcm_name, stream, 0 /* Mode. 0=blocking. Can also use SND_PCM_NONBLOCK, which returns read/write access immediately, or SND_PCM_ASYNC, which sends a SIGIO back to the program whenever a period has been processed. */) < 0) { fprintf(stderr, "Error opening PCM device %s\n", pcm_name); snd_pcm_close(pcm_handle); return -1; } //Before writing PCM data, we specify access type, sample format, # of channels, # of periods and period size. //Init the hwparams with full config space: if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) { fprintf(stderr, "Cannot configure this PCM device!\n"); snd_pcm_close(pcm_handle); return -2; } /* Can get info on configurations with: snd_pcm_hw_params_can_, snd_pcm_hw_params_is_, snd_pcm_hw_params_get_. Can test parameters (access type, buffer size, # of channels, sample format, sample rate & # of periods) with: snd_pcm_hw_params_test_ All of this is especially important with "hw" interfaces. The configuration can be restricted with: snd_pcm_hw_params_set_ */ //Let's assume 16BitLE data sampled at 44.1KHz: int rate = 44100; int exact_rate; //Sample rate returned by snd_pcm_hw_params_set_rate_near() int dir; //if exact_rate==rate, dir=0. if exact_rate>2; if (snd_pcm_hw_params_set_buffer_size(pcm_handle,hwparams,bsize) < 0) { fprintf(stderr, "Error setting buffer size. Attempting to set near %d.\n", bsize); if (snd_pcm_hw_params_set_buffer_size_near(pcm_handle,hwparams,&bsize) < 0) { fprintf(stderr, "Error setting buffer size.\n"); snd_pcm_close(pcm_handle); return -7; } } printf("Buffer is %d.\n",bsize); //Apply the configuration: if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) { fprintf(stderr, "Error setting HW params!\n"); snd_pcm_close(pcm_handle); return -8; } /* Once the device is configured, PCM data can be written. Playback starts at the first write! For Interleaved access we use: snd_pcm_sframes_t snd_pcm_writei(pcm_handle, data, numframes); which writes numframes frames from buffer data to PCM device at pcm_handle, (frame by frame?) returning the number of frames actually written. For Noninterleaved access we use: snd_pcm_frames_t snd_pcm_writen(pcm_handle, data, numframes); which writes numframes frames from buffer data to the PCM device at pcm_handle (period by period?) returning the number of frames actually written. */ if (signal(SIGINT, handlesigint) == SIG_ERR) { fprintf(stderr,"Cannot register SIGINT handler!\n"); } unsigned char *adata; int pcmreturn, l1, l2, wavelen1, wavelen2, seclen; short s1, s2; int frames; int fudge; brkhndl = (void *) pcm_handle; adata = (unsigned char *) malloc(periodsize); if (!adata) { snd_pcm_close(pcm_handle); return -9; } wavelen1 = 128; wavelen2 = 512; //Wavelength = Wavelen / Rate, Frequency = Rate / Wavelen //Therefore, required Wavelen for Frequency = Rate / Frequency if (argc>=4) { wavelen1 = (int) (exact_rate / atoi(argv[2])); wavelen2 = (int) (exact_rate / atoi(argv[3])); } else if (argc == 3) { wavelen1 = (int) (exact_rate / atoi(argv[2])); wavelen2 = wavelen1; } //Fudge factor = time for noise (seconds) * rate * size of frame / size of period if (argc >=5) { seclen = atoi(argv[4]); } else seclen = 5; // 5 seconds fudge = (int) ((seclen * exact_rate * 4) / periodsize); frames = periodsize >> 2; //4 bytes per frame for (l1 = 0; l1 < fudge; l1++) { if (dobreak) break; for (l2 = 0; l2 < frames; l2++) { if (dobreak) break; s1 = (l2 % wavelen1) * 100 - 5000; s2 = (l2 % wavelen2) * 100 - 5000; adata[4*l2] = (unsigned char) (s1 & 255); adata[4*l2+1] = (unsigned char) ((s1 >> 8) & 255); adata[4*l2+2] = (unsigned char) (s2 & 255); adata[4*l2+3] = (unsigned char) ((s2 >> 8) & 255); } while ((pcmreturn = snd_pcm_writei(pcm_handle,adata, frames)) < 0) { if (dobreak) break; snd_pcm_prepare(pcm_handle); fprintf(stderr, "<<<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>>>>>>>> \n"); } if (dobreak) break; } if (dobreak) printf("Cancelled\n"); brkhndl = NULL; snd_pcm_close(pcm_handle); if (signal(SIGINT, SIG_DFL) == SIG_ERR) { fprintf(stderr,"Cannot deregister SIGINT handler!\n"); } free(adata); return 0; }