Subversion Repositories eduke32

Rev

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