fluidsynth.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 21 May 2013 21:21:23 -0700
changeset 617 87116a42526e
parent 601 05123263dab3
child 621 944412baab72
permissions -rw-r--r--
Cleaned up whitespace for the 2.0.0 release
chewi@506
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@601
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
chewi@506
     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.
chewi@506
     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:
chewi@506
    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.
chewi@506
    20
slouken@518
    21
  James Le Cuirot
slouken@518
    22
  chewi@aura-online.co.uk
chewi@506
    23
*/
chewi@506
    24
slouken@532
    25
#ifdef USE_FLUIDSYNTH_MIDI
slouken@532
    26
chewi@506
    27
#include <stdio.h>
chewi@506
    28
#include <sys/types.h>
chewi@506
    29
slouken@532
    30
#include "SDL_mixer.h"
slouken@532
    31
#include "fluidsynth.h"
slouken@532
    32
chewi@506
    33
static Uint16 format;
chewi@506
    34
static Uint8 channels;
chewi@506
    35
static int freq;
chewi@506
    36
chewi@506
    37
int fluidsynth_check_soundfont(const char *path, void *data)
chewi@506
    38
{
slouken@617
    39
    FILE *file = fopen(path, "r");
chewi@506
    40
slouken@617
    41
    if (file) {
slouken@617
    42
        fclose(file);
slouken@617
    43
        return 1;
slouken@617
    44
    } else {
slouken@617
    45
        Mix_SetError("Failed to access the SoundFont %s", path);
slouken@617
    46
        return 0;
slouken@617
    47
    }
chewi@506
    48
}
chewi@506
    49
chewi@506
    50
int fluidsynth_load_soundfont(const char *path, void *data)
chewi@506
    51
{
slouken@617
    52
    /* If this fails, it's too late to try Timidity so pray that at least one works. */
slouken@617
    53
    fluidsynth.fluid_synth_sfload((fluid_synth_t*) data, path, 1);
slouken@617
    54
    return 1;
chewi@506
    55
}
chewi@506
    56
chewi@506
    57
int fluidsynth_init(SDL_AudioSpec *mixer)
chewi@506
    58
{
slouken@617
    59
    if (!Mix_EachSoundFont(fluidsynth_check_soundfont, NULL))
slouken@617
    60
        return -1;
chewi@506
    61
slouken@617
    62
    format = mixer->format;
slouken@617
    63
    channels = mixer->channels;
slouken@617
    64
    freq = mixer->freq;
chewi@506
    65
slouken@617
    66
    return 0;
chewi@506
    67
}
chewi@506
    68
slouken@542
    69
static FluidSynthMidiSong *fluidsynth_loadsong_common(int (*function)(FluidSynthMidiSong*, void*), void *data)
chewi@506
    70
{
slouken@617
    71
    FluidSynthMidiSong *song;
slouken@617
    72
    fluid_settings_t *settings = NULL;
chewi@506
    73
slouken@617
    74
    if (!Mix_Init(MIX_INIT_FLUIDSYNTH)) {
slouken@617
    75
        return NULL;
slouken@617
    76
    }
slouken@545
    77
slouken@617
    78
    if ((song = SDL_malloc(sizeof(FluidSynthMidiSong)))) {
slouken@617
    79
        memset(song, 0, sizeof(FluidSynthMidiSong));
chewi@506
    80
slouken@617
    81
        if (SDL_BuildAudioCVT(&song->convert, AUDIO_S16, 2, freq, format, channels, freq) >= 0) {
slouken@617
    82
            if ((settings = fluidsynth.new_fluid_settings())) {
slouken@617
    83
                fluidsynth.fluid_settings_setnum(settings, "synth.sample-rate", (double) freq);
chewi@506
    84
slouken@617
    85
                if ((song->synth = fluidsynth.new_fluid_synth(settings))) {
slouken@617
    86
                    if (Mix_EachSoundFont(fluidsynth_load_soundfont, (void*) song->synth)) {
slouken@617
    87
                        if ((song->player = fluidsynth.new_fluid_player(song->synth))) {
slouken@617
    88
                            if (function(song, data)) return song;
slouken@617
    89
                            fluidsynth.delete_fluid_player(song->player);
slouken@617
    90
                        } else {
slouken@617
    91
                            Mix_SetError("Failed to create FluidSynth player");
slouken@617
    92
                        }
slouken@617
    93
                    }
slouken@617
    94
                    fluidsynth.delete_fluid_synth(song->synth);
slouken@617
    95
                } else {
slouken@617
    96
                    Mix_SetError("Failed to create FluidSynth synthesizer");
slouken@617
    97
                }
slouken@617
    98
                fluidsynth.delete_fluid_settings(settings);
slouken@617
    99
            } else {
slouken@617
   100
                Mix_SetError("Failed to create FluidSynth settings");
slouken@617
   101
            }
slouken@617
   102
        } else {
slouken@617
   103
            Mix_SetError("Failed to set up audio conversion");
slouken@617
   104
        }
slouken@617
   105
        SDL_free(song);
slouken@617
   106
    } else {
slouken@617
   107
        Mix_SetError("Insufficient memory for song");
slouken@617
   108
    }
slouken@617
   109
    return NULL;
chewi@506
   110
}
chewi@506
   111
slouken@542
   112
static int fluidsynth_loadsong_RW_internal(FluidSynthMidiSong *song, void *data)
chewi@506
   113
{
slouken@617
   114
    off_t offset;
slouken@617
   115
    size_t size;
slouken@617
   116
    char *buffer;
slouken@617
   117
    SDL_RWops *rw = (SDL_RWops*) data;
chewi@506
   118
slouken@617
   119
    offset = SDL_RWtell(rw);
slouken@617
   120
    SDL_RWseek(rw, 0, RW_SEEK_END);
slouken@617
   121
    size = SDL_RWtell(rw) - offset;
slouken@617
   122
    SDL_RWseek(rw, offset, RW_SEEK_SET);
chewi@506
   123
slouken@617
   124
    if ((buffer = (char*) SDL_malloc(size))) {
slouken@617
   125
        if(SDL_RWread(rw, buffer, size, 1) == 1) {
slouken@617
   126
            if (fluidsynth.fluid_player_add_mem(song->player, buffer, size) == FLUID_OK) {
slouken@617
   127
                return 1;
slouken@617
   128
            } else {
slouken@617
   129
                Mix_SetError("FluidSynth failed to load in-memory song");
slouken@617
   130
            }
slouken@617
   131
        } else {
slouken@617
   132
            Mix_SetError("Failed to read in-memory song");
slouken@617
   133
        }
slouken@617
   134
        SDL_free(buffer);
slouken@617
   135
    } else {
slouken@617
   136
        Mix_SetError("Insufficient memory for song");
slouken@617
   137
    }
slouken@617
   138
    return 0;
chewi@506
   139
}
chewi@506
   140
slouken@521
   141
FluidSynthMidiSong *fluidsynth_loadsong_RW(SDL_RWops *rw, int freerw)
chewi@506
   142
{
slouken@617
   143
    FluidSynthMidiSong *song;
slouken@521
   144
slouken@617
   145
    song = fluidsynth_loadsong_common(fluidsynth_loadsong_RW_internal, (void*) rw);
slouken@617
   146
    if (freerw) {
slouken@617
   147
        SDL_RWclose(rw);
slouken@617
   148
    }
slouken@617
   149
    return song;
chewi@506
   150
}
chewi@506
   151
chewi@506
   152
void fluidsynth_freesong(FluidSynthMidiSong *song)
chewi@506
   153
{
slouken@617
   154
    if (!song) return;
slouken@617
   155
    fluidsynth.delete_fluid_player(song->player);
slouken@617
   156
    fluidsynth.delete_fluid_settings(fluidsynth.fluid_synth_get_settings(song->synth));
slouken@617
   157
    fluidsynth.delete_fluid_synth(song->synth);
slouken@617
   158
    SDL_free(song);
chewi@506
   159
}
chewi@506
   160
chewi@506
   161
void fluidsynth_start(FluidSynthMidiSong *song)
chewi@506
   162
{
slouken@617
   163
    fluidsynth.fluid_player_set_loop(song->player, 1);
slouken@617
   164
    fluidsynth.fluid_player_play(song->player);
chewi@506
   165
}
chewi@506
   166
chewi@506
   167
void fluidsynth_stop(FluidSynthMidiSong *song)
chewi@506
   168
{
slouken@617
   169
    fluidsynth.fluid_player_stop(song->player);
chewi@506
   170
}
chewi@506
   171
chewi@506
   172
int fluidsynth_active(FluidSynthMidiSong *song)
chewi@506
   173
{
slouken@617
   174
    return fluidsynth.fluid_player_get_status(song->player) == FLUID_PLAYER_PLAYING ? 1 : 0;
chewi@506
   175
}
chewi@506
   176
chewi@506
   177
void fluidsynth_setvolume(FluidSynthMidiSong *song, int volume)
chewi@506
   178
{
slouken@617
   179
    /* FluidSynth's default is 0.2. Make 1.2 the maximum. */
slouken@617
   180
    fluidsynth.fluid_synth_set_gain(song->synth, (float) (volume * 1.2 / MIX_MAX_VOLUME));
chewi@506
   181
}
chewi@506
   182
chewi@506
   183
int fluidsynth_playsome(FluidSynthMidiSong *song, void *dest, int dest_len)
chewi@506
   184
{
slouken@617
   185
    int result = -1;
slouken@617
   186
    int frames = dest_len / channels / ((format & 0xFF) / 8);
slouken@617
   187
    int src_len = frames * 4; /* 16-bit stereo */
slouken@617
   188
    void *src = dest;
chewi@506
   189
slouken@617
   190
    if (dest_len < src_len) {
slouken@617
   191
        if (!(src = SDL_malloc(src_len))) {
slouken@617
   192
            Mix_SetError("Insufficient memory for audio conversion");
slouken@617
   193
            return result;
slouken@617
   194
        }
slouken@617
   195
    }
chewi@506
   196
slouken@617
   197
    if (fluidsynth.fluid_synth_write_s16(song->synth, frames, src, 0, 2, src, 1, 2) != FLUID_OK) {
slouken@617
   198
        Mix_SetError("Error generating FluidSynth audio");
slouken@617
   199
        goto finish;
slouken@617
   200
    }
chewi@506
   201
slouken@617
   202
    song->convert.buf = src;
slouken@617
   203
    song->convert.len = src_len;
chewi@506
   204
slouken@617
   205
    if (SDL_ConvertAudio(&song->convert) < 0) {
slouken@617
   206
        Mix_SetError("Error during audio conversion");
slouken@617
   207
        goto finish;
slouken@617
   208
    }
chewi@506
   209
slouken@617
   210
    if (src != dest)
slouken@617
   211
        memcpy(dest, src, dest_len);
chewi@506
   212
slouken@617
   213
    result = 0;
chewi@506
   214
chewi@506
   215
finish:
slouken@617
   216
    if (src != dest)
slouken@617
   217
        SDL_free(src);
chewi@506
   218
slouken@617
   219
    return result;
chewi@506
   220
}
slouken@532
   221
slouken@532
   222
#endif /* USE_FLUIDSYNTH_MIDI */