sound.cpp

Go to the documentation of this file.
00001 /* $Id: sound.cpp 15299 2009-01-31 20:16:06Z smatz $ */
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   if (mem == NULL) return false;
00115 
00116   FioSeekToFile(fe->file_slot, fe->file_offset);
00117   FioReadBlock(mem, fe->file_size);
00118 
00119   for (uint i = 0; i != fe->file_size; i++) {
00120     mem[i] += -128; // Convert unsigned sound data to signed
00121   }
00122 
00123   assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0);
00124 
00125   MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE);
00126 
00127   return true;
00128 }
00129 
00130 bool SoundInitialize(const char *filename)
00131 {
00132   OpenBankFile(filename);
00133   return true;
00134 }
00135 
00136 /* Low level sound player */
00137 static void StartSound(uint sound, int panning, uint volume)
00138 {
00139   if (volume == 0) return;
00140 
00141   const FileEntry *fe = GetSound(sound);
00142   if (fe == NULL) return;
00143 
00144   MixerChannel *mc = MxAllocateChannel();
00145   if (mc == NULL) return;
00146 
00147   if (!SetBankSource(mc, fe)) return;
00148 
00149   /* Apply the sound effect's own volume. */
00150   volume = (fe->volume * volume) / 128;
00151 
00152   panning = Clamp(panning, -PANNING_LEVELS, PANNING_LEVELS);
00153   uint left_vol = (volume * PANNING_LEVELS) - (volume * panning);
00154   uint right_vol = (volume * PANNING_LEVELS) + (volume * panning);
00155   MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS);
00156   MxActivateChannel(mc);
00157 }
00158 
00159 
00160 static const byte _vol_factor_by_zoom[] = {255, 190, 134, 87};
00161 assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT);
00162 
00163 static const byte _sound_base_vol[] = {
00164   128,  90, 128, 128, 128, 128, 128, 128,
00165   128,  90,  90, 128, 128, 128, 128, 128,
00166   128, 128, 128,  80, 128, 128, 128, 128,
00167   128, 128, 128, 128, 128, 128, 128, 128,
00168   128, 128,  90,  90,  90, 128,  90, 128,
00169   128,  90, 128, 128, 128,  90, 128, 128,
00170   128, 128, 128, 128,  90, 128, 128, 128,
00171   128,  90, 128, 128, 128, 128, 128, 128,
00172   128, 128,  90,  90,  90, 128, 128, 128,
00173    90,
00174 };
00175 
00176 static const byte _sound_idx[] = {
00177    2,  3,  4,  5,  6,  7,  8,  9,
00178   10, 11, 12, 13, 14, 15, 16, 17,
00179   18, 19, 20, 21, 22, 23, 24, 25,
00180   26, 27, 28, 29, 30, 31, 32, 33,
00181   34, 35, 36, 37, 38, 39, 40,  0,
00182    1, 41, 42, 43, 44, 45, 46, 47,
00183   48, 49, 50, 51, 52, 53, 54, 55,
00184   56, 57, 58, 59, 60, 61, 62, 63,
00185   64, 65, 66, 67, 68, 69, 70, 71,
00186   72,
00187 };
00188 
00189 void SndCopyToPool()
00190 {
00191   for (uint i = 0; i < _file_count; i++) {
00192     FileEntry *orig = &_files[_sound_idx[i]];
00193     FileEntry *fe = AllocateFileEntry();
00194 
00195     *fe = *orig;
00196     fe->volume = _sound_base_vol[i];
00197     fe->priority = 0;
00198   }
00199 }
00200 
00209 static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom)
00210 {
00211   if (msf.effect_vol == 0) return;
00212 
00213   const Window *w;
00214   FOR_ALL_WINDOWS_FROM_BACK(w) {
00215     const ViewPort *vp = w->viewport;
00216 
00217     if (vp != NULL &&
00218         left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
00219         top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
00220       int screen_x = (left + right) / 2 - vp->virtual_left;
00221       int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
00222       int panning = (screen_x * PANNING_LEVELS * 2) / width - PANNING_LEVELS;
00223 
00224       StartSound(
00225         sound,
00226         panning,
00227         (msf.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256
00228       );
00229       return;
00230     }
00231   }
00232 }
00233 
00234 void SndPlayTileFx(SoundFx sound, TileIndex tile)
00235 {
00236   /* emits sound from center of the tile */
00237   int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
00238   int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
00239   uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
00240   Point pt = RemapCoords(x, y, z);
00241   y += 2 * TILE_SIZE;
00242   Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
00243   SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
00244 }
00245 
00246 void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
00247 {
00248   SndPlayScreenCoordFx(sound,
00249     v->left_coord, v->right_coord,
00250     v->top_coord, v->top_coord
00251   );
00252 }
00253 
00254 void SndPlayFx(SoundFx sound)
00255 {
00256   StartSound(sound, 0, msf.effect_vol);
00257 }

Generated on Mon Feb 16 23:12:10 2009 for openttd by  doxygen 1.5.6