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