]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/oal.cpp
plug demo upsells into the game event/state system
[taylor/freespace2.git] / src / sound / oal.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include <vector>
10 #include <list>
11 #include <string>
12
13 #include "pstypes.h"
14 #include "oal.h"
15 #include "oal_efx.h"
16 #include "oal_capture.h"
17 #include "cfile.h"
18 #include "sound.h"
19 #include "acm.h"
20 #include "osregistry.h"
21
22
23 static int OAL_inited = 0;
24
25 static ALCdevice *al_device = NULL;
26 static ALCcontext *al_context = NULL;
27
28
29 struct sound_buffer {
30         ALuint buf_id;          // OpenAL buffer id
31         int chan_idx;           // channel index this buffer is currently bound to
32
33         int frequency;
34         int bits_per_sample;
35         int nchannels;
36         int nseconds;
37         int nbytes;
38
39         sound_buffer() : buf_id(0), chan_idx(-1), frequency(0), bits_per_sample(0),
40                         nchannels(0), nseconds(0), nbytes(0)
41         {
42         }
43 };
44
45 static std::vector<sound_buffer> Buffers;
46
47 static std::vector<sound_channel> Channels;
48 static int channel_next_sig = 1;
49
50 extern void oal_efx_attach(ALuint source_id);
51
52
53 bool oal_check_for_errors(const char *location)
54 {
55         ALenum err = alGetError();
56
57         if (err != AL_NO_ERROR) {
58 #ifndef NDEBUG
59                 if (location) {
60                         const char *str = alGetString(err);
61
62                         nprintf(("OpenAL", "AL-ERROR (%s) => 0x%x: %s\n", location, err, (str) ? str : "??"));
63                 } else {
64                         nprintf(("OpenAL", "AL-ERROR => 0x%x: %s\n", err, alGetString(err)));
65                 }
66 #endif
67                 return true;
68         }
69
70         return false;
71 }
72
73 static void oal_init_channels()
74 {
75         const int MAX_SOURCES = 32;
76
77         Channels.reserve(MAX_SOURCES);
78
79         for (int n = 0; n < MAX_SOURCES; n++) {
80                 sound_channel n_channel;
81
82                 alGenSources(1, &n_channel.source_id);
83
84                 if ( !n_channel.source_id || (alGetError() != AL_NO_ERROR) ) {
85                         break;
86                 }
87
88                 Channels.push_back(n_channel);
89         }
90 }
91
92 int oal_init()
93 {
94         ALint ver_major = 0, ver_minor = 0;
95         std::string PlaybackDevice;
96         const char *ptr = NULL;
97
98         if (OAL_inited) {
99                 return 0;
100         }
101
102         mprintf(("Initializing OpenAL audio device...\n"));
103
104         alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &ver_major);
105         alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &ver_minor);
106
107         if ( (ver_major < 1) || (ver_minor < 1) ) {
108                 Warning(LOCATION, "Minimum supported OpenAL version is 1.1!");
109                 return -1;
110         }
111
112         ptr = os_config_read_string("Audio", "PlaybackDevice", "default");
113
114         if ( ptr && !SDL_strcasecmp(ptr, "default") ) {
115                 ptr = NULL;
116         }
117
118         al_device = alcOpenDevice(ptr);
119
120         if (al_device == NULL) {
121                 al_device = alcOpenDevice(NULL);
122
123                 if (al_device == NULL) {
124                         nprintf(("Sound", "SOUND ==> Unable to open device!\n"));
125                         nprintf(("Sound", "SOUND ==>    %s", alcGetString(al_device, alcGetError(al_device))));
126                         return -1;
127                 }
128         }
129
130         if ( alcIsExtensionPresent(al_device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE ) {
131                 ptr = alcGetString(al_device, ALC_ALL_DEVICES_SPECIFIER);
132         } else {
133                 ptr = alcGetString(al_device, ALC_DEVICE_SPECIFIER);
134         }
135
136         SDL_assert( ptr );
137
138         PlaybackDevice = ptr;
139
140         al_context = alcCreateContext(al_device, NULL);
141
142         if (al_context == NULL) {
143                 nprintf(("Sound", "SOUND ==> Unable to create context!\n"));
144                 nprintf(("Sound", "SOUND ==>    %s", alcGetString(al_device, alcGetError(al_device))));
145
146                 alcCloseDevice(al_device);
147                 al_device = NULL;
148
149                 return -1;
150         }
151
152         alcMakeContextCurrent(al_context);
153
154         OAL_inited = 1;
155
156         oal_init_channels();
157
158         Buffers.reserve(64);
159
160         mprintf(("  Vendor   : %s\n", alGetString(AL_VENDOR)));
161         mprintf(("  Renderer : %s\n", alGetString(AL_RENDERER)));
162         mprintf(("  Version  : %s\n", alGetString(AL_VERSION)));
163
164         if ( os_config_read_uint("Audio", "EFX", 0) ) {
165                 if (oal_efx_init() < 0) {
166                         mprintf(("  EFX      : Not Supported\n"));
167                 } else {
168                         mprintf(("  EFX      : Enabled\n"));
169                 }
170         } else {
171                 mprintf(("  EFX      : Disabled\n"));
172         }
173
174         mprintf(("  Channels : %d\n", Channels.size()));
175         mprintf(("  Playback device : %s\n", PlaybackDevice.c_str()));
176
177         oal_capture_init();
178
179         mprintf(("\n"));
180
181
182         oal_check_for_errors("oal_init() end");
183
184         return 0;
185 }
186
187 void oal_close()
188 {
189         if ( !OAL_inited ) {
190                 return;
191         }
192
193         oal_check_for_errors("oal_close() begin");
194
195         while ( !Channels.empty() ) {
196                 ALuint sid = Channels.back().source_id;
197
198                 alSourceStop(sid);
199
200                 alSourcei(sid, AL_BUFFER, 0);
201
202                 alDeleteSources(1, &sid);
203
204                 Channels.pop_back();
205         }
206
207         while ( !Buffers.empty() ) {
208                 ALuint bid = Buffers.back().buf_id;
209
210                 if ( alIsBuffer(bid) ) {
211                         alDeleteBuffers(1, &bid);
212                 }
213
214                 Buffers.pop_back();
215         }
216
217         oal_efx_close();
218
219         oal_check_for_errors("oal_close() end");
220
221         Channels.clear();
222         Buffers.clear();
223
224         alcMakeContextCurrent(NULL);
225         alcDestroyContext(al_context);
226         alcCloseDevice(al_device);
227
228         al_context = NULL;
229         al_device = NULL;
230
231         OAL_inited = 0;
232 }
233
234 int oal_get_channel(int sig)
235 {
236         int i;
237
238         if ( !OAL_inited ) {
239                 return -1;
240         }
241
242         int size = (int)Channels.size();
243
244         for (i = 0; i < size; i++) {
245                 if (Channels[i].sig == sig) {
246                         ALint status;
247
248                         alGetSourcei(Channels[i].source_id, AL_SOURCE_STATE, &status);
249
250                         if (status == AL_PLAYING) {
251                                 return i;
252                         } else {
253                                 return -1;
254                         }
255                 }
256         }
257
258         return -1;
259 }
260
261 int oal_get_number_channels()
262 {
263         int i;
264         ALint status;
265         int count = 0;
266
267         if ( !OAL_inited ) {
268                 return -1;
269         }
270
271         int size = (int)Channels.size();
272
273         for (i = 0; i < size; i++) {
274                 alGetSourcei(Channels[i].source_id, AL_SOURCE_STATE, &status);
275
276                 if (status == AL_PLAYING) {
277                         count++;
278                 }
279         }
280
281         return count;
282 }
283
284 void oal_stop_buffer(int sid)
285 {
286         if ( !OAL_inited ) {
287                 return;
288         }
289
290         oal_check_for_errors("oal_stop_buffer() begin");
291
292         SDL_assert( sid >= 0 );
293         SDL_assert( sid < (int)Buffers.size() );
294
295         int cid = Buffers[sid].chan_idx;
296
297         if (cid != -1) {
298                 ALuint source_id = Channels[cid].source_id;
299
300                 alSourceStop(source_id);
301                 alSourcei(source_id, AL_BUFFER, 0);
302         }
303
304         oal_check_for_errors("oal_stop_buffer() end");
305 }
306
307 void oal_stop_channel(int channel)
308 {
309         if ( !OAL_inited ) {
310                 return;
311         }
312
313         SDL_assert( channel >= 0 );
314         SDL_assert( channel < (int)Channels.size() );
315
316         if (Channels[channel].flags & SND_FLAG_EXT) {
317                 return;
318         }
319
320         oal_check_for_errors("oal_stop_channel() begin");
321
322         alSourceStop(Channels[channel].source_id);
323
324         alSourcei(Channels[channel].source_id, AL_BUFFER, 0);
325         Channels[channel].buf_idx = -1;
326
327         oal_check_for_errors("oal_stop_channel() end");
328 }
329
330 void oal_stop_channel_all()
331 {
332         if ( !OAL_inited ) {
333                 return;
334         }
335
336         int size = (int)Channels.size();
337
338         for (int i = 0; i < size; i++) {
339                 if (Channels[i].flags & SND_FLAG_EXT) {
340                         continue;
341                 }
342
343                 oal_stop_channel(i);
344         }
345 }
346
347 int oal_get_buffer_size(int sid, int *size)
348 {
349         if ( !OAL_inited ) {
350                 return -1;
351         }
352
353         if ( (sid < 0) || (sid >= (int)Buffers.size()) ) {
354                 return -1;
355         }
356
357         *size = Buffers[sid].nbytes;
358
359         return 0;
360 }
361
362 int oal_get_channel_size(int channel)
363 {
364         if ( !OAL_inited ) {
365                 return -1;
366         }
367
368         if ( (channel < 0) || (channel >= (int)Channels.size()) ) {
369                 return -1;
370         }
371
372         if (Channels[channel].buf_idx >= 0) {
373                 return Buffers[Channels[channel].buf_idx].nbytes;
374         }
375
376         return 0;
377 }
378
379 // -----------------------------------------------------------------------------
380 // Source properties *set functions
381 // -----------------------------------------------------------------------------
382
383 void oal_set_volume(int channel, float volume)
384 {
385         if ( !OAL_inited ) {
386                 return;
387         }
388
389         SDL_assert( channel >= 0 );
390         SDL_assert( channel < (int)Channels.size() );
391         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
392
393         oal_check_for_errors("oal_set_volume() begin");
394
395         alSourcef(Channels[channel].source_id, AL_GAIN, volume);
396
397         oal_check_for_errors("oal_set_volume() end");
398 }
399
400 void oal_set_pan(int channel, float pan)
401 {
402         if ( !OAL_inited ) {
403                 return;
404         }
405
406         SDL_assert( channel >= 0 );
407         SDL_assert( channel < (int)Channels.size() );
408         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
409
410         oal_check_for_errors("oal_set_pan() begin");
411
412         alSource3f(Channels[channel].source_id, AL_POSITION, pan, 0.0f, 0.0f);
413
414         oal_check_for_errors("oal_set_pan() end");
415 }
416
417 void oal_set_pitch(int channel, float pitch)
418 {
419         if ( !OAL_inited ) {
420                 return;
421         }
422
423         SDL_assert( channel >= 0 );
424         SDL_assert( channel < (int)Channels.size() );
425         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
426
427         oal_check_for_errors("oal_set_pitch() begin");
428
429         alSourcef(Channels[channel].source_id, AL_PITCH, pitch);
430
431         oal_check_for_errors("oal_set_pitch() end");
432 }
433
434 void oal_set_play_position(int channel, int position)
435 {
436         if ( !OAL_inited ) {
437                 return;
438         }
439
440         SDL_assert( channel >= 0 );
441         SDL_assert( channel < (int)Channels.size() );
442         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
443
444         oal_check_for_errors("oal_set_play_position() begin");
445
446         alSourcei(Channels[channel].source_id, AL_BYTE_OFFSET, position);
447
448         oal_check_for_errors("oal_set_play_position() end");
449 }
450
451 // -----------------------------------------------------------------------------
452
453 // -----------------------------------------------------------------------------
454 // Source properties *get functions
455 // -----------------------------------------------------------------------------
456
457 float oal_get_pitch(int channel)
458 {
459         float pitch = 1.0f;
460
461         if ( !OAL_inited ) {
462                 return 1.0f;
463         }
464
465         SDL_assert( channel >= 0 );
466         SDL_assert( channel < (int)Channels.size() );
467         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
468
469         oal_check_for_errors("oal_get_pitch() begin");
470
471         alGetSourcef(Channels[channel].source_id, AL_PITCH, &pitch);
472
473         oal_check_for_errors("oal_get_pitch() end");
474
475         return pitch;
476 }
477
478 int oal_get_play_position(int channel)
479 {
480         ALint offset = 0;
481
482         if ( !OAL_inited ) {
483                 return 0;
484         }
485
486         if (channel < 0) {
487                 return 0;
488         }
489
490         //SDL_assert( channel >= 0 );
491         SDL_assert( channel < (int)Channels.size() );
492
493         oal_check_for_errors("oal_get_play_position() begin");
494
495         alGetSourcei(Channels[channel].source_id, AL_BYTE_OFFSET, &offset);
496
497         if (alGetError() != AL_NO_ERROR) {
498                 return offset;
499         }
500
501         return 0;
502 }
503
504 // -----------------------------------------------------------------------------
505
506 int oal_is_initted()
507 {
508         return OAL_inited;
509 }
510
511 int oal_is_channel_playing(int channel)
512 {
513         ALint status;
514
515         if ( !OAL_inited ) {
516                 return 0;
517         }
518
519         SDL_assert( channel >= 0 );
520         SDL_assert( channel < (int)Channels.size() );
521
522         oal_check_for_errors("oal_is_channel_playing() begin");
523
524         alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status);
525
526         oal_check_for_errors("oal_is_channel_playing() end");
527
528         if (status == AL_PLAYING) {
529                 return 1;
530         }
531
532         return 0;
533 }
534
535 void oal_chg_loop_status(int channel, int loop)
536 {
537         if ( !OAL_inited ) {
538                 return;
539         }
540
541         SDL_assert( channel >= 0 );
542         SDL_assert( channel < (int)Channels.size() );
543         SDL_assert( !(Channels[channel].flags & SND_FLAG_EXT) );
544
545         oal_check_for_errors("oal_chg_loop_status() begin");
546
547         alSourcei(Channels[channel].source_id, AL_LOOPING, (loop) ? AL_TRUE : AL_FALSE);
548
549         if (loop) {
550                 Channels[channel].flags |= SND_FLAG_LOOPING;
551         } else {
552                 Channels[channel].flags &= ~SND_FLAG_LOOPING;
553         }
554
555         oal_check_for_errors("oal_chg_loop_status() end");
556 }
557
558 static int oal_get_free_channel_idx(float new_volume, int snd_id, int priority)
559 {
560         int     i, limit;
561         float lowest_vol = 0.0f;
562         int lowest_vol_index = -1;
563         int status;
564         int instance_count = 0; // number of instances of sound already playing
565         float lowest_instance_vol = 1.0f;
566         int lowest_instance_vol_index = -1;
567
568         int first_free_channel = -1;
569
570         if ( !OAL_inited ) {
571                 return -1;
572         }
573
574         int size = (int)Channels.size();
575
576         oal_check_for_errors("oal_get_free_channel_idx() begin");
577
578         // Look for a channel to use to play this sample
579         for (i = 0; i < size; i++) {
580                 sound_channel *chp = &Channels[i];
581                 int looping = chp->flags & SND_FLAG_LOOPING;
582
583                 if (chp->snd_id == 0) {
584                         if (first_free_channel == -1) {
585                                 first_free_channel = i;
586                         }
587
588                         continue;
589                 }
590
591                 alGetSourcei(chp->source_id, AL_SOURCE_STATE, &status);
592
593                 if ( (status != AL_PLAYING) && (status != AL_PAUSED) ) {
594                         if (first_free_channel == -1) {
595                                 first_free_channel = i;
596                         }
597
598                         continue;
599                 } else {
600                         if (chp->snd_id == snd_id) {
601                                 instance_count++;
602
603                                 if ( (chp->vol < lowest_instance_vol) && !looping ) {
604                                         lowest_instance_vol = chp->vol;
605                                         lowest_instance_vol_index = i;
606                                 }
607                         }
608
609                         if ( (chp->vol < lowest_vol) && !looping ) {
610                                 lowest_vol_index = i;
611                                 lowest_vol = chp->vol;
612                         }
613                 }
614         }
615
616         // determine the limit of concurrent instances of this sound
617         switch (priority) {
618                 case SND_PRIORITY_MUST_PLAY:
619                         limit = 100;
620                         break;
621
622                 case SND_PRIORITY_SINGLE_INSTANCE:
623                         limit = 1;
624                         break;
625
626                 case SND_PRIORITY_DOUBLE_INSTANCE:
627                         limit = 2;
628                         break;
629
630                 case SND_PRIORITY_TRIPLE_INSTANCE:
631                         limit = 3;
632                         break;
633
634                 default:
635                         Int3();                 // get Alan
636                         limit = 100;
637                         break;
638         }
639
640
641         // If we've exceeded the limit, then maybe stop the duplicate if it is lower volume
642         if (instance_count >= limit) {
643                 // If there is a lower volume duplicate, stop it.... otherwise, don't play the sound
644                 if ( (lowest_instance_vol_index >= 0) && (Channels[lowest_instance_vol_index].vol <= new_volume) ) {
645                         first_free_channel = lowest_instance_vol_index;
646                 } else {
647                         first_free_channel = -1;
648                 }
649         } else {
650                 // there is no limit barrier to play the sound, so see if we've ran out of channels
651                 if (first_free_channel == -1) {
652                         // stop the lowest volume instance to play our sound if priority demands it
653                         if ( (lowest_vol_index != -1) && (priority == SND_PRIORITY_MUST_PLAY) ) {
654                                 // Check if the lowest volume playing is less than the volume of the requested sound.
655                                 // If so, then we are going to trash the lowest volume sound.
656                                 if (Channels[lowest_vol_index].vol <= new_volume) {
657                                         first_free_channel = lowest_vol_index;
658                                 }
659                         }
660                 }
661         }
662
663         oal_check_for_errors("oal_get_free_channel_idx() end");
664
665         return first_free_channel;
666 }
667
668 // get a channel for use elsewhere (MVE playback, streaming audio, etc.)
669 sound_channel *oal_get_free_channel(float volume, int snd_id, int priority)
670 {
671         if ( !OAL_inited ) {
672                 return NULL;
673         }
674
675         int chan = oal_get_free_channel_idx(volume, snd_id, priority);
676
677         if (chan < 0) {
678                 return NULL;
679         }
680
681         SDL_assert( Channels[chan].source_id != 0 );
682
683         alSourceStop(Channels[chan].source_id);
684         alSourcei(Channels[chan].source_id, AL_BUFFER, 0);
685
686         if (Channels[chan].buf_idx >= 0) {
687                 Buffers[Channels[chan].buf_idx].chan_idx = -1;
688         }
689
690         Channels[chan].vol = volume;
691         Channels[chan].priority = priority;
692         Channels[chan].last_position = 0;
693         Channels[chan].flags = SND_FLAG_EXT;
694         Channels[chan].buf_idx = -1;
695         Channels[chan].snd_id = snd_id;
696         Channels[chan].sig = channel_next_sig++;
697
698         if (channel_next_sig < 0) {
699                 channel_next_sig = 1;
700         }
701
702         return &Channels[chan];
703 }
704
705 int oal_parse_wave(const char *filename, ubyte **dest, uint *dest_size, WAVE_chunk **header)
706 {
707         CFILE *cfp = NULL;
708         int id = 0;
709         unsigned int tag = 0, size = 0, next_chunk;
710         WAVE_chunk hdr;
711
712         if ( !OAL_inited ) {
713                 return 0;
714         }
715
716         cfp = cfopen(filename, "rb");
717
718         if (cfp == NULL) {
719                 nprintf(("Error", "Couldn't open '%s'\n", filename ));
720                 return -1;
721         }
722
723         // check for valid file type
724         id = cfread_int(cfp);
725
726         // 'RIFF'
727         if (id != 0x46464952) {
728                 nprintf(("Error", "Not a WAVE file '%s'\n", filename));
729                 cfclose(cfp);
730                 return -1;
731         }
732
733         // skip RIFF size
734         cfread_int(cfp);
735
736         // check for valid RIFF type
737         id = cfread_int(cfp);
738
739         // 'WAVE'
740         if (id != 0x45564157) {
741                 nprintf(("Error", "Not a WAVE file '%s'\n", filename));
742                 cfclose(cfp);
743                 return -1;
744         }
745
746         // parse WAVE tags
747         while ( !cfeof(cfp) ) {
748                 tag = cfread_uint(cfp);
749                 size = cfread_uint(cfp);
750
751                 next_chunk = cftell(cfp) + size;
752
753                 switch (tag) {
754                         // 'fmt '
755                         case 0x20746d66: {
756                                 hdr.code = cfread_short(cfp);
757                                 hdr.num_channels = cfread_ushort(cfp);
758                                 hdr.sample_rate = cfread_uint(cfp);
759                                 hdr.bytes_per_second = cfread_uint(cfp);
760                                 hdr.block_align = cfread_ushort(cfp);
761                                 hdr.bits_per_sample = cfread_ushort(cfp);
762
763                                 if (hdr.code != 1) {
764                                         hdr.extra_size = cfread_ushort(cfp);
765                                 }
766
767                                 (*header) = (WAVE_chunk*) malloc (sizeof(WAVE_chunk));
768                                 SDL_assert( (*header) != NULL );
769
770                                 memcpy((*header), &hdr, sizeof(WAVE_chunk));
771
772                                 if (hdr.extra_size) {
773                                         (*header)->extra_data = (ubyte*) malloc (hdr.extra_size);
774                                         SDL_assert( (*header)->extra_data != NULL );
775
776                                         cfread((*header)->extra_data, hdr.extra_size, 1, cfp);
777                                 }
778
779                                 break;
780                         }
781
782                         // 'data'
783                         case 0x61746164: {
784                                 *dest_size = size;
785
786                                 (*dest) = (ubyte*) malloc (size);
787                                 SDL_assert( (*dest) != NULL );
788
789                                 cfread((*dest), size, 1, cfp);
790
791                                 break;
792                         }
793
794                         // drop everything else
795                         default:
796                                 break;
797                 }
798
799                 cfseek(cfp, next_chunk, CF_SEEK_SET);
800         }
801
802         cfclose(cfp);
803
804         return 0;
805 }
806
807 static int oal_get_free_buffer()
808 {
809         if ( !OAL_inited ) {
810                 return -1;
811         }
812
813         int size = (int)Buffers.size();
814
815         for (int i = 0; i < size; i++) {
816                 if (Buffers[i].buf_id == 0) {
817                         return i;
818                 }
819         }
820
821         sound_buffer nbuf;
822
823         Buffers.push_back(nbuf);
824
825         return (int)(Buffers.size()-1);
826 }
827
828 int oal_load_buffer(int *sid, int *final_size, WAVE_chunk *header, sound_info *si, int flags)
829 {
830         SDL_assert( final_size != NULL );
831         SDL_assert( header != NULL );
832         SDL_assert( si != NULL );
833
834         if ( !OAL_inited ) {
835                 return 0;
836         }
837
838         int buf_idx = oal_get_free_buffer();
839
840         if (buf_idx < 0) {
841                 return -1;
842         }
843
844         *sid = buf_idx;
845
846         sound_buffer *buf = &Buffers[buf_idx];
847
848         oal_check_for_errors("oal_load_buffer() begin");
849
850         alGenBuffers(1, &buf->buf_id);
851
852         if ( !buf->buf_id ) {
853                 return -1;
854         }
855
856         ALenum format = AL_INVALID;
857         ALsizei size;
858         ALint bits, bps;
859         ALuint frequency;
860         ALvoid *data = NULL;
861
862         // the below conversion variables are only used when the wav format is not PCM.
863         ubyte *convert_buffer = NULL;           // storage for converted wav file
864         int convert_len;                                        // num bytes of converted wav file
865         uint src_bytes_used;                            // number of source bytes actually converted (should always be equal to original size)
866
867
868         switch (si->format) {
869                 case WAVE_FORMAT_PCM: {
870                         SDL_assert( si->data != NULL );
871
872                         bits = si->bits;
873                         bps  = si->avg_bytes_per_sec;
874                         size = si->size;
875
876 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
877                         // swap 16-bit sound data
878                         if (bits == 16) {
879                                 ushort *swap_tmp;
880
881                                 for (uint i=0; i<size; i=i+2) {
882                                         swap_tmp = (ushort*)(si->data + i);
883                                         *swap_tmp = INTEL_SHORT(*swap_tmp);
884                                 }
885                         }
886 #endif
887
888                         data = si->data;
889
890                         break;
891                 }
892
893                 case WAVE_FORMAT_ADPCM: {
894                         SDL_assert( si->data != NULL );
895
896                         // this ADPCM decoder decodes to 16-bit only so keep that in mind
897                         nprintf(( "Sound", "SOUND ==> converting sound from ADPCM to PCM\n" ));
898
899                         int rc = ACM_convert_ADPCM_to_PCM(header, si->data, si->size, &convert_buffer, &convert_len, &src_bytes_used, 16);
900
901                         // ACM conversion failed?
902                         if ( (rc == -1) || (src_bytes_used != si->size) ) {
903                                 alDeleteBuffers(1, &buf->buf_id);
904                                 buf->buf_id = 0;
905
906                                 if (convert_buffer != NULL) {
907                                         free(convert_buffer);
908                                 }
909
910                                 return -1;
911                         }
912
913                         bits = 16;
914                         bps  = (((si->n_channels * bits) / 8) * si->sample_rate);
915                         size = convert_len;
916                         data = convert_buffer;
917
918                         nprintf(( "Sound", "SOUND ==> Coverted sound from ADPCM to PCM successfully\n" ));
919
920                         break;
921                 }
922
923                 default:
924                         nprintf(( "Sound", "Unsupported sound encoding\n" ));
925                         alDeleteBuffers(1, &buf->buf_id);
926                         buf->buf_id = 0;
927                         return -1;
928         }
929
930         // format is now in pcm
931         frequency = si->sample_rate;
932
933         if (bits == 16) {
934                 if (si->n_channels == 2) {
935                         format = AL_FORMAT_STEREO16;
936                 } else if (si->n_channels == 1) {
937                         format = AL_FORMAT_MONO16;
938                 }
939         } else if (bits == 8) {
940                 if (si->n_channels == 2) {
941                         format = AL_FORMAT_STEREO8;
942                 } else if (si->n_channels == 1) {
943                         format = AL_FORMAT_MONO8;
944                 }
945         }
946
947         if (format == AL_INVALID) {
948                 alDeleteBuffers(1, &buf->buf_id);
949                 buf->buf_id = 0;
950
951                 if (convert_buffer != NULL) {
952                         free(convert_buffer);
953                 }
954
955                 return -1;
956         }
957
958         Snd_sram += size;
959         *final_size = size;
960
961         alBufferData(buf->buf_id, format, data, size, frequency);
962
963         buf->chan_idx = -1;
964         buf->frequency = frequency;
965         buf->bits_per_sample = bits;
966         buf->nchannels = si->n_channels;
967         buf->nseconds = size / bps;
968         buf->nbytes = size;
969
970         if (convert_buffer != NULL) {
971                 free(convert_buffer);
972         }
973
974         oal_check_for_errors("oal_load_buffer() end");
975
976         return 0;
977 }
978
979 void oal_unload_buffer(int sid)
980 {
981         if ( !OAL_inited ) {
982                 return;
983         }
984
985         if ( (sid < 0) || (sid >= (int)Buffers.size()) ) {
986                 return;
987         }
988
989         oal_check_for_errors("oal_unload_buffer() begin");
990
991         sound_buffer *buf = &Buffers[sid];
992
993         if (buf->buf_id) {
994                 if (buf->chan_idx >= 0) {
995                         alSourceStop(Channels[buf->chan_idx].source_id);
996                         alSourcei(Channels[buf->chan_idx].source_id, AL_BUFFER, 0);
997                         buf->chan_idx = -1;
998                 }
999
1000                 alDeleteBuffers(1, &buf->buf_id);
1001                 buf->buf_id = 0;
1002         }
1003
1004         oal_check_for_errors("oal_unload_buffer() end");
1005 }
1006
1007 int oal_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
1008 {
1009         if ( !OAL_inited ) {
1010                 return -1;
1011         }
1012
1013         int buf_idx = oal_get_free_buffer();
1014
1015         if (buf_idx < 0) {
1016                 return -1;
1017         }
1018
1019         sound_buffer *buf = &Buffers[buf_idx];
1020
1021         oal_check_for_errors("oal_load_buffer() begin");
1022
1023         alGenBuffers(1, &buf->buf_id);
1024
1025         if ( !buf->buf_id ) {
1026                 return -1;
1027         }
1028
1029         buf->chan_idx = -1;
1030         buf->frequency = frequency;
1031         buf->bits_per_sample = bits_per_sample;
1032         buf->nchannels = nchannels;
1033         buf->nseconds = nseconds;
1034         buf->nbytes = nseconds * (bits_per_sample / 8) * nchannels * frequency;
1035
1036         return buf_idx;
1037 }
1038
1039 int oal_lock_data(int sid, ubyte *data, int size)
1040 {
1041         if ( !OAL_inited ) {
1042                 return -1;
1043         }
1044
1045         oal_check_for_errors("oal_lock_data() begin");
1046
1047         SDL_assert( sid >= 0 );
1048         SDL_assert( sid < (int)Buffers.size() );
1049
1050         ALuint buf_id = Buffers[sid].buf_id;
1051         ALenum format;
1052
1053         if (Buffers[sid].bits_per_sample == 16) {
1054                 if (Buffers[sid].nchannels == 2) {
1055                         format = AL_FORMAT_STEREO16;
1056                 } else if (Buffers[sid].nchannels == 1) {
1057                         format = AL_FORMAT_MONO16;
1058                 } else {
1059                         return -1;
1060                 }
1061         } else if (Buffers[sid].bits_per_sample == 8) {
1062                 if (Buffers[sid].nchannels == 2) {
1063                         format = AL_FORMAT_STEREO8;
1064                 } else if (Buffers[sid].nchannels == 1) {
1065                         format = AL_FORMAT_MONO8;
1066                 } else {
1067                         return -1;
1068                 }
1069         } else {
1070                 return -1;
1071         }
1072
1073         Buffers[sid].nbytes = size;
1074
1075         alBufferData(buf_id, format, data, size, Buffers[sid].frequency);
1076
1077         if ( oal_check_for_errors("oal_lock_data() end") ) {
1078                 return -1;
1079         }
1080
1081         return 0;
1082 }
1083
1084 int oal_play(int sid, int snd_id, int priority, float volume, float pan, int flags)
1085 {
1086         if ( !OAL_inited ) {
1087                 return -1;
1088         }
1089
1090         SDL_assert( sid >= 0 );
1091         SDL_assert( sid < (int)Buffers.size() );
1092
1093         oal_check_for_errors("oal_play() begin");
1094
1095         int channel = oal_get_free_channel_idx(volume, snd_id, priority);
1096
1097         if (channel < 0) {
1098                 return -1;
1099         }
1100
1101         sound_channel *chan = &Channels[channel];
1102
1103         ALint status;
1104         alGetSourcei(chan->source_id, AL_SOURCE_STATE, &status);
1105
1106         if (status == AL_PLAYING) {
1107                 oal_stop_channel(channel);
1108         }
1109
1110         // set all the things
1111         chan->vol = volume;
1112         chan->flags = flags;
1113         chan->priority = priority;
1114         chan->last_position = 0;
1115         chan->buf_idx = sid;
1116         chan->snd_id = snd_id;
1117         chan->sig = channel_next_sig++;
1118
1119         Buffers[sid].chan_idx = channel;
1120
1121         alSource3f(chan->source_id, AL_POSITION, pan, 0.0f, -1.0f);
1122         alSource3f(chan->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1123         alSourcef(chan->source_id, AL_PITCH, 1.0f);
1124         alSourcef(chan->source_id, AL_GAIN, volume);
1125         alSourcei(chan->source_id, AL_BUFFER, Buffers[sid].buf_id);
1126 #ifdef __EMSCRIPTEN__
1127         // Grrrrr...
1128         alSourcei(chan->source_id, AL_SOURCE_RELATIVE, AL_FALSE);
1129 #else
1130         alSourcei(chan->source_id, AL_SOURCE_RELATIVE, AL_TRUE);
1131 #endif
1132         alSourcei(chan->source_id, AL_LOOPING, (flags & SND_FLAG_LOOPING) ? AL_TRUE : AL_FALSE);
1133
1134         // maybe attach source to reverb effect
1135         oal_efx_attach(chan->source_id);
1136
1137         // Actually play it
1138         alSourcePlay(chan->source_id);
1139
1140         if (channel_next_sig < 0) {
1141                 channel_next_sig = 1;
1142         }
1143
1144         oal_check_for_errors("oal_play() end");
1145
1146         return chan->sig;
1147 }
1148
1149 int oal_play_3d( int sid, int snd_id, vector *pos, vector *vel, int min, int max, int looping, float max_volume, float estimated_vol, int priority)
1150 {
1151         if ( !OAL_inited ) {
1152                 return -1;
1153         }
1154
1155         SDL_assert( sid >= 0 );
1156         SDL_assert( sid < (int)Buffers.size() );
1157
1158         oal_check_for_errors("oal_play_3d() begin");
1159
1160         int channel = oal_get_free_channel_idx(estimated_vol, snd_id, priority);
1161
1162         if (channel < 0) {
1163                 return -1;
1164         }
1165
1166         sound_channel *chan = &Channels[channel];
1167
1168         ALint status;
1169         alGetSourcei(chan->source_id, AL_SOURCE_STATE, &status);
1170
1171         if (status == AL_PLAYING) {
1172                 oal_stop_channel(channel);
1173         }
1174
1175         int flags = SND_FLAG_3D;
1176
1177         if (looping) {
1178                 flags |= SND_FLAG_LOOPING;
1179         }
1180
1181         // set all the things
1182         chan->vol = max_volume;
1183         chan->flags = flags;
1184         chan->priority = priority;
1185         chan->last_position = 0;
1186         chan->buf_idx = sid;
1187         chan->snd_id = snd_id;
1188         chan->sig = channel_next_sig++;
1189
1190         Buffers[sid].chan_idx = channel;
1191
1192         oal_update_source(channel, min, max, pos, vel);
1193
1194         alSourcef(chan->source_id, AL_PITCH, 1.0f);
1195         alSourcef(chan->source_id, AL_GAIN, max_volume);
1196         alSourcei(chan->source_id, AL_BUFFER, Buffers[sid].buf_id);
1197         alSourcei(chan->source_id, AL_SOURCE_RELATIVE, AL_FALSE);
1198         alSourcei(chan->source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE);
1199
1200         // maybe attach source to reverb effect
1201         oal_efx_attach(chan->source_id);
1202
1203         // Actually play it
1204         alSourcePlay(chan->source_id);
1205
1206         if (channel_next_sig < 0) {
1207                 channel_next_sig = 1;
1208         }
1209
1210         oal_check_for_errors("oal_play_3d() end");
1211
1212         return chan->sig;
1213 }
1214
1215 void oal_do_frame()
1216 {
1217         ALint state, current_position;
1218
1219         if ( !OAL_inited ) {
1220                 return;
1221         }
1222
1223         oal_check_for_errors("oal_do_frame() begin");
1224
1225         int size = (int)Channels.size();
1226
1227         // make sure there aren't any looping voice messages
1228         for (int i = 0; i < size; i++) {
1229                 if (Channels[i].flags & SND_FLAG_EXT) {
1230                         // streaming sources should be managed elsewhere
1231                         continue;
1232                 }
1233
1234                 if ( (Channels[i].flags & SND_FLAG_VOICE) && (Channels[i].flags & SND_FLAG_LOOPING) ) {
1235                         alGetSourcei(Channels[i].source_id, AL_SOURCE_STATE, &state);
1236
1237                         if (state != AL_PLAYING) {
1238                                 continue;
1239                         }
1240
1241                         alGetSourcei(Channels[i].source_id, AL_BYTE_OFFSET, &current_position);
1242
1243                         if (current_position != 0) {
1244                                 if (current_position < Channels[i].last_position) {
1245                                         alSourceStop(Channels[i].source_id);
1246                                 } else {
1247                                         Channels[i].last_position = current_position;
1248                                 }
1249                         }
1250                 }
1251         }
1252
1253         oal_check_for_errors("oal_do_frame() end");
1254 }
1255
1256 int oal_update_source(int channel, int min, int max, vector *pos, vector *vel)
1257 {
1258         if ( !OAL_inited ) {
1259                 return 0;
1260         }
1261
1262         if (channel < 0) {
1263                 return 0;
1264         }
1265
1266         if ( !(Channels[channel].flags & SND_FLAG_3D) ) {
1267                 return 1;
1268         }
1269
1270         ALuint source_id = Channels[channel].source_id;
1271         ALfloat rolloff = 1.0f;
1272
1273         oal_check_for_errors("oal_update_source() begin");
1274
1275         if (pos) {
1276                 alSource3f(source_id, AL_POSITION, pos->xyz.x, pos->xyz.y, -pos->xyz.z);
1277         }
1278
1279         if (vel) {
1280                 alSource3f(source_id, AL_VELOCITY, vel->xyz.x, vel->xyz.y, vel->xyz.z);
1281         } else {
1282                 alSource3f(source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1283         }
1284
1285         if (min >= 0) {
1286                 if (max <= min) {
1287                         rolloff = 0.0f;
1288                 } else {
1289                         const float MIN_GAIN = 0.05f;
1290                         float minf = i2fl(min);
1291                         float maxf = i2fl(max);
1292
1293                         // yep, just making this shit up
1294                         rolloff = (minf / (minf + (maxf - minf))) / MIN_GAIN;
1295
1296                         if (rolloff < 0.0f) {
1297                                 rolloff = 0.0f;
1298                         }
1299                 }
1300
1301                 alSourcef(source_id, AL_ROLLOFF_FACTOR, rolloff);
1302
1303                 alSourcei(source_id, AL_REFERENCE_DISTANCE, min);
1304                 alSourcei(source_id, AL_MAX_DISTANCE, max);
1305         }
1306
1307         oal_check_for_errors("oal_update_source() end");
1308
1309         return 0;
1310 }
1311
1312 int oal_update_listener(vector *pos, vector *vel, matrix *orient)
1313 {
1314         if ( !OAL_inited ) {
1315                 return 0;
1316         }
1317
1318         oal_check_for_errors("oal_update_listener() begin");
1319
1320         if (pos) {
1321                 alListener3f(AL_POSITION, pos->xyz.x, pos->xyz.y, -pos->xyz.z);
1322         }
1323
1324         if (vel) {
1325                 alListener3f(AL_VELOCITY, vel->xyz.x, vel->xyz.y, vel->xyz.z);
1326         }
1327
1328         if (orient) {
1329                 ALfloat alOrient[6];
1330
1331                 alOrient[0] =  orient->v.fvec.xyz.x;
1332                 alOrient[1] =  orient->v.fvec.xyz.y;
1333                 alOrient[2] = -orient->v.fvec.xyz.z;
1334
1335                 alOrient[3] =  orient->v.uvec.xyz.x;
1336                 alOrient[4] =  orient->v.uvec.xyz.y;
1337                 alOrient[5] = -orient->v.uvec.xyz.z;
1338
1339                 alListenerfv(AL_ORIENTATION, alOrient);
1340         }
1341
1342         oal_check_for_errors("oal_update_listener() end");
1343
1344         return 0;
1345 }