driver_sf2.cpp
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 23 #include "driver_sf2.h" 24 25 #include "_multivc.h" 26 #include "common.h" 27 #include "midi.h" 28 29 int SF2_EffectSampleBlockSize = 16; 30 31 #define TSF_IMPLEMENTATION 32 #define TSF_NO_STDIO 33 #define TSF_RENDER_EFFECTSAMPLEBLOCK SF2_EffectSampleBlockSize 34 #define TSF_MALLOC Xmalloc 35 #define TSF_REALLOC Xrealloc 36 #define TSF_FREE Xfree 37 #define TSF_MEMCPY Bmemcpy 38 #define TSF_MEMSET Bmemset 39 40 #include "tsf.h" 41 42 static tsf *sf2_synth; 43 char SF2_BankFile[BMAX_PATH]; 44 static int SF2_Volume = MIDI_MaxVolume; 45 static int ErrorCode = SF2_Ok; 46 47 static inline int SF2_SetError(int const status) { return (ErrorCode = status); } 48 49 int SF2Drv_GetError(void) { return ErrorCode; } 50 51 static void SF2_NoteOff(int channel, int key, int velocity) 52 { 53 UNREFERENCED_PARAMETER(velocity); 54 tsf_channel_note_off(sf2_synth, channel, key); 55 } 56 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); } 62 63 const char *SF2Drv_ErrorString(int ErrorNumber) 64 { 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 } 72 } 73 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_LoadBank(char const *const filename) 78 { 79 buildvfs_kfd sf2_kfd = kopen4loadfrommod(filename, 0); 80 tsf_stream sf2_stream = { &sf2_kfd, &sf2_stream_read, &sf2_stream_skip }; 81 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 VLOG_F(LOG_ASS, "Loaded \"%s\"", filename); 91 return SF2_Ok; 92 } 93 } 94 95 LOG_F(ERROR, "Unable to load \"%s\"!", filename); 96 return SF2_Error; 97 } 98 99 int SF2Drv_MIDI_Init(midifuncs* const funcs) 100 { 101 SF2Drv_MIDI_Shutdown(); 102 103 auto filename = SF2_BankFile; 104 105 if (!filename[0]) 106 { 107 fnlist_t fnl = FNLIST_INITIALIZER; 108 109 // default to the first .sf2 we find if cvar mus_sf2_bank is unset 110 fnlist_getnames(&fnl, g_modDir, "*.sf2", 0, 0); 111 112 if (!fnl.findfiles) 113 fnlist_getnames(&fnl, "/", "*.sf2", 0, 0); 114 115 if (fnl.findfiles) 116 filename = Xstrdup(fnl.findfiles->name); 117 118 fnlist_clearnames(&fnl); 119 120 if (!filename[0]) 121 { 122 LOG_F(WARNING, "No .sf2 data found!"); 123 return SF2_SetError(SF2_BankError); 124 } 125 } 126 127 int const loaded = SF2_LoadBank(filename); 128 129 if (filename != SF2_BankFile) 130 Xfree(filename); 131 132 if (loaded != SF2_Ok || !sf2_synth) 133 return SF2_SetError(SF2_BankError); 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 151 void SF2Drv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); } 152 153 void SF2Drv_MIDI_Shutdown(void) 154 { 155 SF2Drv_MIDI_HaltPlayback(); 156 157 tsf_close(sf2_synth); 158 sf2_synth = nullptr; 159 ErrorCode = SF2_Ok; 160 } 161 162 int SF2Drv_MIDI_StartPlayback(void) 163 { 164 SF2Drv_MIDI_HaltPlayback(); 165 166 tsf_set_output(sf2_synth, MV_Channels == 1 ? TSF_MONO : TSF_STEREO_INTERLEAVED, TSF_INTERP_CUBIC, MV_MixRate, 0); 167 tsf_channel_set_bank_preset(sf2_synth, 9, 128, 0); 168 tsf_reset(sf2_synth); 169 170 for (int channel = 0; channel < 16; channel++) 171 SF2_ProgramChange(channel, 0); 172 173 MV_HookMusicRoutine(SF2Drv_MIDI_Service); 174 175 return MIDI_Ok; 176 } 177 178 void SF2Drv_MIDI_SetTempo(int const tempo, int const division) 179 { 180 MV_MIDIRenderTempo = tempo * division / 60; 181 MV_MIDIRenderTimer = 0; 182 } 183 184 void SF2Drv_MIDI_Service(void) 185 { 186 int16_t * buffer16 = (int16_t *)MV_MusicBuffer; 187 static float fbuf[MV_MIXBUFFERSIZE * 2]; 188 float const fvolume = SF2_Volume * (32768.f / MIDI_MaxVolume); 189 190 for (int i = 0; i < MV_MIXBUFFERSIZE;) 191 { 192 while (MV_MIDIRenderTimer >= MV_MixRate) 193 { 194 if (MV_MIDIRenderTempo >= 0) 195 MIDI_ServiceRoutine(); 196 MV_MIDIRenderTimer -= MV_MixRate; 197 } 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 203 int const nsamples = samples * MV_Channels; 204 205 for (int j = 0; j < nsamples; j++) 206 *buffer16++ = clamp((fbuf[j] * fvolume), INT16_MIN, INT16_MAX); 207 208 if (MV_MIDIRenderTempo >= 0) 209 MV_MIDIRenderTimer += MV_MIDIRenderTempo * samples; 210 211 i += samples; 212 } 213 }