music_mikmod.c
author Ozkan Sezer <sezeroz@gmail.com>
Wed, 03 Oct 2018 21:55:00 +0300
changeset 863 b81eb791d10d
parent 852 b86f9bd104c8
child 926 d6c9518fb5ee
permissions -rw-r--r--
readmidi.c (groom_list): avoid integer overflow when recomputing time.

from libtimidity -- see:
https://sourceforge.net/p/libtimidity/libtimidity/ci/11be98a89eac229111420e6a3d521edbfddb0dbc/
slouken@411
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@848
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@411
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@411
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@411
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@411
    20
*/
slouken@411
    21
slouken@777
    22
#ifdef MUSIC_MOD_MIKMOD
slouken@411
    23
slouken@411
    24
/* This file supports MOD tracker music streams */
slouken@411
    25
slouken@789
    26
#include "SDL_loadso.h"
slouken@789
    27
slouken@777
    28
#include "music_mikmod.h"
slouken@411
    29
slouken@411
    30
#include "mikmod.h"
slouken@411
    31
slouken@777
    32
slouken@777
    33
/* libmikmod >= 3.3.2 constified several funcs */
slouken@777
    34
#if (LIBMIKMOD_VERSION < 0x030302)
slouken@777
    35
#define MIKMOD3_CONST
slouken@411
    36
#else
slouken@777
    37
#define MIKMOD3_CONST const
slouken@411
    38
#endif
slouken@411
    39
slouken@777
    40
typedef struct {
slouken@777
    41
    int loaded;
slouken@777
    42
    void *handle;
slouken@777
    43
slouken@777
    44
    void (*MikMod_Exit)(void);
slouken@777
    45
    CHAR* (*MikMod_InfoDriver)(void);
slouken@777
    46
    CHAR* (*MikMod_InfoLoader)(void);
slouken@777
    47
    int (*MikMod_Init)(MIKMOD3_CONST CHAR*);
slouken@777
    48
    void (*MikMod_RegisterAllLoaders)(void);
slouken@777
    49
    void (*MikMod_RegisterDriver)(struct MDRIVER*);
slouken@777
    50
    int* MikMod_errno;
slouken@777
    51
    MIKMOD3_CONST char* (*MikMod_strerror)(int);
slouken@777
    52
    void (*MikMod_free)(void*);
slouken@777
    53
    BOOL (*Player_Active)(void);
slouken@777
    54
    void (*Player_Free)(MODULE*);
slouken@777
    55
    MODULE* (*Player_LoadGeneric)(MREADER*,int,BOOL);
slouken@777
    56
    void (*Player_SetPosition)(UWORD);
slouken@777
    57
    void (*Player_SetVolume)(SWORD);
slouken@777
    58
    void (*Player_Start)(MODULE*);
slouken@777
    59
    void (*Player_Stop)(void);
slouken@777
    60
    ULONG (*VC_WriteBytes)(SBYTE*,ULONG);
slouken@777
    61
    struct MDRIVER* drv_nos;
slouken@777
    62
    UWORD* md_device;
slouken@777
    63
    UWORD* md_mixfreq;
slouken@777
    64
    UWORD* md_mode;
slouken@777
    65
    UBYTE* md_musicvolume;
slouken@777
    66
    UBYTE* md_pansep;
slouken@777
    67
    UBYTE* md_reverb;
slouken@777
    68
    UBYTE* md_sndfxvolume;
slouken@777
    69
    UBYTE* md_volume;
slouken@777
    70
} mikmod_loader;
slouken@777
    71
slouken@777
    72
static mikmod_loader mikmod = {
slouken@777
    73
    0, NULL
slouken@777
    74
};
slouken@777
    75
slouken@798
    76
#ifdef MIKMOD_DYNAMIC
slouken@798
    77
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    78
    mikmod.FUNC = (SIG) SDL_LoadFunction(mikmod.handle, #FUNC); \
slouken@798
    79
    if (mikmod.FUNC == NULL) { SDL_UnloadObject(mikmod.handle); return -1; }
slouken@798
    80
#define VARIABLE_LOADER(NAME, SIG) \
slouken@798
    81
    mikmod.NAME = (SIG) SDL_LoadFunction(mikmod.handle, #NAME); \
slouken@798
    82
    if (mikmod.NAME == NULL) { SDL_UnloadObject(mikmod.handle); return -1; }
slouken@798
    83
#else
slouken@798
    84
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@798
    85
    mikmod.FUNC = FUNC;
slouken@798
    86
#define VARIABLE_LOADER(NAME, SIG) \
slouken@798
    87
    mikmod.NAME = &NAME;
slouken@798
    88
#endif
slouken@777
    89
slouken@777
    90
static int MIKMOD_Load()
slouken@777
    91
{
slouken@777
    92
    if (mikmod.loaded == 0) {
slouken@798
    93
#ifdef MIKMOD_DYNAMIC
slouken@798
    94
        mikmod.handle = SDL_LoadObject(MIKMOD_DYNAMIC);
slouken@777
    95
        if (mikmod.handle == NULL) {
slouken@777
    96
            return -1;
slouken@777
    97
        }
slouken@798
    98
#elif defined(__MACOSX__)
slouken@798
    99
        extern void Player_Start(MODULE*) __attribute__((weak_import));
slouken@798
   100
        if (Player_Start == NULL)
slouken@798
   101
        {
slouken@798
   102
            /* Missing weakly linked framework */
slouken@798
   103
            Mix_SetError("Missing mikmod.framework");
slouken@777
   104
            return -1;
slouken@777
   105
        }
slouken@798
   106
#endif
slouken@798
   107
        FUNCTION_LOADER(MikMod_Exit, void (*)(void))
slouken@798
   108
        FUNCTION_LOADER(MikMod_InfoDriver, CHAR* (*)(void))
slouken@798
   109
        FUNCTION_LOADER(MikMod_InfoLoader, CHAR* (*)(void))
slouken@798
   110
        FUNCTION_LOADER(MikMod_Init, int (*)(MIKMOD3_CONST CHAR*))
slouken@798
   111
        FUNCTION_LOADER(MikMod_RegisterAllLoaders, void (*)(void))
slouken@798
   112
        FUNCTION_LOADER(MikMod_RegisterDriver, void (*)(struct MDRIVER*))
slouken@798
   113
        VARIABLE_LOADER(MikMod_errno, int*)
slouken@798
   114
        FUNCTION_LOADER(MikMod_strerror, MIKMOD3_CONST char* (*)(int))
slouken@798
   115
#ifdef MIKMOD_DYNAMIC
slouken@798
   116
        mikmod.MikMod_free = (void (*)(void*)) SDL_LoadFunction(mikmod.handle, "MikMod_free");
slouken@798
   117
        if (!mikmod.MikMod_free) {
slouken@777
   118
            /* libmikmod 3.1 and earlier doesn't have it */
slouken@777
   119
            mikmod.MikMod_free = free;
slouken@777
   120
        }
slouken@798
   121
#else
sezeroz@852
   122
#if (LIBMIKMOD_VERSION < 0x030200) || !defined(DMODE_NOISEREDUCTION)
sezeroz@852
   123
        /* libmikmod 3.2.0-beta2 or older */
slouken@798
   124
        mikmod.MikMod_free = free;
slouken@798
   125
#else
slouken@798
   126
        mikmod.MikMod_free = MikMod_free;
slouken@798
   127
#endif
slouken@798
   128
#endif /* MIKMOD_DYNAMIC */
slouken@798
   129
        FUNCTION_LOADER(Player_Active, BOOL (*)(void))
slouken@798
   130
        FUNCTION_LOADER(Player_Free, void (*)(MODULE*))
slouken@798
   131
        FUNCTION_LOADER(Player_LoadGeneric, MODULE* (*)(MREADER*,int,BOOL))
slouken@798
   132
        FUNCTION_LOADER(Player_SetPosition, void (*)(UWORD))
slouken@798
   133
        FUNCTION_LOADER(Player_SetVolume, void (*)(SWORD))
slouken@798
   134
        FUNCTION_LOADER(Player_Start, void (*)(MODULE*))
slouken@798
   135
        FUNCTION_LOADER(Player_Stop, void (*)(void))
slouken@798
   136
        FUNCTION_LOADER(VC_WriteBytes, ULONG (*)(SBYTE*,ULONG))
slouken@798
   137
        VARIABLE_LOADER(drv_nos, MDRIVER*)
slouken@798
   138
        VARIABLE_LOADER(md_device, UWORD*)
slouken@798
   139
        VARIABLE_LOADER(md_mixfreq, UWORD*)
slouken@798
   140
        VARIABLE_LOADER(md_mode, UWORD*)
slouken@798
   141
        VARIABLE_LOADER(md_musicvolume, UBYTE*)
slouken@798
   142
        VARIABLE_LOADER(md_pansep, UBYTE*)
slouken@798
   143
        VARIABLE_LOADER(md_reverb, UBYTE*)
slouken@798
   144
        VARIABLE_LOADER(md_sndfxvolume, UBYTE*)
slouken@798
   145
        VARIABLE_LOADER(md_volume, UBYTE*)
slouken@777
   146
    }
slouken@777
   147
    ++mikmod.loaded;
slouken@777
   148
slouken@777
   149
    return 0;
slouken@777
   150
}
slouken@777
   151
slouken@777
   152
static void MIKMOD_Unload()
slouken@777
   153
{
slouken@777
   154
    if (mikmod.loaded == 0) {
slouken@777
   155
        return;
slouken@777
   156
    }
slouken@777
   157
    if (mikmod.loaded == 1) {
slouken@798
   158
#ifdef MIKMOD_DYNAMIC
slouken@777
   159
        SDL_UnloadObject(mikmod.handle);
slouken@798
   160
#endif
slouken@777
   161
    }
slouken@777
   162
    --mikmod.loaded;
slouken@777
   163
}
slouken@777
   164
slouken@777
   165
slouken@798
   166
typedef struct
slouken@777
   167
{
slouken@798
   168
    int play_count;
slouken@798
   169
    int volume;
slouken@798
   170
    MODULE *module;
slouken@798
   171
    SDL_AudioStream *stream;
slouken@798
   172
    SBYTE *buffer;
slouken@798
   173
    ULONG buffer_size;
slouken@798
   174
} MIKMOD_Music;
slouken@777
   175
slouken@777
   176
slouken@798
   177
static int MIKMOD_Seek(void *context, double position);
slouken@798
   178
static void MIKMOD_Delete(void *context);
slouken@411
   179
slouken@419
   180
/* Initialize the MOD player, with the given mixer settings
slouken@411
   181
   This function returns 0, or -1 if there was an error.
slouken@411
   182
 */
slouken@777
   183
static int MIKMOD_Open(const SDL_AudioSpec *spec)
slouken@411
   184
{
slouken@617
   185
    CHAR *list;
slouken@419
   186
slouken@617
   187
    /* Set the MikMod music format */
slouken@798
   188
    if (spec->format == AUDIO_S8 || spec->format == AUDIO_U8) {
slouken@798
   189
        /* MIKMOD audio format is AUDIO_U8 */
slouken@798
   190
        *mikmod.md_mode = 0;
slouken@798
   191
    } else {
slouken@798
   192
        /* MIKMOD audio format is AUDIO_S16SYS */
slouken@798
   193
        *mikmod.md_mode = DMODE_16BITS;
slouken@617
   194
    }
slouken@777
   195
    if (spec->channels > 1) {
slouken@617
   196
        *mikmod.md_mode |= DMODE_STEREO;
slouken@617
   197
    }
slouken@777
   198
    *mikmod.md_mixfreq = spec->freq;
slouken@617
   199
    *mikmod.md_device  = 0;
slouken@617
   200
    *mikmod.md_volume  = 96;
slouken@617
   201
    *mikmod.md_musicvolume = 128;
slouken@617
   202
    *mikmod.md_sndfxvolume = 128;
slouken@617
   203
    *mikmod.md_pansep  = 128;
slouken@617
   204
    *mikmod.md_reverb  = 0;
slouken@617
   205
    *mikmod.md_mode    |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;
slouken@419
   206
slouken@617
   207
    list = mikmod.MikMod_InfoDriver();
slouken@798
   208
    if (list) {
slouken@617
   209
      mikmod.MikMod_free(list);
slouken@798
   210
    } else {
slouken@617
   211
      mikmod.MikMod_RegisterDriver(mikmod.drv_nos);
slouken@798
   212
    }
slouken@419
   213
slouken@617
   214
    list = mikmod.MikMod_InfoLoader();
slouken@798
   215
    if (list) {
slouken@617
   216
      mikmod.MikMod_free(list);
slouken@798
   217
    } else {
slouken@617
   218
      mikmod.MikMod_RegisterAllLoaders();
slouken@798
   219
    }
slouken@419
   220
slouken@777
   221
    if (mikmod.MikMod_Init(NULL)) {
slouken@617
   222
        Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
slouken@617
   223
        return -1;
slouken@617
   224
    }
slouken@617
   225
    return 0;
slouken@411
   226
}
slouken@411
   227
slouken@411
   228
/* Uninitialize the music players */
slouken@777
   229
static void MIKMOD_Close(void)
slouken@411
   230
{
slouken@617
   231
    if (mikmod.MikMod_Exit) {
slouken@617
   232
        mikmod.MikMod_Exit();
slouken@617
   233
    }
slouken@411
   234
}
slouken@411
   235
slouken@411
   236
typedef struct
slouken@411
   237
{
slouken@617
   238
    MREADER mr;
slouken@776
   239
    /* struct MREADER in libmikmod <= 3.2.0-beta2
slouken@776
   240
     * doesn't have iobase members. adding them here
slouken@776
   241
     * so that if we compile against 3.2.0-beta2, we
slouken@776
   242
     * can still run OK against 3.2.0b3 and newer. */
slouken@776
   243
    long iobase, prev_iobase;
slouken@621
   244
    Sint64 offset;
slouken@621
   245
    Sint64 eof;
slouken@628
   246
    SDL_RWops *src;
slouken@411
   247
} LMM_MREADER;
slouken@411
   248
slouken@768
   249
int LMM_Seek(struct MREADER *mr,long to,int dir)
slouken@411
   250
{
slouken@800
   251
    Sint64 offset = to;
slouken@617
   252
    LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
slouken@777
   253
    if (dir == SEEK_SET) {
slouken@621
   254
        offset += lmmmr->offset;
slouken@768
   255
        if (offset < lmmmr->offset)
slouken@768
   256
            return -1;
slouken@617
   257
    }
sezeroz@851
   258
    return (SDL_RWseek(lmmmr->src, offset, dir) < lmmmr->offset)? -1 : 0;
slouken@411
   259
}
slouken@411
   260
long LMM_Tell(struct MREADER *mr)
slouken@411
   261
{
slouken@617
   262
    LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
slouken@628
   263
    return (long)(SDL_RWtell(lmmmr->src) - lmmmr->offset);
slouken@411
   264
}
slouken@411
   265
BOOL LMM_Read(struct MREADER *mr,void *buf,size_t sz)
slouken@411
   266
{
slouken@617
   267
    LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
slouken@628
   268
    return SDL_RWread(lmmmr->src, buf, sz, 1);
slouken@411
   269
}
slouken@411
   270
int LMM_Get(struct MREADER *mr)
slouken@411
   271
{
slouken@617
   272
    unsigned char c;
slouken@617
   273
    LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
slouken@777
   274
    if (SDL_RWread(lmmmr->src, &c, 1, 1)) {
slouken@617
   275
        return c;
slouken@617
   276
    }
slouken@617
   277
    return EOF;
slouken@411
   278
}
slouken@411
   279
BOOL LMM_Eof(struct MREADER *mr)
slouken@411
   280
{
slouken@628
   281
    Sint64 offset;
slouken@617
   282
    LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
slouken@617
   283
    offset = LMM_Tell(mr);
slouken@617
   284
    return offset >= lmmmr->eof;
slouken@411
   285
}
slouken@628
   286
MODULE *MikMod_LoadSongRW(SDL_RWops *src, int maxchan)
slouken@411
   287
{
slouken@617
   288
    LMM_MREADER lmmmr = {
slouken@617
   289
        { LMM_Seek, LMM_Tell, LMM_Read, LMM_Get, LMM_Eof },
slouken@617
   290
        0,
slouken@617
   291
        0,
slouken@617
   292
        0
slouken@617
   293
    };
slouken@628
   294
    lmmmr.offset = SDL_RWtell(src);
slouken@628
   295
    SDL_RWseek(src, 0, RW_SEEK_END);
slouken@628
   296
    lmmmr.eof = SDL_RWtell(src);
slouken@628
   297
    SDL_RWseek(src, lmmmr.offset, RW_SEEK_SET);
slouken@628
   298
    lmmmr.src = src;
slouken@617
   299
    return mikmod.Player_LoadGeneric((MREADER*)&lmmmr, maxchan, 0);
slouken@411
   300
}
slouken@411
   301
slouken@411
   302
/* Load a MOD stream from an SDL_RWops object */
slouken@777
   303
void *MIKMOD_CreateFromRW(SDL_RWops *src, int freesrc)
slouken@411
   304
{
slouken@798
   305
    MIKMOD_Music *music;
slouken@798
   306
    SDL_AudioFormat format;
slouken@798
   307
    Uint8 channels;
slouken@419
   308
slouken@798
   309
    music = (MIKMOD_Music *)SDL_calloc(1, sizeof(*music));
slouken@798
   310
    if (!music) {
slouken@798
   311
        SDL_OutOfMemory();
slouken@798
   312
        return NULL;
slouken@798
   313
    }
slouken@798
   314
    music->volume = MIX_MAX_VOLUME;
slouken@798
   315
slouken@798
   316
    music->module = MikMod_LoadSongRW(src, 64);
slouken@798
   317
    if (!music->module) {
slouken@617
   318
        Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
slouken@798
   319
        MIKMOD_Delete(music);
slouken@617
   320
        return NULL;
slouken@617
   321
    }
slouken@411
   322
slouken@825
   323
    /* Allow implicit looping, disable fade out and other flags. */
slouken@798
   324
    music->module->extspd  = 1;
slouken@798
   325
    music->module->panflag = 1;
slouken@798
   326
    music->module->wrap    = 0;
slouken@825
   327
    music->module->loop    = 1;
slouken@825
   328
    music->module->fadeout = 0;
slouken@521
   329
slouken@798
   330
    if ((*mikmod.md_mode & DMODE_16BITS) == DMODE_16BITS) {
slouken@798
   331
        format = AUDIO_S16SYS;
slouken@798
   332
    } else {
slouken@798
   333
        format = AUDIO_U8;
slouken@798
   334
    }
slouken@798
   335
    if ((*mikmod.md_mode & DMODE_STEREO) == DMODE_STEREO) {
slouken@798
   336
        channels = 2;
slouken@798
   337
    } else {
slouken@798
   338
        channels = 1;
slouken@798
   339
    }
slouken@798
   340
    music->stream = SDL_NewAudioStream(format, channels, *mikmod.md_mixfreq,
slouken@798
   341
                                       music_spec.format, music_spec.channels, music_spec.freq);
slouken@798
   342
    if (!music->stream) {
slouken@798
   343
        MIKMOD_Delete(music);
slouken@798
   344
        return NULL;
slouken@798
   345
    }
slouken@798
   346
slouken@798
   347
    music->buffer_size = music_spec.samples * (SDL_AUDIO_BITSIZE(format) / 8) * channels;
slouken@798
   348
    music->buffer = (SBYTE *)SDL_malloc(music->buffer_size);
slouken@798
   349
    if (!music->buffer) {
slouken@798
   350
        SDL_OutOfMemory();
slouken@798
   351
        MIKMOD_Delete(music);
slouken@798
   352
        return NULL;
slouken@798
   353
    }
slouken@798
   354
        
slouken@777
   355
    if (freesrc) {
slouken@628
   356
        SDL_RWclose(src);
slouken@617
   357
    }
slouken@798
   358
    return music;
slouken@411
   359
}
slouken@411
   360
slouken@777
   361
/* Set the volume for a MOD stream */
slouken@777
   362
static void MIKMOD_SetVolume(void *context, int volume)
slouken@777
   363
{
slouken@798
   364
    MIKMOD_Music *music = (MIKMOD_Music *)context;
slouken@798
   365
    music->volume = volume;
slouken@777
   366
    mikmod.Player_SetVolume((SWORD)volume);
slouken@777
   367
}
slouken@777
   368
slouken@411
   369
/* Start playback of a given MOD stream */
slouken@798
   370
static int MIKMOD_Play(void *context, int play_count)
slouken@411
   371
{
slouken@798
   372
    MIKMOD_Music *music = (MIKMOD_Music *)context;
slouken@798
   373
    music->play_count = play_count;
slouken@825
   374
    music->module->initvolume = music->volume;
slouken@798
   375
    mikmod.Player_Start(music->module);
slouken@798
   376
    return MIKMOD_Seek(music, 0.0);
slouken@411
   377
}
slouken@411
   378
slouken@411
   379
/* Return non-zero if a stream is currently playing */
slouken@777
   380
static SDL_bool MIKMOD_IsPlaying(void *context)
slouken@411
   381
{
slouken@777
   382
    return mikmod.Player_Active() ? SDL_TRUE : SDL_FALSE;
slouken@411
   383
}
slouken@411
   384
slouken@411
   385
/* Play some of a stream previously started with MOD_play() */
slouken@798
   386
static int MIKMOD_GetSome(void *context, void *data, int bytes, SDL_bool *done)
slouken@411
   387
{
slouken@798
   388
    MIKMOD_Music *music = (MIKMOD_Music *)context;
slouken@798
   389
    int filled;
slouken@777
   390
slouken@798
   391
    filled = SDL_AudioStreamGet(music->stream, data, bytes);
slouken@798
   392
    if (filled != 0) {
slouken@798
   393
        return filled;
slouken@798
   394
    }
slouken@411
   395
slouken@798
   396
    if (!music->play_count) {
slouken@798
   397
        /* All done */
slouken@798
   398
        *done = SDL_TRUE;
slouken@798
   399
        return 0;
slouken@798
   400
    }
slouken@411
   401
slouken@798
   402
    /* This never fails, and always writes a full buffer */
slouken@798
   403
    mikmod.VC_WriteBytes(music->buffer, music->buffer_size);
slouken@798
   404
slouken@798
   405
    if (SDL_AudioStreamPut(music->stream, music->buffer, music->buffer_size) < 0) {
slouken@798
   406
        return -1;
slouken@617
   407
    }
slouken@411
   408
slouken@798
   409
    /* Check to see if we're done now */
slouken@798
   410
    if (!mikmod.Player_Active()) {
slouken@798
   411
        if (music->play_count == 1) {
slouken@798
   412
            music->play_count = 0;
slouken@798
   413
            SDL_AudioStreamFlush(music->stream);
slouken@798
   414
        } else {
slouken@798
   415
            int play_count = -1;
slouken@798
   416
            if (music->play_count > 0) {
slouken@798
   417
                play_count = (music->play_count - 1);
slouken@798
   418
            }
slouken@798
   419
            if (MIKMOD_Play(music, play_count) < 0) {
slouken@798
   420
                return -1;
slouken@798
   421
            }
slouken@617
   422
        }
slouken@617
   423
    }
slouken@617
   424
    return 0;
slouken@411
   425
}
slouken@798
   426
static int MIKMOD_GetAudio(void *context, void *data, int bytes)
slouken@798
   427
{
slouken@798
   428
    return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, MIKMOD_GetSome);
slouken@798
   429
}
slouken@411
   430
slouken@777
   431
/* Jump (seek) to a given position (time is in seconds) */
slouken@777
   432
static int MIKMOD_Seek(void *context, double position)
slouken@777
   433
{
slouken@777
   434
    mikmod.Player_SetPosition((UWORD)position);
slouken@777
   435
    return 0;
slouken@777
   436
}
slouken@777
   437
slouken@411
   438
/* Stop playback of a stream previously started with MOD_play() */
slouken@777
   439
static void MIKMOD_Stop(void *context)
slouken@411
   440
{
slouken@617
   441
    mikmod.Player_Stop();
slouken@411
   442
}
slouken@411
   443
slouken@411
   444
/* Close the given MOD stream */
slouken@777
   445
static void MIKMOD_Delete(void *context)
slouken@411
   446
{
slouken@798
   447
    MIKMOD_Music *music = (MIKMOD_Music *)context;
slouken@798
   448
slouken@798
   449
    if (music->module) {
slouken@798
   450
        mikmod.Player_Free(music->module);
slouken@798
   451
    }
slouken@798
   452
    if (music->stream) {
slouken@798
   453
        SDL_FreeAudioStream(music->stream);
slouken@798
   454
    }
slouken@798
   455
    if (music->buffer) {
slouken@798
   456
        SDL_free(music->buffer);
slouken@798
   457
    }
slouken@798
   458
    SDL_free(music);
slouken@411
   459
}
slouken@411
   460
slouken@777
   461
Mix_MusicInterface Mix_MusicInterface_MIKMOD =
slouken@411
   462
{
slouken@777
   463
    "MIKMOD",
slouken@777
   464
    MIX_MUSIC_MIKMOD,
slouken@777
   465
    MUS_MOD,
slouken@777
   466
    SDL_FALSE,
slouken@777
   467
    SDL_FALSE,
slouken@411
   468
slouken@777
   469
    MIKMOD_Load,
slouken@777
   470
    MIKMOD_Open,
slouken@777
   471
    MIKMOD_CreateFromRW,
slouken@777
   472
    NULL,   /* CreateFromFile */
slouken@777
   473
    MIKMOD_SetVolume,
slouken@777
   474
    MIKMOD_Play,
slouken@777
   475
    MIKMOD_IsPlaying,
slouken@777
   476
    MIKMOD_GetAudio,
slouken@777
   477
    MIKMOD_Seek,
slouken@777
   478
    NULL,   /* Pause */
slouken@777
   479
    NULL,   /* Resume */
slouken@798
   480
    MIKMOD_Stop,
slouken@777
   481
    MIKMOD_Delete,
slouken@777
   482
    MIKMOD_Close,
slouken@777
   483
    MIKMOD_Unload,
slouken@777
   484
};
slouken@777
   485
slouken@777
   486
#endif /* MUSIC_MOD_MIKMOD */
slouken@777
   487
slouken@777
   488
/* vi: set ts=4 sw=4 expandtab: */