Rev 18 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | #include "s3sound.h" |
2 | #include "audio.h" |
||
3 | #include "backends/backend.h" |
||
11 | pmbaty | 4 | #include "harness/hooks.h" |
1 | pmbaty | 5 | #include "harness/trace.h" |
6 | #include "resource.h" |
||
7 | #include <stdio.h> |
||
8 | #include <stdlib.h> |
||
9 | #include <string.h> |
||
10 | |||
11 | #define MAX_PATH_LENGTH 1024 |
||
12 | extern void dr_dprintf(char* fmt_string, ...); |
||
13 | |||
14 | int gS3_sample_filter_funcs_registered; |
||
15 | long gS3_last_file_length; |
||
16 | tS3_sample_filter* gS3_sample_filter_func; |
||
17 | tS3_sample_filter* gS3_sample_filter_disable_func; |
||
18 | |||
19 | int S3LoadSample(tS3_sound_id id) { |
||
20 | // changed by dethrace for compatibility |
||
21 | // char filename[80]; // [esp+10h] [ebp-5Ch] BYREF |
||
22 | char filename[MAX_PATH_LENGTH]; |
||
23 | tS3_descriptor* descriptor; |
||
24 | tS3_sample* sample; |
||
25 | char* buf; |
||
26 | // LPDIRECTSOUNDBUFFER dsound_buffer; // win95 only |
||
27 | |||
28 | if (!gS3_enabled) { |
||
29 | return 0; |
||
30 | } |
||
31 | descriptor = S3GetDescriptorByID(id); |
||
32 | if (!descriptor) { |
||
33 | return eS3_error_bad_id; |
||
34 | } |
||
35 | if (descriptor->type != eS3_ST_sample) { |
||
36 | return 0; |
||
37 | } |
||
38 | if (descriptor->sound_data) { |
||
39 | return 0; |
||
40 | } |
||
41 | filename[0] = 0; |
||
42 | strcpy(filename, descriptor->filename); |
||
43 | sample = S3MemAllocate(sizeof(tS3_sample), kMem_S3_sound_header); |
||
44 | if (!sample) { |
||
45 | return eS3_error_memory; |
||
46 | } |
||
47 | |||
48 | memset(sample, 0, sizeof(tS3_sample)); |
||
49 | buf = S3LoadWavFile_DOS(filename); |
||
50 | if (buf == NULL) { |
||
51 | S3MemFree(sample); |
||
52 | return gS3_last_error; |
||
53 | } |
||
54 | sample->freeptr = buf; |
||
55 | if (memcmp(buf, "RIFF", 4) == 0) { |
||
56 | wav_header* hdr = (wav_header*)buf; |
||
57 | sample->dataptr = &buf[sizeof(wav_header)]; |
||
58 | sample->size = hdr->data_bytes; |
||
59 | sample->rate = hdr->sample_rate; |
||
60 | sample->resolution = hdr->bit_depth; |
||
61 | sample->channels = hdr->num_channels; |
||
62 | } else { |
||
63 | sample->rate = 16000; |
||
64 | sample->resolution = 8; |
||
65 | sample->channels = 1; |
||
66 | sample->dataptr = buf; |
||
67 | sample->size = gS3_last_file_length; |
||
68 | } |
||
69 | |||
70 | // win95 |
||
71 | // descriptor->sound_buffer = S3LoadWavFile(filename, sample); |
||
72 | // if (!descriptor->sound_buffer) { |
||
73 | // S3MemFree(sample); |
||
74 | // return gS3_last_error; |
||
75 | // } |
||
76 | descriptor->special_fx = 0; |
||
77 | descriptor->sound_data = (char*)sample; |
||
78 | return eS3_error_none; |
||
79 | } |
||
80 | |||
81 | int S3ReadWavHeader_Win95(char* buf, tWAVEFORMATEX_** pWav_format, char** data_ptr, int* pData_size) { |
||
82 | int riff_len; |
||
83 | char* file_eof; // [esp+10h] [ebp-14h] |
||
84 | unsigned int chunk_len; // [esp+18h] [ebp-Ch] |
||
85 | char* chunk_data; // [esp+1Ch] [ebp-8h] |
||
86 | // char* chunk_name; // [esp+20h] [ebp-4h] |
||
87 | char* chunk_ptr; |
||
88 | |||
89 | if (pWav_format) { |
||
90 | *pWav_format = 0; |
||
91 | } |
||
92 | if (data_ptr) { |
||
93 | *data_ptr = 0; |
||
94 | } |
||
95 | if (pData_size) { |
||
96 | *pData_size = 0; |
||
97 | } |
||
98 | chunk_ptr = buf + 12; |
||
99 | if (buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F') { |
||
100 | return 0; |
||
101 | } |
||
102 | if (buf[8] != 'W' || buf[9] != 'A' || buf[10] != 'V' || buf[11] != 'E') { |
||
103 | return 0; |
||
104 | } |
||
105 | memcpy(&riff_len, &buf[4], sizeof(riff_len)); // (int32_t)buf[4]; |
||
106 | #if BR_ENDIAN_BIG |
||
107 | riff_len = BrSwap32(riff_len); |
||
108 | #endif |
||
109 | file_eof = &chunk_ptr[riff_len - 4]; |
||
110 | while (file_eof > chunk_ptr) { |
||
111 | memcpy(&chunk_len, chunk_ptr + 4, sizeof(chunk_len)); |
||
112 | #if BR_ENDIAN_BIG |
||
113 | chunk_len = BrSwap32(chunk_len); |
||
114 | #endif |
||
115 | chunk_data = chunk_ptr + 8; |
||
116 | if (strncmp(chunk_ptr, "fmt ", 4) == 0) { |
||
117 | if (pWav_format && *pWav_format == NULL) { |
||
118 | if (chunk_len < 14) { |
||
119 | return 0; |
||
120 | } |
||
121 | *pWav_format = (tWAVEFORMATEX_*)chunk_data; |
||
122 | if ((!data_ptr || *data_ptr) && (!pData_size || *pData_size)) { |
||
123 | return 1; |
||
124 | } |
||
125 | } |
||
126 | } else if (strncmp(chunk_ptr, "data", 4) == 0 && ((data_ptr && !*data_ptr) || (pData_size && !*pData_size))) { |
||
127 | if (data_ptr) { |
||
128 | *data_ptr = chunk_data; |
||
129 | } |
||
130 | if (pData_size) { |
||
131 | *pData_size = chunk_len; |
||
132 | } |
||
133 | if (!pWav_format || *pWav_format) { |
||
134 | return 1; |
||
135 | } |
||
136 | } |
||
137 | chunk_ptr = &chunk_data[(chunk_len + 1) & 0xFFFFFFFE]; |
||
138 | } |
||
139 | return 0; |
||
140 | } |
||
141 | |||
142 | void* S3LoadWavFile_DOS(char* pFile_name) { |
||
143 | FILE* f; |
||
144 | long file_len; |
||
145 | size_t bytes_read; |
||
146 | char* buf; |
||
147 | |||
20 | pmbaty | 148 | f = Harness_Hook_fopen (pFile_name, "rb"); |
1 | pmbaty | 149 | if (f == NULL) { |
150 | gS3_last_error = eS3_error_readfile; |
||
151 | return 0; |
||
152 | } |
||
153 | fseek(f, 0, SEEK_END); |
||
154 | file_len = ftell(f); |
||
155 | fseek(f, 0, SEEK_SET); |
||
156 | |||
157 | buf = S3MemAllocate(file_len + 1, kMem_S3_sample); |
||
158 | |||
159 | if (buf) { |
||
160 | bytes_read = fread(buf, 1, file_len, f); |
||
161 | if (bytes_read == file_len) { |
||
162 | gS3_last_file_length = file_len; |
||
163 | fclose(f); |
||
164 | return buf; |
||
165 | } else { |
||
166 | gS3_last_error = 4; |
||
167 | } |
||
168 | } else { |
||
169 | fclose(f); |
||
170 | gS3_last_error = eS3_error_memory; |
||
171 | } |
||
172 | return 0; |
||
173 | } |
||
174 | |||
175 | void* S3LoadWavFile_Win95(char* pFile_name, tS3_sample* pSample) { |
||
176 | FILE* f; // [esp+Ch] [ebp-C8h] |
||
177 | size_t bytes_read; // [esp+14h] [ebp-C0h] BYREF |
||
178 | // unsigned int locked_buffer_data_len; // [esp+18h] [ebp-BCh] BYREF |
||
179 | // struct _OFSTRUCT ReOpenBuff; // [esp+1Ch] [ebp-B8h] BYREF |
||
180 | char* buf; // [esp+A4h] [ebp-30h] |
||
181 | // LPDIRECTSOUNDBUFFER ds_buffer; // [esp+A8h] [ebp-2Ch] BYREF |
||
182 | // DSBUFFERDESC buffer_desc; // [esp+ACh] [ebp-28h] BYREF |
||
183 | int data_size; // [esp+C0h] [ebp-14h] BYREF |
||
184 | tWAVEFORMATEX_* wav_format; // [esp+C4h] [ebp-10h] BYREF |
||
185 | char* data_ptr; // [esp+C8h] [ebp-Ch] BYREF |
||
186 | // char* locked_buffer_data; // [esp+CCh] [ebp-8h] BYREF |
||
187 | size_t file_len; // [esp+D0h] [ebp-4h] |
||
188 | |||
20 | pmbaty | 189 | f = Harness_Hook_fopen (pFile_name, "rb"); |
1 | pmbaty | 190 | if (f == NULL) { |
191 | gS3_last_error = eS3_error_readfile; |
||
192 | return 0; |
||
193 | } |
||
194 | fseek(f, 0, SEEK_END); |
||
195 | file_len = (size_t)ftell(f); |
||
196 | fseek(f, 0, SEEK_SET); |
||
197 | |||
198 | buf = S3MemAllocate(file_len, kMem_S3_Windows_95_load_WAV_file); |
||
199 | if (buf == NULL) { |
||
200 | fclose(f); |
||
201 | gS3_last_error = eS3_error_memory; |
||
202 | return 0; |
||
203 | } |
||
204 | bytes_read = fread(buf, file_len, 1, f); |
||
205 | fclose(f); |
||
206 | |||
207 | data_size = 0; |
||
208 | wav_format = 0; |
||
209 | data_ptr = 0; |
||
210 | if (S3ReadWavHeader_Win95(buf, &wav_format, &data_ptr, &data_size) == 0) { |
||
211 | gS3_last_error = eS3_error_readfile; |
||
212 | dr_dprintf("ERROR: .WAV file '%s' is crap", pFile_name); |
||
213 | return 0; |
||
214 | } |
||
215 | pSample->freeptr = 0; |
||
216 | pSample->dataptr = 0; |
||
217 | pSample->size = data_size; |
||
218 | pSample->rate = wav_format->nSamplesPerSec; |
||
219 | pSample->resolution = wav_format->nAvgBytesPerSec; |
||
220 | pSample->channels = wav_format->nChannels; |
||
221 | #if BR_ENDIAN_BIG |
||
222 | pSample->rate = BrSwap32(pSample->rate); |
||
223 | pSample->resolution = BrSwap32(pSample->resolution); |
||
224 | pSample->channels = BrSwap32(pSample->channels); |
||
225 | #endif |
||
226 | |||
227 | // buffer_desc.dwReserved = 0; |
||
228 | // buffer_desc.dwSize = 20; |
||
229 | // buffer_desc.dwFlags = 226; |
||
230 | // buffer_desc.dwBufferBytes = data_size; |
||
231 | // buffer_desc.lpwfxFormat = wav_format; |
||
232 | // if (gS3_direct_sound_ptr->lpVtbl->CreateSoundBuffer(gS3_direct_sound_ptr, &buffer_desc, &ds_buffer, 0)) { |
||
233 | // return 0; |
||
234 | // } else if (ds_buffer->lpVtbl->Lock( |
||
235 | // ds_buffer, |
||
236 | // 0, |
||
237 | // data_size, |
||
238 | // (LPVOID*)&locked_buffer_data, |
||
239 | // &locked_buffer_data_len, |
||
240 | // 0, |
||
241 | // 0, |
||
242 | // 0)) { |
||
243 | // return 0; |
||
244 | // } else { |
||
245 | // qmemcpy(locked_buffer_data, data_ptr, locked_buffer_data_len); |
||
246 | // S3MemFree(buf); |
||
247 | // ds_buffer->lpVtbl->Unlock(ds_buffer, locked_buffer_data, locked_buffer_data_len, 0, 0); |
||
248 | // return ds_buffer; |
||
249 | // } |
||
250 | return NULL; |
||
251 | } |
||
252 | |||
253 | int S3StopSample(tS3_channel* chan) { |
||
254 | if (chan->tag == 0) { |
||
255 | return 1; |
||
256 | } |
||
257 | |||
258 | if (chan->type_struct_sample == NULL) { |
||
259 | return 0; |
||
260 | } |
||
261 | |||
262 | AudioBackend_StopSample(chan); |
||
263 | |||
264 | if (chan->active) { |
||
265 | chan->needs_service = 1; |
||
266 | } |
||
267 | |||
268 | return 1; |
||
269 | } |
||
270 | |||
271 | int S3ExecuteSampleFilterFuncs(tS3_channel* chan) { |
||
272 | if (((chan->descriptor->special_fx == 0) & gS3_sample_filter_funcs_registered) != 0) { |
||
273 | gS3_sample_filter_func(1, chan->tag); |
||
274 | chan->descriptor->special_fx = 1; |
||
275 | } else if (((gS3_sample_filter_funcs_registered == 0) & chan->descriptor->special_fx) != 0) { |
||
276 | gS3_sample_filter_disable_func(1, chan->tag); |
||
277 | chan->descriptor->special_fx = 0; |
||
278 | } |
||
279 | return 0; |
||
280 | } |
||
281 | |||
282 | int S3PlaySample(tS3_channel* chan) { |
||
283 | |||
284 | if (chan->type_struct_sample == NULL) { |
||
285 | return 0; |
||
286 | } |
||
287 | |||
288 | S3SyncSampleVolumeAndPan(chan); |
||
289 | S3SyncSampleRate(chan); |
||
290 | |||
291 | if (AudioBackend_PlaySample(chan) != eAB_success) { |
||
292 | return 0; |
||
293 | } |
||
294 | // if (chan->descriptor && chan->descriptor->type == chan->type) { |
||
295 | // dsound_buffer = chan->descriptor->dsound_buffer; |
||
296 | // if (dsound_buffer) { |
||
297 | // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); |
||
298 | // play_flags = chan->repetitions == 0; // 1 = DSBPLAY_LOOPING |
||
299 | // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); |
||
300 | // if (!dsound_buffer->lpVtbl->GetStatus(dsound_buffer, (LPDWORD)&status)) { |
||
301 | // if ((status & 1) != 0) // DSBSTATUS_PLAYING |
||
302 | // { |
||
303 | // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); |
||
304 | // } else { |
||
305 | // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); |
||
306 | // } |
||
307 | // } |
||
308 | // } |
||
309 | // } |
||
310 | |||
311 | return 1; |
||
312 | } |
||
313 | |||
314 | // this function was only called in DOS build |
||
315 | int S3CreateTypeStructs(tS3_channel* chan) { |
||
316 | void* result; |
||
317 | |||
318 | result = AudioBackend_AllocateSampleTypeStruct(); |
||
319 | if (result == NULL) { |
||
320 | return 0; |
||
321 | } |
||
322 | chan->type_struct_midi = NULL; |
||
323 | chan->type_struct_cda = NULL; |
||
324 | chan->type_struct_sample = (char*)result; |
||
325 | return 1; |
||
326 | } |
||
327 | |||
328 | int S3ReleaseTypeStructs(tS3_channel* chan) { |
||
329 | if (chan->type_struct_sample) { |
||
330 | S3MemFree(chan->type_struct_sample); |
||
331 | chan->type_struct_sample = NULL; |
||
332 | } |
||
333 | if (chan->type_struct_cda) { |
||
334 | S3MemFree(chan->type_struct_cda); |
||
335 | chan->type_struct_cda = NULL; |
||
336 | } |
||
337 | return 1; |
||
338 | } |
||
339 | |||
340 | int S3SyncSampleVolumeAndPan(tS3_channel* chan) { |
||
341 | |||
342 | float pan_ratio; // [esp+38h] [ebp-8h] |
||
343 | float total_vol; // [esp+3Ch] [ebp-4h] |
||
344 | |||
345 | int volume_db; |
||
346 | int pan; |
||
347 | //float linear_volume; // Pierre-Marie Baty -- unused variable |
||
348 | |||
349 | if (chan->type != eS3_ST_sample) { |
||
350 | return 1; |
||
351 | } |
||
352 | total_vol = (float) (chan->left_volume + chan->right_volume); // Pierre-Marie Baty -- added type cast |
||
353 | if (total_vol == 0.0f) { |
||
354 | total_vol = 1.0f; |
||
355 | } |
||
356 | if (chan->descriptor && chan->descriptor->type == chan->type) { |
||
357 | volume_db = (int) (510.0f / total_vol * -5.0f - 350.0f); // Pierre-Marie Baty -- added type cast |
||
358 | if (volume_db >= 0) { |
||
359 | volume_db = 0; |
||
360 | } |
||
361 | |||
362 | if (AudioBackend_SetVolume(chan, volume_db) == eAB_success && chan->spatial_sound) { |
||
363 | |||
364 | if (chan->left_volume != 0 && chan->right_volume > chan->left_volume) { |
||
365 | pan_ratio = chan->right_volume / (float)chan->left_volume; |
||
366 | } else if (chan->right_volume != 0) { |
||
367 | pan_ratio = chan->left_volume / (float)chan->right_volume; |
||
368 | } |
||
369 | if (chan->left_volume != 0 && chan->right_volume != 0) { |
||
370 | pan = (int) ((chan->right_volume - chan->left_volume) * pan_ratio); // Pierre-Marie Baty -- added type cast |
||
371 | pan = MAX(pan, -10000); |
||
372 | pan = MIN(pan, 10000); |
||
373 | } else if (chan->left_volume != 0) { |
||
374 | pan = -10000; |
||
375 | } else { |
||
376 | pan = 10000; |
||
377 | } |
||
378 | AudioBackend_SetPan(chan, pan); |
||
379 | } |
||
380 | } |
||
381 | return 1; |
||
382 | } |
||
383 | |||
384 | int S3SyncSampleRate(tS3_channel* chan) { |
||
385 | if (chan->type != eS3_ST_sample) { |
||
386 | return 1; |
||
387 | } |
||
388 | |||
389 | int rate = chan->rate; |
||
390 | if (rate >= 100000) { |
||
391 | rate = 100000; |
||
392 | } |
||
393 | |||
394 | // sound_buffer->lpVtbl->SetFrequency(sound_buffer, rate); |
||
395 | AudioBackend_SetFrequency(chan, rate); |
||
396 | |||
397 | return 1; |
||
398 | } |
||
399 | |||
400 | int S3SetEffects(tS3_sample_filter* filter1, tS3_sample_filter* filter2) { |
||
401 | STUB_ONCE(); |
||
402 | return 0; |
||
403 | } |