Subversion Repositories eduke32

Rev

Rev 8752 | Rev 8769 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 8752 Rev 8755
Line -... Line 1...
-
 
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
1
#include "driver_sf2.h"
23
#include "driver_sf2.h"
2
#include "compat.h"
-
 
3
#include "midi.h"
-
 
-
 
24
4
#include "_multivc.h"
25
#include "_multivc.h"
-
 
26
#include "common.h"
5
#include "vfs.h"
27
#include "midi.h"
6
28
7
#define TSF_IMPLEMENTATION
29
#define TSF_IMPLEMENTATION
8
#define TSF_NO_STDIO
30
#define TSF_NO_STDIO
9
#define TSF_MALLOC Bmalloc
31
#define TSF_MALLOC  Xmalloc
10
#define TSF_REALLOC Brealloc
32
#define TSF_REALLOC Xrealloc
11
#define TSF_FREE Bfree
33
#define TSF_FREE    Xfree
12
#define TSF_MEMCPY Bmemcpy
34
#define TSF_MEMCPY Bmemcpy
13
#define TSF_MEMSET Bmemset
35
#define TSF_MEMSET Bmemset
-
 
36
14
#include "tsf.h"
37
#include "tsf.h"
15
38
-
 
39
static tsf *sf2_synth;
16
char SF2_BankFile[BMAX_PATH];
40
char        SF2_BankFile[BMAX_PATH];
17
static int SF2_Volume = MIDI_MaxVolume;
41
static int  SF2_Volume = MIDI_MaxVolume;
18
static tsf *synth;
42
static int  ErrorCode  = SF2_Ok;
-
 
43
-
 
44
static inline int SF2_SetError(int const status) { return (ErrorCode = status); }
-
 
45
-
 
46
int SF2Drv_GetError(void) { return ErrorCode; }
19
47
20
static void SF2_NoteOff(int channel, int key, int velocity)
48
static void SF2_NoteOff(int channel, int key, int velocity)
21
{
49
{
22
    UNREFERENCED_PARAMETER(velocity);
50
    UNREFERENCED_PARAMETER(velocity);
23
    tsf_channel_note_off(synth, channel, key);
51
    tsf_channel_note_off(sf2_synth, channel, key);
24
}
52
}
25
53
26
static void SF2_NoteOn(int channel, int key, int velocity)
54
static void SF2_NoteOn(int channel, int key, int velocity)        { tsf_channel_note_on(sf2_synth, channel, key, velocity * (1.f / 127.f)); }
27
{
-
 
-
 
55
static void SF2_ControlChange(int channel, int number, int value) { tsf_channel_midi_control(sf2_synth, channel, number, value); }
-
 
56
static void SF2_ProgramChange(int channel, int program)           { tsf_channel_set_presetnumber(sf2_synth, channel, program, channel == 9); }
28
    tsf_channel_note_on(synth, channel, key, velocity * (1.f/127.f));
57
static void SF2_SetPitchBend(int channel, int lsb, int msb)       { tsf_channel_set_pitchwheel(sf2_synth, channel, (msb << 7) | lsb); }
29
}
-
 
-
 
58
static void SF2_SetVolume(int volume)                             { SF2_Volume = clamp(volume, 0, MIDI_MaxVolume); }
30
59
31
static void SF2_ControlChange(int channel, int number, int value)
60
const char *SF2Drv_ErrorString(int ErrorNumber)
-
 
61
{
-
 
62
    switch (ErrorNumber)
32
{
63
    {
-
 
64
        case SF2_Error:     return SF2Drv_ErrorString(ErrorCode);
-
 
65
        case SF2_Ok:        return "SF2 ok.";
33
    tsf_channel_midi_control(synth, channel, number, value);
66
        case SF2_BankError: return "SF2 bank error.";
-
 
67
        default:            return "Unknown SF2 error.";
34
}
68
    }
-
 
69
}
-
 
70
-
 
71
static int sf2_stream_read(void *handle, void *ptr, unsigned int size) { return kread(*(buildvfs_kfd *)handle, ptr, size); };
-
 
72
static int sf2_stream_skip(void *handle, unsigned int size)            { return !klseek(*(buildvfs_kfd *)handle, size, SEEK_CUR); };
35
73
36
static void SF2_ProgramChange(int channel, int program)
74
static int SF2_Load(char const *const filename)
37
{
75
{
-
 
76
    buildvfs_kfd sf2_kfd    = kopen4loadfrommod(filename, 0);
38
    tsf_channel_set_presetnumber(synth, channel, program, channel == 9);
77
    tsf_stream   sf2_stream = { &sf2_kfd, &sf2_stream_read, &sf2_stream_skip };
39
}
-
 
40
78
41
static void SF2_SetPitchBend(int channel, int lsb, int msb)
79
    if (sf2_kfd != buildvfs_kfd_invalid)
42
{
80
    {
-
 
81
        tsf_close(sf2_synth);
43
    tsf_channel_set_pitchwheel(synth, channel, (msb << 7) | lsb);
82
        sf2_synth = tsf_load(&sf2_stream);
44
}
-
 
-
 
83
        kclose(sf2_kfd);
45
84
46
static void SF2_SetVolume(int volume)
85
        if (sf2_synth)
47
{
86
        {
48
    SF2_Volume = clamp(volume, 0, MIDI_MaxVolume);
87
            MV_Printf(": loaded \"%s\"", filename);
-
 
88
            return SF2_Ok;
-
 
89
        }
49
}
90
    }
50
91
51
static int ErrorCode = SF2_Ok;
-
 
52
-
 
53
#define SF2_SetErrorCode(status) ErrorCode = (status);
92
    MV_Printf(": error loading \"%s\"!", filename);
54
-
 
55
int SF2_GetError(void) { return ErrorCode; }
93
    return SF2_Error;
56
-
 
57
const char* SF2_ErrorString(int ErrorNumber)
-
 
58
{
94
}
59
    const char *ErrorString;
-
 
60
   
95
61
    switch( ErrorNumber )
96
int SF2Drv_MIDI_Init(midifuncs* const funcs)
62
    {
97
{
63
        case SF2_Warning :
98
    SF2Drv_MIDI_Shutdown();
64
        case SF2_Error :
-
 
65
            ErrorString = SF2_ErrorString( ErrorCode );
-
 
66
            break;
-
 
67
99
68
        case SF2_Ok :
100
    auto filename = SF2_BankFile;
69
            ErrorString = "SF2 ok.";
-
 
70
            break;
-
 
71
101
72
        case SF2_BankError:
102
    if (!filename[0])
-
 
103
    {
73
            ErrorString = "SF2 bank error.";
104
        fnlist_t fnl = FNLIST_INITIALIZER;
74
            break;
-
 
75
           
105
76
        default:
-
 
77
            ErrorString = "Unknown SF2 error.";
106
        // default to the first .sf2 we find if cvar mus_sf2_bank is unset
78
            break;
107
        fnlist_getnames(&fnl, g_modDir, "*.sf2", 0, 0);
79
    }
-
 
80
       
108
81
    return ErrorString;
109
        if (!fnl.findfiles)
82
}
-
 
-
 
110
            fnlist_getnames(&fnl, "/", "*.sf2", 0, 0);
83
111
84
static int sf2_stream_read(buildvfs_kfd *handle, void *ptr, unsigned int size)
112
        if (fnl.findfiles)
85
{
-
 
86
    return kread(*handle, ptr, size);
113
            filename = Xstrdup(fnl.findfiles->name);
87
};
-
 
88
114
89
static int sf2_stream_skip(buildvfs_kfd *handle, unsigned int size)
-
 
90
{
-
 
91
    return !klseek(*handle, size, SEEK_CUR);
115
        fnlist_clearnames(&fnl);
92
};
-
 
93
116
94
int SF2_MIDI_Init(midifuncs * const funcs)
117
        if (!filename[0])
95
{
118
        {
96
    SF2_MIDI_Shutdown();
-
 
97
-
 
98
    auto sf2_handle = kopen4load(SF2_BankFile, 0);
119
            MV_Printf(": no .sf2 data found!\n");
99
    if (sf2_handle == buildvfs_kfd_invalid)
120
            return SF2_SetError(SF2_BankError);
100
        return SF2_BankError;
121
        }
-
 
122
    }
101
123
102
    struct tsf_stream sf2_stream = { &sf2_handle, (int(*)(void*,void*,unsigned int)) & sf2_stream_read, (int(*)(void*,unsigned int)) & sf2_stream_skip };
124
    int const loaded = SF2_Load(filename);
103
125
104
    synth = tsf_load(&sf2_stream);
126
    if (filename != SF2_BankFile)
105
    if (!synth)
-
 
106
        return SF2_BankError;
127
        Xfree(filename);
107
   
128
108
    kclose(sf2_handle);
129
    if (loaded != SF2_Ok || !sf2_synth)
-
 
130
        return SF2_SetError(SF2_BankError);
109
131
110
    Bmemset(funcs, 0, sizeof(midifuncs));
132
    Bmemset(funcs, 0, sizeof(midifuncs));
111
133
112
    funcs->NoteOff           = SF2_NoteOff;
134
    funcs->NoteOff           = SF2_NoteOff;
113
    funcs->NoteOn            = SF2_NoteOn;
135
    funcs->NoteOn            = SF2_NoteOn;
Line 121... Line 143...
121
    SF2_Volume = MIDI_MaxVolume;
143
    SF2_Volume = MIDI_MaxVolume;
122
   
144
   
123
    return SF2_Ok;
145
    return SF2_Ok;
124
}
146
}
125
147
126
void SF2_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
148
void SF2Drv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
127
149
128
void SF2_MIDI_Shutdown(void)
150
void SF2Drv_MIDI_Shutdown(void)
129
{
151
{
130
    SF2_MIDI_HaltPlayback();
152
    SF2Drv_MIDI_HaltPlayback();
131
153
132
    if (synth != nullptr)
-
 
133
        tsf_close(synth);
154
    tsf_close(sf2_synth);
134
    synth = nullptr;
155
    sf2_synth = nullptr;
-
 
156
    ErrorCode = SF2_Ok;
135
}
157
}
136
158
137
int SF2_MIDI_StartPlayback(void)
159
int SF2Drv_MIDI_StartPlayback(void)
138
{
160
{
139
    SF2_MIDI_HaltPlayback();
161
    SF2Drv_MIDI_HaltPlayback();
-
 
162
-
 
163
    tsf_set_output(sf2_synth, MV_Channels == 1 ? TSF_MONO : TSF_STEREO_INTERLEAVED, MV_MixRate, 0);
-
 
164
    tsf_channel_set_bank_preset(sf2_synth, 9, 128, 0);
-
 
165
    tsf_reset(sf2_synth);
140
166
141
    tsf_set_output(synth, MV_Channels == 1 ? TSF_MONO : TSF_STEREO_INTERLEAVED, MV_MixRate, 0);
-
 
142
    tsf_reset(synth);
-
 
143
    for (int channel = 0; channel < 16; channel++)
167
    for (int channel = 0; channel < 16; channel++)
144
    {
-
 
145
        SF2_ProgramChange(channel, 0);
168
        SF2_ProgramChange(channel, 0);
146
    }
169
147
    MV_HookMusicRoutine(SF2_MIDI_Service);
170
    MV_HookMusicRoutine(SF2Drv_MIDI_Service);
148
171
149
    return MIDI_Ok;
172
    return MIDI_Ok;
150
}
173
}
151
174
152
void SF2_MIDI_SetTempo(int const tempo, int const division)
175
void SF2Drv_MIDI_SetTempo(int const tempo, int const division)
153
{
176
{
154
    MV_MIDIRenderTempo = tempo * division / 60;
177
    MV_MIDIRenderTempo = tempo * division / 60;
155
    MV_MIDIRenderTimer = 0;
178
    MV_MIDIRenderTimer = 0;
156
}
179
}
157
180
158
void SF2_MIDI_Service(void)
181
void SF2Drv_MIDI_Service(void)
159
{
182
{
160
    int16_t * buffer16 = (int16_t *)MV_MusicBuffer;
183
    int16_t *    buffer16 = (int16_t *)MV_MusicBuffer;
161
    int32_t const samples = MV_MIXBUFFERSIZE;
184
    static float fbuf[MV_MIXBUFFERSIZE * 2];
162
    float buf[samples * 2];
-
 
163
185
164
    for (int32_t i = 0; i < samples;)
186
    for (int i = 0; i < MV_MIXBUFFERSIZE;)
165
    {
187
    {
166
        while (MV_MIDIRenderTimer >= MV_MixRate)
188
        while (MV_MIDIRenderTimer >= MV_MixRate)
167
        {
189
        {
168
            if (MV_MIDIRenderTempo >= 0)
190
            if (MV_MIDIRenderTempo >= 0)
169
                MIDI_ServiceRoutine();
191
                MIDI_ServiceRoutine();
170
            MV_MIDIRenderTimer -= MV_MixRate;
192
            MV_MIDIRenderTimer -= MV_MixRate;
171
        }
193
        }
-
 
194
172
        int32_t samplesrender = MV_MIDIRenderTempo > 0 ? (MV_MixRate - MV_MIDIRenderTimer + MV_MIDIRenderTempo - 1) / MV_MIDIRenderTempo : INT32_MAX;
195
        int samples = MV_MIDIRenderTempo > 0 ? (MV_MixRate - MV_MIDIRenderTimer + MV_MIDIRenderTempo - 1) / MV_MIDIRenderTempo : MV_MIXBUFFERSIZE;
173
        samplesrender = min(samplesrender, samples - i);
196
        samples     = min(samples, MV_MIXBUFFERSIZE - i);
174
        tsf_render_float(synth, buf, samplesrender);
197
        tsf_render_float(sf2_synth, fbuf, samples);
-
 
198
175
        for (int32_t j = 0; j < samplesrender * MV_Channels; j++)
199
        int const   nsamples = samples * MV_Channels;
-
 
200
        float const fvolume  = SF2_Volume * (32768.f / MIDI_MaxVolume);
-
 
201
176
        {
202
        for (int j = 0; j < nsamples; j++)
177
            *buffer16++ = clamp(int32_t(buf[j]*SF2_Volume*(32768.f/MIDI_MaxVolume)), INT16_MIN, INT16_MAX);
203
            *buffer16++ = clamp(Blrintf(fbuf[j] * fvolume), INT16_MIN, INT16_MAX);
-
 
204
178
        }
205
        if (MV_MIDIRenderTempo >= 0)
179
        if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo * samplesrender;
206
            MV_MIDIRenderTimer += MV_MIDIRenderTempo * samples;
-
 
207
180
        i += samplesrender;
208
        i += samples;
181
    }
209
    }
182
}
210
}