sound.cpp

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

Generated on Sun Nov 15 15:40:15 2009 for OpenTTD by  doxygen 1.5.6