music_timidity.c
author Ozkan Sezer <sezeroz@gmail.com>
Wed, 03 Oct 2018 21:55:00 +0300
changeset 863 b81eb791d10d
parent 848 3907db698eb5
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@777
     1
/*
slouken@777
     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@777
     4
slouken@777
     5
  This software is provided 'as-is', without any express or implied
slouken@777
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@777
     7
  arising from the use of this software.
slouken@777
     8
slouken@777
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@777
    10
  including commercial applications, and to alter it and redistribute it
slouken@777
    11
  freely, subject to the following restrictions:
slouken@777
    12
slouken@777
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@777
    14
     claim that you wrote the original software. If you use this software
slouken@777
    15
     in a product, an acknowledgment in the product documentation would be
slouken@777
    16
     appreciated but is not required.
slouken@777
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@777
    18
     misrepresented as being the original software.
slouken@777
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@777
    20
*/
slouken@777
    21
slouken@777
    22
/* This file supports playing MIDI files with timidity */
slouken@777
    23
slouken@777
    24
#ifdef MUSIC_MID_TIMIDITY
slouken@777
    25
slouken@777
    26
#include "music_timidity.h"
slouken@777
    27
slouken@777
    28
#include "timidity/timidity.h"
slouken@777
    29
slouken@777
    30
slouken@797
    31
typedef struct
slouken@797
    32
{
slouken@797
    33
    int play_count;
slouken@797
    34
    MidiSong *song;
slouken@812
    35
    SDL_AudioStream *stream;
slouken@812
    36
    void *buffer;
slouken@812
    37
    Sint32 buffer_size;
slouken@797
    38
} TIMIDITY_Music;
slouken@797
    39
slouken@797
    40
slouken@797
    41
static int TIMIDITY_Seek(void *context, double position);
slouken@812
    42
static void TIMIDITY_Delete(void *context);
slouken@797
    43
slouken@777
    44
static int TIMIDITY_Open(const SDL_AudioSpec *spec)
slouken@777
    45
{
slouken@782
    46
    return Timidity_Init();
slouken@777
    47
}
slouken@777
    48
slouken@777
    49
static void TIMIDITY_Close(void)
slouken@777
    50
{
slouken@782
    51
    Timidity_Exit();
slouken@777
    52
}
slouken@777
    53
slouken@777
    54
void *TIMIDITY_CreateFromRW(SDL_RWops *src, int freesrc)
slouken@777
    55
{
slouken@797
    56
    TIMIDITY_Music *music;
slouken@812
    57
    SDL_AudioSpec spec;
slouken@812
    58
    SDL_bool need_stream = SDL_FALSE;
slouken@797
    59
slouken@797
    60
    music = (TIMIDITY_Music *)SDL_calloc(1, sizeof(*music));
slouken@797
    61
    if (!music) {
slouken@797
    62
        SDL_OutOfMemory();
slouken@797
    63
        return NULL;
slouken@797
    64
    }
slouken@797
    65
slouken@812
    66
    SDL_memcpy(&spec, &music_spec, sizeof(spec));
slouken@812
    67
    if (spec.channels > 2) {
slouken@812
    68
        need_stream = SDL_TRUE;
slouken@812
    69
        spec.channels = 2;
slouken@812
    70
    }
slouken@812
    71
    music->song = Timidity_LoadSong(src, &spec);
slouken@797
    72
    if (!music->song) {
slouken@812
    73
        TIMIDITY_Delete(music);
slouken@797
    74
        return NULL;
slouken@797
    75
    }
slouken@797
    76
slouken@812
    77
    if (need_stream) {
slouken@812
    78
        music->stream = SDL_NewAudioStream(spec.format, spec.channels, spec.freq,
slouken@812
    79
                                           music_spec.format, music_spec.channels, music_spec.freq);
slouken@812
    80
        if (!music->stream) {
slouken@812
    81
            TIMIDITY_Delete(music);
slouken@812
    82
            return NULL;
slouken@812
    83
        }
slouken@812
    84
slouken@812
    85
        music->buffer_size = spec.samples * (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels;
slouken@812
    86
        music->buffer = SDL_malloc(music->buffer_size);
slouken@812
    87
        if (!music->buffer) {
slouken@812
    88
            SDL_OutOfMemory();
slouken@812
    89
            TIMIDITY_Delete(music);
slouken@812
    90
            return NULL;
slouken@812
    91
        }
slouken@812
    92
    }
slouken@812
    93
slouken@797
    94
    if (freesrc) {
slouken@782
    95
        SDL_RWclose(src);
slouken@777
    96
    }
slouken@777
    97
    return music;
slouken@777
    98
}
slouken@777
    99
slouken@777
   100
static void TIMIDITY_SetVolume(void *context, int volume)
slouken@777
   101
{
slouken@797
   102
    TIMIDITY_Music *music = (TIMIDITY_Music *)context;
slouken@797
   103
    Timidity_SetVolume(music->song, volume);
slouken@777
   104
}
slouken@777
   105
slouken@797
   106
static int TIMIDITY_Play(void *context, int play_count)
slouken@777
   107
{
slouken@797
   108
    TIMIDITY_Music *music = (TIMIDITY_Music *)context;
slouken@797
   109
    music->play_count = play_count;
slouken@797
   110
    Timidity_Start(music->song);
slouken@797
   111
    return TIMIDITY_Seek(music, 0.0);
slouken@777
   112
}
slouken@777
   113
slouken@812
   114
static int TIMIDITY_GetSome(void *context, void *data, int bytes, SDL_bool *done)
slouken@777
   115
{
slouken@797
   116
    TIMIDITY_Music *music = (TIMIDITY_Music *)context;
slouken@812
   117
    int filled, amount, expected;
slouken@812
   118
slouken@812
   119
    if (music->stream) {
slouken@812
   120
        filled = SDL_AudioStreamGet(music->stream, data, bytes);
slouken@812
   121
        if (filled != 0) {
slouken@812
   122
            return filled;
slouken@812
   123
        }
slouken@812
   124
    }
slouken@812
   125
slouken@812
   126
    if (!music->play_count) {
slouken@812
   127
        /* All done */
slouken@812
   128
        *done = SDL_TRUE;
slouken@812
   129
        return 0;
slouken@812
   130
    }
slouken@812
   131
slouken@812
   132
    if (music->stream) {
slouken@812
   133
        expected = music->buffer_size;
slouken@812
   134
        amount = Timidity_PlaySome(music->song, music->buffer, music->buffer_size);
slouken@812
   135
        if (SDL_AudioStreamPut(music->stream, music->buffer, amount) < 0) {
slouken@812
   136
            return -1;
slouken@812
   137
        }
slouken@812
   138
    } else {
slouken@812
   139
        expected = bytes;
slouken@812
   140
        amount = Timidity_PlaySome(music->song, data, bytes);
slouken@812
   141
    }
slouken@812
   142
        
slouken@812
   143
    if (amount < expected) {
slouken@797
   144
        if (music->play_count == 1) {
slouken@797
   145
            /* We didn't consume anything and we're done */
slouken@797
   146
            music->play_count = 0;
slouken@797
   147
        } else {
slouken@797
   148
            int play_count = -1;
slouken@797
   149
            if (music->play_count > 0) {
slouken@797
   150
                play_count = (music->play_count - 1);
slouken@797
   151
            }
slouken@797
   152
            if (TIMIDITY_Play(music, play_count) < 0) {
slouken@797
   153
                return -1;
slouken@797
   154
            }
slouken@797
   155
        }
slouken@782
   156
    }
slouken@812
   157
    if (music->stream) {
slouken@812
   158
        /* We'll pick it up from the stream next time around */
slouken@812
   159
        return 0;
slouken@812
   160
    } else {
slouken@812
   161
        /* We wrote output data */
slouken@812
   162
        return amount;
slouken@812
   163
    }
slouken@812
   164
}
slouken@812
   165
static int TIMIDITY_GetAudio(void *context, void *data, int bytes)
slouken@812
   166
{
slouken@812
   167
    return music_pcm_getaudio(context, data, bytes, MIX_MAX_VOLUME, TIMIDITY_GetSome);
slouken@777
   168
}
slouken@777
   169
slouken@782
   170
static int TIMIDITY_Seek(void *context, double position)
slouken@777
   171
{
slouken@797
   172
    TIMIDITY_Music *music = (TIMIDITY_Music *)context;
slouken@797
   173
    Timidity_Seek(music->song, (Uint32)(position * 1000));
slouken@782
   174
    return 0;
slouken@777
   175
}
slouken@777
   176
slouken@777
   177
static void TIMIDITY_Delete(void *context)
slouken@777
   178
{
slouken@797
   179
    TIMIDITY_Music *music = (TIMIDITY_Music *)context;
slouken@812
   180
slouken@812
   181
    if (music->song) {
slouken@812
   182
        Timidity_FreeSong(music->song);
slouken@812
   183
    }
slouken@812
   184
    if (music->stream) {
slouken@812
   185
        SDL_FreeAudioStream(music->stream);
slouken@812
   186
    }
slouken@812
   187
    if (music->buffer) {
slouken@812
   188
        SDL_free(music->buffer);
slouken@812
   189
    }
slouken@797
   190
    SDL_free(music);
slouken@777
   191
}
slouken@777
   192
slouken@777
   193
Mix_MusicInterface Mix_MusicInterface_TIMIDITY =
slouken@777
   194
{
slouken@777
   195
    "TIMIDITY",
slouken@777
   196
    MIX_MUSIC_TIMIDITY,
slouken@777
   197
    MUS_MID,
slouken@777
   198
    SDL_FALSE,
slouken@777
   199
    SDL_FALSE,
slouken@777
   200
slouken@777
   201
    NULL,   /* Load */
slouken@777
   202
    TIMIDITY_Open,
slouken@777
   203
    TIMIDITY_CreateFromRW,
slouken@777
   204
    NULL,   /* CreateFromFile */
slouken@777
   205
    TIMIDITY_SetVolume,
slouken@777
   206
    TIMIDITY_Play,
slouken@782
   207
    NULL,   /* IsPlaying */
slouken@777
   208
    TIMIDITY_GetAudio,
slouken@782
   209
    TIMIDITY_Seek,
slouken@777
   210
    NULL,   /* Pause */
slouken@777
   211
    NULL,   /* Resume */
slouken@777
   212
    NULL,   /* Stop */
slouken@777
   213
    TIMIDITY_Delete,
slouken@777
   214
    TIMIDITY_Close,
slouken@777
   215
    NULL,   /* Unload */
slouken@777
   216
};
slouken@777
   217
slouken@777
   218
#endif /* MUSIC_MID_TIMIDITY */
slouken@777
   219
slouken@777
   220
/* vi: set ts=4 sw=4 expandtab: */