sound.cpp

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

Generated on Sat Apr 17 23:24:53 2010 for OpenTTD by  doxygen 1.6.1