# sound.cpp

Go to the documentation of this file.

    00001 /* $Id: sound.cpp 24900 2013-01-08 22:46:42Z planetmaker $ */
    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, BASESET_DIR);
    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   /* Check for valid sound size. */
    00114   if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
    00115
    00116   int8 *mem = MallocT<int8>(sound->file_size + 2);
    00117   /* Add two extra bytes so rate conversion can read these
    00118    * without reading out of its input buffer. */
    00119   mem[sound->file_size    ] = 0;
    00120   mem[sound->file_size + 1] = 0;
    00121
    00122   FioSeekToFile(sound->file_slot, sound->file_offset);
    00123   FioReadBlock(mem, sound->file_size);
    00124
    00125   /* 16-bit PCM WAV files should be signed by default */
    00126   if (sound->bits_per_sample == 8) {
    00127     for (uint i = 0; i != sound->file_size; i++) {
    00128       mem[i] += -128; // Convert unsigned sound data to signed
    00129     }
    00130   }
    00131
    00132 #if TTD_ENDIAN == TTD_BIG_ENDIAN
    00133   if (sound->bits_per_sample == 16) {
    00134     uint num_samples = sound->file_size / 2;
    00135     int16 *samples = (int16 *)mem;
    00136     for (uint i = 0; i < num_samples; i++) {
    00137       samples[i] = BSWAP16(samples[i]);
    00138     }
    00139   }
    00140 #endif
    00141
    00142   assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
    00143   assert(sound->channels == 1);
    00144   assert(sound->file_size != 0 && sound->rate != 0);
    00145
    00146   MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
    00147
    00148   return true;
    00149 }
    00150
    00151 void InitializeSound()
    00152 {
    00153   DEBUG(misc, 1, "Loading sound effects...");
    00154   OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
    00155 }
    00156
    00157 /* Low level sound player */
    00158 static void StartSound(SoundID sound_id, float pan, uint volume)
    00159 {
    00160   if (volume == 0) return;
    00161
    00162   SoundEntry *sound = GetSound(sound_id);
    00163   if (sound == NULL) return;
    00164
    00165   /* NewGRF sound that wasn't loaded yet? */
    00166   if (sound->rate == 0 && sound->file_slot != 0) {
    00167     if (!LoadNewGRFSound(sound)) {
    00168       /* Mark as invalid. */
    00169       sound->file_slot = 0;
    00170       return;
    00171     }
    00172   }
    00173
    00174   /* Empty sound? */
    00175   if (sound->rate == 0) return;
    00176
    00177   MixerChannel *mc = MxAllocateChannel();
    00178   if (mc == NULL) return;
    00179
    00180   if (!SetBankSource(mc, sound)) return;
    00181
    00182   /* Apply the sound effect's own volume. */
    00183   volume = sound->volume * volume;
    00184
    00185   MxSetChannelVolume(mc, volume, pan);
    00186   MxActivateChannel(mc);
    00187 }
    00188
    00189
    00190 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
    00191 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
    00192
    00193 static const byte _sound_base_vol[] = {
    00194   128,  90, 128, 128, 128, 128, 128, 128,
    00195   128,  90,  90, 128, 128, 128, 128, 128,
    00196   128, 128, 128,  80, 128, 128, 128, 128,
    00197   128, 128, 128, 128, 128, 128, 128, 128,
    00198   128, 128,  90,  90,  90, 128,  90, 128,
    00199   128,  90, 128, 128, 128,  90, 128, 128,
    00200   128, 128, 128, 128,  90, 128, 128, 128,
    00201   128,  90, 128, 128, 128, 128, 128, 128,
    00202   128, 128,  90,  90,  90, 128, 128, 128,
    00203    90,
    00204 };
    00205
    00206 static const byte _sound_idx[] = {
    00207    2,  3,  4,  5,  6,  7,  8,  9,
    00208   10, 11, 12, 13, 14, 15, 16, 17,
    00209   18, 19, 20, 21, 22, 23, 24, 25,
    00210   26, 27, 28, 29, 30, 31, 32, 33,
    00211   34, 35, 36, 37, 38, 39, 40,  0,
    00212    1, 41, 42, 43, 44, 45, 46, 47,
    00213   48, 49, 50, 51, 52, 53, 54, 55,
    00214   56, 57, 58, 59, 60, 61, 62, 63,
    00215   64, 65, 66, 67, 68, 69, 70, 71,
    00216   72,
    00217 };
    00218
    00219 void SndCopyToPool()
    00220 {
    00221   SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT);
    00222   for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
    00223     sound[i] = _original_sounds[_sound_idx[i]];
    00224     sound[i].volume = _sound_base_vol[i];
    00225     sound[i].priority = 0;
    00226   }
    00227 }
    00228
    00237 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
    00238 {
    00239   if (_settings_client.music.effect_vol == 0) return;
    00240
    00241   const Window *w;
    00242   FOR_ALL_WINDOWS_FROM_BACK(w) {
    00243     const ViewPort *vp = w->viewport;
    00244
    00245     if (vp != NULL &&
    00246         left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
    00247         top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
    00248       int screen_x = (left + right) / 2 - vp->virtual_left;
    00249       int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
    00250       float panning = (float)screen_x / width;
    00251
    00252       StartSound(
    00253         sound,
    00254         panning,
    00255         (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
    00256       );
    00257       return;
    00258     }
    00259   }
    00260 }
    00261
    00262 void SndPlayTileFx(SoundID sound, TileIndex tile)
    00263 {
    00264   /* emits sound from center of the tile */
    00265   int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
    00266   int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
    00267   int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
    00268   Point pt = RemapCoords(x, y, z);
    00269   y += 2 * TILE_SIZE;
    00270   Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
    00271   SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
    00272 }
    00273
    00274 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
    00275 {
    00276   SndPlayScreenCoordFx(sound,
    00277     v->coord.left, v->coord.right,
    00278     v->coord.top, v->coord.bottom
    00279   );
    00280 }
    00281
    00282 void SndPlayFx(SoundID sound)
    00283 {
    00284   StartSound(sound, 0.5, _settings_client.music.effect_vol);
    00285 }
    00286
    00287 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<SoundsSet>, SoundsSet)
    00288
    00289
    00290 static const char * const _sound_file_names[] = { "samples" };
    00291
    00292
    00293 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
    00294 /* static */ const char * const *BaseSet<T, Tnum_files, Tsearch_in_tars>::file_names = _sound_file_names;
    00295
    00296 template <class Tbase_set>
    00297 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
    00298 {
    00299   return ".obs"; // OpenTTD Base Sounds
    00300 }
    00301
    00302 template <class Tbase_set>
    00303 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
    00304 {
    00305   if (BaseMedia<Tbase_set>::used_set != NULL) return true;
    00306
    00307   const Tbase_set *best = NULL;
    00308   for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != NULL; c = c->next) {
    00309     /* Skip unusable sets */
    00310     if (c->GetNumMissing() != 0) continue;
    00311
    00312     if (best == NULL ||
    00313         (best->fallback && !c->fallback) ||
    00314         best->valid_files < c->valid_files ||
    00315         (best->valid_files == c->valid_files &&
    00316           (best->shortname == c->shortname && best->version < c->version))) {
    00317       best = c;
    00318     }
    00319   }
    00320
    00321   BaseMedia<Tbase_set>::used_set = best;
    00322   return BaseMedia<Tbase_set>::used_set != NULL;
    00323 }
    00324