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 | } |