// // 1hz.exe - Generate 1PPS with sound card. // // - 1 PPS output timing is as [in]accurate as the sound card. // // - Can be used to determine accuracy (and stability) of the // crystal oscillator on the sound card. // // - For example, use a TI counter to compare a GPS 1 PPS with // the sound card 1 PPS. Collect a few minutes, hours, or even // days of data. Compute frequeny error (= phase drfit) or // frequency drift (delta f over delta t) or Allan Deviation. // // 21-Aug-2005 /tvb // #include #include void wave_init (void); void sound_init (void); void sound_send (void); void sound_done (void); int main (int argc, char *argv[]) { long duration, i; duration = (argc > 1) ? atol(argv[1]) : 10; fprintf(stderr, "duration = %ld seconds\n", duration); wave_init(); sound_init(); for (i = 0; i < duration || duration == 0; i += 1) { sound_send(); fprintf(stderr, "."); } fprintf(stderr, "\n"); sound_done(); return 0; } int sps = 44100; int points = 44100; #define MAX_SAMPLE_SIZE 44100 unsigned char wave[MAX_SAMPLE_SIZE]; void wave_init (void) { int i; for (i = 0; i < points - 1; i += 1) { wave[i] = 128; } wave[i] = 0; } // Begin Windows specific code. #include #define NBUF 3 int nbuf = NBUF; HWAVEOUT wo; WAVEFORMATEX wf; WAVEHDR wh[NBUF]; #define CHECK_MMSYSERR(s) \ if (error != MMSYSERR_NOERROR) { \ fprintf(stderr, "file %s, line %d, %s failed (error %d)\n", \ __FILE__, __LINE__, #s, error); \ exit(1); \ } // Open sound card and initialize buffer pool. void sound_init (void) { int buf, error; wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = 1; wf.wBitsPerSample = 8; wf.nSamplesPerSec = sps; wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8; wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; wf.cbSize = 0; error = waveOutOpen(&wo, 0, &wf, 0, 0, CALLBACK_NULL); if (error == MMSYSERR_NOTENABLED || error == MMSYSERR_ALLOCATED) { fprintf(stderr, "Sound card busy or not available.\n"); exit(1); } CHECK_MMSYSERR(waveOutOpen); for (buf = 0; buf < nbuf; buf += 1) { if ((wh[buf].lpData = malloc(points)) == NULL) { fprintf(stderr, "malloc failed\n"); exit(1); } wh[buf].dwBufferLength = points; wh[buf].dwFlags = 0; wh[buf].dwLoops = 0; error = waveOutPrepareHeader(wo, &wh[buf], sizeof wh); CHECK_MMSYSERR(waveOutPrepareHeader); wh[buf].dwFlags |= WHDR_DONE; } } // Send a one second wave to the sound card. void sound_send (void) { int buf, error; while (1) { for (buf = 0; buf < nbuf; buf += 1) { if (wh[buf].dwFlags & WHDR_DONE) { memcpy(wh[buf].lpData, wave, points); error = waveOutWrite(wo, &wh[buf], sizeof wh); CHECK_MMSYSERR(waveOutWrite); return; } } _sleep(100); } } // Close sound card. void sound_done (void) { int buf, error; error = waveOutReset(wo); CHECK_MMSYSERR(waveOutReset); for (buf = 0; buf < nbuf; buf += 1) { error = waveOutUnprepareHeader(wo, &wh[buf], sizeof wh); CHECK_MMSYSERR(waveOutUnprepareHeader); free(wh[buf].lpData); } error = waveOutClose(wo); CHECK_MMSYSERR(waveOutClose); }