sound.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "landscape.h"
00014 #include "mixer.h"
00015 #include "newgrf_sound.h"
00016 #include "fios.h"
00017 #include "window_gui.h"
00018 #include "vehicle_base.h"
00019 
00020 /* The type of set we're replacing */
00021 #define SET_TYPE "sounds"
00022 #include "base_media_func.h"
00023 
00024 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
00025 
00026 static void OpenBankFile(const char *filename)
00027 {
00028   memset(_original_sounds, 0, sizeof(_original_sounds));
00029 
00030   /* If there is no sound file (nosound set), don't load anything */
00031   if (filename == NULL) return;
00032 
00033   FioOpenFile(SOUND_SLOT, filename);
00034   size_t pos = FioGetPos();
00035   uint count = FioReadDword();
00036 
00037   /* The new format has the highest bit always set */
00038   bool new_format = HasBit(count, 31);
00039   ClrBit(count, 31);
00040   count /= 8;
00041 
00042   /* Simple check for the correct number of original sounds. */
00043   if (count != ORIGINAL_SAMPLE_COUNT) {
00044     /* Corrupt sample data? Just leave the allocated memory as those tell
00045      * there is no sound to play (size = 0 due to calloc). Not allocating
00046      * the memory disables valid NewGRFs that replace sounds. */
00047     DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
00048     return;
00049   }
00050 
00051   FioSeekTo(pos, SEEK_SET);
00052 
00053   for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00054     _original_sounds[i].file_slot = SOUND_SLOT;
00055     _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos;
00056     _original_sounds[i].file_size = FioReadDword();
00057   }
00058 
00059   for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00060     SoundEntry *sound = &_original_sounds[i];
00061     char name[255];
00062 
00063     FioSeekTo(sound->file_offset, SEEK_SET);
00064 
00065     /* Check for special case, see else case */
00066     FioReadBlock(name, FioReadByte()); // Read the name of the sound
00067     if (new_format || strcmp(name, "Corrupt sound") != 0) {
00068       FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
00069 
00070       /* Read riff tags */
00071       for (;;) {
00072         uint32 tag = FioReadDword();
00073         uint32 size = FioReadDword();
00074 
00075         if (tag == ' tmf') {
00076           FioReadWord(); // wFormatTag
00077           sound->channels = FioReadWord();        // wChannels
00078           sound->rate     = FioReadDword();       // samples per second
00079           if (!new_format) sound->rate = 11025;   // seems like all old samples should be played at this rate.
00080           FioReadDword();                         // avg bytes per second
00081           FioReadWord();                          // alignment
00082           sound->bits_per_sample = FioReadByte(); // bits per sample
00083           FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
00084         } else if (tag == 'atad') {
00085           sound->file_size = size;
00086           sound->file_slot = SOUND_SLOT;
00087           sound->file_offset = FioGetPos();
00088           break;
00089         } else {
00090           sound->file_size = 0;
00091           break;
00092         }
00093       }
00094     } else {
00095       /*
00096        * Special case for the jackhammer sound
00097        * (name in sample.cat is "Corrupt sound")
00098        * It's no RIFF file, but raw PCM data
00099        */
00100       sound->channels = 1;
00101       sound->rate = 11025;
00102       sound->bits_per_sample = 8;
00103       sound->file_slot = SOUND_SLOT;
00104       sound->file_offset = FioGetPos();
00105     }
00106   }
00107 }
00108 
00109 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
00110 {
00111   assert(sound != NULL);
00112 
00113   if (sound->file_size == 0) return false;
00114 
00115   int8 *mem = MallocT<int8>(sound->file_size + 2);
00116   /* Add two extra bytes so rate conversion can read these
00117    * without reading out of its input buffer. */
00118   mem[sound->file_size    ] = 0;
00119   mem[sound->file_size + 1] = 0;
00120 
00121   FioSeekToFile(sound->file_slot, sound->file_offset);
00122   FioReadBlock(mem, sound->file_size);
00123 
00124   /* 16-bit PCM WAV files should be signed by default */
00125   if (sound->bits_per_sample == 8) {
00126     for (uint i = 0; i != sound->file_size; i++) {
00127       mem[i] += -128; // Convert unsigned sound data to signed
00128     }
00129   }
00130 
00131 #if TTD_ENDIAN == TTD_BIG_ENDIAN
00132   if (sound->bits_per_sample == 16) {
00133     uint num_samples = sound->file_size / 2;
00134     int16 *samples = (int16 *)mem;
00135     for (uint i = 0; i < num_samples; i++) {
00136       samples[i] = BSWAP16(samples[i]);
00137     }
00138   }
00139 #endif
00140 
00141   assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
00142   assert(sound->channels == 1);
00143   assert(sound->file_size != 0 && sound->rate != 0);
00144 
00145   MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
00146 
00147   return true;
00148 }
00149 
00150 void InitializeSound()
00151 {
00152   DEBUG(misc, 1, "Loading sound effects...");
00153   OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
00154 }
00155 
00156 /* Low level sound player */
00157 static void StartSound(SoundID sound_id, float pan, uint volume)
00158 {
00159   if (volume == 0) return;
00160 
00161   const SoundEntry *sound = GetSound(sound_id);
00162   if (sound == NULL) return;
00163 
00164   /* Empty sound? */
00165   if (sound->rate == 0) return;
00166 
00167   MixerChannel *mc = MxAllocateChannel();
00168   if (mc == NULL) return;
00169 
00170   if (!SetBankSource(mc, sound)) return;
00171 
00172   /* Apply the sound effect's own volume. */
00173   volume = sound->volume * volume;
00174 
00175   MxSetChannelVolume(mc, volume, pan);
00176   MxActivateChannel(mc);
00177 }
00178 
00179 
00180 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
00181 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00182 
00183 static const byte _sound_base_vol[] = {
00184   128,  90, 128, 128, 128, 128, 128, 128,
00185   128,  90,  90, 128, 128, 128, 128, 128,
00186   128, 128, 128,  80, 128, 128, 128, 128,
00187   128, 128, 128, 128, 128, 128, 128, 128,
00188   128, 128,  90,  90,  90, 128,  90, 128,
00189   128,  90, 128, 128, 128,  90, 128, 128,
00190   128, 128, 128, 128,  90, 128, 128, 128,
00191   128,  90, 128, 128, 128, 128, 128, 128,
00192   128, 128,  90,  90,  90, 128, 128, 128,
00193    90,
00194 };
00195 
00196 static const byte _sound_idx[] = {
00197    2,  3,  4,  5,  6,  7,  8,  9,
00198   10, 11, 12, 13, 14, 15, 16, 17,
00199   18, 19, 20, 21, 22, 23, 24, 25,
00200   26, 27, 28, 29, 30, 31, 32, 33,
00201   34, 35, 36, 37, 38, 39, 40,  0,
00202    1, 41, 42, 43, 44, 45, 46, 47,
00203   48, 49, 50, 51, 52, 53, 54, 55,
00204   56, 57, 58, 59, 60, 61, 62, 63,
00205   64, 65, 66, 67, 68, 69, 70, 71,
00206   72,
00207 };
00208 
00209 void SndCopyToPool()
00210 {
00211   for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
00212     SoundEntry *sound = AllocateSound();
00213     *sound = _original_sounds[_sound_idx[i]];
00214     sound->volume = _sound_base_vol[i];
00215     sound->priority = 0;
00216   }
00217 }
00218 
00227 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
00228 {
00229   if (_settings_client.music.effect_vol == 0) return;
00230 
00231   const Window *w;
00232   FOR_ALL_WINDOWS_FROM_BACK(w) {
00233     const ViewPort *vp = w->viewport;
00234 
00235     if (vp != NULL &&
00236         left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00237         top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00238       int screen_x = (left + right) / 2 - vp->virtual_left;
00239       int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00240       float panning = (float)screen_x / width;
00241 
00242       StartSound(
00243         sound,
00244         panning,
00245         (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00246       );
00247       return;
00248     }
00249   }
00250 }
00251 
00252 void SndPlayTileFx(SoundID sound, TileIndex tile)
00253 {
00254   /* emits sound from center of the tile */
00255   int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00256   int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00257   uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00258   Point pt = RemapCoords(x, y, z);
00259   y += 2 * TILE_SIZE;
00260   Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
00261   SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00262 }
00263 
00264 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
00265 {
00266   SndPlayScreenCoordFx(sound,
00267     v->coord.left, v->coord.right,
00268     v->coord.top, v->coord.bottom
00269   );
00270 }
00271 
00272 void SndPlayFx(SoundID sound)
00273 {
00274   StartSound(sound, 0.5, _settings_client.music.effect_vol);
00275 }
00276 
00277 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
00278 
00279 
00280 static const char * const _sound_file_names[] = { "samples" };
00281 
00282 
00283 template <class T, size_t Tnum_files, Subdirectory Tsubdir>
00284 /* static */ const char * const *BaseSet<T, Tnum_files, Tsubdir>::file_names = _sound_file_names;
00285 
00286 template <class Tbase_set>
00287 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
00288 {
00289   return ".obs"; // OpenTTD Base Sounds
00290 }
00291 
00292 template <class Tbase_set>
00293 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
00294 {
00295   if (BaseMedia<Tbase_set>::used_set != NULL) return true;
00296 
00297   const Tbase_set *best = NULL;
00298   for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
00299     /* Skip unuseable sets */
00300     if (c->GetNumMissing() != 0) continue;
00301 
00302     if (best == NULL ||
00303         (best->fallback && !c->fallback) ||
00304         best->valid_files < c->valid_files ||
00305         (best->valid_files == c->valid_files &&
00306           (best->shortname == c->shortname && best->version < c->version))) {
00307       best = c;
00308     }
00309   }
00310 
00311   BaseMedia<Tbase_set>::used_set = best;
00312   return BaseMedia<Tbase_set>::used_set != NULL;
00313 }
00314 

Generated on Fri May 27 04:19:49 2011 for OpenTTD by  doxygen 1.6.1