Subversion Repositories eduke32

Rev

Rev 8755 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8755 terminx 1
//-------------------------------------------------------------------------
2
/*
3
Copyright (C) 2020 EDuke32 developers and contributors
4
 
5
This file is part of EDuke32.
6
 
7
EDuke32 is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License version 2
9
as published by the Free Software Foundation.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 
15
See the GNU General Public License for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
*/
21
//-------------------------------------------------------------------------
22
 
8752 terminx 23
#include "driver_sf2.h"
8755 terminx 24
 
25
#include "_multivc.h"
26
#include "common.h"
8752 terminx 27
#include "midi.h"
28
 
8769 terminx 29
int SF2_EffectSampleBlockSize = 16;
30
 
8752 terminx 31
#define TSF_IMPLEMENTATION
32
#define TSF_NO_STDIO
8769 terminx 33
#define TSF_RENDER_EFFECTSAMPLEBLOCK SF2_EffectSampleBlockSize
8755 terminx 34
#define TSF_MALLOC  Xmalloc
35
#define TSF_REALLOC Xrealloc
36
#define TSF_FREE    Xfree
8752 terminx 37
#define TSF_MEMCPY Bmemcpy
38
#define TSF_MEMSET Bmemset
8755 terminx 39
 
8752 terminx 40
#include "tsf.h"
41
 
8755 terminx 42
static tsf *sf2_synth;
43
char        SF2_BankFile[BMAX_PATH];
44
static int  SF2_Volume = MIDI_MaxVolume;
45
static int  ErrorCode  = SF2_Ok;
8752 terminx 46
 
8755 terminx 47
static inline int SF2_SetError(int const status) { return (ErrorCode = status); }
48
 
49
int SF2Drv_GetError(void) { return ErrorCode; }
50
 
8752 terminx 51
static void SF2_NoteOff(int channel, int key, int velocity)
52
{
53
    UNREFERENCED_PARAMETER(velocity);
8755 terminx 54
    tsf_channel_note_off(sf2_synth, channel, key);
8752 terminx 55
}
56
 
8755 terminx 57
static void SF2_NoteOn(int channel, int key, int velocity)        { tsf_channel_note_on(sf2_synth, channel, key, velocity * (1.f / 127.f)); }
58
static void SF2_ControlChange(int channel, int number, int value) { tsf_channel_midi_control(sf2_synth, channel, number, value); }
59
static void SF2_ProgramChange(int channel, int program)           { tsf_channel_set_presetnumber(sf2_synth, channel, program, channel == 9); }
60
static void SF2_SetPitchBend(int channel, int lsb, int msb)       { tsf_channel_set_pitchwheel(sf2_synth, channel, (msb << 7) | lsb); }
61
static void SF2_SetVolume(int volume)                             { SF2_Volume = clamp(volume, 0, MIDI_MaxVolume); }
8752 terminx 62
 
8755 terminx 63
const char *SF2Drv_ErrorString(int ErrorNumber)
8752 terminx 64
{
8755 terminx 65
    switch (ErrorNumber)
66
    {
67
        case SF2_Error:     return SF2Drv_ErrorString(ErrorCode);
68
        case SF2_Ok:        return "SF2 ok.";
69
        case SF2_BankError: return "SF2 bank error.";
70
        default:            return "Unknown SF2 error.";
71
    }
8752 terminx 72
}
73
 
8755 terminx 74
static int sf2_stream_read(void *handle, void *ptr, unsigned int size) { return kread(*(buildvfs_kfd *)handle, ptr, size); };
75
static int sf2_stream_skip(void *handle, unsigned int size)            { return !klseek(*(buildvfs_kfd *)handle, size, SEEK_CUR); };
76
 
77
static int SF2_Load(char const *const filename)
8752 terminx 78
{
8755 terminx 79
    buildvfs_kfd sf2_kfd    = kopen4loadfrommod(filename, 0);
80
    tsf_stream   sf2_stream = { &sf2_kfd, &sf2_stream_read, &sf2_stream_skip };
8752 terminx 81
 
8755 terminx 82
    if (sf2_kfd != buildvfs_kfd_invalid)
83
    {
84
        tsf_close(sf2_synth);
85
        sf2_synth = tsf_load(&sf2_stream);
86
        kclose(sf2_kfd);
87
 
88
        if (sf2_synth)
89
        {
90
            MV_Printf(": loaded \"%s\"", filename);
91
            return SF2_Ok;
92
        }
93
    }
94
 
95
    MV_Printf(": error loading \"%s\"!", filename);
96
    return SF2_Error;
8752 terminx 97
}
98
 
8755 terminx 99
int SF2Drv_MIDI_Init(midifuncs* const funcs)
8752 terminx 100
{
8755 terminx 101
    SF2Drv_MIDI_Shutdown();
8752 terminx 102
 
8755 terminx 103
    auto filename = SF2_BankFile;
8752 terminx 104
 
8755 terminx 105
    if (!filename[0])
8752 terminx 106
    {
8755 terminx 107
        fnlist_t fnl = FNLIST_INITIALIZER;
8752 terminx 108
 
8755 terminx 109
        // default to the first .sf2 we find if cvar mus_sf2_bank is unset
110
        fnlist_getnames(&fnl, g_modDir, "*.sf2", 0, 0);
8752 terminx 111
 
8755 terminx 112
        if (!fnl.findfiles)
113
            fnlist_getnames(&fnl, "/", "*.sf2", 0, 0);
8752 terminx 114
 
8755 terminx 115
        if (fnl.findfiles)
116
            filename = Xstrdup(fnl.findfiles->name);
8752 terminx 117
 
8755 terminx 118
        fnlist_clearnames(&fnl);
8752 terminx 119
 
8755 terminx 120
        if (!filename[0])
121
        {
122
            MV_Printf(": no .sf2 data found!\n");
123
            return SF2_SetError(SF2_BankError);
124
        }
125
    }
8752 terminx 126
 
8755 terminx 127
    int const loaded = SF2_Load(filename);
8752 terminx 128
 
8755 terminx 129
    if (filename != SF2_BankFile)
130
        Xfree(filename);
8752 terminx 131
 
8755 terminx 132
    if (loaded != SF2_Ok || !sf2_synth)
133
        return SF2_SetError(SF2_BankError);
8752 terminx 134
 
135
    Bmemset(funcs, 0, sizeof(midifuncs));
136
 
137
    funcs->NoteOff           = SF2_NoteOff;
138
    funcs->NoteOn            = SF2_NoteOn;
139
    funcs->PolyAftertouch    = nullptr;
140
    funcs->ControlChange     = SF2_ControlChange;
141
    funcs->ProgramChange     = SF2_ProgramChange;
142
    funcs->ChannelAftertouch = nullptr;
143
    funcs->PitchBend         = SF2_SetPitchBend;
144
    funcs->SetVolume         = SF2_SetVolume;
145
 
146
    SF2_Volume = MIDI_MaxVolume;
147
 
148
    return SF2_Ok;
149
}
150
 
8755 terminx 151
void SF2Drv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
8752 terminx 152
 
8755 terminx 153
void SF2Drv_MIDI_Shutdown(void)
8752 terminx 154
{
8755 terminx 155
    SF2Drv_MIDI_HaltPlayback();
8752 terminx 156
 
8755 terminx 157
    tsf_close(sf2_synth);
158
    sf2_synth = nullptr;
159
    ErrorCode = SF2_Ok;
8752 terminx 160
}
161
 
8755 terminx 162
int SF2Drv_MIDI_StartPlayback(void)
8752 terminx 163
{
8755 terminx 164
    SF2Drv_MIDI_HaltPlayback();
8752 terminx 165
 
8755 terminx 166
    tsf_set_output(sf2_synth, MV_Channels == 1 ? TSF_MONO : TSF_STEREO_INTERLEAVED, MV_MixRate, 0);
167
    tsf_channel_set_bank_preset(sf2_synth, 9, 128, 0);
168
    tsf_reset(sf2_synth);
169
 
8752 terminx 170
    for (int channel = 0; channel < 16; channel++)
171
        SF2_ProgramChange(channel, 0);
172
 
8755 terminx 173
    MV_HookMusicRoutine(SF2Drv_MIDI_Service);
174
 
8752 terminx 175
    return MIDI_Ok;
176
}
177
 
8755 terminx 178
void SF2Drv_MIDI_SetTempo(int const tempo, int const division)
8752 terminx 179
{
180
    MV_MIDIRenderTempo = tempo * division / 60;
181
    MV_MIDIRenderTimer = 0;
182
}
183
 
8755 terminx 184
void SF2Drv_MIDI_Service(void)
8752 terminx 185
{
8755 terminx 186
    int16_t *    buffer16 = (int16_t *)MV_MusicBuffer;
187
    static float fbuf[MV_MIXBUFFERSIZE * 2];
8769 terminx 188
    float const  fvolume = SF2_Volume * (32768.f / MIDI_MaxVolume);
8752 terminx 189
 
8755 terminx 190
    for (int i = 0; i < MV_MIXBUFFERSIZE;)
8752 terminx 191
    {
192
        while (MV_MIDIRenderTimer >= MV_MixRate)
193
        {
194
            if (MV_MIDIRenderTempo >= 0)
195
                MIDI_ServiceRoutine();
196
            MV_MIDIRenderTimer -= MV_MixRate;
197
        }
8755 terminx 198
 
199
        int samples = MV_MIDIRenderTempo > 0 ? (MV_MixRate - MV_MIDIRenderTimer + MV_MIDIRenderTempo - 1) / MV_MIDIRenderTempo : MV_MIXBUFFERSIZE;
200
        samples     = min(samples, MV_MIXBUFFERSIZE - i);
201
        tsf_render_float(sf2_synth, fbuf, samples);
202
 
8769 terminx 203
        int const nsamples = samples * MV_Channels;
8755 terminx 204
 
205
        for (int j = 0; j < nsamples; j++)
206
            *buffer16++ = clamp(Blrintf(fbuf[j] * fvolume), INT16_MIN, INT16_MAX);
207
 
208
        if (MV_MIDIRenderTempo >= 0)
209
            MV_MIDIRenderTimer += MV_MIDIRenderTempo * samples;
210
 
211
        i += samples;
8752 terminx 212
    }
213
}