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