sound.cpp

Go to the documentation of this file.
00001 /* $Id: sound.cpp 15718 2009-03-15 00:32:18Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "landscape.h"
00007 #include "mixer.h"
00008 #include "fileio_func.h"
00009 #include "newgrf_sound.h"
00010 #include "fios.h"
00011 #include "window_gui.h"
00012 #include "map_func.h"
00013 #include "vehicle_base.h"
00014 #include "debug.h"
00015 
00016 static uint _file_count;
00017 static FileEntry *_files;
00018 MusicFileSettings msf;
00019 
00020 /* Number of levels of panning per side */
00021 #define PANNING_LEVELS 16
00022 
00024 static const uint ORIGINAL_SAMPLE_COUNT = 73;
00025 
00026 static void OpenBankFile(const char *filename)
00027 {
00028   FileEntry *fe = CallocT<FileEntry>(ORIGINAL_SAMPLE_COUNT);
00029   _file_count = ORIGINAL_SAMPLE_COUNT;
00030   _files = fe;
00031 
00032   FioOpenFile(SOUND_SLOT, filename);
00033   size_t pos = FioGetPos();
00034   uint count = FioReadDword() / 8;
00035 
00036   /* Simple check for the correct number of original sounds. */
00037   if (count != ORIGINAL_SAMPLE_COUNT) {
00038     /* Corrupt sample data? Just leave the allocated memory as those tell
00039      * there is no sound to play (size = 0 due to calloc). Not allocating
00040      * the memory disables valid NewGRFs that replace sounds. */
00041     DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename);
00042     return;
00043   }
00044 
00045   FioSeekTo(pos, SEEK_SET);
00046 
00047   for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
00048     fe[i].file_slot = SOUND_SLOT;
00049     fe[i].file_offset = FioReadDword() + pos;
00050     fe[i].file_size = FioReadDword();
00051   }
00052 
00053   for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++, fe++) {
00054     char name[255];
00055 
00056     FioSeekTo(fe->file_offset, SEEK_SET);
00057 
00058     /* Check for special case, see else case */
00059     FioReadBlock(name, FioReadByte()); // Read the name of the sound
00060     if (strcmp(name, "Corrupt sound") != 0) {
00061       FioSeekTo(12, SEEK_CUR); // Skip past RIFF header
00062 
00063       /* Read riff tags */
00064       for (;;) {
00065         uint32 tag = FioReadDword();
00066         uint32 size = FioReadDword();
00067 
00068         if (tag == ' tmf') {
00069           FioReadWord(); // wFormatTag
00070           fe->channels = FioReadWord(); // wChannels
00071           FioReadDword();   // samples per second
00072           fe->rate = 11025; // seems like all samples should be played at this rate.
00073           FioReadDword();   // avg bytes per second
00074           FioReadWord();    // alignment
00075           fe->bits_per_sample = FioReadByte(); // bits per sample
00076           FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
00077         } else if (tag == 'atad') {
00078           fe->file_size = size;
00079           fe->file_slot = SOUND_SLOT;
00080           fe->file_offset = FioGetPos();
00081           break;
00082         } else {
00083           fe->file_size = 0;
00084           break;
00085         }
00086       }
00087     } else {
00088       /*
00089        * Special case for the jackhammer sound
00090        * (name in sample.cat is "Corrupt sound")
00091        * It's no RIFF file, but raw PCM data
00092        */
00093       fe->channels = 1;
00094       fe->rate = 11025;
00095       fe->bits_per_sample = 8;
00096       fe->file_slot = SOUND_SLOT;
00097       fe->file_offset = FioGetPos();
00098     }
00099   }
00100 }
00101 
00102 uint GetNumOriginalSounds()
00103 {
00104   return _file_count;
00105 }
00106 
00107 static bool SetBankSource(MixerChannel *mc, const FileEntry *fe)
00108 {
00109   assert(fe != NULL);
00110 
00111   if (fe->file_size == 0) return false;
00112 
00113   int8 *mem = MallocT<int8>(fe->file_size);
00114 
00115   FioSeekToFile(fe->file_slot, fe->file_offset);
00116   FioReadBlock(mem, fe->file_size);
00117 
00118   for (uint i = 0; i != fe->file_size; i++) {
00119     mem[i] += -128; // Convert unsigned sound data to signed
00120   }
00121 
00122   assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
00123 
00124   MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
00125 
00126   return true;
00127 }
00128 
00129 bool SoundInitialize(const char *filename)
00130 {
00131   OpenBankFile(filename);
00132   return true;
00133 }
00134 
00135 /* Low level sound player */
00136 static void StartSound(uint sound, int panning, uint volume)
00137 {
00138   if (volume == 0) return;
00139 
00140   const FileEntry *fe = GetSound(sound);
00141   if (fe == NULL) return;
00142 
00143   MixerChannel *mc = MxAllocateChannel();
00144   if (mc == NULL) return;
00145 
00146   if (!SetBankSource(mc, fe)) return;
00147 
00148   /* Apply the sound effect's own volume. */
00149   volume = (fe->volume * volume) / 128;
00150 
00151   panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
00152   uint left_vol = (volume * PANNING_LEVELS) - (volume * panning);
00153   uint right_vol = (volume * PANNING_LEVELS) + (volume * panning);
00154   MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
00155   MxActivateChannel(mc);
00156 }
00157 
00158 
00159 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
00160 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00161 
00162 static const byte _sound_base_vol[] = {
00163   128,  90, 128, 128, 128, 128, 128, 128,
00164   128,  90,  90, 128, 128, 128, 128, 128,
00165   128, 128, 128,  80, 128, 128, 128, 128,
00166   128, 128, 128, 128, 128, 128, 128, 128,
00167   128, 128,  90,  90,  90, 128,  90, 128,
00168   128,  90, 128, 128, 128,  90, 128, 128,
00169   128, 128, 128, 128,  90, 128, 128, 128,
00170   128,  90, 128, 128, 128, 128, 128, 128,
00171   128, 128,  90,  90,  90, 128, 128, 128,
00172    90,
00173 };
00174 
00175 static const byte _sound_idx[] = {
00176    2,  3,  4,  5,  6,  7,  8,  9,
00177   10, 11, 12, 13, 14, 15, 16, 17,
00178   18, 19, 20, 21, 22, 23, 24, 25,
00179   26, 27, 28, 29, 30, 31, 32, 33,
00180   34, 35, 36, 37, 38, 39, 40,  0,
00181    1, 41, 42, 43, 44, 45, 46, 47,
00182   48, 49, 50, 51, 52, 53, 54, 55,
00183   56, 57, 58, 59, 60, 61, 62, 63,
00184   64, 65, 66, 67, 68, 69, 70, 71,
00185   72,
00186 };
00187 
00188 void SndCopyToPool()
00189 {
00190   for (uint i = 0; i < _file_count; i++) {
00191     FileEntry *orig = &_files[_sound_idx[i]];
00192     FileEntry *fe = AllocateFileEntry();
00193 
00194     *fe = *orig;
00195     fe->volume = _sound_base_vol[i];
00196     fe->priority = 0;
00197   }
00198 }
00199 
00208 static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom)
00209 {
00210   if (msf.effect_vol == 0) return;
00211 
00212   const Window *w;
00213   FOR_ALL_WINDOWS_FROM_BACK(w) {
00214     const ViewPort *vp = w->viewport;
00215 
00216     if (vp != NULL &&
00217         left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00218         top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00219       int screen_x = (left + right) / 2 - vp->virtual_left;
00220       int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00221       int panning = (screen_x * PANNING_LEVELS * 2) / width - PANNING_LEVELS;
00222 
00223       StartSound(
00224         sound,
00225         panning,
00226         (msf.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00227       );
00228       return;
00229     }
00230   }
00231 }
00232 
00233 void SndPlayTileFx(SoundFx sound, TileIndex tile)
00234 {
00235   /* emits sound from center of the tile */
00236   int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00237   int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00238   uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00239   Point pt = RemapCoords(x, y, z);
00240   y += 2 * TILE_SIZE;
00241   Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
00242   SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00243 }
00244 
00245 void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
00246 {
00247   SndPlayScreenCoordFx(sound,
00248     v->coord.left, v->coord.right,
00249     v->coord.top, v->coord.bottom
00250   );
00251 }
00252 
00253 void SndPlayFx(SoundFx sound)
00254 {
00255   StartSound(sound, 0, msf.effect_vol);
00256 }

Generated on Mon Mar 23 00:25:22 2009 for OpenTTD by  doxygen 1.5.6