source: abuse/tags/pd/imlib/port/linux/sound.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: 9.7 KB
Line 
1#include "sound.hpp"
2#include "readwav.hpp"
3#include "specs.hpp"
4#include "sdriver.hpp"
5#include "jmalloc.hpp"
6#include "specs.hpp"
7#include "macs.hpp"
8#include <stdio.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <unistd.h>
12#include <linux/soundcard.h>
13#include <sys/ioctl.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <sys/time.h>
17#include <string.h>
18#include <signal.h>
19#include "dprint.hpp"
20#include <fcntl.h>
21#include <linux/limits.h>
22
23
24int sound_child_fd=-1,
25    sound_parent_fd=-1,
26    sound_status[2],
27    sound_child_pid;
28
29
30#define BUF_BITS 9
31#define BUF_SIZE (1<<BUF_BITS)
32#define NUM_CHANNELS 8
33#define SAMPLE_SPEED 11025
34
35int s_dev,full_pot=0,start_seq;
36
37
38unsigned char buf[BUF_SIZE];   // mixing buffer
39
40
41struct sfx
42{
43  unsigned char *data;
44  long size; 
45} ;
46 
47struct channel
48{
49  unsigned char *data;                  // next data to be qued
50  long left;                   // how much is left to play? 
51  unsigned char volume_shift; 
52  unsigned long add_time;      // time at which the channel started playing 
53} channels[NUM_CHANNELS];
54
55
56
57
58
59sfx *seffects=NULL;
60short total_effects=0;
61
62void sound_watch(int f);
63
64// add a new sound effect into the channel list, if no free channel
65// oldest gets replaced with new sound
66void play(short id, unsigned char volume)
67{
68  int i,free_channel=-1;
69  unsigned long last_channel_time=0; 
70  for (i=0;i<NUM_CHANNELS;i++)
71  {
72    if (channels[i].data)
73    {     
74      if (channels[i].add_time>last_channel_time)
75      {
76        last_channel_time=channels[i].add_time;
77        if (free_channel==-1)
78          free_channel=i;       
79      }     
80    }   
81    else free_channel=i;       
82  }
83
84  channels[free_channel].add_time=last_channel_time+1;
85  channels[free_channel].data=seffects[id].data+1024;
86  channels[free_channel].left=seffects[id].size-1024;
87  channels[free_channel].volume_shift=(127-volume)>>4;
88}
89
90int output_sounds()  // return 0 if no sounds to ouput
91{
92  unsigned char *s;
93  int i,j,bytes=0; 
94
95//  usleep((BUF_SIZE*90000/SAMPLE_SPEED)); // sleep long enough for old sample to alomst finish
96 
97 
98  signed short sums[BUF_SIZE],run_size,*sp;
99  memset(sums,0,BUF_SIZE*sizeof(short));
100  for (j=0;j<NUM_CHANNELS;j++)
101  {
102    if (channels[j].data)
103    {
104      if (channels[j].left<BUF_SIZE)    // hom many bytes will this channel run for?
105        run_size=channels[j].left;
106      else run_size=BUF_SIZE;
107
108      if (run_size>bytes)          // how many bytes to output?
109        bytes=run_size;
110     
111      // add the chanels together into a short
112      for (i=0,sp=sums;i<run_size;i++,sp++)
113        *sp+=(((signed short)*(channels[j].data++))-128)>>channels[j].volume_shift;
114
115      if (channels[j].left<=BUF_SIZE)
116        channels[j].data=NULL;
117      else channels[j].left-=BUF_SIZE;
118     
119    }
120  }
121
122
123
124   
125  for (i=0,sp=sums,s=buf;i<BUF_SIZE;i++,s++,sp++)
126    if (*sp<-128) *s=0;
127    else if (*sp>127) *s=255;
128    else *s=(unsigned char)(*sp+128);
129
130
131  write(s_dev, buf, BUF_SIZE);
132  return 1;    // always say we have something, we will do blanks if nothing else
133 
134}
135
136
137int sound_init(int argc, char **argv)
138
139  int i; 
140  char buf[PIPE_BUF];
141  for (i=1;i<argc;i++)
142  {
143    if (!strcmp(argv[i],"-nosound"))
144      return 0;
145  }
146
147  if (sound_child_fd!=-1)
148  {
149   fprintf(stderr,"Sound already initialized\n");
150    return 1;
151  }
152
153  int fds[2];
154  if (pipe(fds)==-1)
155  {
156    fprintf(stderr,"error creating pipe for sound driver\n");
157    exit(1);
158  }
159
160  if (pipe(sound_status)==-1)
161  {
162    fprintf(stderr,"error creating pipe for sound driver\n");
163    exit(1);
164  }
165
166
167  sound_child_pid=fork();
168  if (sound_child_pid)                // if we are the parent, then check that status from the child
169  {
170
171    char status;
172    read(fds[0],buf,PIPE_BUF);
173    if (buf[0])
174    {
175      sound_child_fd=fds[0];
176      sound_parent_fd=fds[1];
177      atexit(sound_uninit);          // make sure the child dies when the program ends
178      return SFX_INITIALIZED;
179    } else
180    {
181      dprintf("sound : child returned init failure\n");
182      return 0;     
183    }
184  } else
185  {
186    int fd=open("/dev/mixer",O_WRONLY);
187    if (fd!=-1)
188    {
189      int vol=127;
190      ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol);
191      close(fd);
192    } else fprintf(stderr,"sound driver : Unable to open /dev/mixer, can't set volume\n");
193
194   
195    buf[0]=0;                             // get ready to send failure
196    s_dev=open("/dev/dsp",O_WRONLY,0);
197    if (s_dev<0)
198    {
199      fprintf(stderr,"sound driver : Unable to open /dev/dsp, sound effects disabled\n");   
200      write(fds[1],buf,PIPE_BUF);
201      exit(1);
202    }
203    dprintf("sound driver : opened /dev/dsp\n");
204    i = 0x00020000|BUF_BITS;    /* 2 fragments of 2^BUF_BITS bytes */
205    ioctl(s_dev, SNDCTL_DSP_SETFRAGMENT, &i);
206
207    i = 8;     // samples are 8 bit
208    if (ioctl(s_dev, SNDCTL_DSP_SAMPLESIZE, &i)<0)
209    {
210      fprintf(stderr,"SNDDRV : Sample size 8 failed, sound effects disabled\n");   
211      close(s_dev);
212      write(fds[1],buf,PIPE_BUF);
213      exit(1);
214    }
215
216    i = SAMPLE_SPEED;
217    if (ioctl(s_dev, SNDCTL_DSP_SPEED, &i)<0)
218    {
219      fprintf(stderr,"SNDDRV : dsp_speed failed, sound effects disabled\n");   
220      close(s_dev);
221      write(fds[1],buf,PIPE_BUF);
222      exit(1);
223    }
224
225    i = 0;     // no stero
226    if (ioctl(s_dev, SNDCTL_DSP_STEREO, &i)<0)
227    {
228      fprintf(stderr,"SNDDRV : Sample size 8 failed, sound effects disabled\n");   
229      close(s_dev);
230      write(fds[1],buf,PIPE_BUF);
231      exit(1);
232    }
233
234   
235    for (i=0;i<NUM_CHANNELS;i++)    // clear all the sound channels
236      channels[i].data=NULL; 
237
238
239    buf[0]=1;
240    write(fds[1],buf,PIPE_BUF);        // send a success signal to parent
241    sound_child_fd=fds[0];
242    sound_parent_fd=fds[1];
243    sound_watch(sound_child_fd);
244  }
245  CHECK(0);                         // should never get here!
246  return 0;                         
247}
248
249
250int sound_fd_ready_to_read(int fd)
251{
252  struct timeval tv={0,0};
253  fd_set kbd_set,ex_set;
254  FD_ZERO(&kbd_set);
255  FD_SET(fd,&kbd_set);
256  memcpy((void *)&ex_set,(void *)&kbd_set,sizeof(ex_set));
257  select(FD_SETSIZE,&kbd_set,NULL,&ex_set,&tv);                // check for exception
258  return (FD_ISSET(fd,&kbd_set) || FD_ISSET(fd,&ex_set));
259}
260
261
262void sound_quit(int client_fd)
263{
264  close(sound_parent_fd);
265  close(sound_child_fd);
266  close(sound_status[0]);
267  close(sound_status[1]);
268  close(s_dev);
269  exit(0); 
270}
271
272short new_id()
273{
274  int i;
275  for (i=0;i<total_effects;i++)
276    if (seffects[i].size==0)
277      return i;
278  i=total_effects; 
279  total_effects++; 
280  seffects=(sfx *)realloc(seffects,sizeof(sfx)*(total_effects));
281  seffects[i].size=0; 
282  return i; 
283}
284
285
286void sound_watch(int f)
287{
288  int wait=0;
289  char fn[200];
290  while (1)
291  {   
292    if (output_sounds())
293      wait=0;
294    else wait=1;   
295
296    if (wait || sound_fd_ready_to_read(f))    // is there a command waiting?
297    {
298      unsigned char cmd;
299
300      int status=read(f,&cmd,1);
301     
302      if (status!=1)
303      { sound_quit(f); }
304     
305      switch (cmd)
306      {
307        case SDRIVER_QUIT : sound_quit(f); break;
308        case SDRIVER_LOAD :
309        {         
310          short id=new_id();
311          unsigned short sl;
312          read(f,&sl,2);
313          read(f,fn,sl);
314          long sample_speed;
315          seffects[id].data=(unsigned char *)read_wav(fn,sample_speed,seffects[id].size);
316          write(sound_status[1],&id,2);
317        } break;
318        case SDRIVER_UNLOAD :
319        {
320          short id;     
321          read(f,&id,2);
322          if (id>=total_effects || !seffects[id].size)
323          {
324            fprintf(stderr,"SNDDRV : bad unload sound id %d\n",id);
325            sound_quit(f);
326          }
327          free(seffects[id].data);
328          seffects[id].size=0; 
329        } break;       
330        case SDRIVER_PLAY :
331        {
332          unsigned char vol;
333          read(f,&vol,1);         
334
335          short id;     
336          read(f,&id,2);
337          if (id>=total_effects || !seffects[id].size)
338          {
339            fprintf(stderr,"SNDDRV : bad play sound id %d\n",id);
340            sound_quit(f);
341          }
342          play(id,vol);
343        } break;
344        default :
345          fprintf(stderr,"SNDDRV : Bad command %d\n",cmd);
346          sound_quit(f);
347          break;
348         
349      }         
350    }     
351  }
352}
353
354
355sound_effect::sound_effect(char *filename)
356{
357  long rate;   
358  short id; 
359  if (sound_child_fd>=0)
360  {   
361    unsigned char cmd=SDRIVER_LOAD;   
362    write(sound_parent_fd,&cmd,1);
363    unsigned short string_length=strlen(filename)+1;
364    write(sound_parent_fd,&string_length,2);
365    write(sound_parent_fd,filename,string_length);
366    read(sound_status[0],&id,2);
367    size=(long)id;   
368  } 
369}
370
371
372sound_effect::~sound_effect()
373{
374  short id; 
375  if (sound_child_fd>=0)
376  {
377    unsigned char cmd=SDRIVER_UNLOAD;   // tell the driver to unload the sound
378    write(sound_parent_fd,&cmd,1);   
379    id=(short)size;
380    write(sound_parent_fd,&id,2);   
381  }
382}
383
384
385void sound_effect::play(int volume, int pitch, int panpot)
386
387  if (sound_child_fd>=0)
388  {   
389    unsigned char cmd=SDRIVER_PLAY;
390    write(sound_parent_fd,&cmd,1);   
391
392    unsigned char vol=(unsigned char)volume;
393    write(sound_parent_fd,&vol,1);   
394
395    short id=(short)size;
396    write(sound_parent_fd,&id,2);
397  }
398}
399
400void sound_uninit()         // called by parent
401{
402  if (sound_child_fd>=0)    // mkae sure the child has been forked
403  {
404    char cmd=SDRIVER_QUIT;
405    write(sound_parent_fd,&cmd,1);
406    close(sound_parent_fd);
407    close(sound_child_fd);
408    close(sound_status[0]);
409    close(sound_status[1]);
410    sound_child_fd=-1;
411  }
412}
413
414
415song::song(char *filename)
416{
417  data=NULL;
418  Name=strcpy((char *)jmalloc(strlen(filename)+1,"song name"),filename);
419  song_id=0;
420}
421
422song::~song()
423{
424  if (playing())
425    stop(); 
426  if (data) jfree(data);
427  jfree(Name); 
428
429
430void song::play(unsigned char volume)
431{
432  printf("play song %s, volume %d\n",name(),volume); 
433  song_id=1; 
434}
435
436
437void song::stop(long fadeout_time)                                       // time in ms
438{
439  printf("stop song %s, fade timeout %d\n",name(),fadeout_time);
440  song_id=0;
441 
442}
443
444int song::playing()
445{
446  return song_id; 
447}
448
449
450
451void set_music_volume(int volume)                  // 0...127
452{
453
454}
455
456
457
458
Note: See TracBrowser for help on using the repository browser.