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