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