Subversion Repositories Games.Carmageddon

Rev

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
}