DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
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,
00032 #if FLUIDSYNTH_VERSION_MAJOR >= 2
00033                       const
00034 #endif
00035                       char *message,
00036                       void *data) {
00037     (void)data;//UNUSED
00038 
00039         switch (level) {
00040         case FLUID_PANIC:
00041         case FLUID_ERR:
00042                 LOG(LOG_ALL,LOG_ERROR)(message);
00043                 break;
00044 
00045         case FLUID_WARN:
00046                 LOG(LOG_ALL,LOG_WARN)(message);
00047                 break;
00048 
00049         default:
00050                 LOG(LOG_ALL,LOG_NORMAL)(message);
00051                 break;
00052         }
00053 }
00054 
00055 static void synth_CallBack(Bitu len) {
00056         if (synth_soft != NULL) {
00057                 fluid_synth_write_s16(synth_soft, len, MixTemp, 0, 2, MixTemp, 1, 2);
00058                 synthchan->AddSamples_s16(len,(Bit16s *)MixTemp);
00059         }
00060 }
00061 
00062 #if defined (WIN32) || defined (OS2)
00063 #       define PATH_SEP "\\"
00064 #else
00065 #       define PATH_SEP "/"
00066 #endif
00067 
00068 class MidiHandler_synth: public MidiHandler {
00069 private:
00070         fluid_settings_t *settings;
00071         int sfont_id;
00072         bool isOpen;
00073 
00074         void PlayEvent(Bit8u *msg, Bitu len) {
00075                 Bit8u event = msg[0], channel, p1, p2;
00076 
00077                 switch (event) {
00078                 case 0xf0:
00079                 case 0xf7:
00080                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: sysex 0x%02x len %lu", (int)event, (long unsigned)len);
00081                         fluid_synth_sysex(synth_soft, (char *)(msg + 1), len - 1, NULL, NULL, NULL, 0);
00082                         return;
00083                 case 0xf9:
00084                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: midi tick");
00085                         return;
00086                 case 0xff:
00087                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: system reset");
00088                         fluid_synth_system_reset(synth_soft);
00089                         return;
00090                 case 0xf1: case 0xf2: case 0xf3: case 0xf4:
00091                 case 0xf5: case 0xf6: case 0xf8: case 0xfa:
00092                 case 0xfb: case 0xfc: case 0xfd: case 0xfe:
00093                         LOG(LOG_MISC,LOG_WARN)("SYNTH: unhandled event 0x%02x", (int)event);
00094                         return;
00095                 }
00096 
00097                 channel = event & 0xf;
00098                 p1 = len > 1 ? msg[1] : 0;
00099                 p2 = len > 2 ? msg[2] : 0;
00100 
00101                 LOG(LOG_MISC,LOG_DEBUG)("SYNTH: event 0x%02x channel %d, 0x%02x 0x%02x",
00102                         (int)event, (int)channel, (int)p1, (int)p2);
00103 
00104                 switch (event & 0xf0) {
00105                 case 0x80:
00106                         fluid_synth_noteoff(synth_soft, channel, p1);
00107                         break;
00108                 case 0x90:
00109                         fluid_synth_noteon(synth_soft, channel, p1, p2);
00110                         break;
00111                 case 0xb0:
00112                         fluid_synth_cc(synth_soft, channel, p1, p2);
00113                         break;
00114                 case 0xc0:
00115                         fluid_synth_program_change(synth_soft, channel, p1);
00116                         break;
00117                 case 0xd0:
00118                         fluid_synth_channel_pressure(synth_soft, channel, p1);
00119                         break;
00120                 case 0xe0:
00121                         fluid_synth_pitch_bend(synth_soft, channel, (p2 << 7) | p1);
00122                         break;
00123                 }
00124         };
00125 
00126 public:
00127         MidiHandler_synth() : MidiHandler(),isOpen(false) {};
00128 
00129         const char * GetName(void) {
00130                 return "synth";
00131         };
00132 
00133         bool Open(const char *conf) {
00134                 if (isOpen) return false;
00135 
00136                 /* Sound font file required */
00137                 if (!conf || (conf[0] == '\0')) {
00138                         LOG(LOG_MISC,LOG_DEBUG)("SYNTH: Specify .SF2 sound font file with midiconfig=");
00139                         return false;
00140                 }
00141 
00142                 fluid_set_log_function(FLUID_PANIC, synth_log, NULL);
00143                 fluid_set_log_function(FLUID_ERR, synth_log, NULL);
00144                 fluid_set_log_function(FLUID_WARN, synth_log, NULL);
00145                 fluid_set_log_function(FLUID_INFO, synth_log, NULL);
00146                 fluid_set_log_function(FLUID_DBG, synth_log, NULL);
00147 
00148                 /* Create the settings. */
00149                 settings = new_fluid_settings();
00150                 if (settings == NULL) {
00151                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Error allocating MIDI soft synth settings");
00152                         return false;
00153                 }
00154 
00155                 fluid_settings_setstr(settings, "audio.sample-format", "16bits");
00156                 fluid_settings_setnum(settings, "synth.sample-rate", (double)synthsamplerate);
00157                 //fluid_settings_setnum(settings, "synth.gain", 0.5);
00158 
00159                 /* Create the synthesizer. */
00160                 synth_soft = new_fluid_synth(settings);
00161                 if (synth_soft == NULL) {
00162                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Error initialising MIDI soft synth");
00163                         delete_fluid_settings(settings);
00164                         return false;
00165                 }
00166 
00167                 /* Load a SoundFont */
00168                 sfont_id = fluid_synth_sfload(synth_soft, conf, 0);
00169                 if (sfont_id == -1) {
00170                         extern std::string capturedir;
00171                         std::string str = capturedir + std::string(PATH_SEP) + std::string(conf);
00172                         sfont_id = fluid_synth_sfload(synth_soft, str.c_str(), 0);
00173                 }
00174 
00175                 if (sfont_id == -1) {
00176                         LOG(LOG_MISC,LOG_WARN)("SYNTH: Failed to load MIDI sound font file \"%s\"",
00177                            conf);
00178                         delete_fluid_synth(synth_soft);
00179                         delete_fluid_settings(settings);
00180                         return false;
00181                 }
00182 
00183                 synthchan = MIXER_AddChannel(synth_CallBack, (unsigned int)synthsamplerate, "SYNTH");
00184                 synthchan->Enable(false);
00185                 isOpen = true;
00186                 return true;
00187         };
00188 
00189         void Close(void) {
00190                 if (!isOpen) return;
00191 
00192                 synthchan->Enable(false);
00193                 MIXER_DelChannel(synthchan);
00194                 delete_fluid_synth(synth_soft);
00195                 delete_fluid_settings(settings);
00196 
00197                 synthchan = NULL;
00198                 synth_soft = NULL;
00199                 settings = NULL;
00200                 isOpen = false;
00201         };
00202 
00203         void PlayMsg(Bit8u *msg) {
00204                 synthchan->Enable(true);
00205                 PlayEvent(msg, MIDI_evt_len[*msg]);
00206         };
00207 
00208         void PlaySysex(Bit8u *sysex, Bitu len) {
00209                 PlayEvent(sysex, len);
00210         };
00211 };
00212 
00213 MidiHandler_synth Midi_synth;