Rev 20 | 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 pan; |
||
| 346 | |||
| 347 | if (chan->type != eS3_ST_sample) { |
||
| 348 | return 1; |
||
| 349 | } |
||
| 350 | total_vol = (float) (chan->left_volume + chan->right_volume); // Pierre-Marie Baty -- added type cast |
||
| 351 | if (total_vol == 0.0f) { |
||
| 352 | total_vol = 1.0f; |
||
| 353 | } |
||
| 354 | if (chan->descriptor && chan->descriptor->type == chan->type) { |
||
| 355 | |||
| 21 | pmbaty | 356 | if (AudioBackend_SetVolume(chan, total_vol) == eAB_success && chan->spatial_sound) { |
| 1 | pmbaty | 357 | |
| 358 | if (chan->left_volume != 0 && chan->right_volume > chan->left_volume) { |
||
| 359 | pan_ratio = chan->right_volume / (float)chan->left_volume; |
||
| 360 | } else if (chan->right_volume != 0) { |
||
| 361 | pan_ratio = chan->left_volume / (float)chan->right_volume; |
||
| 362 | } |
||
| 363 | if (chan->left_volume != 0 && chan->right_volume != 0) { |
||
| 364 | pan = (int) ((chan->right_volume - chan->left_volume) * pan_ratio); // Pierre-Marie Baty -- added type cast |
||
| 365 | pan = MAX(pan, -10000); |
||
| 366 | pan = MIN(pan, 10000); |
||
| 367 | } else if (chan->left_volume != 0) { |
||
| 368 | pan = -10000; |
||
| 369 | } else { |
||
| 370 | pan = 10000; |
||
| 371 | } |
||
| 372 | AudioBackend_SetPan(chan, pan); |
||
| 373 | } |
||
| 374 | } |
||
| 375 | return 1; |
||
| 376 | } |
||
| 377 | |||
| 378 | int S3SyncSampleRate(tS3_channel* chan) { |
||
| 379 | if (chan->type != eS3_ST_sample) { |
||
| 380 | return 1; |
||
| 381 | } |
||
| 382 | |||
| 383 | int rate = chan->rate; |
||
| 384 | if (rate >= 100000) { |
||
| 385 | rate = 100000; |
||
| 386 | } |
||
| 387 | |||
| 388 | // sound_buffer->lpVtbl->SetFrequency(sound_buffer, rate); |
||
| 389 | AudioBackend_SetFrequency(chan, rate); |
||
| 390 | |||
| 391 | return 1; |
||
| 392 | } |
||
| 393 | |||
| 394 | int S3SetEffects(tS3_sample_filter* filter1, tS3_sample_filter* filter2) { |
||
| 395 | STUB_ONCE(); |
||
| 396 | return 0; |
||
| 397 | } |