source: abuse/tags/pd/macabuse/imlib/port/sgi/gen_drv.c @ 49

Last change on this file since 49 was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 7.7 KB
Line 
1
2#define NUM_CHANNELS 8
3#define STDOUT_FD driver_out_fd
4#define STDIN_FD  driver_in_fd
5
6
7
8#define DOUT_NAME  "/tmp/sfxdrv.signal"
9#define DIN_NAME "/tmp/sfxdrv.command"
10
11
12enum { SFXCMD_QUIT,
13       SFXCMD_REGISTER,
14       SFXCMD_UNREGISTER,
15       SFXCMD_PLAY
16     };
17
18
19class sfx_handle
20{
21  public :
22  int          shm_id;
23  void         *shm_data_pointer;
24  sfx_handle   *next; 
25  long         size;
26  int          use_count;
27} ;
28
29
30
31int driver_out_fd,driver_in_fd;
32sfx_handle *sfx_list=NULL;
33
34
35
36#define TOTAL_SIGS 29
37
38int sigs[TOTAL_SIGS]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,
39                      SIGABRT,SIGIOT,SIGBUS,SIGFPE,SIGKILL,
40                      SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,
41                      SIGTERM,SIGCHLD,SIGCONT,SIGSTOP,
42                      SIGTSTP,SIGTTIN,SIGTTOU,SIGIO,
43                      SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGPROF,
44                      SIGWINCH};
45 
46struct channel
47{
48  unsigned char *data;         // next data to be qued
49  long left;                   // how much is left to play? 
50  unsigned char volume;        // indexed into volume table
51  unsigned long add_time;      // time at which the channel started playing
52  sfx_handle *snd;             // pointer to actual sound, so delete can stop us if need be
53} channels[NUM_CHANNELS];
54
55#define uchar unsigned char
56unsigned char buf[BUF_SIZE];   // mixing buffer
57
58uchar volume_table[256*32];    // 32 volume settings
59
60// add a new sound effect into the channel list, if no free channel
61// oldest gets replaced with new sound
62void play(sfx_handle *snd, unsigned char volume)
63{
64  int i,free_channel=-1;
65  unsigned long oldest_channel=0,
66                oldest_channel_time=10000,
67                newest_channel_time=0;
68
69  for (i=0;i<NUM_CHANNELS;i++)
70  {
71    if (channels[i].data)
72    {
73      int my_time=channels[i].add_time;
74      if (my_time<oldest_channel_time)
75      {
76        oldest_channel=i;
77        oldest_channel_time=my_time;
78      }
79      if (my_time>newest_channel_time)
80        newest_channel_time=my_time;
81    } else free_channel=i;
82  }
83 
84  if (free_channel==-1)
85    free_channel=oldest_channel;
86
87  channels[free_channel].snd=snd;
88  channels[free_channel].add_time=newest_channel_time+1;
89  channels[free_channel].data=(uchar *)snd->shm_data_pointer;
90  channels[free_channel].left=snd->size;
91  channels[free_channel].volume=volume*32/128;
92}
93
94
95int output_sounds()  // return 0 if no sounds to ouput
96{
97  unsigned char *s;
98  int i,j,bytes=0; 
99 
100  signed short sums[BUF_SIZE],run_size,*sp;
101  memset(sums,0,BUF_SIZE*sizeof(short));
102  for (j=0;j<NUM_CHANNELS;j++)
103  {
104    if (channels[j].data)
105    {
106      if (channels[j].left<BUF_SIZE)    // hom many bytes will this channel run for?
107        run_size=channels[j].left;
108      else run_size=BUF_SIZE;
109
110      if (run_size>bytes)          // how many bytes to output?
111        bytes=run_size;
112     
113      // add the chanels together into a short
114      for (i=0,sp=sums;i<run_size;i++,sp++)
115      {
116        uchar cur_data=*(channels[j].data++);
117        short vol_data=volume_table[cur_data+channels[j].volume*256];
118        *sp+=vol_data-128;
119      }
120
121      if (channels[j].left<=BUF_SIZE)
122        channels[j].data=NULL;
123      else channels[j].left-=BUF_SIZE;     
124    }
125  }
126   
127  for (i=0,sp=sums,s=buf;i<BUF_SIZE;i++,s++,sp++)
128  {
129#ifdef __linux__
130    if (*sp<-128) *s=0;
131    else if (*sp>127) *s=255;
132    else *s=(unsigned char)(*sp+128);
133#else
134    if (*sp<-128) *s=((unsigned char)((signed char)-128));
135    else if (*sp>127) *s=((unsigned char)((signed char)127));
136    else *s=((unsigned char)((signed char)*sp));
137#endif
138
139  }
140
141
142  output_samples(buf,BUF_SIZE);
143
144
145  return 1;    // always say we have something, we will do blanks if nothing else
146 
147}
148
149
150
151#ifdef __sgi
152void clean_up(...)
153#else
154void clean_up(int why)      // on exit unattach all shared memory links
155#endif
156
157  while (sfx_list)
158  {
159    shmdt((char *)sfx_list->shm_data_pointer);
160    if (shmctl(sfx_list->shm_id,IPC_RMID,NULL)!=0)
161      printf("shmctl failed, why?\n");
162    sfx_handle *last=sfx_list;
163    sfx_list=sfx_list->next;
164    free(last);
165  }
166  sound_uninit();
167  unlink(DIN_NAME);
168  unlink(DOUT_NAME);
169}
170
171void die()
172{ clean_up(0);
173  exit(0);
174}
175
176
177static int sound_fd_ready_to_read(int fd)
178{
179  struct timeval tv={0,0};
180  fd_set kbd_set,ex_set;
181  FD_ZERO(&kbd_set);
182  FD_SET(fd,&kbd_set);
183  memcpy((void *)&ex_set,(void *)&kbd_set,sizeof(ex_set));
184  select(FD_SETSIZE,&kbd_set,NULL,&ex_set,&tv);                // check for exception
185  if (FD_ISSET(fd,&ex_set))
186    die();
187  return (FD_ISSET(fd,&kbd_set));
188}
189
190
191void sound_watch()
192{
193  while (1)
194  {
195    while (sound_fd_ready_to_read(STDIN_FD))
196    {
197      uchar cmd;
198      if (read(STDIN_FD,&cmd,1)!=1)
199      { die(); }
200      switch (cmd)
201      {
202        case SFXCMD_REGISTER :
203        {
204          int shm_id;
205          long size;
206          uchar return_code;
207          if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
208          { fprintf(stderr,"sndrv er1\n"); die(); }
209          if (read(STDIN_FD,&size,sizeof(size))!=sizeof(size))
210          { fprintf(stderr,"sndrv er2\n"); die(); }
211
212          sfx_handle *sfx=new sfx_handle;
213          sfx->shm_id=shm_id;
214          sfx->shm_data_pointer=shmat(shm_id,NULL,0);
215          if (!sfx->shm_data_pointer)
216          { fprintf(stderr,"Sound driver : unable to attach shared memory segment\n"); die(); }
217          sfx->size=size;
218          sfx->use_count=0;
219          sfx->next=sfx_list;
220          sfx_list=sfx;
221               
222          cmd=1;
223          if (write(STDOUT_FD,&cmd,sizeof(cmd))!=sizeof(cmd))
224          { fprintf(stderr,"sndrv er3\n"); die(); }
225
226        } break;
227        case SFXCMD_UNREGISTER :
228        {
229          int shm_id,i;
230          sfx_handle *f,*find=NULL,*last_find=NULL;
231          if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
232          { die(); }
233          for (f=sfx_list;f && !find;f=f->next)   // see if we can find the shm id in list
234          {
235            if (f->shm_id==shm_id)
236              find=f;
237            last_find=find;         // svae last link so we can remove from the list
238          }
239         
240          if (find)
241          {
242            // see if there are any sound channels playing this sound, if so stop them because
243            // memory is fixing to be deleted
244            for (int i=0;i<NUM_CHANNELS;i++)
245            {
246              if (channels[i].snd==find)
247                channels[i].data=NULL;
248            }
249            // now free the memory
250            shmdt((char *)find->shm_data_pointer);          // detach and remove shm
251            if (last_find)
252              last_find->next=find->next;           // unlink from sound list
253            else
254              sfx_list=sfx_list->next;
255          } else { fprintf(stderr,"Attempt to remove unknown sound effect\n"); die(); }
256        } break;
257
258        case SFXCMD_PLAY :
259        {
260          int shm_id,i,volume;
261          sfx_handle *f;
262          if (read(STDIN_FD,&shm_id,sizeof(shm_id))!=sizeof(shm_id))
263            die();
264          if (read(STDIN_FD,&volume,sizeof(volume))!=sizeof(volume))
265            die();       
266
267          for (f=sfx_list;f && f->shm_id!=shm_id;f=f->next);
268          if (f)
269            play(f,volume);
270          else fprintf(stderr,"sound driver : bad id to play\n");
271        } break;
272        default :     // die on unknown or DIE command
273        { die(); }
274      }
275    }
276    output_sounds();
277  }
278}
279
280
281main()
282{
283  uchar success=sound_init();    // initailize sound and send status to who ever ran us.
284  if (!success)
285  {
286    printf("-1");
287    return 0;
288  }
289
290  unlink(DIN_NAME);
291  unlink(DOUT_NAME);
292
293//  int old_mask=umask(S_IRWXU | S_IRWXG | S_IRWXO);
294  if (mkfifo(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
295  { perror("Sound driver : unable to make fifo in /tmp");
296    return 0;
297  }
298  chmod(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
299
300  if (mkfifo(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
301  { perror("Sound driver : unable to make fifo in /tmp");
302    return 0;
303  }
304
305  chmod(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
306  //umask(old_mask);
307
308  int chd=fork();
309  if (chd)
310  {
311    printf("%d\n",chd);         // tell parent the sound driver's process number
312    return 0;
313  }
314
315  driver_out_fd=open(DOUT_NAME,O_RDWR);
316  if (driver_out_fd<0)
317  { perror(DOUT_NAME);
318    exit(1);
319  }
320
321  driver_in_fd=open(DIN_NAME,O_RDWR);
322  if (driver_in_fd<0)
323  { perror(DIN_NAME);
324    exit(1);
325  }
326
327  for (int i=0;i<TOTAL_SIGS;i++)
328    signal(sigs[i],clean_up);
329
330  sound_watch();
331
332  return 0;
333}
334
335
336
Note: See TracBrowser for help on using the repository browser.