music_modplug.c
author Ozkan Sezer <sezeroz@gmail.com>
Tue, 08 Oct 2019 01:50:02 +0300
changeset 959 e1919e398c29
parent 926 d6c9518fb5ee
permissions -rw-r--r--
minor simplification to file seek for opus detection. remove unused local.
slouken@639
     1
/*
slouken@639
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@926
     3
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
slouken@639
     4
slouken@639
     5
  This software is provided 'as-is', without any express or implied
slouken@639
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@639
     7
  arising from the use of this software.
slouken@639
     8
slouken@639
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@639
    10
  including commercial applications, and to alter it and redistribute it
slouken@639
    11
  freely, subject to the following restrictions:
slouken@639
    12
slouken@639
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@639
    14
     claim that you wrote the original software. If you use this software
slouken@639
    15
     in a product, an acknowledgment in the product documentation would be
slouken@639
    16
     appreciated but is not required.
slouken@639
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@639
    18
     misrepresented as being the original software.
slouken@639
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@639
    20
*/
slouken@639
    21
slouken@777
    22
#ifdef MUSIC_MOD_MODPLUG
slouken@481
    23
slouken@777
    24
#include "SDL_loadso.h"
slouken@777
    25
slouken@481
    26
#include "music_modplug.h"
slouken@481
    27
slouken@777
    28
#ifdef MODPLUG_HEADER
slouken@777
    29
#include MODPLUG_HEADER
slouken@777
    30
#else
slouken@777
    31
#include <libmodplug/modplug.h>
slouken@777
    32
#endif
slouken@777
    33
slouken@777
    34
typedef struct {
slouken@777
    35
    int loaded;
slouken@777
    36
    void *handle;
slouken@777
    37
slouken@777
    38
    ModPlugFile* (*ModPlug_Load)(const void* data, int size);
slouken@777
    39
    void (*ModPlug_Unload)(ModPlugFile* file);
slouken@777
    40
    int  (*ModPlug_Read)(ModPlugFile* file, void* buffer, int size);
slouken@777
    41
    void (*ModPlug_Seek)(ModPlugFile* file, int millisecond);
slouken@777
    42
    void (*ModPlug_GetSettings)(ModPlug_Settings* settings);
slouken@777
    43
    void (*ModPlug_SetSettings)(const ModPlug_Settings* settings);
slouken@777
    44
    void (*ModPlug_SetMasterVolume)(ModPlugFile* file,unsigned int cvol) ;
slouken@777
    45
} modplug_loader;
slouken@777
    46
slouken@777
    47
static modplug_loader modplug = {
slouken@777
    48
    0, NULL
slouken@777
    49
};
slouken@777
    50
slouken@777
    51
slouken@481
    52
static ModPlug_Settings settings;
slouken@481
    53
slouken@777
    54
#ifdef MODPLUG_DYNAMIC
slouken@798
    55
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    56
    modplug.FUNC = (SIG) SDL_LoadFunction(modplug.handle, #FUNC); \
slouken@798
    57
    if (modplug.FUNC == NULL) { SDL_UnloadObject(modplug.handle); return -1; }
slouken@798
    58
#else
slouken@798
    59
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    60
    modplug.FUNC = FUNC;
slouken@798
    61
#endif
slouken@777
    62
slouken@777
    63
static int MODPLUG_Load(void)
slouken@481
    64
{
slouken@777
    65
    if (modplug.loaded == 0) {
slouken@798
    66
#ifdef MODPLUG_DYNAMIC
slouken@777
    67
        modplug.handle = SDL_LoadObject(MODPLUG_DYNAMIC);
slouken@777
    68
        if (modplug.handle == NULL) {
slouken@777
    69
            return -1;
slouken@777
    70
        }
slouken@798
    71
#elif defined(__MACOSX__)
slouken@798
    72
        extern ModPlugFile* ModPlug_Load(const void* data, int size) __attribute__((weak_import));
slouken@798
    73
        if (ModPlug_Load == NULL)
slouken@798
    74
        {
slouken@798
    75
            /* Missing weakly linked framework */
slouken@798
    76
            Mix_SetError("Missing modplug.framework");
slouken@798
    77
            return -1;
slouken@798
    78
        }
slouken@798
    79
#endif
slouken@798
    80
        FUNCTION_LOADER(ModPlug_Load, ModPlugFile* (*)(const void* data, int size))
slouken@798
    81
        FUNCTION_LOADER(ModPlug_Unload, void (*)(ModPlugFile* file))
slouken@798
    82
        FUNCTION_LOADER(ModPlug_Read, int  (*)(ModPlugFile* file, void* buffer, int size))
slouken@798
    83
        FUNCTION_LOADER(ModPlug_Seek, void (*)(ModPlugFile* file, int millisecond))
slouken@798
    84
        FUNCTION_LOADER(ModPlug_GetSettings, void (*)(ModPlug_Settings* settings))
slouken@798
    85
        FUNCTION_LOADER(ModPlug_SetSettings, void (*)(const ModPlug_Settings* settings))
slouken@798
    86
        FUNCTION_LOADER(ModPlug_SetMasterVolume, void (*)(ModPlugFile* file,unsigned int cvol))
slouken@639
    87
    }
slouken@777
    88
    ++modplug.loaded;
slouken@639
    89
slouken@777
    90
    return 0;
slouken@777
    91
}
slouken@777
    92
slouken@777
    93
static void MODPLUG_Unload(void)
slouken@777
    94
{
slouken@777
    95
    if (modplug.loaded == 0) {
slouken@777
    96
        return;
slouken@777
    97
    }
slouken@777
    98
    if (modplug.loaded == 1) {
slouken@798
    99
#ifdef MODPLUG_DYNAMIC
slouken@777
   100
        SDL_UnloadObject(modplug.handle);
slouken@798
   101
#endif
slouken@777
   102
    }
slouken@777
   103
    --modplug.loaded;
slouken@777
   104
}
slouken@777
   105
slouken@777
   106
slouken@797
   107
typedef struct
slouken@797
   108
{
slouken@797
   109
    int play_count;
slouken@797
   110
    ModPlugFile *file;
slouken@797
   111
    SDL_AudioStream *stream;
slouken@797
   112
    void *buffer;
slouken@797
   113
    int buffer_size;
slouken@797
   114
} MODPLUG_Music;
slouken@797
   115
slouken@797
   116
slouken@797
   117
static int MODPLUG_Seek(void *context, double position);
slouken@797
   118
static void MODPLUG_Delete(void *context);
slouken@797
   119
slouken@777
   120
static int MODPLUG_Open(const SDL_AudioSpec *spec)
slouken@777
   121
{
slouken@797
   122
    /* ModPlug supports U8 or S16 audio output */
slouken@639
   123
    modplug.ModPlug_GetSettings(&settings);
slouken@797
   124
    settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING;
slouken@797
   125
    if (spec->channels == 1) {
slouken@797
   126
        settings.mChannels = 1;
slouken@797
   127
    } else {
slouken@797
   128
        settings.mChannels = 2;
slouken@617
   129
    }
slouken@797
   130
    if (SDL_AUDIO_BITSIZE(spec->format) == 8) {
slouken@797
   131
        settings.mBits = 8;
slouken@797
   132
    } else {
slouken@797
   133
        settings.mBits = 16;
slouken@797
   134
    }
slouken@797
   135
    if (spec->freq >= 44100) {
slouken@797
   136
        settings.mFrequency = 44100;
slouken@797
   137
    } else if (spec->freq >= 22050) {
slouken@797
   138
        settings.mFrequency = 22050;
slouken@797
   139
    } else {
slouken@797
   140
        settings.mFrequency = 11025;
slouken@797
   141
    }
slouken@797
   142
    settings.mResamplingMode = MODPLUG_RESAMPLE_FIR;
slouken@797
   143
    settings.mReverbDepth = 0;
slouken@797
   144
    settings.mReverbDelay = 100;
slouken@797
   145
    settings.mBassAmount = 0;
slouken@797
   146
    settings.mBassRange = 50;
slouken@797
   147
    settings.mSurroundDepth = 0;
slouken@797
   148
    settings.mSurroundDelay = 10;
slouken@797
   149
    settings.mLoopCount = 0;
slouken@639
   150
    modplug.ModPlug_SetSettings(&settings);
slouken@617
   151
    return 0;
slouken@481
   152
}
slouken@481
   153
slouken@777
   154
/* Load a modplug stream from an SDL_RWops object */
slouken@777
   155
void *MODPLUG_CreateFromRW(SDL_RWops *src, int freesrc)
slouken@481
   156
{
slouken@797
   157
    MODPLUG_Music *music;
slouken@797
   158
    void *buffer;
slouken@797
   159
    size_t size;
slouken@481
   160
slouken@797
   161
    music = (MODPLUG_Music *)SDL_calloc(1, sizeof(*music));
slouken@797
   162
    if (!music) {
slouken@797
   163
        SDL_OutOfMemory();
slouken@797
   164
        return NULL;
slouken@797
   165
    }
slouken@797
   166
slouken@797
   167
    music->stream = SDL_NewAudioStream((settings.mBits == 8) ? AUDIO_U8 : AUDIO_S16SYS, settings.mChannels, settings.mFrequency,
slouken@797
   168
                                       music_spec.format, music_spec.channels, music_spec.freq);
slouken@797
   169
    if (!music->stream) {
slouken@797
   170
        MODPLUG_Delete(music);
slouken@797
   171
        return NULL;
slouken@797
   172
    }
slouken@797
   173
slouken@797
   174
    music->buffer_size = music_spec.samples * (settings.mBits / 8) * settings.mChannels;
slouken@797
   175
    music->buffer = SDL_malloc(music->buffer_size);
slouken@797
   176
    if (!music->buffer) {
slouken@797
   177
        MODPLUG_Delete(music);
slouken@797
   178
        return NULL;
slouken@797
   179
    }
slouken@797
   180
slouken@797
   181
    buffer = SDL_LoadFile_RW(src, &size, SDL_FALSE);
slouken@797
   182
    if (buffer) {
slouken@797
   183
        music->file = modplug.ModPlug_Load(buffer, (int)size);
slouken@797
   184
        if (!music->file) {
slouken@797
   185
            Mix_SetError("ModPlug_Load failed");
slouken@617
   186
        }
slouken@797
   187
        SDL_free(buffer);
slouken@617
   188
    }
slouken@797
   189
slouken@797
   190
    if (!music->file) {
slouken@797
   191
        MODPLUG_Delete(music);
slouken@797
   192
        return NULL;
slouken@797
   193
    }
slouken@797
   194
slouken@797
   195
    if (freesrc) {
slouken@625
   196
        SDL_RWclose(src);
slouken@617
   197
    }
slouken@617
   198
    return music;
slouken@481
   199
}
slouken@481
   200
slouken@777
   201
/* Set the volume for a modplug stream */
slouken@777
   202
static void MODPLUG_SetVolume(void *context, int volume)
slouken@481
   203
{
slouken@797
   204
    MODPLUG_Music *music = (MODPLUG_Music *)context;
slouken@797
   205
    modplug.ModPlug_SetMasterVolume(music->file, volume*4);
slouken@481
   206
}
slouken@481
   207
slouken@777
   208
/* Start playback of a given modplug stream */
slouken@797
   209
static int MODPLUG_Play(void *context, int play_count)
slouken@481
   210
{
slouken@797
   211
    MODPLUG_Music *music = (MODPLUG_Music *)context;
slouken@797
   212
    music->play_count = play_count;
slouken@797
   213
    return MODPLUG_Seek(music, 0.0);
slouken@481
   214
}
slouken@481
   215
slouken@481
   216
/* Play some of a stream previously started with modplug_play() */
slouken@797
   217
static int MODPLUG_GetSome(void *context, void *data, int bytes, SDL_bool *done)
slouken@797
   218
{
slouken@797
   219
    MODPLUG_Music *music = (MODPLUG_Music *)context;
slouken@797
   220
    int filled, amount;
slouken@797
   221
slouken@797
   222
    filled = SDL_AudioStreamGet(music->stream, data, bytes);
slouken@797
   223
    if (filled != 0) {
slouken@797
   224
        return filled;
slouken@797
   225
    }
slouken@797
   226
slouken@797
   227
    if (!music->play_count) {
slouken@797
   228
        /* All done */
slouken@797
   229
        *done = SDL_TRUE;
slouken@797
   230
        return 0;
slouken@797
   231
    }
slouken@797
   232
slouken@797
   233
    amount = modplug.ModPlug_Read(music->file, music->buffer, music->buffer_size);
slouken@797
   234
    if (amount > 0) {
slouken@797
   235
        if (SDL_AudioStreamPut(music->stream, music->buffer, amount) < 0) {
slouken@797
   236
            return -1;
slouken@797
   237
        }
slouken@797
   238
    } else {
slouken@797
   239
        if (music->play_count == 1) {
slouken@797
   240
            music->play_count = 0;
slouken@797
   241
            SDL_AudioStreamFlush(music->stream);
slouken@797
   242
        } else {
slouken@797
   243
            int play_count = -1;
slouken@797
   244
            if (music->play_count > 0) {
slouken@797
   245
                play_count = (music->play_count - 1);
slouken@797
   246
            }
slouken@797
   247
            if (MODPLUG_Play(music, play_count) < 0) {
slouken@797
   248
                return -1;
slouken@797
   249
            }
slouken@797
   250
        }
slouken@797
   251
    }
slouken@797
   252
    return 0;
slouken@797
   253
}
slouken@777
   254
static int MODPLUG_GetAudio(void *context, void *data, int bytes)
slouken@481
   255
{
slouken@797
   256
    return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, MODPLUG_GetSome);
slouken@777
   257
}
slouken@777
   258
slouken@777
   259
/* Jump (seek) to a given position */
slouken@777
   260
static int MODPLUG_Seek(void *context, double position)
slouken@777
   261
{
slouken@797
   262
    MODPLUG_Music *music = (MODPLUG_Music *)context;
slouken@797
   263
    modplug.ModPlug_Seek(music->file, (int)(position*1000));
slouken@617
   264
    return 0;
slouken@481
   265
}
slouken@481
   266
slouken@777
   267
/* Close the given modplug stream */
slouken@777
   268
static void MODPLUG_Delete(void *context)
slouken@481
   269
{
slouken@797
   270
    MODPLUG_Music *music = (MODPLUG_Music *)context;
slouken@797
   271
    if (music->file) {
slouken@797
   272
        modplug.ModPlug_Unload(music->file);
slouken@797
   273
    }
slouken@797
   274
    if (music->stream) {
slouken@797
   275
        SDL_FreeAudioStream(music->stream);
slouken@797
   276
    }
slouken@797
   277
    if (music->buffer) {
slouken@797
   278
        SDL_free(music->buffer);
slouken@797
   279
    }
slouken@797
   280
    SDL_free(music);
slouken@481
   281
}
slouken@481
   282
slouken@777
   283
Mix_MusicInterface Mix_MusicInterface_MODPLUG =
slouken@481
   284
{
slouken@777
   285
    "MODPLUG",
slouken@777
   286
    MIX_MUSIC_MODPLUG,
slouken@777
   287
    MUS_MOD,
slouken@777
   288
    SDL_FALSE,
slouken@777
   289
    SDL_FALSE,
slouken@481
   290
slouken@777
   291
    MODPLUG_Load,
slouken@777
   292
    MODPLUG_Open,
slouken@777
   293
    MODPLUG_CreateFromRW,
slouken@777
   294
    NULL,   /* CreateFromFile */
slouken@777
   295
    MODPLUG_SetVolume,
slouken@777
   296
    MODPLUG_Play,
slouken@777
   297
    NULL,   /* IsPlaying */
slouken@777
   298
    MODPLUG_GetAudio,
slouken@777
   299
    MODPLUG_Seek,
slouken@777
   300
    NULL,   /* Pause */
slouken@777
   301
    NULL,   /* Resume */
slouken@777
   302
    NULL,   /* Stop */
slouken@777
   303
    MODPLUG_Delete,
slouken@777
   304
    NULL,   /* Close */
slouken@777
   305
    MODPLUG_Unload,
slouken@777
   306
};
slouken@481
   307
slouken@777
   308
#endif /* MUSIC_MOD_MODPLUG */
slouken@777
   309
slouken@777
   310
/* vi: set ts=4 sw=4 expandtab: */