DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/gui/midi_synth.h
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #include <fluidsynth.h>
00020 #include <math.h>
00021 
00022 /* Protect against multiple inclusions */
00023 #ifndef MIXER_BUFSIZE
00024 #include "mixer.h"
00025 #endif
00026 
00027 static MixerChannel *synthchan = NULL;
00028 static fluid_synth_t *synth_soft = NULL;
00029 static int synthsamplerate = 0;
00030 
00031 static void synth_log(int level, char *message, void *data) {
00032     (void)data;//UNUSED
00033 
00034         switch (level) {
00035         case FLUID_PANIC:
00036         case FLUID_ERR:
00037                 LOG(LOG_ALL,LOG_ERROR)(message);
00038                 break;
00039 
00040         case FLUID_WARN:
00041                 LOG(LOG_ALL,LOG_WARN)(message);
00042                 break;
00043 
00044         default:
00045                 LOG(LOG_ALL,LOG_NORMAL)(message);
00046                 break;
00047         }
00048 }
00049 
00050 static void synth_CallBack(Bitu len) {
00051         if (synth_soft != NULL) {
00052                 fluid_synth_write_s16(synth_soft, len, MixTemp, 0, 2, MixTemp, 1, 2);
00053                 synthchan->AddSamples_s16(len,(Bit16s *)MixTemp);
00054         }
00055 }
00056 
00057 #if defined (WIN32) || defined (OS2)
00058 #       define PATH_SEP "\\"
00059 #else
00060 #       define PATH_SEP "/"
00061 #endif
00062 
00063 class MidiHandler_synth: public MidiHandler {
00064 private:
00065         fluid_settings_t *settings;
00066         int sfont_id;
00067         bool isOpen;
00068 
00069         void PlayEvent(Bit8u *msg, Bitu len) {
00070                 Bit8u event = msg[0], channel, p1, p2;
00071 
00072                 switch (event) {
00073                 case 0xf0:
00074                 case 0xf7:
00075                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: sysex 0x%02x len %lu", (int)event, (long unsigned)len);
00076                         fluid_synth_sysex(synth_soft, (char *)(msg + 1), len - 1, NULL, NULL, NULL, 0);
00077                         return;
00078                 case 0xf9:
00079                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: midi tick");
00080                         return;
00081                 case 0xff:
00082                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: system reset");
00083                         fluid_synth_system_reset(synth_soft);
00084                         return;
00085                 case 0xf1: case 0xf2: case 0xf3: case 0xf4:
00086                 case 0xf5: case 0xf6: case 0xf8: case 0xfa:
00087                 case 0xfb: case 0xfc: case 0xfd: case 0xfe:
00088                         LOG(LOG_MISC,LOG_WARN)("SYNTH: unhandled event 0x%02x", (int)event);
00089                         return;
00090                 }
00091 
00092                 channel = event & 0xf;
00093                 p1 = len > 1 ? msg[1] : 0;
00094                 p2 = len > 2 ? msg[2] : 0;
00095 
00096                 LOG(LOG_MISC,LOG_DEBUG)("SYNTH: event 0x%02x channel %d, 0x%02x 0x%02x",
00097                         (int)event, (int)channel, (int)p1, (int)p2);
00098 
00099                 switch (event & 0xf0) {
00100                 case 0x80:
00101                         fluid_synth_noteoff(synth_soft, channel, p1);
00102                         break;
00103                 case 0x90:
00104                         fluid_synth_noteon(synth_soft, channel, p1, p2);
00105                         break;
00106                 case 0xb0:
00107                         fluid_synth_cc(synth_soft, channel, p1, p2);
00108                         break;
00109                 case 0xc0:
00110                         fluid_synth_program_change(synth_soft, channel, p1);
00111                         break;
00112                 case 0xd0:
00113                         fluid_synth_channel_pressure(synth_soft, channel, p1);
00114                         break;
00115                 case 0xe0:
00116                         fluid_synth_pitch_bend(synth_soft, channel, (p2 << 7) | p1);
00117                         break;
00118                 }
00119         };
00120 
00121 public:
00122         MidiHandler_synth() : MidiHandler(),isOpen(false) {};
00123 
00124         const char * GetName(void) {
00125                 return "synth";
00126         };
00127 
00128         bool Open(const char *conf) {
00129                 if (isOpen) return false;
00130 
00131                 /* Sound font file required */
00132                 if (!conf || (conf[0] == '\0')) {
00133                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: Specify .SF2 sound font file with midiconfig=");
00134                         return false;
00135                 }
00136 
00137                 fluid_set_log_function(FLUID_PANIC, synth_log, NULL);
00138                 fluid_set_log_function(FLUID_ERR, synth_log, NULL);
00139                 fluid_set_log_function(FLUID_WARN, synth_log, NULL);
00140                 fluid_set_log_function(FLUID_INFO, synth_log, NULL);
00141                 fluid_set_log_function(FLUID_DBG, synth_log, NULL);
00142 
00143                 /* Create the settings. */
00144                 settings = new_fluid_settings();
00145                 if (settings == NULL) {
00146                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Error allocating MIDI soft synth settings");
00147                         return false;
00148                 }
00149 
00150                 fluid_settings_setstr(settings, "audio.sample-format", "16bits");
00151                 fluid_settings_setnum(settings, "synth.sample-rate", (double)synthsamplerate);
00152                 //fluid_settings_setnum(settings, "synth.gain", 0.5);
00153 
00154                 /* Create the synthesizer. */
00155                 synth_soft = new_fluid_synth(settings);
00156                 if (synth_soft == NULL) {
00157                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Error initialising MIDI soft synth");
00158                         delete_fluid_settings(settings);
00159                         return false;
00160                 }
00161 
00162                 /* Load a SoundFont */
00163                 sfont_id = fluid_synth_sfload(synth_soft, conf, 0);
00164                 if (sfont_id == -1) {
00165                         extern std::string capturedir;
00166                         std::string str = capturedir + std::string(PATH_SEP) + std::string(conf);
00167                         sfont_id = fluid_synth_sfload(synth_soft, str.c_str(), 0);
00168                 }
00169 
00170                 if (sfont_id == -1) {
00171                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Failed to load MIDI sound font file \"%s\"",
00172                            conf);
00173                         delete_fluid_synth(synth_soft);
00174                         delete_fluid_settings(settings);
00175                         return false;
00176                 }
00177 
00178                 synthchan = MIXER_AddChannel(synth_CallBack, (unsigned int)synthsamplerate, "SYNTH");
00179                 synthchan->Enable(false);
00180                 isOpen = true;
00181                 return true;
00182         };
00183 
00184         void Close(void) {
00185                 if (!isOpen) return;
00186 
00187                 synthchan->Enable(false);
00188                 MIXER_DelChannel(synthchan);
00189                 delete_fluid_synth(synth_soft);
00190                 delete_fluid_settings(settings);
00191 
00192                 synthchan = NULL;
00193                 synth_soft = NULL;
00194                 settings = NULL;
00195                 isOpen = false;
00196         };
00197 
00198         void PlayMsg(Bit8u *msg) {
00199                 synthchan->Enable(true);
00200                 PlayEvent(msg, MIDI_evt_len[*msg]);
00201         };
00202 
00203         void PlaySysex(Bit8u *sysex, Bitu len) {
00204                 PlayEvent(sysex, len);
00205         };
00206 };
00207 
00208 MidiHandler_synth Midi_synth;