Subversion Repositories eduke32

Rev

Rev 8769 | Rev 8782 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5817 terminx 1
//-------------------------------------------------------------------------
1471 terminx 2
/*
5817 terminx 3
Copyright (C) 2016 EDuke32 developers and contributors
1471 terminx 4
 
5817 terminx 5
This file is part of EDuke32.
1471 terminx 6
 
5817 terminx 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
 
1471 terminx 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.
1471 terminx 20
*/
5817 terminx 21
//-------------------------------------------------------------------------
1471 terminx 22
 
8221 terminx 23
#include "fx_man.h"
24
 
8760 terminx 25
#include "_multivc.h"
5270 terminx 26
#include "compat.h"
1471 terminx 27
#include "drivers.h"
8221 terminx 28
#include "driver_adlib.h"
8752 terminx 29
#include "driver_sf2.h"
8221 terminx 30
#include "midi.h"
1471 terminx 31
#include "multivoc.h"
8760 terminx 32
#include "music.h"
8221 terminx 33
#include "osd.h"
1471 terminx 34
 
8384 terminx 35
#ifdef _WIN32
36
# include "driver_winmm.h"
37
# include <mmsystem.h>
38
#endif
39
 
8390 terminx 40
#ifdef RENDERTYPESDL
41
# include "driver_sdl.h"
42
#endif
43
 
8216 terminx 44
int FX_ErrorCode = FX_Ok;
45
int FX_Installed;
8771 terminx 46
int FX_MixRate;
1471 terminx 47
 
8225 terminx 48
const char *FX_ErrorString(int const ErrorNumber)
1471 terminx 49
{
50
    const char *ErrorString;
51
 
52
    switch (ErrorNumber)
53
    {
5270 terminx 54
        case FX_Warning:
5817 terminx 55
        case FX_Error:          ErrorString = FX_ErrorString(FX_ErrorCode); break;
56
        case FX_Ok:             ErrorString = "Fx ok."; break;
57
        case FX_MultiVocError:  ErrorString = MV_ErrorString(MV_Error); break;
58
        default:                ErrorString = "Unknown Fx error code."; break;
1471 terminx 59
    }
60
 
3338 hendricks2 61
    return ErrorString;
1471 terminx 62
}
63
 
8222 terminx 64
static int osdcmd_cvar_set_audiolib(osdcmdptr_t parm)
65
{
66
    int32_t r = osdcmd_cvar_set(parm);
67
 
8390 terminx 68
    if (parm->numparms == 0)
69
    {
8384 terminx 70
#ifdef _WIN32
8390 terminx 71
        if (!Bstrcasecmp(parm->name, "mus_winmm_device"))
72
            WinMMDrv_MIDI_PrintDevices();
8384 terminx 73
#endif
8417 hendricks2 74
#if defined RENDERTYPESDL && SDL_MAJOR_VERSION >= 2
8390 terminx 75
        if (!Bstrcasecmp(parm->name, "snd_sdl_audiodriver"))
8567 terminx 76
            SDLDrv_PCM_PrintDrivers();
8390 terminx 77
#endif
78
    }
8384 terminx 79
 
8390 terminx 80
    if (r != OSDCMD_OK || parm->numparms < 1) return r;
8222 terminx 81
 
82
    if (!Bstrcasecmp(parm->name, "mus_emidicard"))
83
        MIDI_Restart();
8238 terminx 84
    else if (!Bstrcasecmp(parm->name, "mus_al_stereo"))
8233 terminx 85
        AL_SetStereo(AL_Stereo);
8383 terminx 86
#ifdef HAVE_XMP
87
    else if (!Bstrcasecmp(parm->name, "mus_xmp_interpolation"))
88
        MV_SetXMPInterpolation();
89
#endif
8417 hendricks2 90
#if defined RENDERTYPESDL && SDL_MAJOR_VERSION >= 2
8390 terminx 91
    else if (!Bstrcasecmp(parm->name, "snd_sdl_audiodriver"))
92
    {
8567 terminx 93
        if (!FX_Installed || !Bstrcasecmp(parm->parms[0], SDLDrv_PCM_GetDriverName()))
8390 terminx 94
            return r;
95
 
8567 terminx 96
        if (!SDLDrv_PCM_CheckDriverName(parm->parms[0]))
8390 terminx 97
        {
8567 terminx 98
            SDLDrv_PCM_PrintDrivers();
8390 terminx 99
            return r;
100
        }
101
 
102
        FX_Init(MV_MaxVoices, MV_Channels, MV_MixRate, MV_InitDataPtr);
103
    }
104
#endif
105
 
8222 terminx 106
    return r;
107
}
108
 
8390 terminx 109
void FX_InitCvars(void)
5270 terminx 110
{
8390 terminx 111
    static osdcvardata_t cvars_audiolib [] ={
112
        { "mus_emidicard", "force a specific EMIDI instrument set", (void*) &ASS_EMIDICard, CVAR_INT | CVAR_FUNCPTR, -1, 10 },
113
        { "mus_al_additivemode", "enable/disable alternate additive AdLib timbre mode", (void*) &AL_AdditiveMode, CVAR_BOOL, 0, 1 },
114
        { "mus_al_postamp", "controls post-synthesization OPL3 volume amplification", (void*) &AL_PostAmp, CVAR_INT, 0, 3 },
115
        { "mus_al_stereo", "enable/disable OPL3 stereo mode", (void*) &AL_Stereo, CVAR_BOOL | CVAR_FUNCPTR, 0, 1 },
8759 terminx 116
        { "mus_sf2_bank", "SoundFont 2 (.sf2) bank filename",  (void*) SF2_BankFile, CVAR_STRING, 0, sizeof(SF2_BankFile) - 1 },
8769 terminx 117
        { "mus_sf2_sampleblocksize", "number of samples per effect processing block", (void*) &SF2_EffectSampleBlockSize, CVAR_INT, 1, 64 },
8384 terminx 118
#ifdef _WIN32
8759 terminx 119
        { "mus_mme_device", "select Windows MME MIDI output device", (void*) &WinMM_DeviceID, CVAR_INT | CVAR_FUNCPTR, -1, WinMMDrv_MIDI_GetNumDevices()-1 },
8384 terminx 120
#endif
8383 terminx 121
#ifdef HAVE_XMP
8390 terminx 122
        { "mus_xmp_interpolation", "XMP output interpolation: 0: none  1: linear  2: spline", (void*) &MV_XMPInterpolation, CVAR_INT | CVAR_FUNCPTR, 0, 2 },
8383 terminx 123
#endif
8417 hendricks2 124
#if defined RENDERTYPESDL && SDL_MAJOR_VERSION >= 2
8567 terminx 125
        { "snd_sdl_audiodriver", "select SDL audio driver (platform-specific)",
8390 terminx 126
          (void *)SDLAudioDriverName, CVAR_STRING | CVAR_FUNCPTR, 0, sizeof(SDLAudioDriverName) - 1 },
127
#endif
128
    };
8222 terminx 129
 
8390 terminx 130
    for (auto& i : cvars_audiolib)
131
        OSD_RegisterCvar(&i, (i.flags & CVAR_FUNCPTR) ? osdcmd_cvar_set_audiolib : osdcmd_cvar_set);
132
}
8225 terminx 133
 
8390 terminx 134
int FX_Init(int numvoices, int numchannels, int mixrate, void* initdata)
135
{
136
    if (FX_Installed)
137
        FX_Shutdown();
138
 
8216 terminx 139
#if defined RENDERTYPESDL
8390 terminx 140
    int SoundCard = ASS_SDL;
8219 terminx 141
#elif defined RENDERTYPEWIN
8390 terminx 142
    int SoundCard = ASS_DirectSound;
1471 terminx 143
#endif
144
 
8390 terminx 145
    MV_Printf("Initializing sound: ");
146
 
8216 terminx 147
    if (SoundCard < 0 || SoundCard >= ASS_NumSoundCards)
1471 terminx 148
    {
8216 terminx 149
        FX_SetErrorCode(FX_InvalidCard);
8390 terminx 150
        MV_Printf("failed! %s\n", FX_ErrorString(FX_InvalidCard));
8216 terminx 151
        return FX_Error;
152
    }
153
 
154
    if (SoundDriver_IsPCMSupported(SoundCard) == 0)
155
    {
1471 terminx 156
        // unsupported cards fall back to no sound
8387 terminx 157
        FX_SetErrorCode(FX_InvalidCard);
158
        return FX_Error;
1471 terminx 159
    }
160
 
5270 terminx 161
    int status = FX_Ok;
162
 
5272 terminx 163
    if (MV_Init(SoundCard, mixrate, numvoices, numchannels, initdata) != MV_Ok)
1471 terminx 164
    {
165
        FX_SetErrorCode(FX_MultiVocError);
8390 terminx 166
        MV_Printf("failed! %s\n", MV_ErrorString(MV_DriverError));
1471 terminx 167
        status = FX_Error;
168
    }
169
 
8771 terminx 170
    FX_MixRate = MV_MixRate;
171
 
1471 terminx 172
    if (status == FX_Ok)
8390 terminx 173
    {
8771 terminx 174
        MV_Printf(": %.1f KHz %s with %d voices\n", MV_MixRate/1000.f, numchannels == 1 ? "mono" : "stereo", numvoices);
1471 terminx 175
        FX_Installed = TRUE;
8390 terminx 176
    }
1471 terminx 177
 
3338 hendricks2 178
    return status;
1471 terminx 179
}
180
 
8216 terminx 181
int FX_Shutdown(void)
1471 terminx 182
{
183
    if (!FX_Installed)
3338 hendricks2 184
        return FX_Ok;
1471 terminx 185
 
5270 terminx 186
    int status = MV_Shutdown();
187
 
1471 terminx 188
    if (status != MV_Ok)
189
    {
190
        FX_SetErrorCode(FX_MultiVocError);
191
        status = FX_Error;
192
    }
193
 
194
    FX_Installed = FALSE;
195
 
3338 hendricks2 196
    return status;
1471 terminx 197
}
198
 
8261 hendricks2 199
int FX_GetDevice()
200
{
201
    return ASS_PCMSoundDriver;
202
}
203
 
5814 terminx 204
static wavefmt_t FX_DetectFormat(char const * const ptr, uint32_t length)
1471 terminx 205
{
5814 terminx 206
    if (length < 12)
207
        return FMT_UNKNOWN;
1471 terminx 208
 
5270 terminx 209
    wavefmt_t fmt = FMT_UNKNOWN;
1471 terminx 210
 
8216 terminx 211
    switch (B_LITTLE32(*(int const *)ptr))
1471 terminx 212
    {
5270 terminx 213
        case 'C' + ('r' << 8) + ('e' << 16) + ('a' << 24):  // Crea
214
            fmt = FMT_VOC;
4268 hendricks2 215
            break;
5270 terminx 216
        case 'O' + ('g' << 8) + ('g' << 16) + ('S' << 24):  // OggS
217
            fmt = FMT_VORBIS;
218
            break;
219
        case 'R' + ('I' << 8) + ('F' << 16) + ('F' << 24):  // RIFF
8216 terminx 220
            switch (B_LITTLE32(*(int const *)(ptr + 8)))
5270 terminx 221
            {
222
                case 'C' + ('D' << 8) + ('X' << 16) + ('A' << 24):  // CDXA
223
                    fmt = FMT_XA;
224
                    break;
6837 terminx 225
                case 'W' + ('A' << 8) + ('V' << 16) + ('E' << 24):  // WAVE
226
                    fmt = FMT_WAV;
227
                    break;
5270 terminx 228
            }
229
            break;
230
        case 'f' + ('L' << 8) + ('a' << 16) + ('C' << 24):  // fLaC
231
            fmt = FMT_FLAC;
232
            break;
4268 hendricks2 233
        default:
5927 hendricks2 234
            if (MV_IdentifyXMP(ptr, length))
235
                fmt = FMT_XMP;
4268 hendricks2 236
            break;
1471 terminx 237
    }
238
 
5270 terminx 239
    return fmt;
1471 terminx 240
}
241
 
8216 terminx 242
int FX_Play(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
8427 hendricks2 243
                          int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval)
1471 terminx 244
{
8216 terminx 245
    static constexpr decltype(MV_PlayVOC) *func[] =
8213 terminx 246
    { nullptr, nullptr, MV_PlayVOC, MV_PlayWAV, MV_PlayVorbis, MV_PlayFLAC, MV_PlayXA, MV_PlayXMP };
1471 terminx 247
 
5927 hendricks2 248
    EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
1487 terminx 249
 
7117 terminx 250
    wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
5270 terminx 251
 
5814 terminx 252
    int handle =
7117 terminx 253
    (func[fmt]) ? func[fmt](ptr, ptrlength, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval) : -1;
5270 terminx 254
 
1658 terminx 255
    if (handle <= MV_Ok)
1471 terminx 256
    {
257
        FX_SetErrorCode(FX_MultiVocError);
258
        handle = FX_Warning;
259
    }
260
 
261
    return handle;
262
}
263
 
8216 terminx 264
int FX_Play3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle, int distance,
8427 hendricks2 265
                      int priority, fix16_t volume, intptr_t callbackval)
1471 terminx 266
{
8216 terminx 267
    static constexpr decltype(MV_PlayVOC3D) *func[] =
8213 terminx 268
    { nullptr, nullptr, MV_PlayVOC3D, MV_PlayWAV3D, MV_PlayVorbis3D, MV_PlayFLAC3D, MV_PlayXA3D, MV_PlayXMP3D };
1471 terminx 269
 
5927 hendricks2 270
    EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
5270 terminx 271
 
7117 terminx 272
    wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
5270 terminx 273
 
5814 terminx 274
    int handle =
7117 terminx 275
    (func[fmt]) ? func[fmt](ptr, ptrlength, loophow, pitchoffset, angle, distance, priority, volume, callbackval) : -1;
5270 terminx 276
 
1658 terminx 277
    if (handle <= MV_Ok)
1471 terminx 278
    {
279
        FX_SetErrorCode(FX_MultiVocError);
280
        handle = FX_Warning;
281
    }
282
 
283
    return handle;
284
}
1658 terminx 285
 
8450 hendricks2 286
int FX_PlayRaw(char *ptr, uint32_t ptrlength, int rate, int pitchoffset, int vol,
287
    int left, int right, int priority, fix16_t volume, intptr_t callbackval)
288
{
289
    int handle = MV_PlayRAW(ptr, ptrlength, rate, NULL, NULL, pitchoffset, vol, left, right, priority, volume, callbackval);
290
 
291
    if (handle <= MV_Ok)
292
    {
293
        FX_SetErrorCode(FX_MultiVocError);
294
        handle = FX_Warning;
295
    }
296
 
297
    return handle;
298
}
299
 
300
int FX_PlayLoopedRaw(char *ptr, uint32_t ptrlength, char *loopstart, char *loopend, int rate,
301
    int pitchoffset, int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval)
302
{
303
    int handle = MV_PlayRAW(ptr, ptrlength, rate, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval);
304
 
305
    if (handle <= MV_Ok)
306
    {
307
        FX_SetErrorCode(FX_MultiVocError);
308
        handle = FX_Warning;
309
    }
310
 
311
    return handle;
312
}
313
 
8741 hendricks2 314
int FX_StartDemandFeedPlayback(void (*function)(const char** ptr, uint32_t* length, void* userdata), int bitdepth, int channels, int rate, int pitchoffset,
315
    int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval, void* userdata)
8451 hendricks2 316
{
8581 hendricks2 317
    int handle = MV_StartDemandFeedPlayback(function, bitdepth, channels, rate,
8741 hendricks2 318
        pitchoffset, vol, left, right, priority, volume, callbackval, userdata);
8451 hendricks2 319
 
320
    if (handle <= MV_Ok)
321
    {
322
        FX_SetErrorCode(FX_MultiVocError);
323
        handle = FX_Warning;
324
    }
325
 
326
    return handle;
327
}
328
 
8216 terminx 329
int FX_SetPrintf(void (*function)(const char *, ...))
3338 hendricks2 330
{
331
    MV_SetPrintf(function);
332
 
333
    return FX_Ok;
334
}