Subversion Repositories eduke32

Rev

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

Rev Author Line No. Line
8752 terminx 1
#include "driver_sf2.h"
2
#include "compat.h"
3
#include "midi.h"
4
#include "_multivc.h"
5
#include "vfs.h"
6
 
7
#define TSF_IMPLEMENTATION
8
#define TSF_NO_STDIO
9
#define TSF_MALLOC Bmalloc
10
#define TSF_REALLOC Brealloc
11
#define TSF_FREE Bfree
12
#define TSF_MEMCPY Bmemcpy
13
#define TSF_MEMSET Bmemset
14
#include "tsf.h"
15
 
16
char SF2_BankFile[BMAX_PATH];
17
static int SF2_Volume = MIDI_MaxVolume;
18
static tsf *synth;
19
 
20
static void SF2_NoteOff(int channel, int key, int velocity)
21
{
22
    UNREFERENCED_PARAMETER(velocity);
23
    tsf_channel_note_off(synth, channel, key);
24
}
25
 
26
static void SF2_NoteOn(int channel, int key, int velocity)
27
{
28
    tsf_channel_note_on(synth, channel, key, velocity * (1.f/127.f));
29
}
30
 
31
static void SF2_ControlChange(int channel, int number, int value)
32
{
33
    tsf_channel_midi_control(synth, channel, number, value);
34
}
35
 
36
static void SF2_ProgramChange(int channel, int program)
37
{
38
    tsf_channel_set_presetnumber(synth, channel, program, channel == 9);
39
}
40
 
41
static void SF2_SetPitchBend(int channel, int lsb, int msb)
42
{
43
    tsf_channel_set_pitchwheel(synth, channel, (msb << 7) | lsb);
44
}
45
 
46
static void SF2_SetVolume(int volume)
47
{
48
    SF2_Volume = clamp(volume, 0, MIDI_MaxVolume);
49
}
50
 
51
static int ErrorCode = SF2_Ok;
52
 
53
#define SF2_SetErrorCode(status) ErrorCode = (status);
54
 
55
int SF2_GetError(void) { return ErrorCode; }
56
 
57
const char* SF2_ErrorString(int ErrorNumber)
58
{
59
    const char *ErrorString;
60
 
61
    switch( ErrorNumber )
62
    {
63
        case SF2_Warning :
64
        case SF2_Error :
65
            ErrorString = SF2_ErrorString( ErrorCode );
66
            break;
67
 
68
        case SF2_Ok :
69
            ErrorString = "SF2 ok.";
70
            break;
71
 
72
        case SF2_BankError:
73
            ErrorString = "SF2 bank error.";
74
            break;
75
 
76
        default:
77
            ErrorString = "Unknown SF2 error.";
78
            break;
79
    }
80
 
81
    return ErrorString;
82
}
83
 
84
static int sf2_stream_read(buildvfs_kfd *handle, void *ptr, unsigned int size)
85
{
86
    return kread(*handle, ptr, size);
87
};
88
 
89
static int sf2_stream_skip(buildvfs_kfd *handle, unsigned int size)
90
{
91
    return !klseek(*handle, size, SEEK_CUR);
92
};
93
 
94
int SF2_MIDI_Init(midifuncs * const funcs)
95
{
96
    SF2_MIDI_Shutdown();
97
 
98
    auto sf2_handle = kopen4load(SF2_BankFile, 0);
99
    if (sf2_handle == buildvfs_kfd_invalid)
100
        return SF2_BankError;
101
 
102
    struct tsf_stream sf2_stream = { &sf2_handle, (int(*)(void*,void*,unsigned int)) & sf2_stream_read, (int(*)(void*,unsigned int)) & sf2_stream_skip };
103
 
104
    synth = tsf_load(&sf2_stream);
105
    if (!synth)
106
        return SF2_BankError;
107
 
108
    kclose(sf2_handle);
109
 
110
    Bmemset(funcs, 0, sizeof(midifuncs));
111
 
112
    funcs->NoteOff           = SF2_NoteOff;
113
    funcs->NoteOn            = SF2_NoteOn;
114
    funcs->PolyAftertouch    = nullptr;
115
    funcs->ControlChange     = SF2_ControlChange;
116
    funcs->ProgramChange     = SF2_ProgramChange;
117
    funcs->ChannelAftertouch = nullptr;
118
    funcs->PitchBend         = SF2_SetPitchBend;
119
    funcs->SetVolume         = SF2_SetVolume;
120
 
121
    SF2_Volume = MIDI_MaxVolume;
122
 
123
    return SF2_Ok;
124
}
125
 
126
void SF2_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
127
 
128
void SF2_MIDI_Shutdown(void)
129
{
130
    SF2_MIDI_HaltPlayback();
131
 
132
    if (synth != nullptr)
133
        tsf_close(synth);
134
    synth = nullptr;
135
}
136
 
137
int SF2_MIDI_StartPlayback(void)
138
{
139
    SF2_MIDI_HaltPlayback();
140
 
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++)
144
    {
145
        SF2_ProgramChange(channel, 0);
146
    }
147
    MV_HookMusicRoutine(SF2_MIDI_Service);
148
 
149
    return MIDI_Ok;
150
}
151
 
152
void SF2_MIDI_SetTempo(int const tempo, int const division)
153
{
154
    MV_MIDIRenderTempo = tempo * division / 60;
155
    MV_MIDIRenderTimer = 0;
156
}
157
 
158
void SF2_MIDI_Service(void)
159
{
160
    int16_t * buffer16 = (int16_t *)MV_MusicBuffer;
161
    int32_t const samples = MV_MIXBUFFERSIZE;
162
    float buf[samples * 2];
163
 
164
    for (int32_t i = 0; i < samples;)
165
    {
166
        while (MV_MIDIRenderTimer >= MV_MixRate)
167
        {
168
            if (MV_MIDIRenderTempo >= 0)
169
                MIDI_ServiceRoutine();
170
            MV_MIDIRenderTimer -= MV_MixRate;
171
        }
172
        int32_t samplesrender = MV_MIDIRenderTempo > 0 ? (MV_MixRate - MV_MIDIRenderTimer + MV_MIDIRenderTempo - 1) / MV_MIDIRenderTempo : INT32_MAX;
173
        samplesrender = min(samplesrender, samples - i);
174
        tsf_render_float(synth, buf, samplesrender);
175
        for (int32_t j = 0; j < samplesrender * MV_Channels; j++)
176
        {
177
            *buffer16++ = clamp(int32_t(buf[j]*SF2_Volume*(32768.f/MIDI_MaxVolume)), INT16_MIN, INT16_MAX);
178
        }
179
        if (MV_MIDIRenderTempo >= 0) MV_MIDIRenderTimer += MV_MIDIRenderTempo * samplesrender;
180
        i += samplesrender;
181
    }
182
}