1 /* XDigger Copyright (C) 1988-99 Alexander Lang.
2
3 XDigger is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 XDigger is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
16
17 #define USE_PIPE
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <netdb.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/ipc.h>
28 #ifdef USE_PIPE
29 #else
30 #include <sys/msg.h>
31 #endif
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <X11/Xlib.h>
36
37 #include "configure.h"
38
39 #ifdef linux
40 #include <linux/soundcard.h>
41 #endif
42 #ifdef __FreeBSD__
43 #include <sys/soundcard.h>
44 #endif
45 #ifdef SOUND_RPLAY
46 #include <rplay.h>
47 #endif
48 #ifdef SOUND_NAS
49 #include <audio/audiolib.h>
50 #include <audio/soundlib.h>
51 #endif
52 #include "xdigger.h"
53 #include "sound.h"
54
55 int ton_laenge[3];
56 unsigned char ton_buffer[3][2000];
57 int sound_device = SD_AUTO;
58 Bool soundserver_started = False;
59
60 #ifdef USE_PIPE
61 int filedes[2];
62 #else
63 int msgqid;
64 #endif
65
66 #ifdef SOUND_NAS
67 AuServer *auserver = NULL;
68 char *aureturn_status;
69 AuBucketID aubucketids[3];
70 #endif
71
StartSoundServer()72 void StartSoundServer()
73 {
74 int fork_ok;
75
76 #ifdef USE_PIPE
77 if(pipe(filedes) == -1)
78 {
79 fprintf(stderr, "%s: No more pipes.\n", progname);
80 sound_device = SD_XBELL;
81 return;
82 }
83 #else
84 struct msqid_ds buf;
85
86 msgqid = msgget(IPC_PRIVATE, IPC_CREAT);
87 if(msgqid == -1)
88 {
89 fprintf(stderr, "%s: No more private keys.\n", progname);
90 sound_device = SD_XBELL;
91 return;
92 }
93 printf("Got Key %d.\n", msgqid);
94
95 msgctl(msgqid, IPC_STAT, &buf);
96 buf.msg_perm.mode = 0600;
97 msgctl(msgqid, IPC_SET, &buf);
98 #endif
99
100 fork_ok = fork();
101 if (fork_ok == -1)
102 {
103 fprintf(stderr, "%s: fork failed.\n", progname);
104 sound_device = SD_XBELL;
105 #ifdef USE_PIPE
106 #else
107 msgctl(msgqid, IPC_RMID, NULL);
108 #endif
109 return;
110 }
111
112 if (fork_ok == 0)
113 {
114
115 /* Das ist der Soundserver */
116
117 Bool done = False;
118 int fd, i;
119 #ifdef USE_PIPE
120 #else
121 struct msgbuf msgp;
122 #endif
123
124 for (i = 1; i < pargc; i++) {strcpy(pargv[i], "");}
125 strcat(pargv[0], " (Soundserver)");
126 if (sound_device == SD_DSP) strcat(pargv[0], " (dsp)");
127 if (sound_device == SD_AUDIO) strcat(pargv[0], " (audio)");
128
129 /* strcpy(LastArgv, " (Soundserver)"); */
130
131 while (!done)
132 {
133 char ton_typ;
134
135 #ifdef USE_PIPE
136 read(filedes[0], &ton_typ ,1);
137 if((ton_typ>=0) && (ton_typ<3))
138 {
139 #else
140 if(msgrcv(msgqid, &msgp, 1, 0, 0) == -1)
141 {
142 /* if (errno != ENOMSG) */
143 /* perror(progname); */
144 fprintf(stderr, "%s: (msgrcv) %s on id %d.\n",
145 progname, strerror(errno), msgqid);
146 continue;
147 }
148
149 if(msgp.mtype == 2)
150 {
151 ton_typ = msgp.mtext[0];
152 #endif
153 #if ( defined(linux) || defined(__FreeBSD__) )
154 if (sound_device == SD_DSP)
155 {
156 int rate = TON_DSP_RATE;
157 int channels = 1;
158 int bits = 8;
159
160 fd = open("/dev/dsp", O_WRONLY, 0);
161 ioctl(fd, SOUND_PCM_WRITE_RATE, &rate);
162 ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &channels);
163 ioctl(fd, SOUND_PCM_WRITE_BITS, &bits);
164 }
165 #endif
166 if (sound_device == SD_AUDIO)
167 {
168 fd = open("/dev/audio", O_WRONLY, 0);
169 }
170
171 write(fd, ton_buffer[(int)ton_typ], ton_laenge[(int)ton_typ]);
172 close(fd);
173 }
174 else
175 done = True;
176 }
177 #if ( defined(linux) || defined(__FreeBSD__) )
178 if(sound_device == SD_DSP)
179 ioctl(fd, SNDCTL_DSP_RESET, 0);
180 #endif
181 exit(0);
182 }
183 else
184 {
185 soundserver_started = True;
186 }
187 } /* StartSoundServer */
188
189 void Create_SND_Header(unsigned char *header, unsigned long data_size)
190 {
191 int sample_rate = TON_AUDIO_RATE;
192
193 strcpy(header, ".snd");
194 header[4] = 0; header[5] = 0; header[6] = 0; header[7] = 24;
195 header[8] = data_size >> 24; header[9] = data_size >> 16;
196 header[10] = data_size >> 8; header[11] = data_size;
197 header[12] = 0; header[13] = 0; header[14] = 0; header[15] = 1;
198 header[16] = sample_rate >> 24; header[17] = sample_rate >> 16;
199 header[18] = sample_rate >> 8; header[19] = sample_rate;
200 header[20] = 0; header[21] = 0; header[22] = 0; header[23] = 1;
201 }
202
203 void Fill_TonBuffer(int ton_low, int ton_high, int rate, Bool sndheader)
204 {
205
206 int i, j, k, offset;
207 unsigned char augenblicklicherpeak;
208
209 if (sndheader) offset = 24; else offset = 0;
210
211 /* TON_SCHRITT */
212 augenblicklicherpeak=ton_low;
213 for (i=0,j=2; j>0; j--)
214 {
215 for(k=0;k<0x40;k++)
216 ton_buffer[TON_SCHRITT][offset+rate*i++/KC_FREQ] =
217 augenblicklicherpeak;
218 augenblicklicherpeak = ton_low + ton_high - augenblicklicherpeak;
219 }
220 ton_laenge[TON_SCHRITT] = rate*i/KC_FREQ;
221
222 /* TON_STEINE */
223 augenblicklicherpeak=ton_low;
224 for (i=0,j=0xfc; ; j++,j&=0xff)
225 {
226 if (j == 0x1c) break;
227 for(k=0;k<j;k++)
228 ton_buffer[TON_STEINE][offset+rate*i++/KC_FREQ] =
229 augenblicklicherpeak;
230 augenblicklicherpeak = ton_low + ton_high - augenblicklicherpeak;
231 }
232 ton_laenge[TON_STEINE] = rate*i/KC_FREQ;
233
234 /* TON_DIAMANT */
235 augenblicklicherpeak=ton_low;
236 for (i=0,j=0x40; j>0; j--)
237 {
238 for(k=0;k<j;k++)
239 ton_buffer[TON_DIAMANT][offset+rate*i++/KC_FREQ] =
240 augenblicklicherpeak;
241 augenblicklicherpeak = ton_low + ton_high - augenblicklicherpeak;
242 }
243 ton_laenge[TON_DIAMANT] = rate*i/KC_FREQ;
244
245 if (sndheader)
246 {
247 Create_SND_Header(ton_buffer[TON_SCHRITT], ton_laenge[TON_SCHRITT]);
248 Create_SND_Header(ton_buffer[TON_STEINE], ton_laenge[TON_STEINE]);
249 Create_SND_Header(ton_buffer[TON_DIAMANT], ton_laenge[TON_DIAMANT]);
250 }
251
252 } /* Fill_TonBuffer(int ton_low, int ton_high, int korrektur, Bool sndheader)*/
253
254 #if ( defined(linux) || defined (__FreeBSD__) )
255 Bool Check_DSP(Bool msg)
256 {
257 int fd;
258 int rate = TON_DSP_RATE;
259 int channels = 1;
260 int bits = 8;
261
262 fd = open("/dev/dsp", O_WRONLY, 0);
263 if ((fd == -1) ||
264 (ioctl(fd, SOUND_PCM_WRITE_RATE, &rate) == -1) ||
265 (ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &channels) == -1) ||
266 (ioctl(fd, SOUND_PCM_WRITE_BITS, &bits) == -1))
267 {
268 if (fd != -1) close(fd);
269 if (msg || debug)
270 fprintf(stderr, "%s: couldn't initialize /dev/dsp\n", progname);
271 return(False);
272 }
273 close(fd);
274 sound_device = SD_DSP;
275 if (debug) fprintf(stderr, "%s: sound is dsp\n", progname);
276 Fill_TonBuffer(TON_DSP_LOW, TON_DSP_HIGH, TON_DSP_RATE, False);
277 StartSoundServer();
278 return(True);
279 } /* Check_DSP */
280 #endif
281
282 Bool Check_SUN_Audio(Bool msg)
283 {
284 int fd;
285
286 fd = open("/dev/audio", O_WRONLY, 0);
287 if(fd == -1)
288 {
289 if (msg || debug)
290 fprintf(stderr, "%s: couldn't initialize /dev/audio\n", progname);
291 return(False);
292 }
293 close(fd);
294 sound_device = SD_AUDIO;
295 if (debug) fprintf(stderr, "%s: sound is audio\n", progname);
296 Fill_TonBuffer(TON_AUDIO_LOW, TON_AUDIO_HIGH, TON_AUDIO_RATE, False);
297 StartSoundServer();
298 return(True);
299 } /* Check_SUN_Audio */
300
301 #ifdef SOUND_NAS
302 Bool Check_NAS(Bool msg)
303 {
304 int i, sample_rate;
305
306 auserver = AuOpenServer(display_name, 0, NULL, 0, NULL, NULL);
307 if (auserver == NULL)
308 {
309 if (msg || debug)
310 fprintf(stderr, "%s: couldn't initialize NAS\n", progname);
311 return(False);
312 }
313 else
314 {
315 sample_rate = AuServerMaxSampleRate(auserver);
316 if (sample_rate > KC_FREQ) sample_rate = KC_FREQ;
317 Fill_TonBuffer(TON_NAS_LOW, TON_NAS_HIGH, sample_rate, False);
318 for (i=0; i<3; i++)
319 {
320 aubucketids[i] =
321 AuSoundCreateBucketFromData(auserver,
322 SoundCreate(SoundFileFormatSnd,
323 AuFormatLinearUnsigned8, 1,
324 sample_rate,
325 ton_laenge[i], NULL),
326 ton_buffer[i],
327 0, NULL, NULL);
328 if (aubucketids[i] == AuNone)
329 {
330 if (msg || debug)
331 fprintf(stderr, "%s: AuSoundCreateBucketFromData failed", progname);
332 AuCloseServer(auserver);
333 return(False);
334 }
335 }
336 sound_device = SD_NAS;
337 if (debug) fprintf(stderr, "%s: sound is NAS\n", progname);
338 return(True);
339 }
340 }
341 #endif
342
343 Bool Check_XBell(Bool msg)
344 {
345 sound_device = SD_XBELL;
346 if (debug) fprintf(stderr, "%s: sound is xbell\n", progname);
347 return(True);
348 }
349
350 Bool XDisplay_is_on_Localhost()
351 {
352 char localhost[1024], xhost[1024];
353 char *c;
354 /*struct hostent localhost_ent, xhost_ent;*/
355
356 gethostname(localhost, sizeof(localhost));
357 strcpy(xhost, DisplayString(display));
358 c = strchr(xhost, ':');
359 if (c) *c = 0; else xhost[0] = 0;
360 if (strlen(xhost) == 0) return(True);
361
362 strcpy(localhost, gethostbyname(localhost)->h_name);
363 strcpy(xhost, gethostbyname(xhost)->h_name);
364 if (debug)
365 fprintf(stderr, "%s: localhost=%s\n xhost=%s\n",
366 progname, localhost, xhost);
367 return(strcmp(localhost, xhost) == 0);
368 }
369
370 void sound_init()
371 {
372 if (sound_device == SD_NONE) return;
373
374 if (sound_device == SD_AUTO)
375 {
376 if (XDisplay_is_on_Localhost())
377 {
378 if (debug) fprintf(stderr, "%s: XDisplay is on localhost\n", progname);
379 #ifdef SOUND_DSP_AUDIO
380 #if ( defined(linux) || defined(__FreeBSD__) )
381 Check_DSP(False);
382 #endif
383 if (sound_device == SD_AUTO) Check_SUN_Audio(False);
384 #endif
385 }
386 else
387 {
388 if (debug) fprintf(stderr, "%s: XDisplay is not on localhost\n",
389 progname);
390 }
391 #ifdef SOUND_NAS
392 if (sound_device == SD_AUTO) Check_NAS(False);
393 #endif
394 #ifdef SOUND_RPLAY
395 #endif
396 if (sound_device == SD_AUTO) Check_XBell(False);
397 if (sound_device == SD_AUTO)
398 {
399 sound_device = SD_NONE;
400 return;
401 }
402 }
403 else
404 {
405 #ifdef SOUND_DSP_AUDIO
406 #if ( defined(linux) || defined(__FreeBSD__) )
407 if (sound_device == SD_DSP)
408 {
409 if (!Check_DSP(True)) sound_device = SD_NONE;
410 }
411 #endif
412 if (sound_device == SD_AUDIO)
413 {
414 if (!Check_SUN_Audio(True)) sound_device = SD_NONE;
415 }
416 #endif
417 #ifdef SOUND_NAS
418 if (sound_device == SD_NAS)
419 {
420 if (!Check_NAS(True)) sound_device = SD_NONE;
421 }
422 #endif
423 #ifdef SOUND_RPLAY
424 #endif
425 if (sound_device == SD_XBELL)
426 {
427 if (!Check_XBell(True)) sound_device = SD_NONE;
428 }
429 }
430 }
431
432 #ifdef SOUND_RPLAY
433 int Play_RPlay_Sound(char *soundfile, int volume)
434 {
435 int rplay_fd;
436 RPLAY *rp;
437
438 rplay_fd = rplay_open_display(); if (rplay_fd == -1) return(-1);
439 rp = rplay_create(RPLAY_PLAY); if (rp == NULL) return(-1);
440
441 rplay_set(rp, RPLAY_APPEND, RPLAY_SOUND, soundfile, RPLAY_VOLUME,
442 volume, RPLAY_PRIORITY, 255, NULL);
443 rplay(rplay_fd, rp);
444
445 rplay_close(rplay_fd);
446 rplay_destroy(rp);
447 return(0);
448 }
449 #endif
450
451 #ifdef SOUND_NAS
452 AuFlowID lastflow = -1;
453
454 void Play_NAS_Sound(char ton_typ)
455 {
456 if (auserver != NULL)
457 {
458 if ((0 <= ton_typ) && (ton_typ <= 2))
459 {
460 /*AuDestroyFlow(auserver, lastflow, NULL);*/
461 if (AuSoundPlayFromBucket(auserver, aubucketids[(int)ton_typ], AuNone,
462 AuFixedPointFromSum(1,0),
463 NULL, NULL, 1,
464 &lastflow, NULL, NULL, NULL) == NULL)
465 fprintf(stderr, "%s: AuSoundPlayFromBucket failed", progname);
466 }
467 AuFlush(auserver);
468 }
469 }
470 #endif
471
472 void sound(char ton_typ)
473 {
474 #ifdef SOUND_DSP_AUDIO
475
476 if (soundserver_started)
477 {
478 #ifdef USE_PIPE
479 write(filedes[1],&ton_typ,1);
480 #else
481 struct msgbuf msgp;
482
483 msgp.mtype = 2;
484 msgp.mtext[0] = ton_typ;
485 msgsnd(msgqid, &msgp, 1, 0);
486 #endif
487 }
488 if (sound_device == SD_XBELL)
489 if (ton_typ == TON_DIAMANT) XBell(display, -50);
490
491 #endif
492
493 #ifdef SOUND_RPLAY
494 if (sound_device == SD_RPLAY)
495 {
496 char name[256] = XDIGGER_LIB_DIR;
497 char error[20];
498
499 switch (ton_typ)
500 {
501 case TON_DIAMANT:
502 strcat(name, "/diamond.au");
503 break;
504 case TON_SCHRITT:
505 strcat(name, "/step.au");
506 break;
507 case TON_STEINE:
508 strcat(name, "/stone.au");
509 break;
510 }
511
512 /* if (rplay_host_volume(hostname, name, 255) < 0) */
513 /* if (rplay_display(name) < 0) */
514 if (Play_RPlay_Sound(name, 200) < 0)
515 {
516 sprintf(error, "%s: (rplay) ", progname);
517 rplay_perror(error);
518 fprintf(stderr, "%s: disable rplay-sound.\n", progname);
519 sound_device = SD_NONE;
520 }
521
522 }
523 #endif
524
525 #ifdef SOUND_NAS
526 if (sound_device == SD_NAS)
527 {
528 Play_NAS_Sound(ton_typ);
529 }
530 #endif
531 }
532
533 void sound_done()
534 {
535 #ifdef SOUND_DSP_AUDIO
536
537 if (soundserver_started)
538 {
539 #ifdef USE_PIPE
540 char beenden = -1;
541
542 write(filedes[1], &beenden, 1);
543 wait(0);
544 #else
545 struct msgbuf msgp;
546
547 msgp.mtype = 1;
548 msgsnd(msgqid, &msgp, 1, 0);
549 wait(0);
550 msgctl(msgqid, IPC_RMID, NULL);
551 #endif
552 }
553 #endif
554
555 #ifdef SOUND_RPLAY
556 #endif
557
558 #ifdef SOUND_NAS
559 if (sound_device == SD_NAS)
560 {
561 if (auserver != NULL)
562 {
563 int i;
564
565 for (i=0; i<3; i++)
566 AuDestroyBucket(auserver, aubucketids[i], NULL);
567 AuCloseServer(auserver);
568 }
569 }
570 #endif
571 } /* sound_done */
572