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/>.
8 /** @file sound.cpp Handling of playing sounds. */
11 #include "landscape.h"
13 #include "newgrf_sound.h"
14 #include "random_access_file_type.h"
15 #include "window_gui.h"
16 #include "vehicle_base.h"
18 /* The type of set we're replacing */
19 #define SET_TYPE "sounds"
20 #include "base_media_func.h"
22 #include "safeguards.h"
24 static SoundEntry _original_sounds
[ORIGINAL_SAMPLE_COUNT
];
26 static void OpenBankFile(const char *filename
)
29 * The sound file for the original sounds, i.e. those not defined/overridden by a NewGRF.
30 * Needs to be kept alive during the game as _original_sounds[n].file refers to this.
32 static std::unique_ptr
<RandomAccessFile
> original_sound_file
;
34 memset(_original_sounds
, 0, sizeof(_original_sounds
));
36 /* If there is no sound file (nosound set), don't load anything */
37 if (filename
== nullptr) return;
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();
43 /* The new format has the highest bit always set */
44 bool new_format
= HasBit(count
, 31);
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
);
57 original_sound_file
->SeekTo(pos
, SEEK_SET
);
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();
65 for (uint i
= 0; i
!= ORIGINAL_SAMPLE_COUNT
; i
++) {
66 SoundEntry
*sound
= &_original_sounds
[i
];
69 original_sound_file
->SeekTo(sound
->file_offset
, SEEK_SET
);
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
78 uint32 tag
= original_sound_file
->ReadDword();
79 uint32 size
= original_sound_file
->ReadDword();
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();
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
108 sound
->bits_per_sample
= 8;
109 sound
->file
= original_sound_file
.get();
110 sound
->file_offset
= original_sound_file
->GetPos();
115 static bool SetBankSource(MixerChannel
*mc
, const SoundEntry
*sound
)
117 assert(sound
!= nullptr);
119 /* Check for valid sound size. */
120 if (sound
->file_size
== 0 || sound
->file_size
> ((size_t)-1) - 2) return false;
122 int8
*mem
= MallocT
<int8
>(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;
128 RandomAccessFile
*file
= sound
->file
;
129 file
->SeekTo(sound
->file_offset
, SEEK_SET
);
130 file
->ReadBlock(mem
, sound
->file_size
);
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
139 #if TTD_ENDIAN == TTD_BIG_ENDIAN
140 if (sound
->bits_per_sample
== 16) {
141 uint num_samples
= sound
->file_size
/ 2;
142 int16
*samples
= (int16
*)mem
;
143 for (uint i
= 0; i
< num_samples
; i
++) {
144 samples
[i
] = BSWAP16(samples
[i
]);
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);
153 MxSetChannelRawSrc(mc
, mem
, sound
->file_size
, sound
->rate
, sound
->bits_per_sample
== 16);
158 void InitializeSound()
160 Debug(misc
, 1, "Loading sound effects...");
161 OpenBankFile(BaseSounds::GetUsedSet()->files
->filename
);
164 /* Low level sound player */
165 static void StartSound(SoundID sound_id
, float pan
, uint volume
)
167 if (volume
== 0) return;
169 SoundEntry
*sound
= GetSound(sound_id
);
170 if (sound
== nullptr) return;
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;
182 if (sound
->rate
== 0) return;
184 MixerChannel
*mc
= MxAllocateChannel();
185 if (mc
== nullptr) return;
187 if (!SetBankSource(mc
, sound
)) return;
189 /* Apply the sound effect's own volume. */
190 volume
= sound
->volume
* volume
;
192 MxSetChannelVolume(mc
, volume
, pan
);
193 MxActivateChannel(mc
);
197 static const byte _vol_factor_by_zoom
[] = {255, 255, 255, 190, 134, 87};
198 static_assert(lengthof(_vol_factor_by_zoom
) == ZOOM_LVL_COUNT
);
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,
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,
228 SoundEntry
*sound
= AllocateSound(ORIGINAL_SAMPLE_COUNT
);
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;
237 * Decide 'where' (between left and right speaker) to play the sound effect.
238 * @param sound Sound effect to play
239 * @param left Left edge of virtual coordinates where the sound is produced
240 * @param right Right edge of virtual coordinates where the sound is produced
241 * @param top Top edge of virtual coordinates where the sound is produced
242 * @param bottom Bottom edge of virtual coordinates where the sound is produced
244 static void SndPlayScreenCoordFx(SoundID sound
, int left
, int right
, int top
, int bottom
)
246 if (_settings_client
.music
.effect_vol
== 0) return;
248 /* Iterate from back, so that main viewport is checked first */
249 for (const Window
*w
: Window::IterateFromBack()) {
250 const Viewport
*vp
= w
->viewport
;
253 left
< vp
->virtual_left
+ vp
->virtual_width
&& right
> vp
->virtual_left
&&
254 top
< vp
->virtual_top
+ vp
->virtual_height
&& bottom
> vp
->virtual_top
) {
255 int screen_x
= (left
+ right
) / 2 - vp
->virtual_left
;
256 int width
= (vp
->virtual_width
== 0 ? 1 : vp
->virtual_width
);
257 float panning
= (float)screen_x
/ width
;
262 _vol_factor_by_zoom
[vp
->zoom
- ZOOM_LVL_BEGIN
]
269 void SndPlayTileFx(SoundID sound
, TileIndex tile
)
271 /* emits sound from center of the tile */
272 int x
= std::min(MapMaxX() - 1, TileX(tile
)) * TILE_SIZE
+ TILE_SIZE
/ 2;
273 int y
= std::min(MapMaxY() - 1, TileY(tile
)) * TILE_SIZE
- TILE_SIZE
/ 2;
274 int z
= (y
< 0 ? 0 : GetSlopePixelZ(x
, y
));
275 Point pt
= RemapCoords(x
, y
, z
);
277 Point pt2
= RemapCoords(x
, y
, GetSlopePixelZ(x
, y
));
278 SndPlayScreenCoordFx(sound
, pt
.x
, pt2
.x
, pt
.y
, pt2
.y
);
281 void SndPlayVehicleFx(SoundID sound
, const Vehicle
*v
)
283 SndPlayScreenCoordFx(sound
,
284 v
->coord
.left
, v
->coord
.right
,
285 v
->coord
.top
, v
->coord
.bottom
289 void SndPlayFx(SoundID sound
)
291 StartSound(sound
, 0.5, UINT8_MAX
);
294 INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia
<SoundsSet
>, SoundsSet
)
296 /** Names corresponding to the sound set's files */
297 static const char * const _sound_file_names
[] = { "samples" };
300 template <class T
, size_t Tnum_files
, bool Tsearch_in_tars
>
301 /* static */ const char * const *BaseSet
<T
, Tnum_files
, Tsearch_in_tars
>::file_names
= _sound_file_names
;
303 template <class Tbase_set
>
304 /* static */ const char *BaseMedia
<Tbase_set
>::GetExtension()
306 return ".obs"; // OpenTTD Base Sounds
309 template <class Tbase_set
>
310 /* static */ bool BaseMedia
<Tbase_set
>::DetermineBestSet()
312 if (BaseMedia
<Tbase_set
>::used_set
!= nullptr) return true;
314 const Tbase_set
*best
= nullptr;
315 for (const Tbase_set
*c
= BaseMedia
<Tbase_set
>::available_sets
; c
!= nullptr; c
= c
->next
) {
316 /* Skip unusable sets */
317 if (c
->GetNumMissing() != 0) continue;
319 if (best
== nullptr ||
320 (best
->fallback
&& !c
->fallback
) ||
321 best
->valid_files
< c
->valid_files
||
322 (best
->valid_files
== c
->valid_files
&&
323 (best
->shortname
== c
->shortname
&& best
->version
< c
->version
))) {
328 BaseMedia
<Tbase_set
>::used_set
= best
;
329 return BaseMedia
<Tbase_set
>::used_set
!= nullptr;