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