00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022
00023 #ifndef PENTAGRAM // Exult only at this stage.
00024
00025
00026 #include <SDL_audio.h>
00027 #include <SDL_timer.h>
00028
00029
00030 #include "Audio.h"
00031 #include "Configuration.h"
00032 #include "Flex.h"
00033 #include "conv.h"
00034 #include "exult.h"
00035 #include "fnames.h"
00036 #include "game.h"
00037 #include "utils.h"
00038
00039 #if !defined(ALPHA_LINUX_CXX)
00040 #ifndef UNDER_CE
00041 # include <csignal>
00042 #endif
00043 # include <cstdio>
00044 # include <cstdlib>
00045 # include <cstring>
00046 # include <iostream>
00047 #endif
00048 #ifndef UNDER_CE
00049 #include <fcntl.h>
00050 #include <unistd.h>
00051 #endif
00052
00053 #if defined(MACOS)
00054 # include <stat.h>
00055 #elif !defined(UNDER_CE)
00056 # include <sys/stat.h>
00057 # include <sys/types.h>
00058 #endif
00059
00060
00061
00062
00063 #ifndef UNDER_CE
00064 using std::cerr;
00065 using std::cout;
00066 using std::endl;
00067 using std::exit;
00068 using std::memcpy;
00069 using std::memset;
00070 using std::string;
00071 using std::strncmp;
00072 using std::vector;
00073 #endif
00074
00075
00076 #ifndef min
00077 using std::min;
00078 #endif
00079 #ifndef max
00080 using std::max;
00081 #endif
00082
00083 #define TRAILING_VOC_SLOP 32
00084 #define LEADING_VOC_SLOP 32
00085
00086
00087 struct Chunk
00088 {
00089 size_t length;
00090 uint8 *data;
00091 Chunk(size_t l, uint8 *d) : length(l),data(d) {}
00092 };
00093
00094 static size_t calc_sample_buffer(uint16 _samplerate);
00095 static uint8 *chunks_to_block(vector<Chunk> &chunks);
00096 static sint16 *resample_new(uint8 *sourcedata,
00097 size_t sourcelen, size_t &destlen,
00098 int current_rate, int wanted_rate);
00099 static sint16 *resample_new_mono(uint8 *sourcedata,
00100 size_t sourcelen, size_t &destlen,
00101 int current_rate, int wanted_rate);
00102 static void resample(uint8 *sourcedata, uint8 **destdata,
00103 size_t sourcelen, size_t *destlen,
00104 int current_rate, int wanted_rate);
00105 static void decode_ADPCM_4(uint8* inBuf,
00106 int bufSize,
00107 uint8* outBuf,
00108 int& reference,
00109 int& scale);
00110
00111 Audio *Audio::self = 0;
00112 int *Audio::bg2si_sfxs = 0;
00113
00114
00115
00116
00117
00118
00119
00120
00121 class CubicInterpolator {
00122 protected:
00123 int x0, x1, x2, x3;
00124 int a, b, c, d;
00125
00126 public:
00127 CubicInterpolator(int a0, int a1, int a2, int a3) : x0(a0), x1(a1), x2(a2), x3(a3)
00128 {
00129 updateCoefficients();
00130 }
00131
00132 CubicInterpolator(int a1, int a2, int a3) : x0(2*a1-a2), x1(a1), x2(a2), x3(a3)
00133 {
00134
00135 updateCoefficients();
00136 }
00137
00138 inline void feedData()
00139 {
00140 x0 = x1;
00141 x1 = x2;
00142 x2 = x3;
00143 x3 = 2*x2-x1;
00144 updateCoefficients();
00145 }
00146
00147 inline void feedData(int xNew)
00148 {
00149 x0 = x1;
00150 x1 = x2;
00151 x2 = x3;
00152 x3 = xNew;
00153 updateCoefficients();
00154 }
00155
00156
00157 inline int interpolate(uint32 fp_pos)
00158 {
00159 int result = 0;
00160 int t = fp_pos >> 8;
00161 result = (a*t + b) >> 8;
00162 result = (result * t + c) >> 8;
00163 result = (result * t + d) >> 8;
00164 result = (result/3 + 1) >> 1;
00165
00166 return result;
00167 }
00168
00169 protected:
00170 inline void updateCoefficients()
00171 {
00172 a = ((-x0*2)+(x1*5)-(x2*4)+x3);
00173 b = ((x0+x2-(2*x1))*6) << 8;
00174 c = ((-4*x0)+x1+(x2*4)-x3) << 8;
00175 d = (x1*6) << 8;
00176 }
00177 };
00178
00179
00180
00181
00182
00183
00184 class SFX_cached
00185 {
00186 int num;
00187 uint8 *buf;
00188
00189 uint32 len;
00190 SFX_cached *next;
00191 public:
00192 friend class Audio;
00193 SFX_cached(int sn, uint8 *b, uint32 l, SFX_cached *oldhead)
00194 : num(sn), len(l), next(oldhead)
00195 {
00196 buf = new uint8[l];
00197 memcpy(buf, b, l);
00198
00199 }
00200 ~SFX_cached()
00201 {
00202 delete [] buf;
00203 }
00204 };
00205
00206
00207 void Audio::Init(void)
00208 {
00209
00210 if (!self)
00211 {
00212 self = new Audio();
00213 #ifdef UNDER_CE
00214 self->Init(SAMPLERATE/2,1);
00215 #else
00216 self->Init(SAMPLERATE,2);
00217 #endif
00218 }
00219 }
00220
00221 void Audio::Destroy(void)
00222 {
00223 delete self;
00224 self = 0;
00225 }
00226
00227 Audio *Audio::get_ptr(void)
00228 {
00229
00230
00231 assert(self != NULL);
00232
00233 return self;
00234 }
00235
00236
00237 Audio::Audio() :
00238 truthful_(false),speech_enabled(true), music_enabled(true),
00239 effects_enabled(true), SDL_open(false),midi(0), sfxs(0),
00240 sfx_file(0), initialized(false)
00241 {
00242 assert(self == NULL);
00243
00244 string s;
00245
00246 config->value("config/audio/enabled",s,"yes");
00247 audio_enabled = (s!="no");
00248 config->set("config/audio/enabled", audio_enabled?"yes":"no",true);
00249
00250 config->value("config/audio/speech/enabled",s,"yes");
00251 speech_enabled = (s!="no");
00252 config->value("config/audio/midi/enabled",s,"---");
00253 music_enabled = (s!="no");
00254 config->value("config/audio/effects/enabled",s,"---");
00255 effects_enabled = (s!="no");
00256 config->value("config/audio/midi/looping",s,"yes");
00257 allow_music_looping = (s!="no");
00258
00259 midi = 0;
00260 }
00261
00262 void Audio::Init(int _samplerate,int _channels)
00263 {
00264 if (!audio_enabled) return;
00265
00266
00267 uint32 _buffering_unit=calc_sample_buffer(_samplerate);
00268 build_speech_vector();
00269
00270 delete midi;
00271 midi=0;
00272
00273
00274 if(SDL_open)
00275 SDL_QuitSubSystem(SDL_INIT_AUDIO);
00276
00277
00278 SDL_InitSubSystem(SDL_INIT_AUDIO);
00279
00280
00281
00282 if ( Mix_OpenAudio(_samplerate, AUDIO_S16SYS, _channels, _buffering_unit) < 0 )
00283 {
00284 cerr << "Couldn't open audio: " << Mix_GetError() << endl;
00285 audio_enabled = false;
00286 return;
00287 }
00288 int art_freq;
00289 Uint16 art_format;
00290 int art_channels;
00291
00292 Mix_QuerySpec(&art_freq,&art_format,&art_channels);
00293
00294 actual.freq = art_freq;
00295 actual.format = art_format;
00296 actual.channels = art_channels;
00297
00298 #ifdef DEBUG
00299 cout << "Audio requested frequency " << _samplerate << ", channels " << _channels << endl;
00300 cout << "Audio actual frequency " << actual.freq << ", channels " << (int) actual.channels << endl;
00301 #endif
00302
00303
00304
00305 Mix_ChannelFinished(channel_complete_callback);
00306
00307
00308 Mix_Pause(-1);
00309
00310 SDL_open=true;
00311
00312 midi=new MyMidiPlayer();
00313
00314 COUT("Audio initialisation OK");
00315
00316 initialized = true;
00317
00318 }
00319
00320
00321
00322 void Audio::channel_complete_callback(int chan)
00323 {
00324 Mix_Chunk *done_chunk = Mix_GetChunk(chan);
00325 Uint8 *chunkbuf=NULL;
00326
00327
00328
00329 if(done_chunk->allocated == 0)
00330 chunkbuf = done_chunk->abuf;
00331
00332 Mix_FreeChunk(done_chunk);
00333
00334
00335 if(chunkbuf)
00336 delete[] chunkbuf;
00337 }
00338
00339 bool Audio::can_sfx(const std::string &game) const
00340 {
00341 string s;
00342 string d = "config/disk/game/" + game + "/waves";
00343 config->value(d.c_str(), s, "---");
00344 if (s != "---" && U7exists(s.c_str()))
00345 return true;
00346
00347
00348 d = "<DATA>/" + s;
00349 if (U7exists(d.c_str()))
00350 return true;
00351
00352 #ifdef ENABLE_MIDISFX
00353 if (U7exists("<DATA>/midisfx.flx"))
00354 return true;
00355 #endif
00356
00357 return false;
00358 }
00359
00360 void Audio::Init_sfx()
00361 {
00362 if (sfx_file)
00363 delete sfx_file;
00364
00365 if (Game::get_game_type() == SERPENT_ISLE)
00366 bg2si_sfxs = bgconv;
00367 else
00368 bg2si_sfxs = 0;
00369
00370 string s;
00371 string d = "config/disk/game/" + Game::get_gametitle() + "/waves";
00372 config->value(d.c_str(), s, "---");
00373 if (s != "---")
00374 {
00375 if (!U7exists(s.c_str()))
00376 {
00377 d = "<DATA>/" + s;
00378 if (!U7exists(d.c_str()))
00379 {
00380 cerr << "Digital SFX's file specified: " << s << "... but file not found" << endl;
00381 return;
00382 }
00383 }
00384 else
00385 d = s;
00386
00387 sfx_file = new Flex(d);
00388 }
00389 }
00390
00391 Audio::~Audio()
00392 {
00393 if (!initialized)
00394 {
00395 self = 0;
00396 SDL_open = false;
00397 return;
00398 }
00399
00400 CERR("~Audio: about to stop_music()");
00401 stop_music();
00402
00403 CERR("~Audio: about to quit subsystem");
00404 SDL_QuitSubSystem(SDL_INIT_AUDIO);
00405
00406 CERR("~Audio: closed audio");
00407
00408 if(midi)
00409 {
00410 delete midi;
00411 midi = 0;
00412 }
00413 while (sfxs)
00414 {
00415 SFX_cached *todel = sfxs;
00416 sfxs = todel->next;
00417 delete todel;
00418 }
00419 delete sfx_file;
00420 CERR("~Audio: deleted midi");
00421
00422
00423
00424 SDL_open = false;
00425 self = 0;
00426 }
00427
00428
00429 uint8 *Audio::convert_VOC(uint8 *old_data,uint32 &visible_len)
00430 {
00431 vector<Chunk> chunks;
00432 size_t data_offset=0x1a;
00433 bool last_chunk=false;
00434 uint16 sample_rate;
00435 size_t l = 0;
00436 size_t chunk_length;
00437 int compression = 0;
00438 int adpcm_reference = -1;
00439 int adpcm_scale = 0;
00440
00441 while(!last_chunk)
00442 {
00443 switch(old_data[data_offset]&0xff)
00444 {
00445 case 0:
00446 COUT("Terminator");
00447 last_chunk = true;
00448 continue;
00449 case 1:
00450 COUT("Sound data");
00451 l = (old_data[3+data_offset]&0xff)<<16;
00452 l |= (old_data[2+data_offset]&0xff)<<8;
00453 l |= (old_data[1+data_offset]&0xff);
00454 COUT("Chunk length appears to be " << l);
00455 sample_rate=1000000/(256-(old_data[4+data_offset]&0xff));
00456 #ifdef FUDGE_SAMPLE_RATES
00457 if (sample_rate == 11111) sample_rate = 11025;
00458 else if (sample_rate == 22222) sample_rate = 22050;
00459 #endif
00460 COUT("Original sample_rate is " << sample_rate << ", hw rate is " << actual.freq);
00461 COUT("Sample rate ("<< sample_rate<<") = _real_rate");
00462 compression = old_data[5+data_offset]&0xff;
00463 COUT("compression type " << compression);
00464 if (compression) {
00465 adpcm_reference = -1;
00466 adpcm_scale = 0;
00467 }
00468 COUT("Channels " << (old_data[6+data_offset]&0xff));
00469 chunk_length=l+4;
00470
00471
00472 last_chunk=true;
00473
00474 break;
00475 case 2:
00476 COUT("Sound continues");
00477 l=(old_data[3+data_offset]&0xff)<<16;
00478 l|=(old_data[2+data_offset]&0xff)<<8;
00479 l|=(old_data[1+data_offset]&0xff);
00480 COUT("Chunk length appears to be " << l);
00481 chunk_length = l+4;
00482 break;
00483 case 3:
00484 COUT("Silence");
00485 chunk_length=0;
00486 break;
00487 case 5:
00488 COUT("Text string chunk");
00489 chunk_length=0;
00490 break;
00491 default:
00492 cerr << "Unknown VOC chunk " << (*(old_data+data_offset)&0xff) << endl;
00493 throw exult_exception("Unknown VOC chunk");
00494 }
00495
00496 if(chunk_length==0)
00497 break;
00498
00499
00500 l -= (TRAILING_VOC_SLOP+LEADING_VOC_SLOP);
00501
00502
00503 uint8 *dec_data = old_data+LEADING_VOC_SLOP;
00504 size_t dec_len = l;
00505
00506
00507 if (compression == 1) {
00508
00509 if (adpcm_reference == -1) dec_len = (dec_len-1)*2;
00510 else dec_len *= 2;
00511 dec_data = new uint8[dec_len];
00512 decode_ADPCM_4(old_data+LEADING_VOC_SLOP, l, dec_data, adpcm_reference, adpcm_scale);
00513 }
00514 else if (compression != 0) {
00515 CERR("Can't handle VOC compression type");
00516 }
00517
00518
00519
00520 #if 1
00521
00522
00523 sint16 *stereo_data;
00524 if (is_stereo())
00525 stereo_data = resample_new(dec_data, dec_len, l, sample_rate, actual.freq);
00526 else
00527 stereo_data = resample_new_mono(dec_data, dec_len, l, sample_rate, actual.freq);
00528 #else
00529
00530
00531
00532
00533 uint8 *new_data;
00534 size_t new_len;
00535 resample(dec_data, &new_data, dec_len, &new_len, sample_rate, actual.freq);
00536 l = new_len;
00537
00538 COUT("Have " << l << " bytes of resampled data");
00539
00540
00541
00542 sint16 *stereo_data = new sint16[l*2];
00543 for(size_t i = 0, j = 0; i < l; i++)
00544 {
00545 stereo_data[j++] = (new_data[i] - 128)<<8;
00546 stereo_data[j++] = (new_data[i] - 128)<<8;
00547 }
00548 l <<= 2;
00549
00550 delete [] new_data;
00551 #endif
00552
00553 if (compression == 1) {
00554 delete [] dec_data;
00555 }
00556
00557 chunks.push_back(Chunk(l,(uint8 *)stereo_data));
00558
00559 data_offset += chunk_length;
00560 }
00561 COUT("Turn chunks to block");
00562 visible_len = l;
00563
00564 return chunks_to_block(chunks);
00565 }
00566
00567 static sint16 *resample_new(uint8 *src,
00568 size_t sourcelen, size_t &size,
00569 int rate, int wanted_rate)
00570 {
00571 int fp_pos = 0;
00572 int fp_speed = (1 << 16) * rate / wanted_rate;
00573 size = sourcelen;
00574
00575
00576 while (size & 0xFFFF0000)
00577 size >>= 1, rate = (rate >> 1) + 1;
00578
00579
00580 size = (size * wanted_rate / rate) << 2;
00581
00582 sint16 *stereo_data = new sint16 [size];
00583 sint16 *data = stereo_data;
00584 uint8 *src_end = src + sourcelen;
00585
00586 int result;
00587
00588
00589
00590
00591 int a = *(src+0); a = (a|(a << 8))-32768;
00592 int b = *(src+1); b = (a|(b << 8))-32768;
00593 int c = *(src+2); c = (a|(c << 8))-32768;
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 #define RANGE_REDUX(x) (((x) * 27) >> 5)
00605
00606
00607
00608 CubicInterpolator interp(RANGE_REDUX(a), RANGE_REDUX(b), RANGE_REDUX(c));
00609
00610 do {
00611 do {
00612
00613 result = interp.interpolate(fp_pos);
00614
00615
00616
00617 if (result < -32768)
00618 result = -32768;
00619 else if (result > 32767)
00620 result = 32767;
00621
00622 *data++ = result;
00623 *data++ = result;
00624
00625 fp_pos += fp_speed;
00626 } while (!(fp_pos & 0xFFFF0000));
00627 src++;
00628 fp_pos &= 0x0000FFFF;
00629
00630
00631 if (src+2 < src_end) {
00632 c = *(src+2);
00633 c = (c|(c << 8))-32768;
00634 interp.feedData(RANGE_REDUX(c));
00635 } else
00636 interp.feedData();
00637
00638 } while (src < src_end);
00639
00640 return stereo_data;
00641 }
00642
00643 static sint16 *resample_new_mono(uint8 *src,
00644 size_t sourcelen, size_t &size,
00645 int rate, int wanted_rate)
00646 {
00647 int fp_pos = 0;
00648 int fp_speed = (1 << 16) * rate / wanted_rate;
00649 size = sourcelen;
00650
00651
00652 while (size & 0xFFFF0000)
00653 size >>= 1, rate = (rate >> 1) + 1;
00654
00655
00656 size = (size * wanted_rate / rate) << 1;
00657
00658 sint16 *stereo_data = new sint16 [size];
00659 sint16 *data = stereo_data;
00660 uint8 *src_end = src + sourcelen;
00661
00662 int result;
00663
00664
00665
00666
00667 int a = *(src+0); a = (a|(a << 8))-32768;
00668 int b = *(src+1); b = (a|(b << 8))-32768;
00669 int c = *(src+2); c = (a|(c << 8))-32768;
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 #define RANGE_REDUX(x) (((x) * 27) >> 5)
00681
00682
00683
00684 CubicInterpolator interp(RANGE_REDUX(a), RANGE_REDUX(b), RANGE_REDUX(c));
00685
00686 do {
00687 do {
00688
00689 result = interp.interpolate(fp_pos);
00690
00691
00692
00693 if (result < -32768)
00694 result = -32768;
00695 else if (result > 32767)
00696 result = 32767;
00697
00698 *data++ = result;
00699
00700 fp_pos += fp_speed;
00701 } while (!(fp_pos & 0xFFFF0000));
00702 src++;
00703 fp_pos &= 0x0000FFFF;
00704
00705
00706 if (src+2 < src_end) {
00707 c = *(src+2);
00708 c = (c|(c << 8))-32768;
00709 interp.feedData(RANGE_REDUX(c));
00710 } else
00711 interp.feedData();
00712
00713 } while (src < src_end);
00714
00715 return stereo_data;
00716 }
00717
00718 void Audio::play(uint8 *sound_data,uint32 len,bool wait)
00719 {
00720 Mix_Chunk *wavechunk;
00721
00722 if (!audio_enabled || !speech_enabled) return;
00723
00724 bool own_audio_data=false;
00725
00726 if(!strncmp((const char *)sound_data,"Creative Voice File",19))
00727 {
00728 sound_data=convert_VOC(sound_data,len);
00729 own_audio_data=true;
00730 }
00731
00732
00733
00734 wavechunk = Mix_QuickLoad_RAW(sound_data, len);
00735
00736 int channel;
00737 channel = Mix_PlayChannel(-1, wavechunk, 0);
00738 Mix_SetPosition(channel, 0, 0);
00739 Mix_Volume(channel, MIX_MAX_VOLUME - 40);
00740
00741 }
00742
00743 void Audio::cancel_streams(void)
00744 {
00745 if (!audio_enabled) return;
00746
00747 Mix_HaltChannel(-1);
00748 }
00749
00750 void Audio::pause_audio(void)
00751 {
00752 if (!audio_enabled) return;
00753
00754 Mix_Pause(-1);
00755 Mix_PauseMusic();
00756 }
00757
00758 void Audio::resume_audio(void)
00759 {
00760 if (!audio_enabled) return;
00761
00762 Mix_Resume(-1);
00763 Mix_ResumeMusic();
00764 }
00765
00766
00767 void Audio::playfile(const char *fname,bool wait)
00768 {
00769 if (!audio_enabled)
00770 return;
00771
00772 FILE *fp;
00773 size_t len;
00774 uint8 *buf;
00775
00776 fp = U7open(fname,"r");
00777 if(!fp)
00778 {
00779 perror(fname);
00780 return;
00781 }
00782 fseek(fp,0L,SEEK_END);
00783 len=ftell(fp);
00784 fseek(fp,0L,SEEK_SET);
00785 if(len<=0)
00786 {
00787 perror("seek");
00788 fclose(fp);
00789 return;
00790 }
00791 buf=new uint8[len];
00792 fread(buf,len,1,fp);
00793 fclose(fp);
00794 play(buf,len,wait);
00795 delete [] buf;
00796 }
00797
00798
00799 bool Audio::playing(void)
00800 {
00801 return false;
00802 }
00803
00804
00805 void Audio::start_music(int num, bool continuous, int bank)
00806 {
00807 if(audio_enabled && music_enabled && midi != 0)
00808 midi->start_music(num,continuous && allow_music_looping,bank);
00809 }
00810
00811 void Audio::start_music(const char *fname, int num, bool continuous)
00812 {
00813 if(audio_enabled && music_enabled && midi != 0)
00814 midi->start_music(fname,num,continuous && allow_music_looping);
00815 }
00816
00817 void Audio::start_music(XMIDIEventList *mid_file,bool continuous)
00818 {
00819 if(audio_enabled && music_enabled && midi != 0)
00820 midi->start_track(mid_file,continuous && allow_music_looping);
00821 }
00822
00823 void Audio::start_music_combat (Combat_song song, bool continuous, int bank)
00824 {
00825 if(!audio_enabled || !music_enabled || midi == 0)
00826 return;
00827
00828 int num = -1;
00829
00830 if (Game::get_game_type()!=SERPENT_ISLE) switch (song)
00831 {
00832 case CSBattle_Over:
00833 num = 9;
00834 break;
00835
00836 case CSAttacked1:
00837 num = 11;
00838 break;
00839
00840 case CSAttacked2:
00841 num = 12;
00842 break;
00843
00844 case CSVictory:
00845 num = 15;
00846 break;
00847
00848 case CSRun_Away:
00849 num = 16;
00850 break;
00851
00852 case CSDanger:
00853 num = 10;
00854 break;
00855
00856 case CSHidden_Danger:
00857 num = 18;
00858 break;
00859
00860 default:
00861 CERR("Error: Unable to Find combat track for song " << song << ".");
00862 break;
00863 }
00864 else switch (song)
00865 {
00866 case CSBattle_Over:
00867 num = 0;
00868 break;
00869
00870 case CSAttacked1:
00871 num = 2;
00872 break;
00873
00874 case CSAttacked2:
00875 num = 3;
00876 break;
00877
00878 case CSVictory:
00879 num = 6;
00880 break;
00881
00882 case CSRun_Away:
00883 num = 7;
00884 break;
00885
00886 case CSDanger:
00887 num = 1;
00888 break;
00889
00890 case CSHidden_Danger:
00891 num = 9;
00892 break;
00893
00894 default:
00895 CERR("Error: Unable to Find combat track for song " << song << ".");
00896 break;
00897 }
00898
00899 midi->start_music(num,continuous && allow_music_looping,bank);
00900 }
00901
00902 void Audio::stop_music()
00903 {
00904 if (!audio_enabled) return;
00905
00906 if(midi)
00907 midi->stop_music();
00908 }
00909
00910 bool Audio::start_speech(int num,bool wait)
00911 {
00912 if (!audio_enabled || !speech_enabled)
00913 return false;
00914
00915 char *buf=0;
00916 size_t len;
00917 const char *filename;
00918
00919 if (Game::get_game_type() == SERPENT_ISLE)
00920 filename = SISPEECH;
00921 else
00922 filename = U7SPEECH;
00923
00924 U7object sample(filename,num);
00925 try
00926 {
00927 buf = sample.retrieve(len);
00928 }
00929 catch( const std::exception & err )
00930 {
00931 return false;
00932 }
00933 play(reinterpret_cast<uint8*>(buf),len,wait);
00934 delete [] buf;
00935
00936 return true;
00937 }
00938
00939 void Audio::build_speech_vector(void)
00940 {
00941 }
00942
00943
00944
00945
00946 int Audio::play_sound_effect (int num, int volume, int dir, int repeat)
00947 {
00948 if (!audio_enabled || !effects_enabled) return -1;
00949
00950
00951 if (sfx_file != 0)
00952 return play_wave_sfx(num, volume, dir, repeat);
00953 #ifdef ENABLE_MIDISFX
00954 else if (midi != 0)
00955 midi->start_sound_effect(num);
00956 #endif
00957 return -1;
00958 }
00959
00960
00961
00962
00963
00964 int Audio::play_wave_sfx
00965 (
00966 int num,
00967 int volume,
00968 int dir,
00969 int repeat
00970 )
00971 {
00972 if (!effects_enabled || !sfx_file )
00973 return -1;
00974
00975 CERR("Playing SFX: " << num);
00976 #if 0
00977 if (Game::get_game_type() == BLACK_GATE)
00978 num = bgconv[num];
00979 CERR("; after bgconv: " << num);
00980 #endif
00981 if (num < 0 || num >= sfx_file->number_of_objects())
00982 {
00983 cerr << "SFX " << num << " is out of range" << endl;
00984 return -1;
00985 }
00986
00987 const int max_cached = 6;
00988
00989 SFX_cached *each = sfxs, *prev = 0;
00990 int cnt = 0;
00991 size_t wavlen;
00992 SDL_RWops *rwsrc;
00993 bool foundcache=false;
00994 unsigned char *wavbuf;
00995
00996
00997 while (each && each->num != num && each->next)
00998 {
00999 cnt++;
01000 prev = each;
01001 each = each->next;
01002 }
01003 if (each && each->num == num)
01004 {
01005
01006 if (prev)
01007 {
01008 prev->next = each->next;
01009 each->next = sfxs;
01010 sfxs = each;
01011 }
01012
01013
01014 foundcache = true;
01015 wavbuf = new uint8[each->len];
01016 memcpy(wavbuf, each->buf, each->len);
01017 wavlen = each->len;
01018 }
01019 if (cnt == max_cached && !foundcache)
01020 {
01021 prev->next = 0;
01022 delete each;
01023 }
01024
01025
01026 if(!foundcache)
01027 {
01028 wavbuf = (unsigned char *) sfx_file->retrieve(num, wavlen);
01029 rwsrc = SDL_RWFromMem(wavbuf, wavlen);
01030 wave = Mix_LoadWAV_RW(rwsrc, 1);
01031 if (!wave) {
01032 cerr << "SFX " << num << " is an invalid wave. ";
01033 } else {
01034 sfxs = new SFX_cached(num, wave->abuf, wave->alen, sfxs);
01035 }
01036 delete [] wavbuf;
01037 }
01038 else
01039 {
01040 wave = Mix_QuickLoad_RAW(wavbuf, wavlen);
01041
01042 }
01043
01044 if (!wave)
01045 {
01046 cerr << "Couldn't play sfx '" << num << "'" << endl;
01047 return -1;
01048 }
01049
01050 int sfxchannel;
01051 sfxchannel = Mix_PlayChannel(-1, wave, repeat);
01052
01053 Mix_Volume(sfxchannel, volume);
01054 Mix_SetPosition(sfxchannel, (dir * 22), 0);
01055 return sfxchannel;
01056 }
01057
01058
01059
01060
01061
01062 void Audio::stop_sound_effects()
01063 {
01064 if (sfx_file != 0)
01065 Mix_HaltChannel(-1);
01066
01067 #ifdef ENABLE_MIDISFX
01068 else if (midi)
01069 midi->stop_sound_effects();
01070 #endif
01071 }
01072
01073
01074 void Audio::set_audio_enabled(bool ena)
01075 {
01076 if (ena && audio_enabled && initialized)
01077 {
01078
01079 }
01080 else if (!ena && audio_enabled && initialized)
01081 {
01082 stop_sound_effects();
01083 stop_music();
01084 audio_enabled = false;
01085 }
01086 else if (ena && !audio_enabled && initialized)
01087 {
01088 audio_enabled = true;
01089 }
01090 else if (!ena && !audio_enabled && initialized)
01091 {
01092
01093 }
01094 else if (ena && !audio_enabled && !initialized)
01095 {
01096 audio_enabled = true;
01097
01098 Init(SAMPLERATE,2);
01099 }
01100 else if (!ena && !audio_enabled && !initialized)
01101 {
01102
01103 }
01104 }
01105
01106
01107 static size_t calc_sample_buffer(uint16 _samplerate)
01108 {
01109 uint32 _buffering_unit=1;
01110 while(_buffering_unit<_samplerate/10U)
01111 _buffering_unit<<=1;
01112
01113 return _buffering_unit;
01114 }
01115
01116
01117 static uint8 *chunks_to_block(vector<Chunk> &chunks)
01118 {
01119 uint8 *unified_block;
01120 size_t aggregate_length=0;
01121 size_t working_offset=0;
01122
01123 for(std::vector<Chunk>::iterator it=chunks.begin();
01124 it!=chunks.end(); ++it)
01125 {
01126 aggregate_length+=it->length;
01127 }
01128 unified_block=new uint8[aggregate_length];
01129 {
01130 for(std::vector<Chunk>::iterator it=chunks.begin();
01131 it!=chunks.end(); ++it)
01132 {
01133 memcpy(unified_block+working_offset,it->data,it->length);
01134 working_offset+=it->length;
01135 delete [] it->data; it->data=0; it->length=0;
01136 }
01137 }
01138
01139 return unified_block;
01140 }
01141
01142
01143 static void resample(uint8 *sourcedata, uint8 **destdata,
01144 size_t sourcelen, size_t *destlen,
01145 int current_rate, int wanted_rate)
01146 {
01147
01148
01149
01150
01151 float ratio= (static_cast<float>(wanted_rate))/(static_cast<float>(current_rate));
01152 *destlen = static_cast<unsigned int> ((sourcelen*ratio)+1);
01153 if(!*destlen||current_rate==wanted_rate)
01154 {
01155
01156 *destlen=sourcelen;
01157 *destdata=new uint8[sourcelen];
01158 memcpy(*destdata,sourcedata,sourcelen);
01159 return;
01160 }
01161 *destdata=new uint8[*destlen];
01162 size_t last=0;
01163 for(size_t i=0;i<sourcelen;i++)
01164 {
01165 size_t pos = (size_t) (i*ratio);
01166 assert(pos<=*destlen);
01167 (*destdata)[pos]=sourcedata[i];
01168
01169 if(last!=pos&&last!=pos-1)
01170 for(size_t j=last+1;j<=pos-1;j++)
01171 {
01172 unsigned int x=(unsigned char)sourcedata[i];
01173 unsigned int y=(unsigned char)sourcedata[i-1];
01174 x=(x+y)/2;
01175 (*destdata)[j]=(uint8) x;
01176 }
01177 last=pos;
01178 }
01179 CERR("End resampling. Resampled " << sourcelen << " bytes to " << *destlen << " bytes");
01180 }
01181
01182
01183
01184
01185
01186
01187
01188 inline int decode_ADPCM_4_sample(uint8 sample,
01189 int& reference,
01190 int& scale)
01191 {
01192 static int scaleMap[8] = { -2, -1, 0, 0, 1, 1, 1, 1 };
01193
01194 if (sample & 0x08) {
01195 reference = max(0x00, reference - ((sample & 0x07) << scale));
01196 } else {
01197 reference = min(0xff, reference + ((sample & 0x07) << scale));
01198 }
01199
01200 scale = max(2, min(6, scaleMap[sample & 0x07]));
01201
01202 return reference;
01203 }
01204
01205
01206
01207
01208 static void decode_ADPCM_4(uint8* inBuf,
01209 int bufSize,
01210 uint8* outBuf,
01211 int& reference,
01212 int& scale)
01213 {
01214 int i, skip = 0;
01215
01216 if (reference < 0) {
01217 reference = inBuf[0] & 0xff;
01218 bufSize--;
01219 }
01220
01221 for (i = 0; i < bufSize; i++) {
01222 outBuf[i * 2 + 0] = decode_ADPCM_4_sample(inBuf[i] >> 4, reference, scale);
01223 outBuf[i * 2 + 1] = decode_ADPCM_4_sample(inBuf[i] >> 0, reference, scale);
01224 }
01225 }
01226
01227 #endif // PENTAGRAM