Subversion Repositories eduke32

Rev

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