Subversion Repositories eduke32

Rev

Rev 8782 | 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
 
8783 terminx 198
#define FMT_MAGIC(i, j, k, l) (i + (j << 8) + (k << 16) + (l << 24))
199
uint32_t constexpr FMT_CDXA_MAGIC = FMT_MAGIC('C','D','X','A');
200
uint32_t constexpr FMT_FLAC_MAGIC = FMT_MAGIC('f','L','a','C');
201
uint32_t constexpr FMT_OGG_MAGIC  = FMT_MAGIC('O','g','g','S');
202
uint32_t constexpr FMT_RIFF_MAGIC = FMT_MAGIC('R','I','F','F');
203
uint32_t constexpr FMT_VOC_MAGIC  = FMT_MAGIC('C','r','e','a');
204
uint32_t constexpr FMT_WAVE_MAGIC = FMT_MAGIC('W','A','V','E');
205
#undef FMT_MAGIC
206
 
207
static wavefmt_t FX_ReadFmt(char const * const ptr, uint32_t length)
1471 terminx 208
{
5814 terminx 209
    if (length < 12)
210
        return FMT_UNKNOWN;
1471 terminx 211
 
8783 terminx 212
    auto const ptr32 = (uint32_t const *)ptr;
1471 terminx 213
 
8783 terminx 214
    switch (B_LITTLE32(*ptr32))
1471 terminx 215
    {
8783 terminx 216
        case FMT_OGG_MAGIC:  return FMT_VORBIS;
217
        case FMT_VOC_MAGIC:  return FMT_VOC;
218
        case FMT_FLAC_MAGIC: return FMT_FLAC;
219
        case FMT_RIFF_MAGIC:
220
            if (B_LITTLE32(ptr32[2]) == FMT_WAVE_MAGIC) return FMT_WAV;
221
            if (B_LITTLE32(ptr32[2]) == FMT_CDXA_MAGIC) return FMT_XA;
4268 hendricks2 222
            break;
223
        default:
8783 terminx 224
            if (MV_IdentifyXMP(ptr, length)) return FMT_XMP;
4268 hendricks2 225
            break;
1471 terminx 226
    }
227
 
8783 terminx 228
    return FMT_UNKNOWN;
1471 terminx 229
}
230
 
8783 terminx 231
static int FX_BadFmt(char *, uint32_t, int, int, int, int, int, int, int, fix16_t, intptr_t) { return MV_SetErrorCode(MV_InvalidFile); }
232
static int FX_BadFmt3D(char *, uint32_t, int, int, int, int, int, fix16_t, intptr_t)         { return MV_SetErrorCode(MV_InvalidFile); }
233
 
8216 terminx 234
int FX_Play(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
8783 terminx 235
            int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval)
1471 terminx 236
{
8783 terminx 237
    static constexpr decltype(FX_Play) *func[] = { FX_BadFmt, nullptr, MV_PlayVOC, MV_PlayWAV, MV_PlayVorbis, MV_PlayFLAC, MV_PlayXA, MV_PlayXMP };
1471 terminx 238
 
5927 hendricks2 239
    EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
1487 terminx 240
 
8783 terminx 241
    int handle = func[FX_ReadFmt(ptr, ptrlength)](ptr, ptrlength, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval);
5270 terminx 242
 
1658 terminx 243
    if (handle <= MV_Ok)
1471 terminx 244
    {
245
        FX_SetErrorCode(FX_MultiVocError);
246
        handle = FX_Warning;
247
    }
248
 
249
    return handle;
250
}
251
 
8216 terminx 252
int FX_Play3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle, int distance,
8783 terminx 253
              int priority, fix16_t volume, intptr_t callbackval)
1471 terminx 254
{
8783 terminx 255
    static constexpr decltype(FX_Play3D) *func[] = { FX_BadFmt3D, nullptr, MV_PlayVOC3D, MV_PlayWAV3D, MV_PlayVorbis3D, MV_PlayFLAC3D, MV_PlayXA3D, MV_PlayXMP3D };
1471 terminx 256
 
5927 hendricks2 257
    EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
5270 terminx 258
 
8783 terminx 259
    int handle = func[FX_ReadFmt(ptr, ptrlength)](ptr, ptrlength, loophow, pitchoffset, angle, distance, priority, volume, callbackval);
5270 terminx 260
 
1658 terminx 261
    if (handle <= MV_Ok)
1471 terminx 262
    {
263
        FX_SetErrorCode(FX_MultiVocError);
264
        handle = FX_Warning;
265
    }
266
 
267
    return handle;
268
}
1658 terminx 269
 
8450 hendricks2 270
int FX_PlayRaw(char *ptr, uint32_t ptrlength, int rate, int pitchoffset, int vol,
271
    int left, int right, int priority, fix16_t volume, intptr_t callbackval)
272
{
273
    int handle = MV_PlayRAW(ptr, ptrlength, rate, NULL, NULL, pitchoffset, vol, left, right, priority, volume, callbackval);
274
 
275
    if (handle <= MV_Ok)
276
    {
277
        FX_SetErrorCode(FX_MultiVocError);
278
        handle = FX_Warning;
279
    }
280
 
281
    return handle;
282
}
283
 
284
int FX_PlayLoopedRaw(char *ptr, uint32_t ptrlength, char *loopstart, char *loopend, int rate,
285
    int pitchoffset, int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval)
286
{
287
    int handle = MV_PlayRAW(ptr, ptrlength, rate, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval);
288
 
289
    if (handle <= MV_Ok)
290
    {
291
        FX_SetErrorCode(FX_MultiVocError);
292
        handle = FX_Warning;
293
    }
294
 
295
    return handle;
296
}
297
 
8741 hendricks2 298
int FX_StartDemandFeedPlayback(void (*function)(const char** ptr, uint32_t* length, void* userdata), int bitdepth, int channels, int rate, int pitchoffset,
299
    int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval, void* userdata)
8451 hendricks2 300
{
8581 hendricks2 301
    int handle = MV_StartDemandFeedPlayback(function, bitdepth, channels, rate,
8741 hendricks2 302
        pitchoffset, vol, left, right, priority, volume, callbackval, userdata);
8451 hendricks2 303
 
304
    if (handle <= MV_Ok)
305
    {
306
        FX_SetErrorCode(FX_MultiVocError);
307
        handle = FX_Warning;
308
    }
309
 
310
    return handle;
311
}
312
 
8216 terminx 313
int FX_SetPrintf(void (*function)(const char *, ...))
3338 hendricks2 314
{
315
    MV_SetPrintf(function);
316
 
317
    return FX_Ok;
318
}