Subversion Repositories Games.Carmageddon

Rev

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
}