source: golgotha/src/i4/sound/linux/linux_sound.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 15 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 7.3 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "error/error.hh"
10#include "error/alert.hh"
11#include "sound/linux/linux_sound.hh"
12#include "loaders/wav_load.hh"
13#include "string/string.hh"
14#include "file/file.hh"
15
16#include <linux/soundcard.h>
17#include <sys/ioctl.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <string.h>
21
22enum { LINUX_SOUND_BUFFER_BITS = 11 };
23enum { LINUX_SOUND_SAMPLE_SPEED = 11025 };
24
25// Thread State Enumeration
26enum
27{
28  LINUX_SOUND_UNINITIALIZED,
29  LINUX_SOUND_RUNNING,
30  LINUX_SOUND_REQUEST_STOP,
31  LINUX_SOUND_STOPPED,
32};
33
34static sw16 volume_table[I4_SOUND_VOLUME_LEVELS][256];
35static sw32 mix_buffer[1<<LINUX_SOUND_BUFFER_BITS];
36static sw32 output_buffer[1<<LINUX_SOUND_BUFFER_BITS];
37linux_sound_class linux_sound;
38
39void linux_voice_class::play()
40{
41  index = 0;
42  active = 1;
43}
44
45void linux_voice_class::stop()
46{
47#error implement
48}
49
50
51void linux_voice_class::set_frequency(i4_frequency freq)
52{
53  linux_sound_index f(freq);
54 
55  f.value /= LINUX_SOUND_SAMPLE_SPEED;
56  increment = f;
57}
58
59
60void linux_voice_class::set_volume(i4_volume _vol)
61{
62  volume = _vol;
63
64  left_vol  = (pan<0) ? ((volume < -pan)? 0 : volume + pan) : volume;
65  right_vol = (pan<0) ? volume : ((volume < pan) ? 0 : volume - pan);
66}
67
68
69void linux_voice_class::set_pan(i4_pan _pan)
70{
71  pan = _pan;
72
73  left_vol  = (pan<0) ? ((volume < -pan)? 0 : volume + pan) : volume;
74  right_vol = (pan<0) ? volume : ((volume < pan) ? 0 : volume - pan);
75}
76
77
78void linux_sound_class::start_thread()
79{
80  if (thread_state == LINUX_SOUND_UNINITIALIZED)
81  {
82    pthread_t handle;
83    pthread_attr_t attr;
84    pthread_attr_init(&attr);
85    pthread_create(&handle, &attr, linux_sound_mixer, 0);
86
87    thread_state = LINUX_SOUND_RUNNING;
88  }
89}
90
91
92void linux_sound_class::stop_thread()
93{
94  if (thread_state != LINUX_SOUND_UNINITIALIZED)
95  {
96    if (thread_state == LINUX_SOUND_RUNNING)
97      thread_state = LINUX_SOUND_REQUEST_STOP;
98
99    while (thread_state != LINUX_SOUND_STOPPED && thread_state != LINUX_SOUND_UNINITIALIZED)
100      sched_yield();
101
102    thread_state = LINUX_SOUND_UNINITIALIZED;
103  }
104}
105
106
107void linux_sound_class::initialize_volume_table()
108{
109  for (int level=0; level<I4_SOUND_VOLUME_LEVELS; level++)
110    for (int i=0; i<256; i++)
111      volume_table[level][i] = (i-128) * level;
112}
113
114
115extern int i4_global_native_argc;
116extern char **i4_global_native_argv;
117
118
119void linux_sound_class::init()
120{
121  int i;
122
123  for (i=0; i<i4_global_native_argc; i++)
124    if (!strcmp(i4_global_native_argv[i],"-nosound"))
125      return ;
126
127#if 0
128  fd=open("/dev/mixer",O_WRONLY);
129  if (fd!=-1)
130  {
131    int vol=127;
132    ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol);
133    close(fd);
134  }
135  else
136    i4_warning("sound driver : Unable to open /dev/mixer, can't set volume\n");
137#endif
138
139  fd=open("/dev/dsp",O_WRONLY,0);
140  if (fd<0)
141  {
142    i4_warning("sound driver : Unable to open /dev/dsp, sound effects disabled\n");
143    return;
144  }
145
146  // 2 fragments of 2^LINUX_SOUND_BUFFER_BITS bytes
147  i = 0x00020000|LINUX_SOUND_BUFFER_BITS;
148  ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &i);
149
150  i = 16;     // samples are 16 bit
151  if (ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &i)<0)
152  {
153    i4_warning("SNDDRV : Sample size 16 failed, sound effects disabled\n");   
154    close(fd);
155    return;
156  }
157
158  i = LINUX_SOUND_SAMPLE_SPEED;
159  if (ioctl(fd, SNDCTL_DSP_SPEED, &i)<0)
160  {
161    i4_warning("SNDDRV : dsp_speed failed, sound effects disabled\n");   
162    close(fd);
163    return;
164  }
165
166  i = 1;     // stero
167  if (ioctl(fd, SNDCTL_DSP_STEREO, &i)<0)
168  {
169    i4_warning("SNDDRV : set stereo failed, sound effects disabled\n");   
170    close(fd);
171    return;
172  }
173
174  thread_state = LINUX_SOUND_UNINITIALIZED;
175
176  initialize_volume_table();
177
178  start_thread();
179
180  i4_sound_manager_class::init();
181}
182
183
184void linux_sound_class::load_sounds(w32 max_sounds)
185{
186  sound = new linux_sample_class[max_sounds];
187
188  i4_sound_info info;
189  i4_const_str *sounds=i4_string_man.get_array("sounds");
190 
191  for (w32 count=0; !sounds[count].null(); count++)
192  { 
193    i4_file_class *fp=i4_file_man.open(sounds[count]);
194    if (!fp)   
195      i4_alert(i4gets("file_missing"),200,&sounds[count]);
196    else
197    {
198      if (i4_load_wav(fp,info))
199      {
200        linux_sample_class *snd = &sound[count];
201
202        if (info.sample_size==1)
203        {
204          snd->data = (w8*)info.data;
205          snd->sample_rate = linux_sound_index(info.sample_rate);
206          snd->size = linux_sound_index(info.size);
207        }
208        else
209        {
210          snd->size = 0;
211          i4_alert(i4gets("bad_format"),200,&sounds[count]);
212        }
213      }
214      else
215        i4_alert(i4gets("bad_format"),200,&sounds[count]);
216      delete fp;
217    }
218  }
219
220  i4_free(sounds);
221}
222
223i4_voice_class *linux_sound_class::alloc(i4_sound_id sound_id, const sound_parameters& param)
224{
225  int i=0;
226
227  if (!sound[sound_id].data)
228    return 0;
229
230  while (i<LINUX_SOUND_NUM_VOICE && voice[i].sound)
231    i++;
232
233  if (i<LINUX_SOUND_NUM_VOICE)
234  {
235    voice[i].looping = param.looping;
236    voice[i].index = 0;
237    voice[i].active = 0;
238
239    voice[i].set_frequency(param.frequency);
240    voice[i].set_volume(param.volume);
241    voice[i].set_pan(param.pan);
242
243    voice[i].sound = &sound[sound_id];
244
245    return &voice[i];
246  }
247  else
248    return 0;
249}
250
251
252void *linux_sound_mixer(void *arg)
253{
254  w16 voc,i;
255
256  while (linux_sound.thread_state == LINUX_SOUND_RUNNING)
257  {
258    memset(mix_buffer, 0, sizeof(mix_buffer));
259    memset(output_buffer, 0, sizeof(output_buffer));
260    for (voc=0; voc<LINUX_SOUND_NUM_VOICE; voc++)
261    {
262      linux_voice_class& v(linux_sound.voice[voc]);
263
264      if (v.sound && v.active)
265      {
266        for (i=0; i<1<<(LINUX_SOUND_BUFFER_BITS-2); i++)
267        {
268          mix_buffer[i] += volume_table[v.left_vol][ v.sound->data[ w32(v.index) ] ];
269          output_buffer[i] += volume_table[v.right_vol][ v.sound->data[ w32(v.index) ] ];
270          v.index += v.increment;
271
272          if (v.index >= v.sound->size)
273          {
274            if ( !v.looping && (v.complete == 0 || v.complete(&v)) )
275            {
276              v.sound = 0;
277              break;
278            }
279            else
280              while (v.index >= v.sound->size)
281                v.index -= v.sound->size;
282          }
283        }
284      }
285    }
286    for (i=0; i<1<<(LINUX_SOUND_BUFFER_BITS-2); i++)
287    {
288      sw32 val;
289
290      val = output_buffer[i];
291      val = (w16)((val<-32768) ? -32768 : ( (val>32767)? 32767 : val ));
292      output_buffer[i] = val;
293      val = mix_buffer[i];
294      val = (w16)((val<-32768) ? -32768 : ( (val>32767)? 32767 : val ));
295      output_buffer[i] |= val<<16;
296    }
297    write(linux_sound.fd, output_buffer, 1<<LINUX_SOUND_BUFFER_BITS);
298    sched_yield();
299  }
300  linux_sound.thread_state = LINUX_SOUND_STOPPED;
301
302
303  pthread_exit(0);
304}
305
306
Note: See TracBrowser for help on using the repository browser.