|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "functions.h" |
|
6 #include "map.h" |
|
7 #include "mixer.h" |
|
8 #include "sound.h" |
|
9 #include "vehicle.h" |
|
10 #include "window.h" |
|
11 #include "viewport.h" |
|
12 #include "fileio.h" |
|
13 #include "newgrf_sound.h" |
|
14 |
|
15 static uint _file_count; |
|
16 static FileEntry *_files; |
|
17 |
|
18 #define SOUND_SLOT 63 |
|
19 // Number of levels of panning per side |
|
20 #define PANNING_LEVELS 16 |
|
21 |
|
22 |
|
23 static void OpenBankFile(const char *filename) |
|
24 { |
|
25 FileEntry *fe; |
|
26 uint count; |
|
27 uint i; |
|
28 |
|
29 FioOpenFile(SOUND_SLOT, filename); |
|
30 count = FioReadDword() / 8; |
|
31 fe = calloc(count, sizeof(*fe)); |
|
32 |
|
33 if (fe == NULL) { |
|
34 _file_count = 0; |
|
35 _files = NULL; |
|
36 return; |
|
37 } |
|
38 |
|
39 _file_count = count; |
|
40 _files = fe; |
|
41 |
|
42 FioSeekTo(0, SEEK_SET); |
|
43 |
|
44 for (i = 0; i != count; i++) { |
|
45 fe[i].file_offset = FioReadDword(); |
|
46 fe[i].file_size = FioReadDword(); |
|
47 } |
|
48 |
|
49 for (i = 0; i != count; i++, fe++) { |
|
50 char name[255]; |
|
51 |
|
52 FioSeekTo(fe->file_offset, SEEK_SET); |
|
53 |
|
54 // Check for special case, see else case |
|
55 FioReadBlock(name, FioReadByte()); // Read the name of the sound |
|
56 if (strcmp(name, "Corrupt sound") != 0) { |
|
57 FioSeekTo(12, SEEK_CUR); // Skip past RIFF header |
|
58 |
|
59 // Read riff tags |
|
60 for (;;) { |
|
61 uint32 tag = FioReadDword(); |
|
62 uint32 size = FioReadDword(); |
|
63 |
|
64 if (tag == ' tmf') { |
|
65 FioReadWord(); // wFormatTag |
|
66 fe->channels = FioReadWord(); // wChannels |
|
67 FioReadDword(); // samples per second |
|
68 fe->rate = 11025; // seems like all samples should be played at this rate. |
|
69 FioReadDword(); // avg bytes per second |
|
70 FioReadWord(); // alignment |
|
71 fe->bits_per_sample = FioReadByte(); // bits per sample |
|
72 FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR); |
|
73 } else if (tag == 'atad') { |
|
74 fe->file_size = size; |
|
75 fe->file_offset = FioGetPos() | (SOUND_SLOT << 24); |
|
76 break; |
|
77 } else { |
|
78 fe->file_size = 0; |
|
79 break; |
|
80 } |
|
81 } |
|
82 } else { |
|
83 /* |
|
84 * Special case for the jackhammer sound |
|
85 * (name in sample.cat is "Corrupt sound") |
|
86 * It's no RIFF file, but raw PCM data |
|
87 */ |
|
88 fe->channels = 1; |
|
89 fe->rate = 11025; |
|
90 fe->bits_per_sample = 8; |
|
91 fe->file_offset = FioGetPos() | (SOUND_SLOT << 24); |
|
92 } |
|
93 } |
|
94 } |
|
95 |
|
96 uint GetNumOriginalSounds(void) |
|
97 { |
|
98 return _file_count; |
|
99 } |
|
100 |
|
101 static bool SetBankSource(MixerChannel *mc, uint bank) |
|
102 { |
|
103 const FileEntry *fe; |
|
104 int8 *mem; |
|
105 uint i; |
|
106 |
|
107 if (bank >= GetNumSounds()) return false; |
|
108 fe = GetSound(bank); |
|
109 |
|
110 if (fe->file_size == 0) return false; |
|
111 |
|
112 mem = malloc(fe->file_size); |
|
113 if (mem == NULL) return false; |
|
114 |
|
115 FioSeekToFile(fe->file_offset); |
|
116 FioReadBlock(mem, fe->file_size); |
|
117 |
|
118 for (i = 0; i != fe->file_size; i++) |
|
119 mem[i] += -128; // Convert unsigned sound data to signed |
|
120 |
|
121 assert(fe->bits_per_sample == 8 && fe->channels == 1 && fe->file_size != 0 && fe->rate != 0); |
|
122 |
|
123 MxSetChannelRawSrc(mc, mem, fe->file_size, fe->rate, MX_AUTOFREE); |
|
124 |
|
125 return true; |
|
126 } |
|
127 |
|
128 bool SoundInitialize(const char *filename) |
|
129 { |
|
130 OpenBankFile(filename); |
|
131 return true; |
|
132 } |
|
133 |
|
134 // Low level sound player |
|
135 static void StartSound(uint sound, int panning, uint volume) |
|
136 { |
|
137 MixerChannel *mc; |
|
138 uint left_vol, right_vol; |
|
139 |
|
140 if (volume == 0) return; |
|
141 mc = MxAllocateChannel(); |
|
142 if (mc == NULL) return; |
|
143 if (!SetBankSource(mc, sound)) return; |
|
144 |
|
145 panning = clamp(panning, -PANNING_LEVELS, PANNING_LEVELS); |
|
146 left_vol = (volume * PANNING_LEVELS) - (volume * panning); |
|
147 right_vol = (volume * PANNING_LEVELS) + (volume * panning); |
|
148 MxSetChannelVolume(mc, left_vol * 128 / PANNING_LEVELS, right_vol * 128 / PANNING_LEVELS); |
|
149 MxActivateChannel(mc); |
|
150 } |
|
151 |
|
152 |
|
153 static const byte _vol_factor_by_zoom[] = {255, 190, 134}; |
|
154 |
|
155 static const byte _sound_base_vol[] = { |
|
156 128, 90, 128, 128, 128, 128, 128, 128, |
|
157 128, 90, 90, 128, 128, 128, 128, 128, |
|
158 128, 128, 128, 80, 128, 128, 128, 128, |
|
159 128, 128, 128, 128, 128, 128, 128, 128, |
|
160 128, 128, 90, 90, 90, 128, 90, 128, |
|
161 128, 90, 128, 128, 128, 90, 128, 128, |
|
162 128, 128, 128, 128, 90, 128, 128, 128, |
|
163 128, 90, 128, 128, 128, 128, 128, 128, |
|
164 128, 128, 90, 90, 90, 128, 128, 128, |
|
165 90, |
|
166 }; |
|
167 |
|
168 static const byte _sound_idx[] = { |
|
169 2, 3, 4, 5, 6, 7, 8, 9, |
|
170 10, 11, 12, 13, 14, 15, 16, 17, |
|
171 18, 19, 20, 21, 22, 23, 24, 25, |
|
172 26, 27, 28, 29, 30, 31, 32, 33, |
|
173 34, 35, 36, 37, 38, 39, 40, 0, |
|
174 1, 41, 42, 43, 44, 45, 46, 47, |
|
175 48, 49, 50, 51, 52, 53, 54, 55, |
|
176 56, 57, 58, 59, 60, 61, 62, 63, |
|
177 64, 65, 66, 67, 68, 69, 70, 71, |
|
178 72, |
|
179 }; |
|
180 |
|
181 void SndCopyToPool(void) |
|
182 { |
|
183 uint i; |
|
184 |
|
185 for (i = 0; i < _file_count; i++) { |
|
186 FileEntry *orig = &_files[_sound_idx[i]]; |
|
187 FileEntry *fe = AllocateFileEntry(); |
|
188 |
|
189 *fe = *orig; |
|
190 fe->volume = _sound_base_vol[i]; |
|
191 fe->priority = 0; |
|
192 } |
|
193 } |
|
194 |
|
195 static void SndPlayScreenCoordFx(SoundFx sound, int x, int y) |
|
196 { |
|
197 Window* const *wz; |
|
198 |
|
199 if (msf.effect_vol == 0) return; |
|
200 |
|
201 FOR_ALL_WINDOWS(wz) { |
|
202 const ViewPort *vp = (*wz)->viewport; |
|
203 |
|
204 if (vp != NULL && |
|
205 IS_INSIDE_1D(x, vp->virtual_left, vp->virtual_width) && |
|
206 IS_INSIDE_1D(y, vp->virtual_top, vp->virtual_height)) { |
|
207 int left = (x - vp->virtual_left); |
|
208 |
|
209 StartSound( |
|
210 sound, |
|
211 left / (vp->virtual_width / ((PANNING_LEVELS << 1) + 1)) - PANNING_LEVELS, |
|
212 (GetSound(sound)->volume * msf.effect_vol * _vol_factor_by_zoom[vp->zoom]) >> 15 |
|
213 ); |
|
214 return; |
|
215 } |
|
216 } |
|
217 |
|
218 } |
|
219 |
|
220 void SndPlayTileFx(SoundFx sound, TileIndex tile) |
|
221 { |
|
222 /* emits sound from center of the tile */ |
|
223 int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2; |
|
224 int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2; |
|
225 Point pt = RemapCoords(x, y, GetSlopeZ(x, y)); |
|
226 SndPlayScreenCoordFx(sound, pt.x, pt.y); |
|
227 } |
|
228 |
|
229 void SndPlayVehicleFx(SoundFx sound, const Vehicle *v) |
|
230 { |
|
231 SndPlayScreenCoordFx(sound, |
|
232 (v->left_coord + v->right_coord) / 2, |
|
233 (v->top_coord + v->bottom_coord) / 2 |
|
234 ); |
|
235 } |
|
236 |
|
237 void SndPlayFx(SoundFx sound) |
|
238 { |
|
239 StartSound( |
|
240 sound, |
|
241 0, |
|
242 (GetSound(sound)->volume * msf.effect_vol) >> 7 |
|
243 ); |
|
244 } |