Audio.cc

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2000-2001  The Exult Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 //#include "SDL_mapping.h"
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 //#include <crtdbg.h>
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 // These MIGHT be macros!
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,        // Size of inbuf
00107               uint8* outBuf,  // Size is 2x bufsize
00108               int& reference,     // ADPCM reference value
00109               int& scale);
00110 
00111 Audio *Audio::self = 0;
00112 int *Audio::bg2si_sfxs = 0;
00113 
00114 //----- Utilities ----------------------------------------------------
00115 
00116 /*
00117  * Class that performs cubic interpolation on integer data.
00118  * It is expected that the data is equidistant, i.e. all have the same
00119  * horizontal distance. This is obviously the case for sampled audio.
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     // We use a simple linear interpolation for x0
00135     updateCoefficients();
00136   }
00137   
00138   inline void feedData()
00139   {
00140     x0 = x1;
00141     x1 = x2;
00142     x2 = x3;
00143     x3 = 2*x2-x1; // Simple linear interpolation
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   /* t must be a 16.16 fixed point number between 0 and 1 */
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 //----- SFX ----------------------------------------------------------
00180 
00181 /*
00182  *  For caching sound effects:
00183  */
00184 class SFX_cached
00185   {
00186   int num;      // Sound-effects #.
00187   uint8 *buf;     // The data.  It's passed in to us,
00188           //   and then we own it.
00189   uint32 len;
00190   SFX_cached *next;   // Next in chain.
00191 public:
00192   friend class Audio;
00193   SFX_cached(int sn, uint8 *b, uint32 l, SFX_cached *oldhead)
00194     : num(sn), /*buf(b), */ 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 //---- Audio ---------------------------------------------------------
00207 void Audio::Init(void)
00208 {
00209   // Crate the Audio singleton object
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   // The following assert here might be too harsh, maybe we should leave
00230   // it to the caller to handle non-inited audio-system?
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),/*mixer(0),*/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   // Initialise the speech vectors
00267   uint32 _buffering_unit=calc_sample_buffer(_samplerate);
00268   build_speech_vector();
00269 
00270   delete midi;
00271   midi=0;
00272 
00273   // Avoid closing SDL audio. This seems to trigger a segfault
00274   if(SDL_open)
00275     SDL_QuitSubSystem(SDL_INIT_AUDIO);
00276 
00277   // Init the SDL audio system
00278   SDL_InitSubSystem(SDL_INIT_AUDIO);
00279 
00280   /* Open the audio device, forcing the desired format */
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;  // Prevent crashes.
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   //SDL_mixer will always go here when it has played a sound, we want to free up
00304   //the memory used as we don't re-play the sound.
00305   Mix_ChannelFinished(channel_complete_callback);
00306 
00307   // Disable playing initially.
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 //Free up memory used by the just played WAV. We only ever play a sound
00321 //once and discard it.
00322 void Audio::channel_complete_callback(int chan)
00323 {
00324   Mix_Chunk *done_chunk = Mix_GetChunk(chan);
00325   Uint8 *chunkbuf=NULL;
00326 
00327   //We need to free these chunks as they were allocated by us and not SDL_Mixer
00328   //This happens when Mix_QuickLoadRAW is used.
00329   if(done_chunk->allocated == 0)
00330     chunkbuf = done_chunk->abuf;
00331     
00332   Mix_FreeChunk(done_chunk);
00333 
00334   //Must be freed after the Mix_FreeChunk
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   // Also just check in the actual data dir
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           // Collection of .wav's?
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); // SDL 1.1 lets us diddle with
00405             // subsystems
00406   CERR("~Audio:  closed audio");
00407 
00408   if(midi)
00409   {
00410     delete midi;
00411     midi = 0;
00412   }
00413   while (sfxs)      // Cached sound effects.
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   // Avoid closing SDL audio. This seems to trigger a segfault
00423   // SDL::CloseAudio();
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         //workaround here to exit this loop, it fixes start speech which was
00471         //causing this function to go exit too early.
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:   // A null terminated string
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     // Decompress data
00507     if (compression == 1) {
00508       // Allocate temp buffer
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     // Our input is 8 bit mono unsigned; but want to output 16 bit stereo signed.
00519     // In addition, the rates don't match, we have to upsample.
00520 #if 1
00521     // New code: Do it all in one step with cubic interpolation
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     // Old code: resample using pseudo-breshenham, then in a second step convert
00530     // to 16 bit stereo.
00531 
00532     // Resample to the current rate
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     // And convert to 16 bit stereo
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; // because it's 16bit
00549 
00550     delete [] new_data;
00551 #endif
00552     // Delete temp buffer
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   // adjust the magnitudes of size and rate to prevent division error
00576   while (size & 0xFFFF0000)
00577     size >>= 1, rate = (rate >> 1) + 1;
00578   
00579   // Compute the output size (times 4 since it is 16 stereo)
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   // Compute the initial data feed for the interpolator. We don't simply
00589   // shift by 8, but rather duplicate the byte, this way we cover the full
00590   // range. Probably doesn't make a big difference, listening wise :-)
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   // We divide the data by 2, to prevent overshots. Imagine this sample pattern:
00596   // 0, 65535, 65535, 0. Now you want to compute a value between the two 65535.
00597   // Obviously, it will be *bigger* than 65535 (it can get to about 80,000).
00598   // It is possibly to clamp it, but that leads to a distored wave form. Compare
00599   // this to turning up the volume of your stereo to much, it will start to sound
00600   // bad at a certain level (depending on the power of your stereo, your speakers 
00601   // etc, this can be quite loud, though ;-). Hence we reduce the original range.
00602   // A factor of roughly 1/1.2 = 0.8333 is sufficient. Since we want to avoid 
00603   // floating point, we approximate that by 27/32
00604   #define RANGE_REDUX(x)  (((x) * 27) >> 5)
00605 //  #define RANGE_REDUX(x)  ((x) >> 1)
00606 //  #define RANGE_REDUX(x)  ((x) / 1.2)
00607 
00608   CubicInterpolator interp(RANGE_REDUX(a), RANGE_REDUX(b), RANGE_REDUX(c));
00609   
00610   do {
00611     do {
00612       // Convert to signed data
00613       result = interp.interpolate(fp_pos);
00614 
00615       // Enforce range in case of an "overshot". Shouldn't happen since we
00616       // scale down already, but safe is safe.
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   // adjust the magnitudes of size and rate to prevent division error
00652   while (size & 0xFFFF0000)
00653     size >>= 1, rate = (rate >> 1) + 1;
00654   
00655   // Compute the output size (times 2 since it is 16 stereo)
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   // Compute the initial data feed for the interpolator. We don't simply
00665   // shift by 8, but rather duplicate the byte, this way we cover the full
00666   // range. Probably doesn't make a big difference, listening wise :-)
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   // We divide the data by 2, to prevent overshots. Imagine this sample pattern:
00672   // 0, 65535, 65535, 0. Now you want to compute a value between the two 65535.
00673   // Obviously, it will be *bigger* than 65535 (it can get to about 80,000).
00674   // It is possibly to clamp it, but that leads to a distored wave form. Compare
00675   // this to turning up the volume of your stereo to much, it will start to sound
00676   // bad at a certain level (depending on the power of your stereo, your speakers 
00677   // etc, this can be quite loud, though ;-). Hence we reduce the original range.
00678   // A factor of roughly 1/1.2 = 0.8333 is sufficient. Since we want to avoid 
00679   // floating point, we approximate that by 27/32
00680   #define RANGE_REDUX(x)  (((x) * 27) >> 5)
00681 //  #define RANGE_REDUX(x)  ((x) >> 1)
00682 //  #define RANGE_REDUX(x)  ((x) / 1.2)
00683 
00684   CubicInterpolator interp(RANGE_REDUX(a), RANGE_REDUX(b), RANGE_REDUX(c));
00685   
00686   do {
00687     do {
00688       // Convert to signed data
00689       result = interp.interpolate(fp_pos);
00690 
00691       // Enforce range in case of an "overshot". Shouldn't happen since we
00692       // scale down already, but safe is safe.
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   //Play voice sample using RAW sample we created above. ConvertVOC() produced a stereo, 22KHz, 16bit
00733   //sample. Currently SDL does not resample very well so we do it in ConvertVOC()
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);   //Voice is loud compared to other SFX,music
00740                 //so adjust to match volumes
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"); // DARKE FIXME
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  *  This returns a 'unique' ID, but only for .wav SFX's (for now).
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   // Where sort of sfx are we using????
00951   if (sfx_file != 0)    // Digital .wav's?
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  *  Play a .wav format sound effect, 
00962  *  return the channel number playing on or -1 if not playing, (0 is a valid channel in SDL_Mixer!)
00963  */
00964 int Audio::play_wave_sfx
00965   (
00966   int num,
00967   int volume,     // 0-128.
00968   int dir,      // 0-15, from North, clockwise.
00969   int repeat      // Keep playing.
00970   )
00971 {
00972   if (!effects_enabled || !sfx_file /*|| !mixer*/) 
00973     return -1;  // no .wav sfx available
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; // Max. we'll cache.
00988 
00989   SFX_cached *each = sfxs, *prev = 0;
00990   int cnt = 0;
00991   size_t wavlen;      // Read .wav file.
00992   SDL_RWops *rwsrc;
00993   bool foundcache=false;
00994   unsigned char *wavbuf;
00995 
00996   // First see if we have it already in our cache
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) // Found it?
01004   {
01005     // Move to head of chain.
01006     if (prev)
01007     {
01008       prev->next = each->next;
01009       each->next = sfxs;
01010       sfxs = each;
01011     }
01012     // Return the cached data
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)   // Hit our limit?  Remove last.
01020   {
01021     prev->next = 0;
01022     delete each;
01023   }
01024 
01025   // Retrieve the .wav data from the SFX file
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     //Wavbuf will be deleted by the channel_complete_callback function
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  *  Halt sound effects.
01060  */
01061 
01062 void Audio::stop_sound_effects()
01063 {
01064   if (sfx_file != 0)    // .Wav's?
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   // _buffering_unit=128;
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   // I have no idea what I'm doing here - Dancer
01148   // This is really Breshenham's line-drawing algorithm in
01149   // a false nose, and clutching a crude smoothing loop.
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     // Least work
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     // Interpolate if need be
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 // Decode 4bit ADPCM vocs (thunder in SI intro)
01184 //
01185 // Code grabbed from VDMS
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 // Performs 4-bit ADPCM decoding in-place.
01207 //
01208 static void decode_ADPCM_4(uint8* inBuf,  
01209               int bufSize,        // Size of inbuf
01210               uint8* outBuf,      // Size is 2x bufsize
01211               int& reference,     // ADPCM reference value
01212               int& scale)
01213 {
01214   int i, skip = 0;
01215   
01216   if (reference < 0) {
01217     reference = inBuf[0] & 0xff;   // use the first byte in the buffer as the reference byte
01218     bufSize--;                          // remember to skip the reference byte
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

Generated on Mon Jul 9 14:42:40 2007 for ExultEngine by  doxygen 1.5.1