Rev 18 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1 | pmbaty | 1 | #include "audio.h" | 
| 2 | #include "resource.h" | ||
| 3 | |||
| 4 | #include "3d.h" | ||
| 5 | #include "backends/backend.h" | ||
| 6 | #include "harness/config.h" | ||
| 7 | #include "harness/os.h" | ||
| 8 | #include "harness/trace.h" | ||
| 9 | #include "s3/s3.h" | ||
| 10 | #include "s3cda.h" | ||
| 11 | #include "s3music.h" | ||
| 12 | #include "s3sound.h" | ||
| 13 | #include <ctype.h> | ||
| 14 | #include <errno.h> | ||
| 15 | #include <stddef.h> | ||
| 16 | #include <stdio.h> | ||
| 17 | #include <stdlib.h> | ||
| 18 | #include <string.h> | ||
| 19 | |||
| 20 | extern int PDGetTotalTime(void); | ||
| 21 | |||
| 22 | int gS3_enabled; | ||
| 23 | int gS3_noutlets; | ||
| 24 | int gS3_nsound_sources; | ||
| 25 | int gS3_next_outlet_id; | ||
| 26 | tS3_outlet* gS3_outlets; | ||
| 27 | tS3_sound_source* gS3_sound_sources; | ||
| 28 | tS3_descriptor* gS3_descriptors; | ||
| 29 | tS3_descriptor* gS3_root_descriptor; | ||
| 30 | int gS3_opened_output_devices; | ||
| 31 | int gS3_last_service_time; | ||
| 32 | int gS3_service_time_delta; | ||
| 33 | tS3_channel* gS3_unbound_channels; | ||
| 34 | tS3_channel* gS3_last_unbound_channel; | ||
| 35 | int gS3_last_error; | ||
| 36 | int gS3_default_pitch; | ||
| 37 | tS3_hardware_info gS3_hardware_info; | ||
| 38 | char* gS3_soundbank_buffer; | ||
| 39 | int gS3_soundbank_buffer_len; | ||
| 40 | int gS3_inside_cockpit; | ||
| 41 | |||
| 42 | tS3_channel gS3_channel_template; | ||
| 43 | int gS3_tag_seed; | ||
| 44 | |||
| 45 | char gS3_directory_separator[4]; | ||
| 46 | char gS3_directory_name[8]; | ||
| 47 | int gS3_have_current_dir; | ||
| 48 | char gS3_current_dir[260]; | ||
| 49 | |||
| 50 | int dword_5216C0; | ||
| 51 | |||
| 52 | int S3Init(char* pPath, int pLow_memory_mode) { | ||
| 53 | tS3_descriptor* root_descriptor; | ||
| 54 | |||
| 55 | gS3_noutlets = 0; | ||
| 56 | gS3_nsound_sources = 0; | ||
| 57 | gS3_next_outlet_id = 0; | ||
| 58 | gS3_outlets = NULL; | ||
| 59 | gS3_sound_sources = NULL; | ||
| 60 | gS3_descriptors = NULL; | ||
| 61 | gS3_root_descriptor = NULL; | ||
| 62 | |||
| 63 | S3Disable(); | ||
| 64 | S3DisableMIDI(); | ||
| 65 | S3DisableCDA(); | ||
| 66 | gS3_sample_filter_funcs_registered = 0; | ||
| 67 | gS3_sample_filter_func = NULL; | ||
| 68 | gS3_sample_filter_disable_func = NULL; | ||
| 69 | if (S3OpenOutputDevices() == 0) { | ||
| 70 | return 1; | ||
| 71 |     } | ||
| 72 | gS3_opened_output_devices = 1; | ||
| 73 | root_descriptor = S3MemAllocate(sizeof(tS3_descriptor), kMem_S3_sentinel); | ||
| 74 | if (!root_descriptor) { | ||
| 75 | return 3; | ||
| 76 |     } | ||
| 77 | memset(root_descriptor, 0, sizeof(tS3_descriptor)); | ||
| 78 | root_descriptor->id = 2495081; | ||
| 79 | gS3_root_descriptor = root_descriptor; | ||
| 80 | gS3_descriptors = root_descriptor; | ||
| 81 | if (S3LoadSoundbank(pPath, pLow_memory_mode)) { | ||
| 82 | return 5; | ||
| 83 |     } | ||
| 84 | gS3_last_service_time = PDGetTotalTime(); | ||
| 85 | gS3_unbound_channels = 0; | ||
| 86 | gS3_last_unbound_channel = 0; | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | void S3Shutdown(void) { | ||
| 91 | tS3_outlet* outlet; // [esp+10h] [ebp-10h] | ||
| 92 | tS3_outlet* next_outlet; // [esp+14h] [ebp-Ch] | ||
| 93 | tS3_descriptor* next_descriptor; // [esp+18h] [ebp-8h] | ||
| 94 | tS3_descriptor* descriptor; // [esp+1Ch] [ebp-4h] | ||
| 95 | |||
| 96 | S3StopAllOutletSounds(); | ||
| 97 | S3DisableMIDI(); | ||
| 98 | S3DisableCDA(); | ||
| 99 | if (gS3_enabled) { | ||
| 100 | S3Disable(); | ||
| 101 | for (descriptor = gS3_descriptors; descriptor != NULL; descriptor = next_descriptor) { | ||
| 102 | next_descriptor = descriptor->next; | ||
| 103 | S3ReleaseSound(descriptor->id); | ||
| 104 | S3MemFree(descriptor); | ||
| 105 |         } | ||
| 106 | for (outlet = gS3_outlets; outlet != NULL; outlet = next_outlet) { | ||
| 107 | next_outlet = outlet->next; | ||
| 108 | S3ReleaseOutlet(outlet); | ||
| 109 |         } | ||
| 110 | S3ReleaseUnboundChannels(); | ||
| 111 |     } | ||
| 112 | if (gS3_opened_output_devices) { | ||
| 113 | S3CloseDevices(); | ||
| 114 |     } | ||
| 115 | } | ||
| 116 | |||
| 117 | void S3Enable(void) { | ||
| 118 | gS3_enabled = 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | void S3Disable(void) { | ||
| 122 | S3StopAllOutletSounds(); | ||
| 123 | gS3_enabled = 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | int S3OpenOutputDevices(void) { | ||
| 127 | |||
| 128 |     // strcpy(gS3_directory_separator, "\\"); | ||
| 129 | strcpy(gS3_directory_separator, "/"); | ||
| 130 | strcpy(gS3_directory_name, "SOUND"); | ||
| 131 | memset(&gS3_hardware_info, 0, sizeof(gS3_hardware_info)); | ||
| 132 | if (S3OpenSampleDevice() == 0) { | ||
| 133 | return 0; | ||
| 134 |     } | ||
| 135 | S3OpenCDADevice(); | ||
| 136 | gS3_hardware_info.timer_installed = 0; | ||
| 137 | gS3_hardware_info.device_installed = 1; | ||
| 138 | gS3_hardware_info.independent_pitch = 0; | ||
| 139 | return 1; | ||
| 140 | } | ||
| 141 | |||
| 142 | int S3OpenSampleDevice(void) { | ||
| 143 | |||
| 144 |     // if (DirectSoundCreate(0, &gS3_direct_sound_ptr, 0)) { | ||
| 145 |     //     return 0; | ||
| 146 |     // } | ||
| 147 |     // if (gS3_direct_sound_ptr->lpVtbl->SetCooperativeLevel(gS3_direct_sound_ptr, gWin32_hwnd, 3)) { | ||
| 148 |     //     return 0; | ||
| 149 |     // } | ||
| 150 | |||
| 151 | if (AudioBackend_Init() != eAB_success) { | ||
| 152 | return 0; | ||
| 153 |     } | ||
| 154 | S3Enable(); | ||
| 155 | return 1; | ||
| 156 | } | ||
| 157 | |||
| 158 | // returns 0 on failure, 1 on success | ||
| 159 | int S3OpenCDADevice(void) { | ||
| 160 |     // gS3_cda_device.lpstrDeviceType = (LPCSTR)516; | ||
| 161 |     // if (mciSendCommandA(0, 0x803u, 0x3000u, (DWORD_PTR)&gS3_cda_device) | ||
| 162 |     //     && mciSendCommandA(0, 0x803u, 0x3100u, (DWORD_PTR)&gS3_cda_device)) { | ||
| 163 |     //     return 0; | ||
| 164 |     // } | ||
| 165 |     // stru_550560.dwTimeFormat = 10; // MCI_FORMAT_TMSF | ||
| 166 |     // mciSendCommandA(gS3_cda_device.wDeviceID, 0x80Du, 0x400u, (DWORD_PTR)&stru_550560); | ||
| 167 | |||
| 168 | if (AudioBackend_InitCDA() != eAB_success) { | ||
| 169 | return 0; | ||
| 170 |     } | ||
| 171 | |||
| 172 | S3EnableCDA(); | ||
| 173 | return 1; | ||
| 174 | } | ||
| 175 | |||
| 176 | void S3CloseDevices(void) { | ||
| 177 | if (gS3_hardware_info.device_installed) { | ||
| 178 |         // gS3_direct_sound_ptr->lpVtbl->Release(gS3_direct_sound_ptr); | ||
| 179 |         // gS3_direct_sound_ptr = NULL; | ||
| 180 | |||
| 181 | AudioBackend_UnInit(); | ||
| 182 |     } | ||
| 183 |     // if (gS3_cda_device.wDeviceID) { | ||
| 184 |     //     mciSendCommandA(gS3_cda_device.wDeviceID, 0x804u, 0, 0); // MCI_CLOSE | ||
| 185 |     // } | ||
| 186 | |||
| 187 | AudioBackend_UnInitCDA(); | ||
| 188 | } | ||
| 189 | |||
| 190 | int S3ReleaseSound(tS3_sound_id id) { | ||
| 191 | tS3_channel* c; // [esp+Ch] [ebp-10h] | ||
| 192 | tS3_outlet* o; // [esp+10h] [ebp-Ch] | ||
| 193 | tS3_descriptor* desc; // [esp+14h] [ebp-8h] | ||
| 194 | tS3_sample* sample_ptr; | ||
| 195 | |||
| 196 | if (!gS3_enabled) { | ||
| 197 | return 0; | ||
| 198 |     } | ||
| 199 | |||
| 200 | desc = S3GetDescriptorByID(id); | ||
| 201 | if (desc == NULL) { | ||
| 202 | return eS3_error_bad_id; | ||
| 203 |     } | ||
| 204 | if (desc->type == eS3_ST_midi) { | ||
| 205 | for (o = gS3_outlets; o; o = o->next) { | ||
| 206 | for (c = o->channel_list; c; c = c->next) { | ||
| 207 | if (c->descriptor && c->descriptor->id == id) { | ||
| 208 | S3ReleaseMIDI(c->tag); | ||
| 209 |                 } | ||
| 210 |             } | ||
| 211 |         } | ||
| 212 | } else if (desc->type == eS3_ST_sample) { | ||
| 213 | sample_ptr = (tS3_sample*)desc->sound_data; | ||
| 214 | if (sample_ptr == NULL) { | ||
| 215 | return 0; | ||
| 216 |         } | ||
| 217 | S3MemFree(sample_ptr->freeptr); | ||
| 218 | S3MemFree(sample_ptr); | ||
| 219 | desc->sound_data = NULL; | ||
| 220 |     } | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | int S3LoadSoundbank(const char* pSoundbank_filename, int pLow_memory_mode) { | ||
| 225 | char soundbank_filename[256]; // [esp+Ch] [ebp-218h] BYREF | ||
| 226 | void* buffer; // [esp+10Ch] [ebp-118h] | ||
| 227 | tS3_soundbank_read_ctx read_ctx; // [esp+110h] [ebp-114h] BYREF | ||
| 228 | char* cur_dir; // [esp+120h] [ebp-104h] | ||
| 229 | char dir_name[256]; // [esp+124h] [ebp-100h] BYREF | ||
| 230 | |||
| 231 | if (gS3_enabled) { | ||
| 232 | dir_name[0] = 0; | ||
| 233 | soundbank_filename[0] = 0; | ||
| 234 | cur_dir = S3GetCurrentDir(); | ||
| 235 | strcpy(dir_name, cur_dir); | ||
| 236 | strcat(dir_name, gS3_directory_separator); | ||
| 237 | strcat(dir_name, "DATA"); | ||
| 238 | strcat(dir_name, gS3_directory_separator); | ||
| 239 | strcat(dir_name, gS3_directory_name); | ||
| 240 | strcat(dir_name, gS3_directory_separator); | ||
| 241 | strcpy(soundbank_filename, pSoundbank_filename); | ||
| 242 | buffer = S3LoadSoundBankFile(soundbank_filename); | ||
| 243 | if (!buffer) { | ||
| 244 | return gS3_last_error; | ||
| 245 |         } | ||
| 246 | read_ctx.data = (char*)buffer; | ||
| 247 | read_ctx.data_len = gS3_soundbank_buffer_len; | ||
| 248 | read_ctx.nlines = 0; | ||
| 249 | S3SoundBankReaderSkipWhitespace(&read_ctx); | ||
| 250 | while (S3SoundBankReadEntry(&read_ctx, dir_name, pLow_memory_mode)) { | ||
| 251 |             ; | ||
| 252 |         } | ||
| 253 | S3MemFree(buffer); | ||
| 254 |     } | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | char* S3LoadSoundBankFile(char* pThe_path) { | ||
| 259 | size_t bytes_read; | ||
| 260 |     // int fd;                   // [esp+Ch] [ebp-2Ch] | ||
| 261 | char* buffer; | ||
| 262 |     // struct _stat stat_result; | ||
| 263 | |||
| 264 | FILE* fd; | ||
| 265 | size_t file_size; | ||
| 266 | |||
| 267 |     // fd = _open(pThe_path, 0x8000); | ||
| 268 | fd = OS_fopen(pThe_path, "rb"); | ||
| 269 | if (!fd) { | ||
| 270 | gS3_last_error = eS3_error_readfile; | ||
| 271 | return 0; | ||
| 272 |     } | ||
| 273 | |||
| 274 |     // if (_fstat(fd, &stat_result)) { | ||
| 275 |     //     gS3_last_error = eS3_error_readfile; | ||
| 276 |     //     return 0; | ||
| 277 |     // } | ||
| 278 | |||
| 279 | if (fseek(fd, 0, SEEK_END) != 0) { | ||
| 280 | gS3_last_error = eS3_error_readfile; | ||
| 281 | return 0; | ||
| 282 |     } | ||
| 283 | file_size = ftell(fd); | ||
| 284 | fseek(fd, 0, SEEK_SET); | ||
| 285 | |||
| 286 | buffer = S3MemAllocate(file_size + 1, kMem_S3_sample); | ||
| 287 | if (buffer == NULL) { | ||
| 288 | fclose(fd); | ||
| 289 | gS3_last_error = eS3_error_memory; | ||
| 290 | return 0; | ||
| 291 |     } | ||
| 292 | buffer[file_size] = 0; | ||
| 293 | bytes_read = fread(buffer, 1, file_size, fd); | ||
| 294 | if (bytes_read == file_size) { | ||
| 295 | gS3_soundbank_buffer = buffer; | ||
| 296 | gS3_soundbank_buffer_len = file_size; | ||
| 297 | fclose(fd); | ||
| 298 | return buffer; | ||
| 299 |     } | ||
| 300 | gS3_last_error = eS3_error_readfile; | ||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | void S3SoundBankReaderNextLine(tS3_soundbank_read_ctx* ctx) { | ||
| 305 | S3SoundBankReaderSkipToNewline(ctx); | ||
| 306 | S3SoundBankReaderSkipWhitespace(ctx); | ||
| 307 | } | ||
| 308 | |||
| 309 | void S3SoundBankReaderSkipWhitespace(tS3_soundbank_read_ctx* ctx) { | ||
| 310 | while (ctx->data_len) { | ||
| 311 | if (isalnum(*ctx->data) || *ctx->data == '-') { | ||
| 312 | break; | ||
| 313 |         } | ||
| 314 | S3SoundBankReaderSkipToNewline(ctx); | ||
| 315 |     } | ||
| 316 | } | ||
| 317 | |||
| 318 | void S3SoundBankReaderSkipToNewline(tS3_soundbank_read_ctx* ctx) { | ||
| 319 | char* newline_ptr; // [esp+Ch] [ebp-4h] | ||
| 320 | |||
| 321 | newline_ptr = memchr(ctx->data, '\n', ctx->data_len); | ||
| 322 | if (newline_ptr) { | ||
| 323 | S3SoundBankReaderAdvance(ctx, newline_ptr + 1 - ctx->data); | ||
| 324 | ctx->nlines++; | ||
| 325 | } else { | ||
| 326 | ctx->data_len = 0; | ||
| 327 |     } | ||
| 328 | } | ||
| 329 | |||
| 330 | void S3SoundBankReaderAdvance(tS3_soundbank_read_ctx* buffer, int bytes_read) { | ||
| 331 | buffer->data += bytes_read; | ||
| 332 | buffer->data_len -= bytes_read; | ||
| 333 | } | ||
| 334 | |||
| 335 | int S3SoundBankReadEntry(tS3_soundbank_read_ctx* ctx, char* dir_name, int low_memory_mode) { | ||
| 336 | int nmemory_proxies; // [esp+Ch] [ebp-24h] BYREF | ||
| 337 | int i; // [esp+10h] [ebp-20h] | ||
| 338 | int proxy_id; // [esp+14h] [ebp-1Ch] BYREF | ||
| 339 | tS3_descriptor* desc; // [esp+18h] [ebp-18h] | ||
| 340 | double tmp1; // [esp+1Ch] [ebp-14h] BYREF | ||
| 341 | double tmp2; // [esp+24h] [ebp-Ch] BYREF | ||
| 342 | int char_count; // [esp+2Ch] [ebp-4h] BYREF | ||
| 343 | char cda_dir_name[4]; | ||
| 344 | |||
| 345 | desc = S3CreateDescriptor(); | ||
| 346 | if (!desc) { | ||
| 347 | return gS3_last_error; | ||
| 348 |     } | ||
| 349 | if (sscanf(ctx->data, "%i%n", &desc->id, &char_count) != 1) { | ||
| 350 | return 0; | ||
| 351 |     } | ||
| 352 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 353 | S3SoundBankReaderNextLine(ctx); | ||
| 354 | if (sscanf(ctx->data, "%i,%i%n", &desc->type, &desc->flags, &char_count) != 2) { | ||
| 355 | return 0; | ||
| 356 |     } | ||
| 357 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 358 | S3SoundBankReaderNextLine(ctx); | ||
| 359 | if (desc->type == eS3_ST_cda) { | ||
| 360 | dir_name = cda_dir_name; | ||
| 361 | cda_dir_name[0] = '\0'; | ||
| 362 |     } | ||
| 363 | if (!S3SoundBankReaderReadFilename(&desc->filename, ctx, dir_name)) { | ||
| 364 | return 0; | ||
| 365 |     } | ||
| 366 | S3SoundBankReaderNextLine(ctx); | ||
| 367 | if (sscanf(ctx->data, "%i%n", (int*)&desc->priority, &char_count) != 1) { | ||
| 368 | return 0; | ||
| 369 |     } | ||
| 370 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 371 | S3SoundBankReaderNextLine(ctx); | ||
| 372 | if (sscanf(ctx->data, "%i%n", &desc->repeats, &char_count) != 1) { | ||
| 373 | return 0; | ||
| 374 |     } | ||
| 375 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 376 | S3SoundBankReaderNextLine(ctx); | ||
| 377 | if (sscanf(ctx->data, "%i,%i%n", &desc->min_volume, &desc->max_volume, &char_count) != 2) { | ||
| 378 | return 0; | ||
| 379 |     } | ||
| 380 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 381 | S3SoundBankReaderNextLine(ctx); | ||
| 382 | if (sscanf(ctx->data, "%lf,%lf%n", &tmp1, &tmp2, &char_count) != 2) { | ||
| 383 | return 0; | ||
| 384 |     } | ||
| 385 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 386 | S3SoundBankReaderNextLine(ctx); | ||
| 387 | if (tmp1 == 0.0f) { | ||
| 388 | tmp1 = 1.0f; | ||
| 389 |     } | ||
| 390 | if (tmp2 == 0.0f) { | ||
| 391 | tmp2 = 1.0f; | ||
| 392 |     } | ||
| 393 | desc->min_pitch = ldexpf(tmp1, 16); | ||
| 394 | desc->max_pitch = ldexpf(tmp2, 16); | ||
| 395 | if (sscanf(ctx->data, "%lf,%lf%n", &tmp1, &tmp2, &char_count) != 2) { | ||
| 396 | return 0; | ||
| 397 |     } | ||
| 398 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 399 | S3SoundBankReaderNextLine(ctx); | ||
| 400 | if (tmp1 == 0.0) { | ||
| 401 | tmp1 = 1.0; | ||
| 402 |     } | ||
| 403 | if (tmp2 == 0.0) { | ||
| 404 | tmp2 = 1.0; | ||
| 405 |     } | ||
| 406 | desc->min_speed = ldexpf(tmp1, 16); | ||
| 407 | desc->max_speed = ldexpf(tmp2, 16); | ||
| 408 | if (sscanf(ctx->data, "%i%n", &desc->special_fx, &char_count) != 1) { | ||
| 409 | return 0; | ||
| 410 |     } | ||
| 411 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 412 | S3SoundBankReaderNextLine(ctx); | ||
| 413 | if (sscanf(ctx->data, "%d%n", &nmemory_proxies, &char_count) != 1) { | ||
| 414 | return 0; | ||
| 415 |     } | ||
| 416 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 417 | S3SoundBankReaderNextLine(ctx); | ||
| 418 | desc->memory_proxy = -1; | ||
| 419 | for (i = 0; i < nmemory_proxies; i++) { | ||
| 420 | if (sscanf(ctx->data, "%d%n", &proxy_id, &char_count) != 1) { | ||
| 421 | return 0; | ||
| 422 |         } | ||
| 423 | if (low_memory_mode == i + 1) { | ||
| 424 | desc->memory_proxy = proxy_id; | ||
| 425 |         } | ||
| 426 | S3SoundBankReaderAdvance(ctx, char_count); | ||
| 427 | S3SoundBankReaderNextLine(ctx); | ||
| 428 |     } | ||
| 429 | if ((desc->flags & 1) != 0 && desc->memory_proxy == -1) { | ||
| 430 | if (desc->type == eS3_ST_midi) { | ||
| 431 | desc->sound_data = NULL; | ||
| 432 | } else if (S3LoadSample(desc->id) != 0) { | ||
| 433 | printf("\nSound bank file: couldn't load '%s'\n", desc->filename); | ||
| 434 | ctx->data_len = 1; | ||
| 435 | return 0; | ||
| 436 |         } | ||
| 437 |     } | ||
| 438 | return 1; | ||
| 439 | } | ||
| 440 | |||
| 441 | tS3_descriptor* S3CreateDescriptor(void) { | ||
| 442 | tS3_descriptor* root; | ||
| 443 | tS3_descriptor* d; | ||
| 444 | |||
| 445 | d = S3MemAllocate(sizeof(tS3_descriptor), kMem_S3_descriptor); | ||
| 446 | if (!d) { | ||
| 447 | gS3_last_error = eS3_error_memory; | ||
| 448 | return NULL; | ||
| 449 |     } | ||
| 450 | memset(d, 0, sizeof(tS3_descriptor)); | ||
| 451 | root = gS3_root_descriptor; | ||
| 452 | gS3_root_descriptor->next = d; | ||
| 453 | d->prev = root; | ||
| 454 | gS3_root_descriptor = d; | ||
| 455 | return d; | ||
| 456 | } | ||
| 457 | |||
| 458 | int S3SoundBankReaderReadFilename(char** filename, tS3_soundbank_read_ctx* ctx, const char* dir_name) { | ||
| 459 | char* data_start; // [esp+10h] [ebp-Ch] | ||
| 460 | unsigned int bytes_read; // [esp+14h] [ebp-8h] | ||
| 461 | unsigned int dir_name_len; // [esp+18h] [ebp-4h] | ||
| 462 | |||
| 463 | data_start = ctx->data; | ||
| 464 | dir_name_len = strlen(dir_name); | ||
| 465 | while (ctx->data_len) { | ||
| 466 | if (isspace(*ctx->data)) { | ||
| 467 | break; | ||
| 468 |         } | ||
| 469 | S3SoundBankReaderAdvance(ctx, 1); | ||
| 470 |     } | ||
| 471 | bytes_read = ctx->data - data_start; | ||
| 472 | if (!bytes_read) { | ||
| 473 | return 0; | ||
| 474 |     } | ||
| 475 | *filename = S3MemAllocate(bytes_read + dir_name_len + 1, kMem_S3_scan_name); | ||
| 476 | if (!*filename) { | ||
| 477 | return 0; | ||
| 478 |     } | ||
| 479 | strcpy(*filename, dir_name); | ||
| 480 | memcpy(&(*filename)[dir_name_len], data_start, bytes_read); | ||
| 481 | (*filename)[bytes_read + dir_name_len] = '\0'; | ||
| 482 | return 1; | ||
| 483 | } | ||
| 484 | |||
| 485 | tS3_outlet* S3CreateOutlet(int unk1, int pChannel_count) { | ||
| 486 | tS3_outlet* o; | ||
| 487 | int nchannels; | ||
| 488 | tS3_outlet* outlet; | ||
| 489 | int channels_remaining; | ||
| 490 | |||
| 491 |     // nchannels = (int)operator new(unk1, (void*)pChannel_count); | ||
| 492 | nchannels = pChannel_count; | ||
| 493 | |||
| 494 | if (nchannels == 0) { | ||
| 495 | gS3_last_error = eS3_error_channel_alloc; | ||
| 496 | return NULL; | ||
| 497 |     } | ||
| 498 | outlet = S3MemAllocate(sizeof(tS3_outlet), kMem_S3_outlet); | ||
| 499 | if (outlet == NULL) { | ||
| 500 | gS3_last_error = eS3_error_memory; | ||
| 501 | return 0; | ||
| 502 |     } | ||
| 503 | memset(outlet, 0, sizeof(tS3_outlet)); | ||
| 504 | channels_remaining = S3CreateOutletChannels(outlet, nchannels); | ||
| 505 | if (channels_remaining == nchannels) { | ||
| 506 | S3MemFree(outlet); | ||
| 507 | return NULL; | ||
| 508 |     } | ||
| 509 | o = gS3_outlets; | ||
| 510 | if (gS3_outlets) { | ||
| 511 | while (o->next) { | ||
| 512 | o = o->next; | ||
| 513 |         } | ||
| 514 | o->next = outlet; | ||
| 515 | outlet->prev = o; | ||
| 516 | } else { | ||
| 517 | gS3_outlets = outlet; | ||
| 518 |     } | ||
| 519 | outlet->max_channels = nchannels - channels_remaining; | ||
| 520 | outlet->id = gS3_next_outlet_id; | ||
| 521 |     gS3_next_outlet_id++; | ||
| 522 | outlet->independent_pitch = gS3_hardware_info.independent_pitch; | ||
| 523 |     gS3_noutlets++; | ||
| 524 | return outlet; | ||
| 525 | } | ||
| 526 | |||
| 527 | int S3CreateOutletChannels(tS3_outlet* outlet, int pChannel_count) { | ||
| 528 | tS3_channel* chan; // [esp+Ch] [ebp-8h] | ||
| 529 | tS3_channel* last_chan; // [esp+10h] [ebp-4h] | ||
| 530 | |||
| 531 | last_chan = NULL; | ||
| 532 | while (pChannel_count) { | ||
| 533 | chan = (tS3_channel*)S3MemAllocate(sizeof(tS3_channel), kMem_S3_channel); | ||
| 534 | if (!chan) { | ||
| 535 | return pChannel_count; | ||
| 536 |         } | ||
| 537 | memset(chan, 0, sizeof(tS3_channel)); | ||
| 538 | chan->owner_outlet = outlet; | ||
| 539 | |||
| 540 | if (S3CreateTypeStructs(chan) == 0) { | ||
| 541 | S3MemFree(chan); | ||
| 542 | return pChannel_count; | ||
| 543 |         } | ||
| 544 | chan->volume_multiplier = 1.0f; | ||
| 545 | if (last_chan) { | ||
| 546 | last_chan->next = chan; | ||
| 547 | } else { | ||
| 548 | outlet->channel_list = chan; | ||
| 549 |         } | ||
| 550 | last_chan = chan; | ||
| 551 |         pChannel_count--; | ||
| 552 |     } | ||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | void S3ReleaseOutlet(tS3_outlet* outlet) { | ||
| 557 | tS3_outlet* next; | ||
| 558 | tS3_outlet* prev; | ||
| 559 | |||
| 560 | if (outlet) { | ||
| 561 | S3UnbindChannels(outlet); | ||
| 562 | prev = outlet->prev; | ||
| 563 | next = outlet->next; | ||
| 564 | if (prev != NULL) { | ||
| 565 | prev->next = next; | ||
| 566 | } else { | ||
| 567 | gS3_outlets = outlet->next; | ||
| 568 |         } | ||
| 569 | if (next != NULL) { | ||
| 570 | next->prev = prev; | ||
| 571 |         } | ||
| 572 | if (gS3_noutlets) { | ||
| 573 |             gS3_noutlets--; | ||
| 574 | if (gS3_noutlets == 0) { | ||
| 575 | gS3_outlets = NULL; | ||
| 576 |             } | ||
| 577 |         } | ||
| 578 | S3MemFree(outlet); | ||
| 579 |     } | ||
| 580 | } | ||
| 581 | |||
| 582 | int S3UnbindChannels(tS3_outlet* outlet) { | ||
| 583 | tS3_channel* chan; | ||
| 584 | tS3_channel* next; | ||
| 585 | |||
| 586 | for (chan = outlet->channel_list; chan; chan = next) { | ||
| 587 | next = chan->next; | ||
| 588 | S3ReleaseTypeStructs(chan); | ||
| 589 | if (gS3_unbound_channels) { | ||
| 590 | gS3_last_unbound_channel->next = chan; | ||
| 591 | } else { | ||
| 592 | gS3_unbound_channels = chan; | ||
| 593 |         } | ||
| 594 | gS3_last_unbound_channel = chan; | ||
| 595 | memset(chan, 0, sizeof(tS3_channel)); | ||
| 596 |     } | ||
| 597 | outlet->channel_list = NULL; | ||
| 598 | return 1; | ||
| 599 | } | ||
| 600 | |||
| 601 | void S3ReleaseUnboundChannels(void) { | ||
| 602 | tS3_channel* channel; // [esp+Ch] [ebp-8h] | ||
| 603 | tS3_channel* next_channel; // [esp+10h] [ebp-4h] | ||
| 604 | |||
| 605 | for (channel = gS3_unbound_channels; channel != NULL; channel = next_channel) { | ||
| 606 | next_channel = channel->next; | ||
| 607 | S3MemFree(channel); | ||
| 608 |     } | ||
| 609 | } | ||
| 610 | |||
| 611 | tS3_channel* S3AllocateChannel(tS3_outlet* outlet, int priority) { | ||
| 612 | tS3_channel* c; // [esp+Ch] [ebp-10h] | ||
| 613 | int lowest_priority; // [esp+10h] [ebp-Ch] MAPDST | ||
| 614 | int this_priority; // [esp+14h] [ebp-8h] | ||
| 615 | tS3_channel* lowest_priority_chan; // [esp+18h] [ebp-4h] | ||
| 616 | |||
| 617 | lowest_priority_chan = outlet->channel_list; | ||
| 618 | c = outlet->channel_list; | ||
| 619 | if (lowest_priority_chan == NULL) { | ||
| 620 | return NULL; | ||
| 621 |     } | ||
| 622 | while (c) { | ||
| 623 | if (!c->active || c->needs_service) { | ||
| 624 | if (!c->needs_service) { | ||
| 625 | c->active = 1; | ||
| 626 | return c; | ||
| 627 |             } | ||
| 628 | } else { | ||
| 629 | if (lowest_priority_chan->descriptor) { | ||
| 630 | lowest_priority = lowest_priority_chan->descriptor->priority | ||
| 631 | * (lowest_priority_chan->right_volume + lowest_priority_chan->left_volume + 1); | ||
| 632 | } else { | ||
| 633 | lowest_priority = 0; | ||
| 634 |             } | ||
| 635 | if (c->descriptor) { | ||
| 636 | this_priority = c->descriptor->priority * (c->left_volume + c->right_volume + 1); | ||
| 637 | } else { | ||
| 638 | this_priority = 0; | ||
| 639 |             } | ||
| 640 | if (this_priority <= lowest_priority) { | ||
| 641 | lowest_priority_chan = c; | ||
| 642 |             } | ||
| 643 |         } | ||
| 644 | c = c->next; | ||
| 645 |     } | ||
| 646 | if (!lowest_priority_chan->descriptor || lowest_priority_chan->needs_service) { | ||
| 647 | lowest_priority = 0; | ||
| 648 | } else { | ||
| 649 | lowest_priority = lowest_priority_chan->descriptor->priority * (lowest_priority_chan->right_volume + lowest_priority_chan->left_volume + 1); | ||
| 650 |     } | ||
| 651 | if (priority > lowest_priority && !lowest_priority_chan->needs_service) { | ||
| 652 | lowest_priority_chan->termination_reason = 2; | ||
| 653 | S3StopChannel(lowest_priority_chan); | ||
| 654 | lowest_priority_chan->active = 1; | ||
| 655 |     } | ||
| 656 | |||
| 657 | return NULL; | ||
| 658 | } | ||
| 659 | |||
| 660 | int S3StopChannel(tS3_channel* chan) { | ||
| 661 | if (!chan->tag) { | ||
| 662 | return eS3_error_bad_stag; | ||
| 663 |     } | ||
| 664 | chan->termination_reason = eS3_tr_stopped; | ||
| 665 | if (chan->active) { | ||
| 666 | chan->needs_service = 1; | ||
| 667 |     } | ||
| 668 | if (chan->type == eS3_ST_sample) { | ||
| 669 | if (chan->sound_source_ptr) { | ||
| 670 | chan->sound_source_ptr->tag = 0; | ||
| 671 | chan->sound_source_ptr->channel = 0; | ||
| 672 | chan->sound_source_ptr->volume = 0; | ||
| 673 |         } | ||
| 674 | if (S3StopSample(chan) == 0) { | ||
| 675 | return eS3_error_function_failed; | ||
| 676 |         } | ||
| 677 | } else if (chan->type == eS3_ST_midi) { | ||
| 678 | if (S3StopMIDI(chan) != 0) { | ||
| 679 | return eS3_error_function_failed; | ||
| 680 |         } | ||
| 681 | } else if (chan->type == eS3_ST_cda) { | ||
| 682 | if (S3StopCDA(chan) != 0) { | ||
| 683 | return eS3_error_function_failed; | ||
| 684 |         } | ||
| 685 |     } | ||
| 686 | |||
| 687 | if ((chan->descriptor->flags & 2) != 0) { | ||
| 688 | S3ReleaseSound(chan->descriptor->id); | ||
| 689 |     } | ||
| 690 | chan->repetitions = 1; | ||
| 691 | return 0; | ||
| 692 | } | ||
| 693 | |||
| 694 | tS3_sound_source* S3CreateSoundSourceBR(br_vector3* pPosition, br_vector3* pVelocity, tS3_outlet* pBound_outlet) { | ||
| 695 | tS3_sound_source* source; // [esp+Ch] [ebp-4h] | ||
| 696 | |||
| 697 | if (!gS3_enabled) { | ||
| 698 | return 0; | ||
| 699 |     } | ||
| 700 | source = S3CreateSoundSource(pPosition, pVelocity, pBound_outlet); | ||
| 701 | if (source != NULL) { | ||
| 702 | source->brender_vector = 1; | ||
| 703 |     } | ||
| 704 | return source; | ||
| 705 | } | ||
| 706 | |||
| 707 | tS3_sound_source* S3CreateSoundSource(void* pPosition, void* pVelocity, tS3_outlet* pBound_outlet) { | ||
| 708 | tS3_sound_source* src; // [esp+Ch] [ebp-8h] | ||
| 709 | tS3_sound_source* s; // [esp+10h] [ebp-4h] | ||
| 710 | |||
| 711 | src = S3MemAllocate(sizeof(tS3_sound_source), kMem_S3_source); | ||
| 712 | if (src == NULL) { | ||
| 713 | gS3_last_error = eS3_error_memory; | ||
| 714 | return 0; | ||
| 715 |     } | ||
| 716 | memset(src, 0, sizeof(tS3_sound_source)); | ||
| 717 | src->bound_outlet = pBound_outlet; | ||
| 718 | src->position_ptr = pPosition; | ||
| 719 | src->velocity_ptr = pVelocity; | ||
| 720 | s = gS3_sound_sources; | ||
| 721 | if (gS3_sound_sources) { | ||
| 722 | while (s->next) { | ||
| 723 | s = s->next; | ||
| 724 |         } | ||
| 725 | s->next = src; | ||
| 726 | src->prev = s; | ||
| 727 | } else { | ||
| 728 | gS3_sound_sources = src; | ||
| 729 |     } | ||
| 730 |     gS3_nsound_sources++; | ||
| 731 | return src; | ||
| 732 | } | ||
| 733 | |||
| 734 | int S3ReleaseSoundSource(tS3_sound_source* src) { | ||
| 735 | tS3_sound_source* prev; // [esp+Ch] [ebp-8h] | ||
| 736 | tS3_sound_source* next; // [esp+10h] [ebp-4h] | ||
| 737 | |||
| 738 | if (!gS3_enabled) { | ||
| 739 | return 0; | ||
| 740 |     } | ||
| 741 | |||
| 742 | if (src) { | ||
| 743 | prev = src->prev; | ||
| 744 | next = src->next; | ||
| 745 | if (prev) { | ||
| 746 | prev->next = next; | ||
| 747 | } else { | ||
| 748 | gS3_sound_sources = src->next; | ||
| 749 |         } | ||
| 750 | if (next) { | ||
| 751 | next->prev = prev; | ||
| 752 |         } | ||
| 753 | if (gS3_nsound_sources) { | ||
| 754 |             gS3_nsound_sources--; | ||
| 755 | if (gS3_nsound_sources == 0) { | ||
| 756 | gS3_sound_sources = NULL; | ||
| 757 |             } | ||
| 758 |         } | ||
| 759 | S3StopSoundSource(src); | ||
| 760 | S3MemFree(src); | ||
| 761 |     } | ||
| 762 | return 0; | ||
| 763 | } | ||
| 764 | |||
| 765 | void S3Service(int inside_cockpit, int unk1) { | ||
| 766 | |||
| 767 | int now; // [esp+Ch] [ebp-10h] | ||
| 768 | tS3_channel* c; // [esp+10h] [ebp-Ch] | ||
| 769 | tS3_outlet* o; // [esp+14h] [ebp-8h] | ||
| 770 | int v5; // [esp+18h] [ebp-4h] | ||
| 771 | |||
| 772 | v5 = 0; | ||
| 773 | gS3_inside_cockpit = inside_cockpit; | ||
| 774 | if (!gS3_enabled) { | ||
| 775 | return; | ||
| 776 |     } | ||
| 777 | now = PDGetTotalTime(); | ||
| 778 | gS3_service_time_delta = now - gS3_last_service_time; | ||
| 779 | gS3_last_service_time = now; | ||
| 780 | S3ServiceOutlets(); | ||
| 781 | if (unk1 == 1) { | ||
| 782 | S3UpdateListenerVectors(); | ||
| 783 | S3ServiceAmbientSoundSources(); | ||
| 784 |     } | ||
| 785 | for (o = gS3_outlets; o; o = o->next) { | ||
| 786 | for (c = o->channel_list; c; c = c->next) { | ||
| 787 | if (c->needs_service) { | ||
| 788 | c->needs_service = 0; | ||
| 789 | if (c->descriptor && c->descriptor->flags == 2) { | ||
| 790 | S3ReleaseSound(c->descriptor->id); | ||
| 791 |                 } | ||
| 792 | c->active = 0; | ||
| 793 | if (c->type != eS3_ST_midi) { | ||
| 794 | c->tag = 0; | ||
| 795 |                 } | ||
| 796 | } else if (c->spatial_sound && c->active) { | ||
| 797 | if (S3UpdateSpatialSound(c)) { | ||
| 798 | if (c->sound_source_ptr && c->sound_source_ptr->ambient && !S3SoundStillPlaying(c->tag)) { | ||
| 799 | S3UpdateSoundSource(NULL, -1, c->sound_source_ptr, -1.0f, -1, -1, 0, -1, -1); | ||
| 800 |                     } | ||
| 801 | } else if (c->sound_source_ptr) { | ||
| 802 | if (c->sound_source_ptr->ambient) { | ||
| 803 | S3UpdateSoundSource(NULL, -1, c->sound_source_ptr, -1.0f, -1, -1, 0, -1, -1); | ||
| 804 |                     } | ||
| 805 | } else { | ||
| 806 | S3StopChannel(c); | ||
| 807 |                 } | ||
| 808 | } else if (c->type == eS3_ST_midi && c->active) { | ||
| 809 |                 // sub_4124BE(c); | ||
| 810 |             } | ||
| 811 | if (unk1 < 2 && gS3_last_service_time > dword_5216C0) { | ||
| 812 | v5 = 1; | ||
| 813 | if (!c->active && c->spatial_sound == 2) { | ||
| 814 |                     // null_unknown_libname_8();  /* no-op */ | ||
| 815 |                 } | ||
| 816 |             } | ||
| 817 |         } | ||
| 818 |     } | ||
| 819 | if (v5) { | ||
| 820 | dword_5216C0 = gS3_last_service_time; | ||
| 821 |     } | ||
| 822 | } | ||
| 823 | |||
| 824 | void S3ServiceOutlets(void) { | ||
| 825 | tS3_channel* c; // [esp+Ch] [ebp-8h] | ||
| 826 | tS3_outlet* o; // [esp+10h] [ebp-4h] | ||
| 827 | |||
| 828 | for (o = gS3_outlets; o; o = o->next) { | ||
| 829 | for (c = o->channel_list; c; c = c->next) { | ||
| 830 | S3ServiceChannel(c); | ||
| 831 |         } | ||
| 832 |     } | ||
| 833 | } | ||
| 834 | |||
| 835 | int S3ServiceChannel(tS3_channel* chan) { | ||
| 836 | if (chan->type == eS3_ST_sample) { | ||
| 837 | if (AudioBackend_SoundIsPlaying(chan)) { | ||
| 838 | return 1; | ||
| 839 |         } | ||
| 840 | S3StopSample(chan); | ||
| 841 | return 0; | ||
| 842 | } else if (chan->type == eS3_ST_midi) { | ||
| 843 | return !S3IsMIDIStopped(chan); | ||
| 844 | } else if (chan->type == eS3_ST_cda) { | ||
| 845 | return S3IsCDAPlaying(); | ||
| 846 | } else { | ||
| 847 | return 0; | ||
| 848 |     } | ||
| 849 | } | ||
| 850 | |||
| 851 | void S3StopAllOutletSounds(void) { | ||
| 852 | tS3_outlet* o; // [esp+Ch] [ebp-4h] | ||
| 853 | |||
| 854 | if (!gS3_enabled) { | ||
| 855 | return; | ||
| 856 |     } | ||
| 857 | |||
| 858 | for (o = gS3_outlets; o; o = o->next) { | ||
| 859 | S3StopOutletSound(o); | ||
| 860 |     } | ||
| 861 | } | ||
| 862 | |||
| 863 | tS3_sound_tag S3StartSound(tS3_outlet* pOutlet, tS3_sound_id pSound) { | ||
| 864 | int repetitions; // eax | ||
| 865 | tS3_channel* chan; // [esp+14h] [ebp-Ch] | ||
| 866 | tS3_descriptor* desc; // [esp+1Ch] [ebp-4h] | ||
| 867 | |||
| 868 | if (!gS3_enabled) { | ||
| 869 | return 0; | ||
| 870 |     } | ||
| 871 | if (!pOutlet) { | ||
| 872 | gS3_last_error = eS3_error_bad_id; | ||
| 873 | return 0; | ||
| 874 |     } | ||
| 875 | desc = S3GetDescriptorByID(pSound); | ||
| 876 | if (!desc) { | ||
| 877 | gS3_last_error = eS3_error_bad_id; | ||
| 878 | return 0; | ||
| 879 |     } | ||
| 880 | memset(&gS3_channel_template, 0, sizeof(gS3_channel_template)); | ||
| 881 | S3CalculateRandomizedFields(&gS3_channel_template, desc); | ||
| 882 | chan = S3AllocateChannel(pOutlet, desc->priority * (gS3_channel_template.right_volume + gS3_channel_template.left_volume + 1)); | ||
| 883 | if (!chan) { | ||
| 884 | gS3_last_error = eS3_error_channel_alloc; | ||
| 885 | return 0; | ||
| 886 |     } | ||
| 887 | chan->left_volume = gS3_channel_template.left_volume * chan->volume_multiplier; | ||
| 888 | chan->right_volume = gS3_channel_template.right_volume * chan->volume_multiplier; | ||
| 889 | chan->rate = gS3_channel_template.rate; | ||
| 890 | if (desc->type == eS3_ST_sample && (!desc->sound_data || desc->flags == 2)) { | ||
| 891 | if (!S3LoadSample(pSound)) { | ||
| 892 | chan->needs_service = 1; | ||
| 893 | gS3_last_error = eS3_error_load_sound; | ||
| 894 | return 0; | ||
| 895 |         } | ||
| 896 |     } | ||
| 897 | if (chan->descriptor && chan->descriptor->type == 1 && chan->descriptor->id != pSound) { | ||
| 898 | S3ReleaseMIDI(chan->tag); | ||
| 899 |     } | ||
| 900 | chan->spatial_sound = 0; | ||
| 901 | chan->sound_source_ptr = 0; | ||
| 902 | chan->descriptor = desc; | ||
| 903 | chan->type = desc->type; | ||
| 904 | repetitions = desc->repeats; | ||
| 905 | if (repetitions <= 0) { | ||
| 906 | repetitions = 0; | ||
| 907 |     } | ||
| 908 | chan->repetitions = repetitions; | ||
| 909 | chan->needs_service = 0; | ||
| 910 | chan->termination_reason = eS3_tr_natural; | ||
| 911 | chan->tag = S3GenerateTag(pOutlet); | ||
| 912 | if (desc->type == eS3_ST_midi && !desc->sound_data) { | ||
| 913 | if (S3MIDILoadSong(chan)) { | ||
| 914 | chan->needs_service = 1; | ||
| 915 | return 0; | ||
| 916 |         } | ||
| 917 |     } | ||
| 918 | if (chan->type == eS3_ST_sample) { | ||
| 919 | S3ExecuteSampleFilterFuncs(chan); | ||
| 920 | if (S3PlaySample(chan) == 0) { | ||
| 921 | gS3_last_error = eS3_error_start_sound; | ||
| 922 | chan->needs_service = 1; | ||
| 923 | return 0; | ||
| 924 |         } | ||
| 925 | } else if (chan->type == eS3_ST_midi) { | ||
| 926 | if (S3PlayMIDI(chan)) { | ||
| 927 | chan->needs_service = 1; | ||
| 928 | gS3_last_error = eS3_error_start_song; | ||
| 929 | return 0; | ||
| 930 |         } | ||
| 931 | S3SetMIDIVolume(chan); | ||
| 932 | } else if (chan->type == eS3_ST_cda) { | ||
| 933 | if (S3PlayCDA(chan)) { | ||
| 934 | chan->needs_service = 1; | ||
| 935 | gS3_last_error = eS3_error_start_cda; | ||
| 936 | return 0; | ||
| 937 |         } | ||
| 938 |     } | ||
| 939 | |||
| 940 | return chan->tag; | ||
| 941 | } | ||
| 942 | |||
| 943 | tS3_sound_tag S3StartSound2(tS3_outlet* pOutlet, tS3_sound_id pSound, tS3_repeats pRepeats, tS3_volume pLVolume, tS3_volume pRVolume, tS3_pitch pPitch, tS3_speed pSpeed) { | ||
| 944 | tS3_channel* chan; // [esp+30h] [ebp-Ch] | ||
| 945 | tS3_descriptor* desc; // [esp+38h] [ebp-4h] | ||
| 946 | |||
| 947 | if (!gS3_enabled) { | ||
| 948 | return 0; | ||
| 949 |     } | ||
| 950 | desc = S3GetDescriptorByID(pSound); | ||
| 951 | if (!desc) { | ||
| 952 | gS3_last_error = eS3_error_bad_id; | ||
| 953 | return 0; | ||
| 954 |     } | ||
| 955 | if (pLVolume < 0) { | ||
| 956 | pLVolume = 128; | ||
| 957 |     } | ||
| 958 | if (pRVolume < 0) { | ||
| 959 | pRVolume = 128; | ||
| 960 |     } | ||
| 961 | if (pLVolume > 255) { | ||
| 962 | pLVolume = 255; | ||
| 963 |     } | ||
| 964 | if (pRVolume > 255) { | ||
| 965 | pRVolume = 255; | ||
| 966 |     } | ||
| 967 | chan = S3AllocateChannel(pOutlet, desc->priority * (pLVolume + pRVolume + 1)); | ||
| 968 | if (chan == NULL) { | ||
| 969 | gS3_last_error = eS3_error_channel_alloc; | ||
| 970 | return 0; | ||
| 971 |     } | ||
| 972 | if (desc->type == eS3_ST_sample) { | ||
| 973 | if (desc->sound_data == NULL && (!S3LoadSample(pSound) || (desc->flags & 2) != 0)) { | ||
| 974 | chan->needs_service = 1; | ||
| 975 | gS3_last_error = eS3_error_load_sound; | ||
| 976 | return 0; | ||
| 977 |         } | ||
| 978 |     } | ||
| 979 | |||
| 980 | if (chan->descriptor && chan->descriptor->type == eS3_ST_midi) { | ||
| 981 | if (chan->descriptor->id != pSound) { | ||
| 982 | S3ReleaseMIDI(chan->tag); | ||
| 983 |         } | ||
| 984 |     } | ||
| 985 | chan->spatial_sound = 0; | ||
| 986 | chan->descriptor = desc; | ||
| 987 | chan->needs_service = 0; | ||
| 988 | chan->termination_reason = eS3_tr_natural; | ||
| 989 | chan->type = desc->type; | ||
| 990 | chan->sound_source_ptr = NULL; | ||
| 991 | chan->repetitions = MAX(pRepeats, 0); | ||
| 992 | S3CalculateRandomizedFields(chan, desc); | ||
| 993 | chan->left_volume = pLVolume * chan->volume_multiplier; | ||
| 994 | chan->right_volume = pRVolume * chan->volume_multiplier; | ||
| 995 | chan->tag = S3GenerateTag(pOutlet); | ||
| 996 | if (pPitch == -1) { | ||
| 997 | pPitch = 0x10000; | ||
| 998 |     } | ||
| 999 | if (pSpeed == -1) { | ||
| 1000 | pSpeed = 0x10000; | ||
| 1001 |     } | ||
| 1002 | chan->rate = ldexpf(pPitch, -16) * chan->rate; | ||
| 1003 | if (!pOutlet->independent_pitch) { | ||
| 1004 | chan->rate = ldexpf(pSpeed, -16) * chan->rate; | ||
| 1005 |     } | ||
| 1006 | if (desc->type == eS3_ST_midi && desc->sound_data == NULL && S3MIDILoadSong(chan)) { | ||
| 1007 | chan->needs_service = 1; | ||
| 1008 | return 0; | ||
| 1009 |     } | ||
| 1010 | |||
| 1011 | switch (chan->type) { | ||
| 1012 | case eS3_ST_sample: | ||
| 1013 | S3ExecuteSampleFilterFuncs(chan); | ||
| 1014 | if (!S3PlaySample(chan)) { | ||
| 1015 | chan->needs_service = 1; | ||
| 1016 | gS3_last_error = eS3_error_start_sound; | ||
| 1017 | return 0; | ||
| 1018 |         } | ||
| 1019 | break; | ||
| 1020 | |||
| 1021 | case eS3_ST_midi: | ||
| 1022 | if (S3PlayMIDI(chan)) { | ||
| 1023 | chan->needs_service = 1; | ||
| 1024 | gS3_last_error = eS3_error_start_song; | ||
| 1025 | return 0; | ||
| 1026 |         } | ||
| 1027 | S3SetMIDIVolume(chan); | ||
| 1028 | break; | ||
| 1029 | |||
| 1030 | case eS3_ST_cda: | ||
| 1031 | if (S3PlayCDA(chan)) { | ||
| 1032 | chan->needs_service = 1; | ||
| 1033 | gS3_last_error = eS3_error_start_cda; | ||
| 1034 | return 0; | ||
| 1035 |         } | ||
| 1036 | break; | ||
| 1037 |     } | ||
| 1038 | |||
| 1039 | return chan->tag; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | void S3CalculateRandomizedFields(tS3_channel* chan, tS3_descriptor* desc) { | ||
| 1043 | int vol; // eax | ||
| 1044 | |||
| 1045 | vol = S3IRandomBetween(desc->min_volume, desc->max_volume, 128); | ||
| 1046 | chan->left_volume = vol; | ||
| 1047 | chan->right_volume = vol; | ||
| 1048 | if (desc->type == eS3_ST_sample) { | ||
| 1049 | #if defined(DETHRACE_FIX_BUGS) | ||
| 1050 |         /* Avoid a possible NULL pointer dereference. */ | ||
| 1051 | if (desc->sound_data == NULL) { | ||
| 1052 | chan->rate = desc->min_pitch; | ||
| 1053 | return; | ||
| 1054 |         } | ||
| 1055 | #endif | ||
| 1056 | chan->rate = S3IRandomBetweenLog(desc->min_pitch, desc->max_pitch, ((tS3_sample*)desc->sound_data)->rate); | ||
| 1057 |     } | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | // duplicate of S3IRandomBetween2 | ||
| 1061 | int S3IRandomBetween(int pMin, int pMax, int pDefault) { | ||
| 1062 | if (pMin == -1) { | ||
| 1063 | return pDefault; | ||
| 1064 |     } | ||
| 1065 | if (pMax <= pMin) { | ||
| 1066 | return pMin; | ||
| 1067 |     } | ||
| 1068 | return rand() % (pMax - pMin) + pMin; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | // duplicate of S3IRandomBetweenLog2 | ||
| 1072 | int S3IRandomBetweenLog(int pMin, int pMax, int pDefault) { | ||
| 1073 | float v4; // st7 | ||
| 1074 | |||
| 1075 | if (pMin == -1 || pMin >= pMax) { | ||
| 1076 | return pDefault; | ||
| 1077 |     } | ||
| 1078 | v4 = S3FRandomBetween(log(pMin), log(pMax)); | ||
| 1079 | return ldexp(exp(v4), -16) * pDefault; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | // duplicate of S3FRandomBetween2 | ||
| 1083 | double S3FRandomBetween(double pMin, double pMax) { | ||
| 1084 | return (double)rand() * (pMax - pMin) / (double)RAND_MAX + pMin; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | int S3GenerateTag(tS3_outlet* outlet) { | ||
| 1088 | gS3_tag_seed += 256; | ||
| 1089 | return gS3_tag_seed | outlet->id; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | int S3SoundStillPlaying(tS3_sound_tag pTag) { | ||
| 1093 | tS3_channel* chan; | ||
| 1094 | |||
| 1095 | if (!gS3_enabled) { | ||
| 1096 | return 0; | ||
| 1097 |     } | ||
| 1098 | if (!pTag) { | ||
| 1099 | return 0; | ||
| 1100 |     } | ||
| 1101 | chan = S3GetChannelForTag(pTag); | ||
| 1102 | if (!chan) { | ||
| 1103 | return 0; | ||
| 1104 |     } | ||
| 1105 | return S3ServiceChannel(chan) != 0; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | int S3ChangePitchSpeed(tS3_sound_tag pTag, tS3_pitch pNew_pitch) { | ||
| 1109 | tS3_channel* chan; | ||
| 1110 | |||
| 1111 | if (!gS3_enabled) { | ||
| 1112 | return 0; | ||
| 1113 |     } | ||
| 1114 | if (pNew_pitch == -1) { | ||
| 1115 | pNew_pitch = 0x10000; | ||
| 1116 |     } | ||
| 1117 | chan = S3GetChannelForTag(pTag); | ||
| 1118 | if (chan == NULL) { | ||
| 1119 | return eS3_error_bad_stag; | ||
| 1120 |     } | ||
| 1121 | if (chan->type != eS3_ST_sample) { | ||
| 1122 | return 0; | ||
| 1123 |     } | ||
| 1124 | chan->rate = ldexp(pNew_pitch, -16) * ((tS3_sample*)chan->descriptor->sound_data)->rate; | ||
| 1125 | if (S3SyncSampleRate(chan)) { | ||
| 1126 | return 0; | ||
| 1127 | } else { | ||
| 1128 | return eS3_error_function_failed; | ||
| 1129 |     } | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | int S3StopSound(tS3_sound_tag pTag) { | ||
| 1133 | tS3_channel* chan; // [esp+Ch] [ebp-4h] | ||
| 1134 | |||
| 1135 | if (!gS3_enabled) { | ||
| 1136 | return 0; | ||
| 1137 |     } | ||
| 1138 | if (!pTag) { | ||
| 1139 | return eS3_error_bad_stag; | ||
| 1140 |     } | ||
| 1141 | chan = S3GetChannelForTag(pTag); | ||
| 1142 | if (!chan) { | ||
| 1143 | return eS3_error_bad_stag; | ||
| 1144 |     } | ||
| 1145 | chan->termination_reason = eS3_tr_stopped; | ||
| 1146 | chan->initial_volume = 0; | ||
| 1147 | if (chan->active) { | ||
| 1148 | chan->needs_service = 1; | ||
| 1149 |     } | ||
| 1150 | if (chan->type == eS3_ST_sample) { | ||
| 1151 | if (chan->sound_source_ptr) { | ||
| 1152 | chan->sound_source_ptr->tag = 0; | ||
| 1153 | chan->sound_source_ptr->channel = NULL; | ||
| 1154 | chan->sound_source_ptr->volume = 0; | ||
| 1155 |         } | ||
| 1156 | if (!S3StopSample(chan)) { | ||
| 1157 | return eS3_error_function_failed; | ||
| 1158 |         } | ||
| 1159 | } else if (chan->type == eS3_ST_midi) { | ||
| 1160 | if (S3StopMIDI(chan)) { | ||
| 1161 | return eS3_error_function_failed; | ||
| 1162 |         } | ||
| 1163 | } else if (chan->type == eS3_ST_cda) { | ||
| 1164 | if (S3StopCDA(chan)) { | ||
| 1165 | return eS3_error_function_failed; | ||
| 1166 |         } | ||
| 1167 |     } | ||
| 1168 | |||
| 1169 | if ((chan->descriptor->flags & 2) != 0) { | ||
| 1170 | S3ReleaseSound(chan->descriptor->id); | ||
| 1171 |     } | ||
| 1172 | chan->repetitions = 1; | ||
| 1173 | return 0; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | int S3StopOutletSound(tS3_outlet* pOutlet) { | ||
| 1177 | tS3_channel* c; // [esp+Ch] [ebp-4h] | ||
| 1178 | |||
| 1179 | if (!gS3_enabled) { | ||
| 1180 | return 0; | ||
| 1181 |     } | ||
| 1182 | for (c = pOutlet->channel_list; c; c = c->next) { | ||
| 1183 |         // null_unknown_libname_8(); | ||
| 1184 | if (c->active) { | ||
| 1185 | c->spatial_sound = 0; | ||
| 1186 | S3StopChannel(c); | ||
| 1187 | c->needs_service = 1; | ||
| 1188 |         } | ||
| 1189 |     } | ||
| 1190 | return 0; | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | char* S3GetCurrentDir(void) { | ||
| 1194 | if (!gS3_have_current_dir) { | ||
| 1195 | if (getcwd(gS3_current_dir, 260) == NULL) { | ||
| 1196 | LOG_PANIC("failed to call getcwd"); // added by dethrace | ||
| 1197 | }; | ||
| 1198 | gS3_have_current_dir = 1; | ||
| 1199 |     } | ||
| 1200 | return gS3_current_dir; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | tS3_descriptor* S3GetDescriptorByID(tS3_sound_tag id) { | ||
| 1204 | tS3_descriptor* d; // [esp+Ch] [ebp-4h] | ||
| 1205 | |||
| 1206 | for (d = gS3_descriptors;; d = d->next) { | ||
| 1207 | if (!d) { | ||
| 1208 | return 0; | ||
| 1209 |         } | ||
| 1210 | if (d->id == id) { | ||
| 1211 | break; | ||
| 1212 |         } | ||
| 1213 |     } | ||
| 1214 | if (d->memory_proxy < 0) { | ||
| 1215 | return d; | ||
| 1216 | } else { | ||
| 1217 | return S3GetDescriptorByID(d->memory_proxy); | ||
| 1218 |     } | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | int S3SetOutletVolume(tS3_outlet* pOutlet, tS3_volume pVolume) { | ||
| 1222 | tS3_channel* c; // [esp+10h] [ebp-4h] | ||
| 1223 | |||
| 1224 | if (!gS3_enabled) { | ||
| 1225 | return 0; | ||
| 1226 |     } | ||
| 1227 | if (pVolume > 255) { | ||
| 1228 | pVolume = 255; | ||
| 1229 |     } | ||
| 1230 | if (pVolume < 10) { | ||
| 1231 | pVolume = 10; | ||
| 1232 |     } | ||
| 1233 | if (!pOutlet) { | ||
| 1234 | return 0; | ||
| 1235 |     } | ||
| 1236 | for (c = pOutlet->channel_list; c; c = c->next) { | ||
| 1237 | c->volume_multiplier = pVolume / 150.0f; | ||
| 1238 | if (c->active) { | ||
| 1239 | S3ChangeVolume(c->tag, pVolume); | ||
| 1240 |         } | ||
| 1241 |     } | ||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | tS3_channel* S3GetChannelForTag(tS3_sound_tag tag) { | ||
| 1246 | tS3_channel* c; // [esp+Ch] [ebp-Ch] | ||
| 1247 | tS3_outlet* o; // [esp+14h] [ebp-4h] | ||
| 1248 | |||
| 1249 | if (!tag) { | ||
| 1250 | return 0; | ||
| 1251 |     } | ||
| 1252 | for (o = gS3_outlets; o && o->id != (uint8_t)tag; o = o->next) { | ||
| 1253 |         ; | ||
| 1254 |     } | ||
| 1255 | if (!o) { | ||
| 1256 | return 0; | ||
| 1257 |     } | ||
| 1258 | for (c = o->channel_list; c; c = c->next) { | ||
| 1259 | if (c->tag == tag) { | ||
| 1260 | return c; | ||
| 1261 |         } | ||
| 1262 |     } | ||
| 1263 | return 0; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | int S3ChangeVolume(tS3_sound_tag pTag, tS3_volume pVolume) { | ||
| 1267 | tS3_channel* chan; // [esp+14h] [ebp-4h] | ||
| 1268 | |||
| 1269 | if (!gS3_enabled) { | ||
| 1270 | return 0; | ||
| 1271 |     } | ||
| 1272 | chan = S3GetChannelForTag(pTag); | ||
| 1273 | if (!chan) { | ||
| 1274 | return eS3_error_bad_stag; | ||
| 1275 |     } | ||
| 1276 | if (pVolume < 0) { | ||
| 1277 | pVolume = 128; | ||
| 1278 |     } | ||
| 1279 | if (pVolume > 255) { | ||
| 1280 | pVolume = 255; | ||
| 1281 |     } | ||
| 1282 | if (chan->type == eS3_ST_sample) { | ||
| 1283 | chan->left_volume = pVolume * chan->volume_multiplier; | ||
| 1284 | chan->right_volume = pVolume * chan->volume_multiplier; | ||
| 1285 | if (!S3SyncSampleVolumeAndPan(chan)) { | ||
| 1286 | return eS3_error_function_failed; | ||
| 1287 |         } | ||
| 1288 | } else if (chan->type == eS3_ST_midi) { | ||
| 1289 | S3SetMIDIVolume(chan); | ||
| 1290 | } else if (chan->type == eS3_ST_cda) { | ||
| 1291 | S3SetCDAVolume(chan, pVolume); | ||
| 1292 |     } | ||
| 1293 | |||
| 1294 | return 0; | ||
| 1295 | } |