Subversion Repositories eduke32

Rev

Rev 4745 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 Plagman 1
//-------------------------------------------------------------------------
2
/*
1652 terminx 3
Copyright (C) 2010 EDuke32 developers and contributors
5 Plagman 4
 
1652 terminx 5
This file is part of EDuke32.
5 Plagman 6
 
7
EDuke32 is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License version 2
9
as published by the Free Software Foundation.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 
15
See the GNU General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
4541 hendricks2 19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
5 Plagman 20
*/
21
//-------------------------------------------------------------------------
22
 
4762 hendricks2 23
#ifndef __STDC_FORMAT_MACROS
3116 hendricks2 24
#define __STDC_FORMAT_MACROS
4762 hendricks2 25
#endif
4540 hendricks2 26
#ifndef __STDC_LIMIT_MACROS
3116 hendricks2 27
#define __STDC_LIMIT_MACROS
4540 hendricks2 28
#endif
3116 hendricks2 29
 
5 Plagman 30
#include <stdio.h>
31
#include <string.h>
1346 terminx 32
 
5 Plagman 33
#include "fx_man.h"
34
#include "music.h"
35
#include "duke3d.h"
559 terminx 36
#include "osd.h"
1677 terminx 37
#include "sounds.h"
5 Plagman 38
 
3839 hendricks2 39
#ifdef _WIN32
1672 terminx 40
#include "winlayer.h"
41
#endif
42
 
4294 helixhorne 43
int32_t g_numEnvSoundsPlaying, g_maxSoundPos = 0;
5 Plagman 44
 
1468 terminx 45
static int32_t MusicIsWaveform = 0;
1677 terminx 46
static char *MusicPtr = 0;
1468 terminx 47
static int32_t MusicVoice = -1;
48
static int32_t MusicPaused = 0;
49
 
1658 terminx 50
static mutex_t s_mutex;
1672 terminx 51
static volatile uint32_t dq[128], dnum = 0;
1658 terminx 52
 
1143 terminx 53
void S_SoundStartup(void)
29 terminx 54
{
1677 terminx 55
    int32_t fxdevicetype, i;
56
    void *initdata = 0;
5 Plagman 57
 
1487 terminx 58
    if (ud.config.FXDevice >= 0)
1468 terminx 59
        fxdevicetype = ASS_AutoDetect;
1487 terminx 60
    else return;
29 terminx 61
 
4084 hendricks2 62
#ifdef MIXERTYPEWIN
3221 hendricks2 63
    initdata = (void *) win_gethwnd(); // used for DirectSound
1468 terminx 64
#endif
1454 terminx 65
 
1909 terminx 66
    initprintf("Initializing sound... ");
1487 terminx 67
 
1601 terminx 68
    if (FX_Init(fxdevicetype, ud.config.NumVoices, ud.config.NumChannels, ud.config.NumBits, ud.config.MixRate, initdata) != FX_Ok)
335 terminx 69
    {
1909 terminx 70
        initprintf("failed! %s\n", FX_ErrorString(FX_Error));
1779 terminx 71
        return;
29 terminx 72
    }
1468 terminx 73
 
2439 helixhorne 74
    initprintf("%d voices, %d channels, %d-bit %d Hz\n", ud.config.NumVoices, ud.config.NumChannels,
1909 terminx 75
        ud.config.NumBits, ud.config.MixRate);
76
 
1677 terminx 77
    for (i=g_maxSoundPos; i >= 0 ; i--)
78
    {
79
        int32_t j = MAXSOUNDINSTANCES-1;
80
 
81
        for (; j>=0; j--)
82
        {
83
            g_sounds[i].num = 0;
84
            g_sounds[i].SoundOwner[j].voice = 0;
2442 helixhorne 85
            g_sounds[i].SoundOwner[j].ow = -1;
3066 terminx 86
            g_sounds[i].SoundOwner[j].sndist = UINT32_MAX;
87
            g_sounds[i].SoundOwner[j].clock = 0;
1677 terminx 88
        }
89
 
90
        g_soundlocks[i] = 199;
91
    }
92
 
3993 terminx 93
    FX_SetVolume(ud.config.MasterVolume);
4289 helixhorne 94
    S_MusicVolume(MASTER_VOLUME(ud.config.MusicVolume));
95
 
1487 terminx 96
    FX_SetReverseStereo(ud.config.ReverseStereo);
1601 terminx 97
    FX_SetCallBack(S_Callback);
1658 terminx 98
    FX_SetPrintf(initprintf);
99
    mutex_init(&s_mutex);
29 terminx 100
}
101
 
1143 terminx 102
void S_SoundShutdown(void)
29 terminx 103
{
563 terminx 104
    if (ud.config.FXDevice < 0)
29 terminx 105
        return;
106
 
1468 terminx 107
    if (MusicVoice >= 0)
108
        S_MusicShutdown();
109
 
1601 terminx 110
    if (FX_Shutdown() != FX_Ok)
335 terminx 111
    {
1601 terminx 112
        Bsprintf(tempbuf, "S_SoundShutdown(): error: %s", FX_ErrorString(FX_Error));
1143 terminx 113
        G_GameExit(tempbuf);
29 terminx 114
    }
115
}
116
 
1143 terminx 117
void S_MusicStartup(void)
5 Plagman 118
{
563 terminx 119
    if (ud.config.MusicDevice < 0)
5 Plagman 120
        return;
121
 
1454 terminx 122
    initprintf("Initializing music...\n");
123
 
1601 terminx 124
    if (MUSIC_Init(ud.config.MusicDevice, 0) == MUSIC_Ok || MUSIC_Init((ud.config.MusicDevice = 0), 0) == MUSIC_Ok)
5 Plagman 125
    {
3993 terminx 126
        MUSIC_SetVolume(MASTER_VOLUME(ud.config.MusicVolume));
1601 terminx 127
        return;
5 Plagman 128
    }
129
 
1601 terminx 130
    initprintf("S_MusicStartup(): failed initializing\n");
5 Plagman 131
}
132
 
1143 terminx 133
void S_MusicShutdown(void)
5 Plagman 134
{
563 terminx 135
    if (ud.config.MusicDevice < 0)
5 Plagman 136
        return;
137
 
1468 terminx 138
    S_StopMusic();
139
 
1601 terminx 140
    if (MUSIC_Shutdown() != MUSIC_Ok)
3668 hendricks2 141
        initprintf("%s\n", MUSIC_ErrorString(MUSIC_ErrorCode));
5 Plagman 142
}
143
 
1468 terminx 144
void S_PauseMusic(int32_t onf)
145
{
146
    if (MusicPaused == onf || (MusicIsWaveform && MusicVoice < 0))
147
        return;
148
 
1601 terminx 149
    MusicPaused = onf;
150
 
1468 terminx 151
    if (MusicIsWaveform)
1601 terminx 152
    {
1468 terminx 153
        FX_PauseVoice(MusicVoice, onf);
1601 terminx 154
        return;
1481 terminx 155
    }
1468 terminx 156
 
1601 terminx 157
    if (onf)
158
        MUSIC_Pause();
159
    else
160
        MUSIC_Continue();
1468 terminx 161
}
162
 
163
void S_MusicVolume(int32_t volume)
164
{
165
    if (MusicIsWaveform && MusicVoice >= 0)
166
        FX_SetPan(MusicVoice, volume, volume, volume);
1601 terminx 167
 
168
    MUSIC_SetVolume(volume);
1468 terminx 169
}
170
 
4585 helixhorne 171
void S_RestartMusic(void)
172
{
173
    if (ud.recstat != 2 && g_player[myconnectindex].ps->gm&MODE_GAME)
174
    {
175
        if (MapInfo[g_musicIndex].musicfn != NULL)
176
            S_PlayMusic(MapInfo[g_musicIndex].musicfn, g_musicIndex);
177
    }
4588 helixhorne 178
    else if (MapInfo[MUS_INTRO].musicfn != 0)
179
    {
180
        S_PlayMusic(MapInfo[MUS_INTRO].musicfn, MUS_INTRO);
181
    }
4585 helixhorne 182
}
183
 
1143 terminx 184
void S_MenuSound(void)
5 Plagman 185
{
1205 terminx 186
    static int32_t SoundNum=0;
4069 helixhorne 187
    int32_t menusnds[] =
559 terminx 188
    {
3846 helixhorne 189
        LASERTRIP_EXPLODE,
190
        DUKE_GRUNT,
191
        DUKE_LAND_HURT,
192
        CHAINGUN_FIRE,
193
        SQUISHED,
194
        KICK_HIT,
195
        PISTOL_RICOCHET,
196
        PISTOL_BODYHIT,
197
        PISTOL_FIRE,
198
        SHOTGUN_FIRE,
199
        BOS1_WALK,
200
        RPG_EXPLODE,
201
        PIPEBOMB_BOUNCE,
202
        PIPEBOMB_EXPLODE,
203
        NITEVISION_ONOFF,
204
        RPG_SHOOT,
205
        SELECT_WEAPON,
559 terminx 206
    };
5 Plagman 207
 
4385 terminx 208
    S_PlaySound(menusnds[SoundNum++ % ARRAY_SIZE(menusnds)]);
5 Plagman 209
}
210
 
1205 terminx 211
int32_t S_PlayMusic(const char *fn, const int32_t sel)
680 terminx 212
{
4585 helixhorne 213
    const char *const ofn = fn;
214
    char *testfn, *extension;
4294 helixhorne 215
    int32_t fp, MusicLen;
1601 terminx 216
    const char *alt = 0;
1468 terminx 217
 
218
    if (ud.config.MusicToggle == 0) return 0;
219
    if (ud.config.MusicDevice < 0) return 0;
220
 
4703 terminx 221
    if (MapInfo[sel].ext_musicfn != NULL)
222
        alt = fn = MapInfo[sel].ext_musicfn;
1475 terminx 223
 
4491 helixhorne 224
    testfn = (char *)Xmalloc(strlen(fn) + 6);
1468 terminx 225
    strcpy(testfn, fn);
226
    extension = strrchr(testfn, '.');
227
 
228
    do
229
    {
230
        if (extension && !Bstrcasecmp(extension, ".mid"))
231
        {
1601 terminx 232
            // we've been asked to load a .mid file, but first let's see
3335 hendricks2 233
            // if there's a flac or an ogg with the same base name lying around
234
            strcpy(extension, ".flac");
235
            fp = kopen4loadfrommod(testfn, 0);
236
            if (fp >= 0)
237
            {
238
                Bfree(testfn);
239
                break;
240
            }
4585 helixhorne 241
 
1468 terminx 242
            strcpy(extension, ".ogg");
1473 terminx 243
            fp = kopen4loadfrommod(testfn, 0);
1468 terminx 244
            if (fp >= 0)
245
            {
1527 terminx 246
                Bfree(testfn);
1468 terminx 247
                break;
248
            }
249
        }
1601 terminx 250
 
1527 terminx 251
        Bfree(testfn);
1468 terminx 252
 
253
        // just use what we've been given
4585 helixhorne 254
        fp = kopen4loadfrommod(fn, 0);
1475 terminx 255
 
256
        if (alt && fp < 0)
257
            fp = kopen4loadfrommod(ofn, 0);
1468 terminx 258
    }
259
    while (0);
260
 
4699 terminx 261
    if (EDUKE32_PREDICT_FALSE(fp < 0))
1488 terminx 262
    {
2538 hendricks2 263
        OSD_Printf(OSD_ERROR "S_PlayMusic(): error: can't open \"%s\" for playback!\n",fn);
1488 terminx 264
        return 0;
265
    }
1468 terminx 266
 
267
    S_StopMusic();
268
 
4294 helixhorne 269
    MusicLen = kfilelength(fp);
1488 terminx 270
 
4699 terminx 271
    if (EDUKE32_PREDICT_FALSE(MusicLen < 4))
1488 terminx 272
    {
4294 helixhorne 273
        OSD_Printf(OSD_ERROR "S_PlayMusic(): error: empty music file \"%s\"\n", fn);
1488 terminx 274
        kclose(fp);
4294 helixhorne 275
        return 0;
276
    }
277
 
278
    Bfree(MusicPtr);  // in case the following allocation was never freed
4491 helixhorne 279
    MusicPtr = (char *)Xmalloc(MusicLen);
4294 helixhorne 280
    g_musicSize = kread(fp, (char *)MusicPtr, MusicLen);
281
 
4699 terminx 282
    if (EDUKE32_PREDICT_FALSE(g_musicSize != MusicLen))
4294 helixhorne 283
    {
284
        OSD_Printf(OSD_ERROR "S_PlayMusic(): error: read %d bytes from \"%s\", expected %d\n",
285
                   g_musicSize, fn, MusicLen);
286
        kclose(fp);
1488 terminx 287
        g_musicSize = 0;
288
        return 0;
289
    }
290
 
1468 terminx 291
    kclose(fp);
292
 
1472 terminx 293
    if (!Bmemcmp(MusicPtr, "MThd", 4))
1468 terminx 294
    {
295
        MUSIC_PlaySong(MusicPtr, MUSIC_LoopSong);
296
        MusicIsWaveform = 0;
297
    }
298
    else
299
    {
3993 terminx 300
        int32_t mvol = MASTER_VOLUME(ud.config.MusicVolume);
3631 helixhorne 301
        MusicVoice = FX_PlayLoopedAuto(MusicPtr, MusicLen, 0, 0,
302
                                       0, mvol, mvol, mvol,
303
                                       FX_MUSIC_PRIORITY, MUSIC_ID);
304
        if (MusicVoice > FX_Ok)
1488 terminx 305
            MusicIsWaveform = 1;
1468 terminx 306
    }
4294 helixhorne 307
 
1475 terminx 308
    return (alt != 0);
1468 terminx 309
}
310
 
311
void S_StopMusic(void)
312
{
1488 terminx 313
    MusicPaused = 0;
314
 
1468 terminx 315
    if (MusicIsWaveform && MusicVoice >= 0)
316
    {
317
        FX_StopSound(MusicVoice);
318
        MusicVoice = -1;
1488 terminx 319
        MusicIsWaveform = 0;
1468 terminx 320
    }
321
 
1472 terminx 322
    MUSIC_StopSong();
323
 
4294 helixhorne 324
    Bfree(MusicPtr);
325
    MusicPtr = NULL;
326
    g_musicSize = 0;
1468 terminx 327
}
328
 
1658 terminx 329
void S_Cleanup(void)
330
{
331
    // process from our own local copy of the delete queue so we don't hold the lock long
332
    uint32_t ldq[128], ldnum;
333
 
334
    mutex_lock(&s_mutex);
335
 
336
    if (!dnum)
337
    {
338
        mutex_unlock(&s_mutex);
339
        return;
340
    }
341
 
2471 helixhorne 342
    ldnum = dnum;
343
    Bmemcpy(ldq, (void *)dq, ldnum*sizeof(int32_t));
1658 terminx 344
    dnum = 0;
345
 
346
    mutex_unlock(&s_mutex);
347
 
348
    do
349
    {
350
        uint32_t num = ldq[--ldnum];
351
 
352
        // negative index is RTS playback
353
        if ((int32_t)num < 0)
354
        {
1677 terminx 355
            if (rts_lumplockbyte[-(int32_t)num] >= 200)
356
                rts_lumplockbyte[-(int32_t)num]--;
1658 terminx 357
            continue;
358
        }
359
 
2093 helixhorne 360
        // num + (MAXSOUNDS*MAXSOUNDINSTANCES) is a sound played globally
361
        // for which there was no open slot to keep track of the voice
362
        if (num >= (MAXSOUNDS*MAXSOUNDINSTANCES))
1658 terminx 363
        {
2093 helixhorne 364
            g_soundlocks[num-(MAXSOUNDS*MAXSOUNDINSTANCES)]--;
1898 helixhorne 365
            continue;
366
        }
367
 
368
        {
1658 terminx 369
            int32_t j = num & (MAXSOUNDINSTANCES-1);
1665 terminx 370
            int32_t i;
371
 
1658 terminx 372
            num = (num - j) / MAXSOUNDINSTANCES;
373
 
2442 helixhorne 374
            i = g_sounds[num].SoundOwner[j].ow;
1665 terminx 375
 
4699 terminx 376
            if (EDUKE32_PREDICT_FALSE(g_sounds[num].num > MAXSOUNDINSTANCES))
1658 terminx 377
                OSD_Printf(OSD_ERROR "S_Cleanup(): num exceeds MAXSOUNDINSTANCES! g_sounds[%d].num %d wtf?\n", num, g_sounds[num].num);
378
 
379
            if (g_sounds[num].num > 0)
1665 terminx 380
                g_sounds[num].num--;
1658 terminx 381
 
1665 terminx 382
            // MUSICANDSFX uses t_data[0] to control restarting the sound
4352 helixhorne 383
            // CLEAR_SOUND_T0
384
            if (i != -1 && S_IsAmbientSFX(i) && sector[sprite[i].sectnum].lotag < 3)  // ST_2_UNDERWATER
1665 terminx 385
                actor[i].t_data[0] = 0;
1658 terminx 386
 
2442 helixhorne 387
            g_sounds[num].SoundOwner[j].ow = -1;
1665 terminx 388
            g_sounds[num].SoundOwner[j].voice = 0;
3066 terminx 389
            g_sounds[num].SoundOwner[j].sndist = UINT32_MAX;
390
            g_sounds[num].SoundOwner[j].clock = 0;
1658 terminx 391
        }
392
        g_soundlocks[num]--;
393
    }
394
    while (ldnum);
395
}
396
 
1601 terminx 397
// returns number of bytes read
1205 terminx 398
int32_t S_LoadSound(uint32_t num)
5 Plagman 399
{
1205 terminx 400
    int32_t   fp = -1, l;
5 Plagman 401
 
2245 helixhorne 402
    if (num > (unsigned)g_maxSoundPos || ud.config.SoundToggle == 0 || ud.config.FXDevice < 0) return 0;
1677 terminx 403
 
4699 terminx 404
    if (EDUKE32_PREDICT_FALSE(g_sounds[num].filename == NULL && g_sounds[num].filename1 == NULL))
600 terminx 405
    {
909 terminx 406
        OSD_Printf(OSD_ERROR "Sound (#%d) not defined!\n",num);
600 terminx 407
        return 0;
408
    }
409
 
3065 terminx 410
    if (g_sounds[num].filename1)
411
        fp = kopen4loadfrommod(g_sounds[num].filename1,g_loadFromGroupOnly);
412
 
331 terminx 413
    if (fp == -1)
5 Plagman 414
    {
3065 terminx 415
        fp = kopen4loadfrommod(g_sounds[num].filename,g_loadFromGroupOnly);
416
 
4699 terminx 417
        if (EDUKE32_PREDICT_FALSE(fp == -1))
3065 terminx 418
        {
419
            OSD_Printf(OSDTEXT_RED "Sound %s(#%d) not found!\n",g_sounds[num].filename,num);
420
            return 0;
421
        }
5 Plagman 422
    }
423
 
1601 terminx 424
    g_sounds[num].soundsiz = l = kfilelength(fp);
1625 terminx 425
 
1457 terminx 426
    g_soundlocks[num] = 200;
5 Plagman 427
 
1601 terminx 428
    allocache((intptr_t *)&g_sounds[num].ptr, l, (char *)&g_soundlocks[num]);
2471 helixhorne 429
    l = kread(fp, g_sounds[num].ptr, l);
333 terminx 430
    kclose(fp);
1582 terminx 431
 
1601 terminx 432
    return l;
5 Plagman 433
}
434
 
2883 helixhorne 435
 
3065 terminx 436
static int32_t S_GetPitch(int32_t num)
2883 helixhorne 437
{
438
    int32_t j = klabs(g_sounds[num].pe-g_sounds[num].ps);
439
 
3066 terminx 440
    if (j == 0)
441
        return g_sounds[num].ps;
442
 
443
    return min(g_sounds[num].ps, g_sounds[num].pe) + rand()%j;
2883 helixhorne 444
}
445
 
3066 terminx 446
static int32_t S_TakeSlot(int32_t num)
2883 helixhorne 447
{
3066 terminx 448
    uint32_t dist = 0, clock = UINT32_MAX;
449
    int32_t i = 0, j = 0;
2883 helixhorne 450
 
3080 terminx 451
    S_Cleanup();
452
 
2883 helixhorne 453
    while (j < MAXSOUNDINSTANCES && g_sounds[num].SoundOwner[j].voice > 0)
3066 terminx 454
    {
455
        if (g_sounds[num].SoundOwner[j].sndist > dist ||
456
            (g_sounds[num].SoundOwner[j].sndist == dist && g_sounds[num].SoundOwner[j].clock < clock))
457
        {
458
            clock = g_sounds[num].SoundOwner[j].clock;
459
            dist = g_sounds[num].SoundOwner[j].sndist;
460
            i = j;
461
        }
462
 
2883 helixhorne 463
        j++;
3066 terminx 464
    }
2883 helixhorne 465
 
3066 terminx 466
    if (j != MAXSOUNDINSTANCES)
467
        return j;
3065 terminx 468
 
3066 terminx 469
    if (FX_SoundActive(g_sounds[num].SoundOwner[i].voice))
470
        FX_StopSound(g_sounds[num].SoundOwner[i].voice);
3065 terminx 471
 
3066 terminx 472
    mutex_lock(&s_mutex);
473
    dq[dnum++] = (num * MAXSOUNDINSTANCES) + i;
474
    mutex_unlock(&s_mutex);
475
    S_Cleanup();
3065 terminx 476
 
3066 terminx 477
    return i;
478
}
3065 terminx 479
 
3066 terminx 480
static int32_t S_GetSlot(int32_t num)
481
{
482
    int32_t j = 0;
3065 terminx 483
 
3066 terminx 484
    while (j < MAXSOUNDINSTANCES && g_sounds[num].SoundOwner[j].voice > 0)
485
        j++;
3065 terminx 486
 
3066 terminx 487
    if (j == MAXSOUNDINSTANCES)
488
        j = S_TakeSlot(num);
3065 terminx 489
 
2883 helixhorne 490
    return j;
491
}
492
 
3065 terminx 493
static inline int32_t S_GetAngle(int32_t camang, const vec3_t *cam, const vec3_t *pos)
2885 helixhorne 494
{
3066 terminx 495
    return (2048 + camang - getangle(cam->x-pos->x, cam->y-pos->y))&2047;
2885 helixhorne 496
}
497
 
2884 helixhorne 498
static int32_t S_CalcDistAndAng(int32_t i, int32_t num, int32_t camsect, int32_t camang,
499
                                const vec3_t *cam, const vec3_t *pos,
500
                                int32_t *sndistptr, int32_t *sndangptr)
501
{
502
    int32_t sndang, sndist;
503
    int32_t explosion = 0;
504
 
4226 helixhorne 505
    if (PN == APLAYER && P_Get(i) == screenpeek)
2884 helixhorne 506
    {
507
        sndang = sndist = 0;
2885 helixhorne 508
        goto sound_further_processing;
2884 helixhorne 509
    }
2885 helixhorne 510
 
3065 terminx 511
    sndang = S_GetAngle(camang, cam, pos);
2885 helixhorne 512
 
4659 terminx 513
    sndist = FindDistance3D(cam->x-pos->x, cam->y-pos->y, (cam->z-pos->z));
2885 helixhorne 514
 
4249 hendricks2 515
#ifdef SPLITSCREEN_MOD_HACKS
2957 helixhorne 516
    if (g_fakeMultiMode==2)
2884 helixhorne 517
    {
2885 helixhorne 518
        // HACK for splitscreen mod: take the min of sound distances
519
        // to 1st and 2nd player.
2884 helixhorne 520
 
4226 helixhorne 521
        if (PN == APLAYER && P_Get(i) == 1)
2885 helixhorne 522
        {
523
            sndist = sndang = 0;
524
            goto sound_further_processing;
525
        }
526
 
527
        {
528
            const vec3_t *cam2 = &g_player[1].ps->pos;
4659 terminx 529
            int32_t sndist2 = FindDistance3D(cam2->x-pos->x, cam2->y-pos->y, (cam2->z-pos->z));
2885 helixhorne 530
 
531
            if (sndist2 < sndist)
532
            {
533
                cam = cam2;
534
                camsect = g_player[1].ps->cursectnum;
535
                camang = g_player[1].ps->ang;
536
 
537
                sndist = sndist2;
3065 terminx 538
                sndang = S_GetAngle(camang, cam, pos);
2885 helixhorne 539
            }
540
        }
2884 helixhorne 541
    }
4249 hendricks2 542
#endif
2884 helixhorne 543
 
4055 helixhorne 544
    if ((g_sounds[num].m & SF_GLOBAL) == 0 && S_IsAmbientSFX(i) && (sector[SECT].lotag&0xff) < 9)  // ST_9_SLIDING_ST_DOOR
2885 helixhorne 545
        sndist = divscale14(sndist, SHT+1);
546
 
547
sound_further_processing:
2884 helixhorne 548
    sndist += g_sounds[num].vo;
549
    if (sndist < 0)
550
        sndist = 0;
551
 
552
    if (camsect > -1 && sndist && PN != MUSICANDSFX &&
553
            !cansee(cam->x,cam->y,cam->z-(24<<8),camsect, SX,SY,SZ-(24<<8),SECT))
554
        sndist += sndist>>5;
555
 
3834 hendricks2 556
    switch (DYNAMICSOUNDMAP(num))
2884 helixhorne 557
    {
3834 hendricks2 558
    case PIPEBOMB_EXPLODE__STATIC:
559
    case LASERTRIP_EXPLODE__STATIC:
560
    case RPG_EXPLODE__STATIC:
2884 helixhorne 561
        explosion = 1;
562
        if (sndist > 6144)
563
            sndist = 6144;
564
        break;
565
    }
566
 
4055 helixhorne 567
    if ((g_sounds[num].m & SF_GLOBAL) || sndist < ((255-LOUDESTVOLUME)<<6))
2884 helixhorne 568
        sndist = ((255-LOUDESTVOLUME)<<6);
569
 
570
    *sndistptr = sndist;
571
    *sndangptr = sndang;
572
 
573
    return explosion;
574
}
575
 
1487 terminx 576
int32_t S_PlaySound3D(int32_t num, int32_t i, const vec3_t *pos)
5 Plagman 577
{
4520 hendricks2 578
    int32_t j;
2884 helixhorne 579
    int32_t sndist, sndang, explosionp;
580
    int32_t voice, pitch;
5 Plagman 581
 
2883 helixhorne 582
    const DukePlayer_t *const myps = g_player[myconnectindex].ps;
583
    const DukePlayer_t *peekps;
584
 
4745 terminx 585
    j = VM_OnEventWithReturn(EVENT_SOUND, i, screenpeek, num);
2659 terminx 586
 
4520 hendricks2 587
    if (j == -1 && num != -1) // check that the user returned -1, but only if -1 wasn't playing already (in which case, warn)
588
        return -1;
589
 
590
    num = j;
591
 
2245 helixhorne 592
    if ((unsigned)num > (unsigned)g_maxSoundPos ||
563 terminx 593
            ud.config.FXDevice < 0 ||
4055 helixhorne 594
            ((g_sounds[num].m & SF_ADULT) && ud.lockout) ||
563 terminx 595
            ud.config.SoundToggle == 0 ||
3631 helixhorne 596
//            g_sounds[num].num >= MAXSOUNDINSTANCES ||
1820 terminx 597
            (unsigned)i >= MAXSPRITES ||
580 terminx 598
            FX_VoiceAvailable(g_sounds[num].pr) == 0 ||
2883 helixhorne 599
            (myps->timebeforeexit > 0 && myps->timebeforeexit <= GAMETICSPERSEC*3) ||
3631 helixhorne 600
            (myps->gm&MODE_MENU))
601
        return -1;
5 Plagman 602
 
4055 helixhorne 603
    if (g_sounds[num].m & SF_DTAG)  // Duke-Tag sound
5 Plagman 604
    {
1667 terminx 605
        if ((voice = S_PlaySound(num)) <= FX_Ok)
606
            return -1;
607
 
4520 hendricks2 608
        j = 0;
1667 terminx 609
        while (j < MAXSOUNDINSTANCES && g_sounds[num].SoundOwner[j].voice != voice)
1658 terminx 610
            j++;
611
 
4699 terminx 612
        if (EDUKE32_PREDICT_FALSE(j >= MAXSOUNDINSTANCES))
1461 terminx 613
        {
1658 terminx 614
            OSD_Printf(OSD_ERROR "%s %d: WTF?\n", __FILE__, __LINE__);
615
            return -1;
616
        }
1582 terminx 617
 
2442 helixhorne 618
        g_sounds[num].SoundOwner[j].ow = i;
1582 terminx 619
 
1658 terminx 620
        return voice;
5 Plagman 621
    }
622
 
1601 terminx 623
    // Duke talk
4055 helixhorne 624
    if (g_sounds[num].m & SF_TALK)
5 Plagman 625
    {
4226 helixhorne 626
        if ((g_netServer || ud.multimode > 1) && PN == APLAYER && P_Get(i) != screenpeek) // other player sound
915 terminx 627
        {
628
            if (!(ud.config.VoiceToggle&4))
629
                return -1;
630
        }
631
        else if (!(ud.config.VoiceToggle&1))
29 terminx 632
            return -1;
1601 terminx 633
 
634
        // don't play if any Duke talk sounds are already playing
1465 terminx 635
        for (j=g_maxSoundPos; j>=0; j--)
4055 helixhorne 636
            if ((g_sounds[j].m & SF_TALK) && g_sounds[j].num > 0)
1601 terminx 637
                return -1;
5 Plagman 638
    }
639
 
3631 helixhorne 640
    explosionp = S_CalcDistAndAng(i, num, CAMERA(sect), CAMERA(ang), &CAMERA(pos), pos, &sndist, &sndang);
5 Plagman 641
 
3065 terminx 642
    pitch = S_GetPitch(num);
2883 helixhorne 643
    peekps = g_player[screenpeek].ps;
1465 terminx 644
 
4249 hendricks2 645
#ifdef SPLITSCREEN_MOD_HACKS
2957 helixhorne 646
    if (g_fakeMultiMode==2)
2956 helixhorne 647
    {
648
        // splitscreen HACK
649
        if (g_player[1].ps->i == i)
650
            peekps = g_player[1].ps;
651
    }
4249 hendricks2 652
#endif
2956 helixhorne 653
 
2884 helixhorne 654
    if (peekps->sound_pitch)
655
        pitch += peekps->sound_pitch;
656
 
657
    if (explosionp)
5 Plagman 658
    {
3073 helixhorne 659
        if (peekps->cursectnum > -1 && sector[peekps->cursectnum].lotag == ST_2_UNDERWATER)
337 terminx 660
            pitch -= 1024;
2884 helixhorne 661
    }
662
    else
663
    {
4055 helixhorne 664
        if (sndist > 32767 && PN != MUSICANDSFX && (g_sounds[num].m & (SF_LOOP|SF_MSFX)) == 0)
1820 terminx 665
            return -1;
2884 helixhorne 666
 
4055 helixhorne 667
        if (peekps->cursectnum > -1 && sector[peekps->cursectnum].lotag == ST_2_UNDERWATER
668
                && (g_sounds[num].m & SF_TALK) == 0)
337 terminx 669
            pitch = -768;
5 Plagman 670
    }
671
 
580 terminx 672
    if (g_sounds[num].num > 0 && PN != MUSICANDSFX)
1601 terminx 673
        S_StopEnvSound(num, i);
5 Plagman 674
 
580 terminx 675
    if (g_sounds[num].ptr == 0)
335 terminx 676
    {
1601 terminx 677
        if (S_LoadSound(num) == 0)
678
            return -1;
335 terminx 679
    }
1677 terminx 680
    else
1625 terminx 681
    {
682
        if (g_soundlocks[num] < 200)
683
            g_soundlocks[num] = 200;
684
        else g_soundlocks[num]++;
685
    }
5 Plagman 686
 
3066 terminx 687
    j = S_GetSlot(num);
1601 terminx 688
 
689
    if (j >= MAXSOUNDINSTANCES)
5 Plagman 690
    {
1601 terminx 691
        g_soundlocks[num]--;
692
        return -1;
693
    }
5 Plagman 694
 
1601 terminx 695
    {
4055 helixhorne 696
        const int32_t repeatp = (g_sounds[num].m & SF_LOOP);
3631 helixhorne 697
        const int32_t ambsfxp = S_IsAmbientSFX(i);
698
 
4055 helixhorne 699
        if (repeatp && (g_sounds[num].m & SF_ONEINST_INTERNAL) && g_sounds[num].num > 0)
1658 terminx 700
        {
701
            g_soundlocks[num]--;
702
            return -1;
703
        }
4294 helixhorne 704
 
3631 helixhorne 705
        if (repeatp && !ambsfxp)
706
        {
707
            voice = FX_PlayLoopedAuto(g_sounds[num].ptr, g_sounds[num].soundsiz, 0, -1,
3993 terminx 708
                                      pitch, FX_VOLUME(sndist>>6), FX_VOLUME(sndist>>6), 0,  // XXX: why is 'right' 0?
3631 helixhorne 709
                                      g_sounds[num].pr, (num * MAXSOUNDINSTANCES) + j);
710
        }
711
        else
712
        {
713
            // Ambient MUSICANDSFX always start playing using the 3D routines!
714
            voice = FX_PlayAuto3D(g_sounds[num].ptr, g_sounds[num].soundsiz,
3632 helixhorne 715
                                  repeatp ? FX_LOOP : FX_ONESHOT,
3993 terminx 716
                                  pitch, sndang>>4, FX_VOLUME(sndist>>6),
3631 helixhorne 717
                                  g_sounds[num].pr, (num * MAXSOUNDINSTANCES) + j);
718
        }
1601 terminx 719
    }
1582 terminx 720
 
1665 terminx 721
    if (voice <= FX_Ok)
1601 terminx 722
    {
1665 terminx 723
        g_soundlocks[num]--;
724
        return -1;
1601 terminx 725
    }
1599 terminx 726
 
1665 terminx 727
    g_sounds[num].num++;
2442 helixhorne 728
    g_sounds[num].SoundOwner[j].ow = i;
1665 terminx 729
    g_sounds[num].SoundOwner[j].voice = voice;
3066 terminx 730
    g_sounds[num].SoundOwner[j].sndist = sndist>>6;
731
    g_sounds[num].SoundOwner[j].clock = totalclock;
3631 helixhorne 732
 
1665 terminx 733
    return voice;
5 Plagman 734
}
735
 
1461 terminx 736
int32_t S_PlaySound(int32_t num)
5 Plagman 737
{
2883 helixhorne 738
    int32_t pitch;
1665 terminx 739
    int32_t voice, j;
5 Plagman 740
 
4745 terminx 741
    j = VM_OnEventWithReturn(EVENT_SOUND, g_player[screenpeek].ps->i, screenpeek, num);
2659 terminx 742
 
4520 hendricks2 743
    if (j == -1 && num != -1) // check that the user returned -1, but only if -1 wasn't playing already (in which case, warn)
744
        return -1;
745
 
746
    num = j;
747
 
1461 terminx 748
    if (ud.config.FXDevice < 0) return -1;
749
    if (ud.config.SoundToggle==0) return -1;
2245 helixhorne 750
 
751
    if ((unsigned)num > (unsigned)g_maxSoundPos || (g_sounds[num].filename == NULL && g_sounds[num].filename1 == NULL))
554 terminx 752
    {
559 terminx 753
        OSD_Printf("WARNING: invalid sound #%d\n",num);
1461 terminx 754
        return -1;
554 terminx 755
    }
5 Plagman 756
 
4055 helixhorne 757
    if (!(ud.config.VoiceToggle&1) && (g_sounds[num].m & SF_TALK)) return -1;
758
    if ((g_sounds[num].m & SF_ADULT) && ud.lockout) return -1;
2245 helixhorne 759
    if (FX_VoiceAvailable(g_sounds[num].pr) == 0) return -1;
760
 
3065 terminx 761
    pitch = S_GetPitch(num);
5 Plagman 762
 
580 terminx 763
    if (g_sounds[num].ptr == 0)
335 terminx 764
    {
1601 terminx 765
        if (S_LoadSound(num) == 0)
766
            return -1;
335 terminx 767
    }
1677 terminx 768
    else
1625 terminx 769
    {
770
        if (g_soundlocks[num] < 200)
771
            g_soundlocks[num] = 200;
772
        else g_soundlocks[num]++;
773
    }
5 Plagman 774
 
3066 terminx 775
    j = S_GetSlot(num);
1665 terminx 776
 
3066 terminx 777
    if (j >= MAXSOUNDINSTANCES)
778
    {
779
        g_soundlocks[num]--;
780
        return -1;
781
    }
1677 terminx 782
 
4055 helixhorne 783
    if (g_sounds[num].m & SF_LOOP)
3631 helixhorne 784
        voice = FX_PlayLoopedAuto(g_sounds[num].ptr, g_sounds[num].soundsiz, 0, -1,
3993 terminx 785
                                  pitch,FX_VOLUME(LOUDESTVOLUME), FX_VOLUME(LOUDESTVOLUME), FX_VOLUME(LOUDESTVOLUME),
3631 helixhorne 786
                                  g_sounds[num].soundsiz, (num * MAXSOUNDINSTANCES) + j);
787
    else
788
        voice = FX_PlayAuto3D(g_sounds[num].ptr, g_sounds[num].soundsiz, FX_ONESHOT,
3993 terminx 789
                              pitch, 0, FX_VOLUME(255-LOUDESTVOLUME),
3631 helixhorne 790
                              g_sounds[num].pr, (num * MAXSOUNDINSTANCES) + j);
1601 terminx 791
 
1658 terminx 792
    if (voice <= FX_Ok)
5 Plagman 793
    {
1601 terminx 794
        g_soundlocks[num]--;
795
        return -1;
5 Plagman 796
    }
797
 
1665 terminx 798
    g_sounds[num].num++;
2442 helixhorne 799
    g_sounds[num].SoundOwner[j].ow = -1;
1665 terminx 800
    g_sounds[num].SoundOwner[j].voice = voice;
3066 terminx 801
    g_sounds[num].SoundOwner[j].sndist = 255-LOUDESTVOLUME;
802
    g_sounds[num].SoundOwner[j].clock = totalclock;
1601 terminx 803
    return voice;
5 Plagman 804
}
805
 
1205 terminx 806
int32_t A_PlaySound(uint32_t num, int32_t i)
5 Plagman 807
{
2656 terminx 808
    if ((unsigned)num > (unsigned)g_maxSoundPos) return -1;
2652 terminx 809
 
2656 terminx 810
    return i < 0 ? S_PlaySound(num) :
811
        S_PlaySound3D(num, i, (vec3_t *)&sprite[i]);
5 Plagman 812
}
813
 
1665 terminx 814
void S_StopEnvSound(int32_t num, int32_t i)
29 terminx 815
{
1665 terminx 816
    int32_t j, iter = 0;
1662 terminx 817
 
1820 terminx 818
    if ((unsigned)num > (unsigned)g_maxSoundPos || g_sounds[num].num <= 0)
1601 terminx 819
        return;
820
 
1665 terminx 821
    do
1465 terminx 822
    {
4699 terminx 823
        if (EDUKE32_PREDICT_FALSE(iter++ > MAXSOUNDINSTANCES<<1))
1625 terminx 824
        {
1665 terminx 825
            initprintf(OSD_ERROR "S_StopEnvSound(): too many iterations! The following IDs are still active for sound %d:\n", num);
826
            for (j=MAXSOUNDINSTANCES-1; j>=0; j--)
2442 helixhorne 827
                if (g_sounds[num].SoundOwner[j].ow == i)
828
                    initprintf(OSD_ERROR "slot %d, voice %d, sprite %d\n", j, g_sounds[num].SoundOwner[j].voice, g_sounds[num].SoundOwner[j].ow);
1665 terminx 829
            return;
1625 terminx 830
        }
5 Plagman 831
 
1665 terminx 832
        for (j=MAXSOUNDINSTANCES-1; j>=0; j--)
1625 terminx 833
        {
2442 helixhorne 834
            if ((i == -1 && g_sounds[num].SoundOwner[j].voice > FX_Ok) || (i != -1 && g_sounds[num].SoundOwner[j].ow == i))
1625 terminx 835
            {
4699 terminx 836
                if (EDUKE32_PREDICT_FALSE(i >= 0 && g_sounds[num].SoundOwner[j].voice <= FX_Ok))
1662 terminx 837
                    initprintf(OSD_ERROR "S_StopEnvSound(): bad voice %d for sound ID %d index %d!\n", g_sounds[num].SoundOwner[j].voice, num, j);
3080 terminx 838
                else if (g_sounds[num].SoundOwner[j].voice > FX_Ok)
839
                {
1662 terminx 840
                    FX_StopSound(g_sounds[num].SoundOwner[j].voice);
3080 terminx 841
                    return;
842
                }
1625 terminx 843
            }
844
        }
1461 terminx 845
    }
1665 terminx 846
    while (j >= 0);
5 Plagman 847
}
848
 
2104 helixhorne 849
void S_ChangeSoundPitch(int32_t num, int32_t i, int32_t pitchoffset)
850
{
851
    int32_t j;
852
 
853
    if ((unsigned)num > (unsigned)g_maxSoundPos || g_sounds[num].num <= 0)
854
        return;
855
 
856
    for (j=MAXSOUNDINSTANCES-1; j>=0; j--)
857
    {
858
        int32_t voice = g_sounds[num].SoundOwner[j].voice;
859
 
2442 helixhorne 860
        if ((i == -1 && voice > FX_Ok) || (i != -1 && g_sounds[num].SoundOwner[j].ow == i))
2104 helixhorne 861
        {
4699 terminx 862
            if (EDUKE32_PREDICT_FALSE(i >= 0 && voice <= FX_Ok))
2104 helixhorne 863
                initprintf(OSD_ERROR "S_ChangeSoundPitch(): bad voice %d for sound ID %d index %d!\n", voice, num, j);
864
            else if (voice > FX_Ok && FX_SoundActive(voice))
865
                FX_SetPitch(voice, pitchoffset);
866
            break;
867
        }
868
    }
869
}
870
 
1625 terminx 871
void S_Update(void)
5 Plagman 872
{
2884 helixhorne 873
    const vec3_t *c;
874
    int32_t ca,cs;
2883 helixhorne 875
    int32_t num;  // the sound index...
1677 terminx 876
 
1658 terminx 877
    S_Cleanup();
5 Plagman 878
 
1667 terminx 879
    if ((g_player[myconnectindex].ps->gm & (MODE_GAME|MODE_DEMO)) == 0)
880
        return;
881
 
1143 terminx 882
    g_numEnvSoundsPlaying = 0;
5 Plagman 883
 
331 terminx 884
    if (ud.camerasprite == -1)
5 Plagman 885
    {
3405 helixhorne 886
        c = &CAMERA(pos);
887
        cs = CAMERA(sect);
888
        ca = CAMERA(ang);
5 Plagman 889
    }
890
    else
891
    {
1601 terminx 892
        c = (vec3_t *)&sprite[ud.camerasprite];
5 Plagman 893
        cs = sprite[ud.camerasprite].sectnum;
894
        ca = sprite[ud.camerasprite].ang;
895
    }
896
 
2883 helixhorne 897
    num = g_maxSoundPos;
1465 terminx 898
 
1468 terminx 899
    do
1465 terminx 900
    {
2883 helixhorne 901
        int32_t k;
902
 
1582 terminx 903
        for (k=MAXSOUNDINSTANCES-1; k>=0; k--)
5 Plagman 904
        {
2883 helixhorne 905
            int32_t i = g_sounds[num].SoundOwner[k].ow;
2884 helixhorne 906
            int32_t sndist, sndang;
5 Plagman 907
 
2883 helixhorne 908
            if ((unsigned)i >= MAXSPRITES || g_sounds[num].num == 0 || g_sounds[num].SoundOwner[k].voice <= FX_Ok)
1488 terminx 909
                continue;
1593 terminx 910
 
2883 helixhorne 911
            if (!FX_SoundActive(g_sounds[num].SoundOwner[k].voice))
1658 terminx 912
            {
1677 terminx 913
                /*
2883 helixhorne 914
                  OSD_Printf("S_Update(): stale voice %d from sound %d position %d sprite %d\n",
915
                  g_sounds[num].SoundOwner[k].voice, num, k, g_sounds[num].SoundOwner[k].ow);
1677 terminx 916
                */
1658 terminx 917
                continue;
918
            }
919
 
2884 helixhorne 920
            S_CalcDistAndAng(i, num, cs, ca, c, (const vec3_t *)&sprite[i], &sndist, &sndang);
5 Plagman 921
 
3631 helixhorne 922
            if (S_IsAmbientSFX(i))
1143 terminx 923
                g_numEnvSoundsPlaying++;
5 Plagman 924
 
3631 helixhorne 925
            // AMBIENT_SOUND
3993 terminx 926
            FX_Pan3D(g_sounds[num].SoundOwner[k].voice, sndang>>4, FX_VOLUME(sndist>>6));
3066 terminx 927
            g_sounds[num].SoundOwner[k].sndist = sndist>>6;
5 Plagman 928
        }
1468 terminx 929
    }
2883 helixhorne 930
    while (num--);
5 Plagman 931
}
932
 
1599 terminx 933
void S_Callback(uint32_t num)
1582 terminx 934
{
935
    if ((int32_t)num == MUSIC_ID)
936
        return;
937
 
1658 terminx 938
    mutex_lock(&s_mutex);
939
    dq[dnum++] = num;
940
    mutex_unlock(&s_mutex);
941
}
1625 terminx 942
 
1658 terminx 943
void S_ClearSoundLocks(void)
944
{
945
    int32_t i;
1625 terminx 946
 
1658 terminx 947
    for (i=g_maxSoundPos; i >= 0 ; i--)
1457 terminx 948
        if (g_soundlocks[i] >= 200)
949
            g_soundlocks[i] = 199;
5 Plagman 950
 
1229 terminx 951
    for (i=0; i<11; i++)
1677 terminx 952
        if (rts_lumplockbyte[i] >= 200)
953
            rts_lumplockbyte[i] = 199;
5 Plagman 954
}
955
 
1205 terminx 956
int32_t A_CheckSoundPlaying(int32_t i, int32_t num)
29 terminx 957
{
1601 terminx 958
    if (num > g_maxSoundPos || num < 0) return 0;
1461 terminx 959
 
1601 terminx 960
    if (g_sounds[num].num > 0 && i >= 0)
961
    {
962
        int32_t j=MAXSOUNDINSTANCES-1;
1461 terminx 963
 
1601 terminx 964
        for (; j>=0; j--)
2442 helixhorne 965
            if (g_sounds[num].SoundOwner[j].ow == i)
1461 terminx 966
                return 1;
967
    }
968
 
1601 terminx 969
    return (i == -1) ? g_sounds[num].num : 0;
29 terminx 970
}
971
 
3365 helixhorne 972
// Check if actor <i> is playing any sound.
973
int32_t A_CheckAnySoundPlaying(int32_t i)
974
{
975
    int32_t j;
976
 
977
    for (j=g_maxSoundPos; j>=0; j--)
978
    {
979
        int32_t k;
980
 
981
        for (k=0; k<MAXSOUNDINSTANCES; k++)
982
            if (g_sounds[j].SoundOwner[k].ow == i)
983
                return 1;
984
    }
985
 
986
    return 0;
987
}
988
 
1205 terminx 989
int32_t S_CheckSoundPlaying(int32_t i, int32_t num)
29 terminx 990
{
1601 terminx 991
    if (num > g_maxSoundPos || num < 0) return 0;
992
    return (i == -1) ? (g_soundlocks[num] >= 200) : g_sounds[num].num;
29 terminx 993
}