|
|
1.1 root 1: /* $Id: xpbeep.c,v 1.46 2006/05/31 05:09:02 deuce Exp $ */
2:
3: /* standard headers */
4: #include <math.h>
5:
6: #if defined(_WIN32)
7: #include <windows.h>
8: #include <mmsystem.h>
9: #elif defined(__unix__)
10: #include <fcntl.h>
11: #if SOUNDCARD_H_IN==1
12: #include <sys/soundcard.h>
13: #elif SOUNDCARD_H_IN==2
14: #include <soundcard.h>
15: #elif SOUNDCARD_H_IN==3
16: #include <linux/soundcard.h>
17: #else
18: #ifndef USE_ALSA_SOUND
19: #warning Cannot find soundcard.h
20: #endif
21: #endif
22: #ifdef USE_ALSA_SOUND
23: #include <alsa/asoundlib.h>
24: #endif
25: /* KIOCSOUND */
26: #if defined(__FreeBSD__)
27: #include <sys/kbio.h>
28: #elif defined(__linux__)
29: #include <sys/kd.h>
30: #elif defined(__solaris__)
31: #include <sys/kbio.h>
32: #include <sys/kbd.h>
33: #endif
34: #if (defined(__OpenBSD__) || defined(__NetBSD__)) && defined(HAS_MACHINE_SPKR_H)
35: #include <machine/spkr.h>
36: #elif defined(__FreeBSD__)
37: #if defined(HAS_DEV_SPEAKER_SPEAKER_H)
38: #include <dev/speaker/speaker.h>
39: #elif defined(HAS_MACHINE_SPEAKER_H)
40: #include <machine/speaker.h>
41: #endif
42: #endif
43: #endif
44:
45: /* xpdev headers */
46: #ifdef WITH_SDL
47: #include "sdlfuncs.h"
48: #endif
49: #include "genwrap.h"
50: #include "xpbeep.h"
51:
52: #define S_RATE 22050
53:
54: static BOOL sound_device_open_failed=FALSE;
55: static BOOL alsa_device_open_failed=FALSE;
56: static BOOL sdl_device_open_failed=FALSE;
57:
58: enum {
59: SOUND_DEVICE_CLOSED
60: ,SOUND_DEVICE_WIN32
61: ,SOUND_DEVICE_ALSA
62: ,SOUND_DEVICE_OSS
63: ,SOUND_DEVICE_SDL
64: };
65:
66: static int handle_type=SOUND_DEVICE_CLOSED;
67:
68: #ifdef WITH_SDL
69: static SDL_AudioSpec spec;
70: static int sdl_audio_buf_len=0;
71: static int sdl_audio_buf_pos=0;
72: static unsigned char swave[S_RATE*15/2+1];
73: static SDL_sem *sdlToneDone;
74: #endif
75:
76: #ifdef _WIN32
77: static HWAVEOUT waveOut;
78: static WAVEHDR wh;
79: static unsigned char wave[S_RATE*15/2+1];
80: #endif
81:
82: #ifdef USE_ALSA_SOUND
83: static snd_pcm_t *playback_handle;
84: #endif
85:
86: #ifdef AFMT_U8
87: static int dsp;
88: #endif
89:
90: #define WAVE_PI 3.14159265358979323846
91: #define WAVE_TPI 6.28318530717958647692
92:
93: #ifdef USE_ALSA_SOUND
94: struct alsa_api_struct {
95: int (*snd_pcm_open)
96: (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
97: int (*snd_pcm_hw_params_malloc)
98: (snd_pcm_hw_params_t **ptr);
99: int (*snd_pcm_hw_params_any)
100: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
101: int (*snd_pcm_hw_params_set_access)
102: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access);
103: int (*snd_pcm_hw_params_set_format)
104: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
105: int (*snd_pcm_hw_params_set_rate_near)
106: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
107: int (*snd_pcm_hw_params_set_channels)
108: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
109: int (*snd_pcm_hw_params)
110: (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
111: int (*snd_pcm_prepare)
112: (snd_pcm_t *pcm);
113: void (*snd_pcm_hw_params_free)
114: (snd_pcm_hw_params_t *obj);
115: int (*snd_pcm_close)
116: (snd_pcm_t *pcm);
117: snd_pcm_sframes_t (*snd_pcm_writei)
118: (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
119: };
120:
121: struct alsa_api_struct *alsa_api=NULL;
122: #endif
123:
124: /********************************************************************************/
125: /* Calculate and generate a sound wave pattern (thanks to Deuce!) */
126: /********************************************************************************/
127: void makewave(double freq, unsigned char *wave, int samples, enum WAVE_SHAPE shape)
128: {
129: int i;
130: int midpoint;
131: double inc;
132: double pos;
133: BOOL endhigh;
134:
135: midpoint=samples/2;
136: inc=8.0*atan(1.0);
137: inc *= ((double)freq / (double)S_RATE);
138:
139: for(i=0;i<samples;i++) {
140: pos=(inc*(double)i);
141: pos -= (int)(pos/WAVE_TPI)*WAVE_TPI;
142: switch(shape) {
143: case WAVE_SHAPE_SINE:
144: wave[i]=(sin (pos))*127+128;
145: break;
146: case WAVE_SHAPE_SINE_HARM:
147: wave[i]=(sin (pos))*64+128;
148: wave[i]=(sin ((inc*2)*(double)i))*24;
149: wave[i]=(sin ((inc*3)*(double)i))*16;
150: break;
151: case WAVE_SHAPE_SAWTOOTH:
152: wave[i]=(WAVE_TPI-pos)*40.5;
153: break;
154: case WAVE_SHAPE_SQUARE:
155: wave[i]=(pos<WAVE_PI)?255:0;
156: break;
157: case WAVE_SHAPE_SINE_SAW:
158: wave[i]=(((sin (pos))*127+128)+((WAVE_TPI-pos)*40.5))/2;
159: break;
160: case WAVE_SHAPE_SINE_SAW_CHORD:
161: wave[i]=(((sin (pos))*64+128)+((WAVE_TPI-pos)*6.2))/2;
162: wave[i]+=(sin ((inc/2)*(double)i))*24;
163: wave[i]+=(sin ((inc/3)*(double)i))*16;
164: break;
165: case WAVE_SHAPE_SINE_SAW_HARM:
166: wave[i]=(((sin (pos))*64+128)+((WAVE_TPI-pos)*6.2))/2;
167: wave[i]+=(sin ((inc*2)*(double)i))*24;
168: wave[i]+=(sin ((inc*3)*(double)i))*16;
169: break;
170: }
171: }
172:
173: /* Now we have a "perfect" wave...
174: * we must clean it up now to avoid click/pop
175: */
176: if(wave[samples-1]>128)
177: endhigh=TRUE;
178: else
179: endhigh=FALSE;
180: /* Completely remove the last wave fragment */
181: i=samples-1;
182: if(wave[i]!=128) {
183: for(;i>midpoint;i--) {
184: if(endhigh && wave[i]<128)
185: break;
186: if(!endhigh && wave[i]>128)
187: break;
188: wave[i]=128;
189: }
190: }
191: }
192:
193: #ifdef WITH_SDL
194: void sdl_fillbuf(void *userdata, Uint8 *stream, int len)
195: {
196: int copylen=len;
197: int maxlen=sdl_audio_buf_len-sdl_audio_buf_pos;
198:
199: /* Copy in the current buffer */
200: if(copylen>maxlen)
201: copylen=maxlen;
202: /* Fill with silence */
203: if(len>copylen)
204: memset(stream+copylen, spec.silence, len-copylen);
205: if(copylen) {
206: memcpy(stream, swave+sdl_audio_buf_pos, copylen);
207: sdl_audio_buf_pos+=copylen;
208: /* If we're done, post the semaphore */
209: if(sdl_audio_buf_pos>=sdl_audio_buf_len) {
210: sdl.SemPost(sdlToneDone);
211: sdl_audio_buf_len=0;
212: sdl_audio_buf_pos=0;
213: }
214: }
215: }
216: #endif
217:
218: BOOL xptone_open(void)
219: {
220: #ifdef _WIN32
221: WAVEFORMATEX w;
222: #endif
223:
224: #ifdef AFMT_U8
225: int format=AFMT_U8;
226: int channels=1;
227: int rate=S_RATE;
228: int fragsize=0x7fff0004;
229: #endif
230:
231: /* Already open */
232: if(handle_type!=SOUND_DEVICE_CLOSED)
233: return(TRUE);
234:
235: #ifdef WITH_SDL
236: if(!sdl_device_open_failed) {
237: if(init_sdl_audio()==-1)
238: sdl_device_open_failed=TRUE;
239: else {
240: spec.freq=22050;
241: spec.format=AUDIO_U8;
242: spec.channels=1;
243: spec.samples=256; /* Size of audio buffer */
244: spec.size=256;
245: spec.callback=sdl_fillbuf;
246: spec.userdata=NULL;
247: if(sdl.OpenAudio(&spec, NULL)==-1) {
248: sdl_device_open_failed=TRUE;
249: }
250: else {
251: sdlToneDone=sdl.SDL_CreateSemaphore(0);
252: sdl_audio_buf_len=0;
253: sdl_audio_buf_pos=0;
254: sdl.PauseAudio(FALSE);
255: handle_type=SOUND_DEVICE_SDL;
256: return(TRUE);
257: }
258: }
259: }
260: #endif
261:
262: #ifdef _WIN32
263: if(!sound_device_open_failed) {
264: w.wFormatTag = WAVE_FORMAT_PCM;
265: w.nChannels = 1;
266: w.nSamplesPerSec = S_RATE;
267: w.wBitsPerSample = 8;
268: w.nBlockAlign = (w.wBitsPerSample * w.nChannels) / 8;
269: w.nAvgBytesPerSec = w.nSamplesPerSec * w.nBlockAlign;
270:
271: if(!sound_device_open_failed && waveOutOpen(&waveOut, WAVE_MAPPER, &w, 0, 0, 0)!=MMSYSERR_NOERROR)
272: sound_device_open_failed=TRUE;
273: if(sound_device_open_failed)
274: return(FALSE);
275: memset(&wh, 0, sizeof(wh));
276: wh.lpData=wave;
277: wh.dwBufferLength=S_RATE*15/2+1;
278: if(waveOutPrepareHeader(waveOut, &wh, sizeof(wh))!=MMSYSERR_NOERROR) {
279: sound_device_open_failed=TRUE;
280: waveOutClose(waveOut);
281: return(FALSE);
282: }
283: handle_type=SOUND_DEVICE_WIN32;
284: if(!sound_device_open_failed)
285: return(TRUE);
286: }
287: #endif
288:
289: #ifdef USE_ALSA_SOUND
290: if(!alsa_device_open_failed) {
291: if(alsa_api==NULL) {
292: if(((alsa_api=(struct alsa_api_struct *)malloc(sizeof(struct alsa_api_struct)))==NULL)
293: || ((dl=dlopen("libasound.so",RTLD_LAZY))==NULL)
294: || ((alsa_api->snd_pcm_open=dlsym(dl,"snd_pcm_open"))==NULL)
295: || ((alsa_api->snd_pcm_hw_params_malloc=dlsym(dl,"snd_pcm_hw_params_malloc"))==NULL)
296: || ((alsa_api->snd_pcm_hw_params_any=dlsym(dl,"snd_pcm_hw_params_any"))==NULL)
297: || ((alsa_api->snd_pcm_hw_params_set_access=dlsym(dl,"snd_pcm_hw_params_set_access"))==NULL)
298: || ((alsa_api->snd_pcm_hw_params_set_format=dlsym(dl,"snd_pcm_hw_params_set_format"))==NULL)
299: || ((alsa_api->snd_pcm_hw_params_set_rate_near=dlsym(dl,"snd_pcm_hw_params_set_rate_near"))==NULL)
300: || ((alsa_api->snd_pcm_hw_params_set_channels=dlsym(dl,"snd_pcm_hw_params_set_channels"))==NULL)
301: || ((alsa_api->snd_pcm_hw_params=dlsym(dl,"snd_pcm_hw_params"))==NULL)
302: || ((alsa_api->snd_pcm_prepare=dlsym(dl,"snd_pcm_prepare"))==NULL)
303: || ((alsa_api->snd_pcm_hw_params_free=dlsym(dl,"snd_pcm_hw_params_free"))==NULL)
304: || ((alsa_api->snd_pcm_close=dlsym(dl,"snd_pcm_close"))==NULL)
305: || ((alsa_api->snd_pcm_writei=dlsym(dl,"snd_pcm_writei"))==NULL)
306: || ((alsa_api->=dlsym(dl,""))==NULL)) {
307: alsa_device_open_failed=TRUE;
308: }
309: if(alsa_api==NULL)
310: alsa_device_open_failed=TRUE;
311: }
312: if(alsa_api!=NULL) {
313: if((alsa_api->snd_pcm_open(&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)<0)
314: || (alsa_api->snd_pcm_hw_params_malloc(&hw_params)<0)
315: || (alsa_api->snd_pcm_hw_params_any(playback_handle, hw_params)<0)
316: || (alsa_api->snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0)
317: || (alsa_api->snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_U8) < 0)
318: || (alsa_api->snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, S_RATE, 0) < 0)
319: || (alsa_api->snd_pcm_hw_params_set_channels(playback_handle, hw_params, 1) < 0)
320: || (alsa_api->snd_pcm_hw_params(playback_handle, hw_params) < 0)
321: || (alsa_api->snd_pcm_prepare(playback_handle) < 0)) {
322: alsa_device_open_failed=TRUE;
323: if(hw_params!=NULL)
324: alsa_api->snd_pcm_hw_params_free(hw_params);
325: if(playback_handle!=NULL) {
326: alsa_api->snd_pcm_close(playback_handle);
327: playback_handle=NULL;
328: }
329: }
330: else {
331: handle_type=SOUND_DEVICE_ALSA;
332: return(TRUE);
333: }
334: }
335: }
336: #endif
337:
338: #ifdef AFMT_U8
339: if(!sound_device_open_failed) {
340: if((dsp=open("/dev/dsp",O_WRONLY,0))<0) {
341: sound_device_open_failed=TRUE;
342: }
343: else {
344: ioctl(dsp, SNDCTL_DSP_SETFRAGMENT, &fragsize);
345: if((ioctl(dsp, SNDCTL_DSP_SETFMT, &format)==-1) || format!=AFMT_U8) {
346: sound_device_open_failed=TRUE;
347: close(dsp);
348: }
349: else if((ioctl(dsp, SNDCTL_DSP_CHANNELS, &channels)==-1) || channels!=1) {
350: sound_device_open_failed=TRUE;
351: close(dsp);
352: }
353: else if((ioctl(dsp, SNDCTL_DSP_SPEED, &rate)==-1) || rate!=S_RATE) {
354: sound_device_open_failed=TRUE;
355: close(dsp);
356: }
357: }
358: }
359: if(sound_device_open_failed)
360: return(FALSE);
361: handle_type=SOUND_DEVICE_OSS;
362: if(!sound_device_open_failed)
363: return(TRUE);
364: #endif
365: return(FALSE);
366: }
367:
368: BOOL xptone_close(void)
369: {
370: #ifdef WITH_SDL
371: if(handle_type==SOUND_DEVICE_SDL) {
372: sdl.CloseAudio();
373: sdl.SDL_DestroySemaphore(sdlToneDone);
374: }
375: #endif
376:
377: #ifdef _WIN32
378: if(handle_type==SOUND_DEVICE_WIN32) {
379: waveOutClose(waveOut);
380: while(waveOutUnprepareHeader(waveOut, &wh, sizeof(wh))==WAVERR_STILLPLAYING)
381: SLEEP(1);
382: }
383: #endif
384:
385: #ifdef USE_ALSA_SOUND
386: if(handle_type==SOUND_DEVICE_ALSA)
387: alsa_api->snd_pcm_close (playback_handle);
388: #endif
389:
390: #ifdef AFMT_U8
391: if(handle_type==SOUND_DEVICE_OSS)
392: close(dsp);
393: #endif
394: handle_type=SOUND_DEVICE_CLOSED;
395: sound_device_open_failed=FALSE;
396: alsa_device_open_failed=FALSE;
397: sdl_device_open_failed=FALSE;
398:
399: return(TRUE);
400: }
401:
402: /********************************************************************************/
403: /* Play a tone through the wave/DSP output device (sound card) - Deuce */
404: /********************************************************************************/
405:
406: BOOL DLLCALL xptone(double freq, DWORD duration, enum WAVE_SHAPE shape)
407: {
408: BOOL must_close=FALSE;
409:
410: #if defined(USE_ALSA_SOUND) || defined(AFMT_U8)
411: unsigned char wave[S_RATE*15/2+1];
412: int samples;
413: #endif
414:
415: #ifdef USE_ALSA_SOUND
416: snd_pcm_hw_params_t *hw_params=NULL;
417: void *dl;
418: #endif
419:
420: #ifdef AFMT_U8
421: int wr;
422: int i;
423: #endif
424:
425: if(handle_type==SOUND_DEVICE_CLOSED) {
426: must_close=TRUE;
427: if(!xptone_open())
428: return(FALSE);
429: }
430:
431: #ifdef WITH_SDL
432: if(handle_type==SOUND_DEVICE_SDL) {
433: sdl.LockAudio();
434: sdl_audio_buf_pos=0;
435: sdl_audio_buf_len=S_RATE*duration/1000;
436: if(sdl_audio_buf_len<=S_RATE/freq*2)
437: sdl_audio_buf_len=S_RATE/freq*2;
438: makewave(freq,swave,sdl_audio_buf_len,shape);
439: sdl.UnlockAudio();
440: sdl.SemWait(sdlToneDone);
441: }
442: #endif
443:
444: #ifdef _WIN32
445: if(handle_type==SOUND_DEVICE_WIN32) {
446: wh.dwBufferLength=S_RATE*duration/1000;
447: if(wh.dwBufferLength<=S_RATE/freq*2)
448: wh.dwBufferLength=S_RATE/freq*2;
449:
450: makewave(freq,wave,wh.dwBufferLength,shape);
451:
452: if(waveOutWrite(waveOut, &wh, sizeof(wh))==MMSYSERR_NOERROR) {
453: while(!(wh.dwFlags & WHDR_DONE))
454: SLEEP(1);
455: }
456: }
457: #endif
458:
459: #if defined(USE_ALSA_SOUND) || defined(AFMT_U8)
460: if(freq<17)
461: freq=17;
462: samples=S_RATE*duration/1000;
463: if(samples<=S_RATE/freq*2)
464: samples=S_RATE/freq*2;
465: makewave(freq,wave,samples,shape);
466: #endif
467:
468: #ifdef USE_ALSA_SOUND
469: if(handle_type==SOUND_DEVICE_ALSA) {
470: alsa_api->snd_pcm_hw_params_free(hw_params);
471: if(alsa_api->snd_pcm_writei(handle, wave, samples)!=samples) {
472: /* Go back and try OSS */
473: alsa_device_open_failed=TRUE;
474: alsa_api->snd_pcm_close (handle);
475: xptone_open();
476: }
477: else {
478: if(must_close)
479: xptone_close();
480: return(TRUE);
481: }
482: }
483: #endif
484:
485: #ifdef AFMT_U8
486: if(handle_type==SOUND_DEVICE_OSS) {
487: wr=0;
488: while(wr<samples) {
489: i=write(dsp, wave+wr, samples-wr);
490: if(i>=0)
491: wr+=i;
492: }
493: if(must_close)
494: xptone_close();
495: return(TRUE);
496: }
497: #endif
498: if(must_close)
499: xptone_close();
500: return(FALSE);
501: }
502:
503: #ifdef __unix__
504: /****************************************************************************/
505: /* Generate a tone at specified frequency for specified milliseconds */
506: /* Thanks to Casey Martin (and Deuce) for this code */
507: /****************************************************************************/
508: void DLLCALL unix_beep(int freq, int dur)
509: {
510: static int console_fd=-1;
511:
512: #if (defined(__FreeBSD__) && defined(HAS_MACHINE_SPEAKER_H)) || ((defined(__OpenBSD__) || defined(__NetBSD__)) && defined(HAS_MACHINE_SPKR_H))
513: int speaker_fd=-1;
514: tone_t tone;
515:
516: speaker_fd = open("/dev/speaker", O_WRONLY|O_APPEND);
517: if(speaker_fd != -1) {
518: tone.frequency=freq;
519: tone.duration=dur/10;
520: ioctl(speaker_fd,SPKRTONE,&tone);
521: close(speaker_fd);
522: return;
523: }
524: #endif
525:
526: #if !defined(__GNU__) && !defined(__QNX__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(__CYGWIN__)
527: if(console_fd == -1)
528: console_fd = open("/dev/console", O_NOCTTY);
529:
530: if(console_fd != -1) {
531: #if defined(__solaris__)
532: ioctl(console_fd, KIOCCMD, KBD_CMD_BELL);
533: #else
534: if(freq != 0) /* Don't divide by zero */
535: ioctl(console_fd, KIOCSOUND, (int) (1193180 / freq));
536: #endif /* solaris */
537: SLEEP(dur);
538: #if defined(__solaris__)
539: ioctl(console_fd, KIOCCMD, KBD_CMD_NOBELL); /* turn off tone */
540: #else
541: ioctl(console_fd, KIOCSOUND, 0); /* turn off tone */
542: #endif /* solaris */
543: }
544: #endif
545: }
546:
547: #endif
548:
549: /********************************************************************************/
550: /* Play sound through DSP/wave device, if unsuccessful, play through PC speaker */
551: /********************************************************************************/
552: void xpbeep(double freq, DWORD duration)
553: {
554: if(xptone(freq,duration,WAVE_SHAPE_SINE_SAW_HARM))
555: return;
556:
557: #if defined(_WIN32)
558: Beep((DWORD)(freq+.5), duration);
559: #elif defined(__unix__)
560: unix_beep((int)(freq+.5),duration);
561: #endif
562: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.