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

Generated on Sat Dec 26 20:06:05 2009 for OpenTTD by  doxygen 1.5.6