OpenTTD Source  14.0-beta3
sound.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "stdafx.h"
11 #include "landscape.h"
12 #include "mixer.h"
13 #include "newgrf_sound.h"
15 #include "window_gui.h"
16 #include "vehicle_base.h"
17 
18 /* The type of set we're replacing */
19 #define SET_TYPE "sounds"
20 #include "base_media_func.h"
21 
22 #include "safeguards.h"
23 
24 static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT];
25 
26 static void OpenBankFile(const std::string &filename)
27 {
32  static std::unique_ptr<RandomAccessFile> original_sound_file;
33 
34  memset(_original_sounds, 0, sizeof(_original_sounds));
35 
36  /* If there is no sound file (nosound set), don't load anything */
37  if (filename.empty()) return;
38 
39  original_sound_file.reset(new RandomAccessFile(filename, BASESET_DIR));
40  size_t pos = original_sound_file->GetPos();
41  uint count = original_sound_file->ReadDword();
42 
43  /* The new format has the highest bit always set */
44  bool new_format = HasBit(count, 31);
45  ClrBit(count, 31);
46  count /= 8;
47 
48  /* Simple check for the correct number of original sounds. */
49  if (count != ORIGINAL_SAMPLE_COUNT) {
50  /* Corrupt sample data? Just leave the allocated memory as those tell
51  * there is no sound to play (size = 0 due to calloc). Not allocating
52  * the memory disables valid NewGRFs that replace sounds. */
53  Debug(misc, 6, "Incorrect number of sounds in '{}', ignoring.", filename);
54  return;
55  }
56 
57  original_sound_file->SeekTo(pos, SEEK_SET);
58 
59  for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
60  _original_sounds[i].file = original_sound_file.get();
61  _original_sounds[i].file_offset = GB(original_sound_file->ReadDword(), 0, 31) + pos;
62  _original_sounds[i].file_size = original_sound_file->ReadDword();
63  }
64 
65  for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) {
66  SoundEntry *sound = &_original_sounds[i];
67  char name[255];
68 
69  original_sound_file->SeekTo(sound->file_offset, SEEK_SET);
70 
71  /* Check for special case, see else case */
72  original_sound_file->ReadBlock(name, original_sound_file->ReadByte()); // Read the name of the sound
73  if (new_format || strcmp(name, "Corrupt sound") != 0) {
74  original_sound_file->SeekTo(12, SEEK_CUR); // Skip past RIFF header
75 
76  /* Read riff tags */
77  for (;;) {
78  uint32_t tag = original_sound_file->ReadDword();
79  uint32_t size = original_sound_file->ReadDword();
80 
81  if (tag == ' tmf') {
82  original_sound_file->ReadWord(); // wFormatTag
83  sound->channels = original_sound_file->ReadWord(); // wChannels
84  sound->rate = original_sound_file->ReadDword(); // samples per second
85  if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate.
86  original_sound_file->ReadDword(); // avg bytes per second
87  original_sound_file->ReadWord(); // alignment
88  sound->bits_per_sample = original_sound_file->ReadByte(); // bits per sample
89  original_sound_file->SeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR);
90  } else if (tag == 'atad') {
91  sound->file_size = size;
92  sound->file = original_sound_file.get();
93  sound->file_offset = original_sound_file->GetPos();
94  break;
95  } else {
96  sound->file_size = 0;
97  break;
98  }
99  }
100  } else {
101  /*
102  * Special case for the jackhammer sound
103  * (name in sample.cat is "Corrupt sound")
104  * It's no RIFF file, but raw PCM data
105  */
106  sound->channels = 1;
107  sound->rate = 11025;
108  sound->bits_per_sample = 8;
109  sound->file = original_sound_file.get();
110  sound->file_offset = original_sound_file->GetPos();
111  }
112  }
113 }
114 
115 static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound)
116 {
117  assert(sound != nullptr);
118 
119  /* Check for valid sound size. */
120  if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false;
121 
122  int8_t *mem = MallocT<int8_t>(sound->file_size + 2);
123  /* Add two extra bytes so rate conversion can read these
124  * without reading out of its input buffer. */
125  mem[sound->file_size ] = 0;
126  mem[sound->file_size + 1] = 0;
127 
128  RandomAccessFile *file = sound->file;
129  file->SeekTo(sound->file_offset, SEEK_SET);
130  file->ReadBlock(mem, sound->file_size);
131 
132  /* 16-bit PCM WAV files should be signed by default */
133  if (sound->bits_per_sample == 8) {
134  for (uint i = 0; i != sound->file_size; i++) {
135  mem[i] += -128; // Convert unsigned sound data to signed
136  }
137  }
138 
139 #if TTD_ENDIAN == TTD_BIG_ENDIAN
140  if (sound->bits_per_sample == 16) {
141  uint num_samples = sound->file_size / 2;
142  int16_t *samples = (int16_t *)mem;
143  for (uint i = 0; i < num_samples; i++) {
144  samples[i] = BSWAP16(samples[i]);
145  }
146  }
147 #endif
148 
149  assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16);
150  assert(sound->channels == 1);
151  assert(sound->file_size != 0 && sound->rate != 0);
152 
153  MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16);
154 
155  return true;
156 }
157 
158 void InitializeSound()
159 {
160  Debug(misc, 1, "Loading sound effects...");
161  OpenBankFile(BaseSounds::GetUsedSet()->files->filename);
162 }
163 
164 /* Low level sound player */
165 static void StartSound(SoundID sound_id, float pan, uint volume)
166 {
167  if (volume == 0) return;
168 
169  SoundEntry *sound = GetSound(sound_id);
170  if (sound == nullptr) return;
171 
172  /* NewGRF sound that wasn't loaded yet? */
173  if (sound->rate == 0 && sound->file != nullptr) {
174  if (!LoadNewGRFSound(sound)) {
175  /* Mark as invalid. */
176  sound->file = nullptr;
177  return;
178  }
179  }
180 
181  /* Empty sound? */
182  if (sound->rate == 0) return;
183 
184  MixerChannel *mc = MxAllocateChannel();
185  if (mc == nullptr) return;
186 
187  if (!SetBankSource(mc, sound)) return;
188 
189  /* Apply the sound effect's own volume. */
190  volume = sound->volume * volume;
191 
192  MxSetChannelVolume(mc, volume, pan);
193  MxActivateChannel(mc);
194 }
195 
196 
197 static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87};
198 static_assert(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_END);
199 
200 static const byte _sound_base_vol[] = {
201  128, 90, 128, 128, 128, 128, 128, 128,
202  128, 90, 90, 128, 128, 128, 128, 128,
203  128, 128, 128, 80, 128, 128, 128, 128,
204  128, 128, 128, 128, 128, 128, 128, 128,
205  128, 128, 90, 90, 90, 128, 90, 128,
206  128, 90, 128, 128, 128, 90, 128, 128,
207  128, 128, 128, 128, 90, 128, 128, 128,
208  128, 90, 128, 128, 128, 128, 128, 128,
209  128, 128, 90, 90, 90, 128, 128, 128,
210  90,
211 };
212 
213 static const byte _sound_idx[] = {
214  2, 3, 4, 5, 6, 7, 8, 9,
215  10, 11, 12, 13, 14, 15, 16, 17,
216  18, 19, 20, 21, 22, 23, 24, 25,
217  26, 27, 28, 29, 30, 31, 32, 33,
218  34, 35, 36, 37, 38, 39, 40, 0,
219  1, 41, 42, 43, 44, 45, 46, 47,
220  48, 49, 50, 51, 52, 53, 54, 55,
221  56, 57, 58, 59, 60, 61, 62, 63,
222  64, 65, 66, 67, 68, 69, 70, 71,
223  72,
224 };
225 
226 void SndCopyToPool()
227 {
229  for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) {
230  sound[i] = _original_sounds[_sound_idx[i]];
231  sound[i].volume = _sound_base_vol[i];
232  sound[i].priority = 0;
233  }
234 }
235 
245 static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
246 {
247  /* Iterate from back, so that main viewport is checked first */
248  for (const Window *w : Window::IterateFromBack()) {
249  const Viewport *vp = w->viewport;
250 
251  if (vp != nullptr &&
252  left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left &&
253  top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) {
254  int screen_x = (left + right) / 2 - vp->virtual_left;
255  int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width);
256  float panning = (float)screen_x / width;
257 
258  StartSound(
259  sound,
260  panning,
261  _vol_factor_by_zoom[vp->zoom]
262  );
263  return;
264  }
265  }
266 }
267 
268 void SndPlayTileFx(SoundID sound, TileIndex tile)
269 {
270  /* emits sound from center of the tile */
271  int x = std::min(Map::MaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
272  int y = std::min(Map::MaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
273  int z = (y < 0 ? 0 : GetSlopePixelZ(x, y));
274  Point pt = RemapCoords(x, y, z);
275  y += 2 * TILE_SIZE;
276  Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y));
277  SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
278 }
279 
280 void SndPlayVehicleFx(SoundID sound, const Vehicle *v)
281 {
282  SndPlayScreenCoordFx(sound,
283  v->coord.left, v->coord.right,
284  v->coord.top, v->coord.bottom
285  );
286 }
287 
288 void SndPlayFx(SoundID sound)
289 {
290  StartSound(sound, 0.5, UINT8_MAX);
291 }
292 
294 
295 
296 static const char * const _sound_file_names[] = { "samples" };
297 
298 
299 template <class T, size_t Tnum_files, bool Tsearch_in_tars>
301 
302 template <class Tbase_set>
303 /* static */ const char *BaseMedia<Tbase_set>::GetExtension()
304 {
305  return ".obs"; // OpenTTD Base Sounds
306 }
307 
308 template <class Tbase_set>
309 /* static */ bool BaseMedia<Tbase_set>::DetermineBestSet()
310 {
311  if (BaseMedia<Tbase_set>::used_set != nullptr) return true;
312 
313  const Tbase_set *best = nullptr;
314  for (const Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
315  /* Skip unusable sets */
316  if (c->GetNumMissing() != 0) continue;
317 
318  if (best == nullptr ||
319  (best->fallback && !c->fallback) ||
320  best->valid_files < c->valid_files ||
321  (best->valid_files == c->valid_files &&
322  (best->shortname == c->shortname && best->version < c->version))) {
323  best = c;
324  }
325  }
326 
328  return BaseMedia<Tbase_set>::used_set != nullptr;
329 }
330 
TileY
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition: map_func.h:437
AllocateSound
SoundEntry * AllocateSound(uint num)
Allocate sound slots.
Definition: newgrf_sound.cpp:31
base_media_func.h
BaseMedia::DetermineBestSet
static bool DetermineBestSet()
Determine the graphics pack that has to be used.
Definition: gfxinit.cpp:475
SoundsSet
All data of a sounds set.
Definition: base_media_base.h:294
Map::MaxX
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition: map_func.h:297
ZOOM_LVL_END
@ ZOOM_LVL_END
End for iteration.
Definition: zoom_type.h:28
BASESET_DIR
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Definition: fileio_type.h:116
GB
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition: bitmath_func.hpp:32
vehicle_base.h
TILE_SIZE
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
Vehicle
Vehicle data structure.
Definition: vehicle_base.h:240
Viewport::virtual_top
int virtual_top
Virtual top coordinate.
Definition: viewport_type.h:29
RandomAccessFile::ReadBlock
void ReadBlock(void *ptr, size_t size)
Read a block.
Definition: random_access_file.cpp:139
GetSlopePixelZ
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Definition: landscape.cpp:299
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
OpenBankFile
static void OpenBankFile(const std::string &filename)
Definition: sound.cpp:26
random_access_file_type.h
window_gui.h
Viewport
Data structure for viewport, display of a part of the world.
Definition: viewport_type.h:22
LoadNewGRFSound
bool LoadNewGRFSound(SoundEntry *sound)
Extract meta data from a NewGRF sound.
Definition: newgrf_sound.cpp:66
Viewport::virtual_left
int virtual_left
Virtual left coordinate.
Definition: viewport_type.h:28
BaseMedia< SoundsSet >
safeguards.h
Viewport::virtual_width
int virtual_width
width << zoom
Definition: viewport_type.h:30
Point
Coordinates of a point in 2D.
Definition: geometry_type.hpp:21
SoundEntry
Definition: sound_type.h:13
stdafx.h
landscape.h
Window::AllWindows
Iterable ensemble of all valid Windows.
Definition: window_gui.h:906
INSTANTIATE_BASE_MEDIA_METHODS
#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type)
Force instantiation of methods so we don't get linker errors.
Definition: base_media_func.h:414
SndPlayScreenCoordFx
static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom)
Decide 'where' (between left and right speaker) to play the sound effect.
Definition: sound.cpp:245
BSWAP16
static uint16_t BSWAP16(uint16_t x)
Perform a 16 bits endianness bitswap on x.
Definition: bitmath_func.hpp:360
newgrf_sound.h
Map::MaxY
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition: map_func.h:306
MixerChannel
Definition: mixer.cpp:20
BaseSet
Information about a single base set.
Definition: base_media_base.h:49
MxSetChannelVolume
void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan)
Set volume and pan parameters for a sound.
Definition: mixer.cpp:191
ORIGINAL_SAMPLE_COUNT
static const uint ORIGINAL_SAMPLE_COUNT
The number of sounds in the original sample.cat.
Definition: sound_type.h:116
Vehicle::coord
Rect coord
NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves.
Definition: vehicle_base.h:275
RandomAccessFile::SeekTo
void SeekTo(size_t pos, int mode)
Seek in the current file.
Definition: random_access_file.cpp:84
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:300
Viewport::zoom
ZoomLevel zoom
The zoom level of the viewport.
Definition: viewport_type.h:33
_sound_file_names
static const char *const _sound_file_names[]
Names corresponding to the sound set's files.
Definition: sound.cpp:296
Window
Data structure for an opened window.
Definition: window_gui.h:267
BaseMedia< SoundsSet >::GetUsedSet
static const SoundsSet * GetUsedSet()
Return the used set.
Definition: base_media_func.h:394
TileX
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition: map_func.h:427
Viewport::virtual_height
int virtual_height
height << zoom
Definition: viewport_type.h:31
ClrBit
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Definition: bitmath_func.hpp:151
BaseMedia::GetExtension
static const char * GetExtension()
Get the extension that is used to identify this set.
Definition: gfxinit.cpp:499
RemapCoords
Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition: landscape.h:82
mixer.h
RandomAccessFile
A file from which bytes, words and double words are read in (potentially) a random order.
Definition: random_access_file_type.h:22
HasBit
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition: bitmath_func.hpp:103