Midi.cc

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2000  Dancer A.L Vesperman
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (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 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 #ifdef HAVE_CONFIG_H
00020 #  include <config.h>
00021 #endif
00022 
00023 
00024 #ifndef ALPHA_LINUX_CXX
00025 #ifndef UNDER_CE
00026 #  include <csignal>
00027 #endif
00028 #  include <iostream>
00029 #endif
00030 #include <unistd.h>
00031 
00032 #include "fnames.h"
00033 #include "exult.h"
00034 #include "game.h"
00035 #include "Audio.h"
00036 
00037 #include "../files/U7file.h"
00038 #include "../files/utils.h"
00039 #include "Midi.h"
00040 #include "xmidi.h"
00041 #include "conv.h"
00042 #include "convmusic.h"
00043 
00044 #include "../conf/Configuration.h"
00045 extern  Configuration *config;
00046 
00047 #ifndef UNDER_CE
00048 using std::cerr;
00049 using std::cout;
00050 using std::endl;
00051 using std::string;
00052 using std::strcpy;
00053 #endif
00054 
00055 static Mix_Music *oggmusic;
00056 
00057 
00058 void    MyMidiPlayer::start_track(int num,bool repeat,int bank)
00059 {
00060   if (!midi_device && !init_device())
00061           return;
00062 
00063 
00064   #ifdef DEBUG
00065         cout << "Audio subsystem request: Music track # " << num << endl;
00066   #endif
00067   // -1 and 255 are stop tracks
00068   if (num == -1 || num == 255)
00069   {
00070     stop_music();
00071     return;
00072   }
00073 
00074   current_track = num;
00075   repeating = repeat;
00076 
00077   if (output_driver_type == MIDI_DRIVER_OGG)
00078   {
00079       char filename[255] ;
00080     string s;
00081 
00082     //Free previous music, may not have been properly stopped
00083     if(oggmusic)
00084     {
00085       Mix_FreeMusic(oggmusic);
00086       oggmusic = NULL;
00087     }
00088 
00089     if(Game::get_game_type()==SERPENT_ISLE)
00090     {
00091       if(bank == 2 && num == 28)  //Convert title track number only in SI
00092         num = 70;
00093 
00094       s = midi_bank[bank];
00095       to_uppercase(s);
00096       if((num == 30 || num == 32) && s.find("MAINSHP") != std::string::npos)
00097       {
00098         //Convert credit/quote tracks
00099         if(num == 30)
00100           s = "endcr01.ogg";
00101         else
00102           s = "endcr02.ogg";
00103       }
00104       else
00105       {
00106         s = bgconvmusic[num];
00107         s = s + ".ogg";
00108       }
00109 
00110       s = get_system_path("<MUSIC>/" + s);
00111       strcpy(filename, s.c_str());
00112     }
00113     else
00114     {
00115       char outputstr[255];
00116 
00117       s = midi_bank[bank];
00118       to_uppercase(s);
00119       if((num == 4 || num == 5) && s.find("INTRORDM") != std::string::npos)
00120       {
00121         //Convert credit/quotes tracks
00122         if(num == 4)
00123           s = "endcr01.ogg";
00124         else
00125           s = "endcr02.ogg";
00126       }
00127       else
00128         s = "%02dbg.ogg";
00129 
00130       s = get_system_path("<MUSIC>/" + s);
00131       strcpy(outputstr, s.c_str());
00132       sprintf(filename, outputstr, num);
00133     }
00134 
00135     if(num == 99)   //Play the Exult theme tune
00136     {
00137       s = get_system_path("<MUSIC>/exult.ogg");
00138       strcpy(filename, s.c_str());
00139     }
00140 
00141     if(repeat)
00142       repeat = 2;   //Convert repeats to repeat 2 times only
00143 
00144       oggmusic = Mix_LoadMUS(filename);
00145     if (!oggmusic) {
00146       cout << "Error playing " << filename << ": " << Mix_GetError()
00147          << std::endl;
00148     }
00149 
00150     Mix_PlayMusic(oggmusic, repeat);
00151     Mix_VolumeMusic(MIX_MAX_VOLUME);
00152 
00153 #ifdef DEBUG
00154         cout << "OGG audio: Music track " << filename << endl;
00155 #endif
00156 
00157     return;   //We don't want to continue with Midi conversions!!
00158   }
00159 
00160   // Bank 0 is mainmus, but it's for mt32. If our hardware is an fm synth,
00161   // use the fmsynth music, which is bank 3
00162   if (bank == 0 && midi_device->is_fm_synth()) bank = 3;
00163   // Bank 1 is BG menu/intro. We need Bank 4
00164   else if (bank == 1 && midi_device->is_fm_synth()) bank = 4;
00165   // Bank 2 is SI menu/intro. We need to offset -1
00166   else if (bank == 2 && midi_device->is_fm_synth()) num--;
00167 
00168   U7object  track(midi_bank[bank].c_str(),num);
00169 
00170   char    *buffer;
00171   size_t    size;
00172   DataSource  *mid_data;
00173   
00174   try
00175   {
00176     buffer = track.retrieve(size);
00177   }
00178   catch( const std::exception & /*err*/ )
00179   {
00180     return;
00181   }
00182 
00183   // Read the data into the XMIDI class
00184   mid_data = new BufferDataSource(buffer, size);
00185 
00186   // Play with the conversion type for the FMSynth or MT32EMU drivers
00187   int conv = music_conversion;
00188 
00189   if (midi_device->use_gs127())
00190   //if (midi_device->is_fmsynth())
00191     conv = XMIDI_CONVERT_MT32_TO_GS127;
00192   //else if (midi_device->is_mt32())
00193     //conv = XMIDI_CONVERT_NOCONVERSION;
00194 
00195   XMIDI   midfile(mid_data, conv);
00196   
00197   delete mid_data;
00198   delete [] buffer;
00199 
00200   // Now give the xmidi object to the midi device
00201 
00202   XMIDIEventList *eventlist = midfile.GetEventList(0);
00203   if (eventlist) midi_device->start_track(eventlist, repeat);
00204 
00205 }
00206 
00207 void    MyMidiPlayer::start_track(const char *fname,int num,bool repeat)
00208 {
00209   if (!fname || (!midi_device && !init_device()))
00210           return;
00211 
00212   current_track = -1;
00213   repeating = repeat;
00214 
00215   #ifdef DEBUG
00216         cout << "Audio subsystem request: Music track # " << num << " in file "<< fname << endl;
00217   #endif
00218 
00219   // -1 and 255 are stop tracks
00220   if (num == -1 || num == 255)
00221   {
00222     midi_device->stop_track();
00223     return;
00224   }
00225 
00226   //Only called from the endgame sequences  
00227   if (output_driver_type == MIDI_DRIVER_OGG)
00228   {
00229       char filename[255] ;
00230 
00231     //Free previous music, may not have been properly stopped
00232     if(oggmusic)
00233     {
00234       Mix_FreeMusic(oggmusic);
00235       oggmusic = NULL;
00236     }
00237 
00238     string s = fname;
00239     to_uppercase(s);
00240 
00241     if(s.find("ENDSCORE") != std::string::npos && Game::get_game_type()!=SERPENT_ISLE)
00242     {
00243         sprintf(filename, "end%02dbg.ogg", num);
00244     }
00245     else if(s.find("R_SINTRO") != std::string::npos && Game::get_game_type()==SERPENT_ISLE)
00246       strcpy(filename, "si01.ogg");   //SI introduction sequence
00247     else if(s.find("R_SEND") != std::string::npos && Game::get_game_type()==SERPENT_ISLE)
00248       strcpy(filename, "si13.ogg");   //SI end sequence
00249     else
00250       return;
00251 
00252     string s2 = filename;
00253     s2 = get_system_path("<MUSIC>/" + s2);
00254     strcpy(filename, s2.c_str());
00255 
00256         oggmusic = Mix_LoadMUS(filename);
00257         Mix_PlayMusic(oggmusic, repeat);
00258     Mix_VolumeMusic(MIX_MAX_VOLUME);
00259 
00260     return;   //We don't want to continue with Midi conversions!!
00261   }
00262 
00263 
00264   FILE    *mid_file;
00265   DataSource  *mid_data;
00266   
00267 
00268   // Read the data into the XMIDI class
00269 
00270   mid_file = U7open(fname, "rb");  //DARKE FIXME
00271   mid_data = new FileDataSource(mid_file);
00272 
00273   // Play with the conversion type for the FMSynth or MT32EMU drivers
00274   int conv = music_conversion;
00275 
00276   if (midi_device->use_gs127())
00277   //if (midi_device->is_fmsynth())
00278     conv = XMIDI_CONVERT_MT32_TO_GS127;
00279   //else if (midi_device->is_mt32())
00280     //conv = XMIDI_CONVERT_NOCONVERSION;
00281 
00282   XMIDI   midfile(mid_data, conv);
00283   
00284   delete mid_data;
00285   fclose(mid_file);
00286   
00287   // Now give the xmidi object to the midi device
00288   XMIDIEventList *eventlist = midfile.GetEventList(num);
00289   if (eventlist) midi_device->start_track(eventlist, repeat);
00290 }
00291 
00292 void    MyMidiPlayer::start_track(XMIDIEventList *midfile, bool repeat)
00293 {
00294 
00295   #ifdef DEBUG
00296         cout << "Audio subsystem request: Custom Music track" << endl;
00297   #endif
00298   if (!midi_device && !init_device())
00299           return;
00300   
00301   // Now give the xmidi object to the midi device
00302   midi_device->start_track(midfile, repeat);
00303 }
00304 
00305 void  MyMidiPlayer::start_music(int num,bool repeat,int bank)
00306 {
00307   if(!midi_device && !init_device())
00308     return;
00309   if(current_track==num&&midi_device->is_playing())
00310     return; // Already playing it
00311 
00312   if(num == 0 && bank == 0 && Game::get_game_type() == BLACK_GATE)
00313     return;   //Gets around Usecode bug where track 0 is played at Intro Earthquake
00314 
00315   start_track(num,repeat,bank);
00316 }
00317 
00318 void  MyMidiPlayer::start_music(const char *fname,int num,bool repeat)
00319 {
00320   if(!fname || (!midi_device && !init_device()))
00321     return;
00322   start_track(fname,num,repeat);
00323 }
00324 
00325 void  MyMidiPlayer::stop_music()
00326 {
00327   if(!midi_device && !init_device())
00328     return;
00329 
00330   current_track = -1;
00331   repeating = false;
00332   
00333   midi_device->stop_track();
00334 }
00335 
00336 bool  MyMidiPlayer::add_midi_bank(const char *bankname)
00337 {
00338   string  bank(bankname);
00339   midi_bank.push_back(bank);
00340   return true;
00341 }
00342 
00343 
00344 #if HAVE_TIMIDITY_BIN
00345   #include "midi_drivers/Timidity_binary.h"
00346 #endif
00347 #if HAVE_LIBKMIDI
00348   #include "midi_drivers/KMIDI.h"
00349 #endif
00350 #if !defined(MACOS) && !defined(WIN32)
00351   #include "midi_drivers/forked_player.h"
00352 #endif
00353 #ifdef USE_FMOPL_MIDI
00354   #include "midi_drivers/fmopl_midi.h"
00355 #endif
00356 #ifdef WIN32
00357   #include "midi_drivers/win_midiout.h"
00358 #endif
00359 #ifdef BEOS
00360   #include "midi_drivers/be_midi.h"
00361 #endif
00362 #if defined(MACOS) || defined(MACOSX)
00363   #include "midi_drivers/mac_midi.h"
00364 #endif
00365 #if defined( __MORPHOS__ ) || defined( AMIGA )
00366   #include "midi_drivers/amiga_midi.h"
00367 #endif
00368 
00369 #define TRY_MIDI_DRIVER(CLASS_NAME) do { \
00370   if(no_device) { \
00371     try { \
00372       midi_device=new CLASS_NAME(); \
00373       no_device=false;  \
00374       cout << "Music player: " << midi_device->copyright() << endl; \
00375     } catch(...) {  \
00376       no_device=true; \
00377     } \
00378   } \
00379 } while(0)
00380   
00381 void MyMidiPlayer::set_music_conversion(int conv)
00382 {
00383   music_conversion = conv;
00384   
00385   switch(music_conversion) {
00386   case XMIDI_CONVERT_MT32_TO_GS:
00387     config->set("config/audio/midi/convert","gs",true);
00388     break;
00389   case XMIDI_CONVERT_NOCONVERSION:
00390     config->set("config/audio/midi/convert","none",true);
00391     break;
00392   case XMIDI_CONVERT_MT32_TO_GS127:
00393     config->set("config/audio/midi/convert","gs127",true);
00394     break;
00395   default:
00396     config->set("config/audio/midi/convert","gm",true);
00397     break;
00398   }
00399 }
00400 
00401 void MyMidiPlayer::set_effects_conversion(int conv)
00402 {
00403   effects_conversion = conv;
00404   
00405   switch(effects_conversion) {
00406   case XMIDI_CONVERT_NOCONVERSION:
00407     config->set("config/audio/effects/convert","none",true);
00408     break;
00409   default:
00410     config->set("config/audio/effects/convert","gs",true);
00411     break;
00412   }
00413 }
00414 
00415 void MyMidiPlayer::set_output_driver_type(int type)
00416 {
00417   // Don't kill the device if we don't need to
00418   if (type != output_driver_type) {
00419     stop_music();
00420     delete midi_device;
00421     midi_device = 0;
00422     initialized = false;
00423   }
00424 
00425   output_driver_type = type;
00426 
00427   switch(output_driver_type) {
00428   case MIDI_DRIVER_OGG:
00429     config->set("config/audio/midi/driver","digital",true);
00430     break;
00431 #ifdef USE_FMOPL_MIDI
00432   case MIDI_DRIVER_FMSYNTH:
00433     config->set("config/audio/midi/driver","fmsynth",true);
00434     break;
00435 #endif
00436 #ifdef USE_MT32EMU_MIDI
00437   case MIDI_DRIVER_MT32EMU:
00438     config->set("config/audio/midi/driver","mt32emu",true);
00439     break;
00440 #endif
00441   default:
00442     config->set("config/audio/midi/driver","normal",true);
00443     break;
00444   };
00445 }
00446 
00447 
00448 bool MyMidiPlayer::init_device(void)
00449 {
00450   // already initialized? Do this first
00451   if (initialized) return (midi_device != 0);
00452 
00453   bool  no_device=true;
00454 
00455   // instrument_patches=AccessTableFile(XMIDI_MT);
00456   string  s;
00457 
00458   bool sfx = Audio::get_ptr()->are_effects_enabled();
00459 
00460   if (!sfx) s = "no";
00461   else s = "yes";
00462 
00463   config->set("config/audio/effects/enabled",s,true);
00464 
00465   bool music = Audio::get_ptr()->is_music_enabled();
00466 
00467   if (!music) s = "no";
00468   else s = "yes";
00469 
00470   // Global Midi Enable/Disable
00471   config->set("config/audio/midi/enabled",s,true);
00472 
00473   // String for default value for driver type
00474   std::string driver_default = "normal";
00475 
00476   // Music conversion
00477   config->value("config/audio/midi/convert",s,"gm");
00478 
00479   if (s == "gs")
00480     music_conversion = XMIDI_CONVERT_MT32_TO_GS;
00481   else if (s == "none")
00482     music_conversion = XMIDI_CONVERT_NOCONVERSION;
00483   else if (s == "gs127")
00484     music_conversion = XMIDI_CONVERT_MT32_TO_GS127;
00485   else if (s == "gs127drum")
00486   {
00487     music_conversion = XMIDI_CONVERT_MT32_TO_GS;
00488     config->set("config/audio/midi/convert","gs",true);
00489   }
00490   else
00491   {
00492     music_conversion = XMIDI_CONVERT_MT32_TO_GM;
00493     config->set("config/audio/midi/convert","gm",true);
00494     driver_default = s;
00495   }
00496 
00497   // Effects conversion
00498   config->value("config/audio/effects/convert",s,"gs");
00499 
00500   if (s == "none")
00501     effects_conversion = XMIDI_CONVERT_NOCONVERSION;
00502   else if (s == "gs127")
00503     effects_conversion = XMIDI_CONVERT_NOCONVERSION;
00504   else
00505   {
00506     effects_conversion = XMIDI_CONVERT_GS127_TO_GS;
00507     config->set("config/audio/effects/convert","gs",true);
00508   }
00509 
00510   // Midi driver type.
00511   config->value("config/audio/midi/driver",s,driver_default.c_str());
00512 
00513   if (s == "digital")
00514   {
00515     output_driver_type = MIDI_DRIVER_OGG;
00516     config->set("config/audio/effects/driver","digital",true);
00517   }
00518 #ifdef USE_FMOPL_MIDI
00519   else if (s == "fmsynth")
00520   {
00521     output_driver_type = MIDI_DRIVER_FMSYNTH;
00522     config->set("config/audio/effects/driver","fmsynth",true);
00523   }
00524 #endif
00525 #ifdef USE_MT32EMU_MIDI
00526   else if (s == "mt32emu")
00527   {
00528     output_driver_type = MIDI_DRIVER_MT32EMU;
00529   }
00530 #endif
00531   else
00532   {
00533     output_driver_type = MIDI_DRIVER_NORMAL;
00534     config->set("config/audio/effects/driver","normal",true);
00535   }
00536 
00537   // no need for a MIDI device (for now)
00538   if (!sfx && !music)
00539   {
00540     midi_device = 0;
00541     return false;
00542   }
00543 
00544 
00545   // OGG is handled differently to the other MIDI devices, due to it
00546   // not actually being a midi device. There are hacks all over the place 
00547   // for it. The OGG_MIDI driver does do some 'stuff', such as init
00548   if (output_driver_type == MIDI_DRIVER_OGG)
00549     TRY_MIDI_DRIVER(OGG_MIDI);
00550 #ifdef USE_FMOPL_MIDI
00551   else if (output_driver_type == MIDI_DRIVER_FMSYNTH)
00552     TRY_MIDI_DRIVER(FMOpl_Midi);
00553 #endif
00554 
00555 #if defined(WIN32) && !defined(UNDER_CE)
00556   TRY_MIDI_DRIVER(Windows_MidiOut);
00557 #endif
00558 #ifdef BEOS
00559   TRY_MIDI_DRIVER(Be_midi);
00560 #endif
00561 #if defined(HAVE_TIMIDITY_BIN) && (defined(XWIN) || defined(WIN32))
00562   TRY_MIDI_DRIVER(Timidity_binary);
00563 #endif
00564 #if HAVE_LIBKMIDI
00565   TRY_MIDI_DRIVER(KMIDI);
00566 #endif
00567 #if (defined(XWIN) && !defined(OPENBSD) && !defined(__zaurus__))
00568   TRY_MIDI_DRIVER(forked_player);
00569 #endif
00570 #if defined(MACOS) || defined(MACOSX)
00571   TRY_MIDI_DRIVER(Mac_QT_midi);
00572 #endif
00573 #if defined(__MORPHOS__) || defined(AMIGA)
00574   TRY_MIDI_DRIVER(AmigaMIDI);
00575 #endif
00576 #ifdef USE_FMOPL_MIDI
00577   TRY_MIDI_DRIVER(FMOpl_Midi);
00578 #endif
00579 
00580   initialized = true;
00581 
00582   if(no_device)
00583   {
00584     midi_device=0;
00585     cerr << "Unable to create a MIDI device. No music will be played." << endl;
00586     return false;
00587   }
00588 
00589   load_patches(false);
00590     
00591   return true;
00592 }
00593 
00594 
00595 MyMidiPlayer::MyMidiPlayer()  : current_track(-1),repeating(false),
00596           midi_device(0), initialized(false),
00597           music_conversion(XMIDI_CONVERT_MT32_TO_GM),
00598           effects_conversion(XMIDI_CONVERT_GS127_TO_GS),
00599           output_driver_type(MIDI_DRIVER_NORMAL)
00600 {
00601   add_midi_bank(MAINMUS);
00602   add_midi_bank(INTROMUS);
00603   add_midi_bank("<STATIC>/mainshp.flx");
00604   add_midi_bank(MAINMUS_AD);
00605   add_midi_bank(INTROMUS_AD);
00606   
00607   init_device();
00608 }
00609 
00610 MyMidiPlayer::~MyMidiPlayer()
00611 {
00612   if(midi_device)//&&midi_device->is_playing())
00613     //midi_device->stop_track();
00614     delete midi_device;
00615 }
00616 
00617 
00618 void    MyMidiPlayer::start_sound_effect(int num)
00619 {
00620 #ifdef DEBUG
00621   cout << "Audio subsystem request: sound effect # " << num << endl;
00622 #endif
00623 
00624   int real_num = num;
00625 
00626   if (Game::get_game_type() == BLACK_GATE) real_num = bgconv[num];
00627 
00628   cout << "Real num " << real_num << endl;
00629 
00630   U7object  track("<DATA>/midisfx.flx",real_num);
00631 
00632   if (!midi_device && !init_device())
00633           return;
00634   
00635   char    *buffer;
00636   size_t    size;
00637   DataSource  *mid_data;
00638   
00639   try
00640   {
00641     buffer = track.retrieve(size);
00642   }
00643   catch( const std::exception & /*err*/ )
00644   {
00645     return;
00646   }
00647 
00648   // Read the data into the XMIDI class
00649   mid_data = new BufferDataSource(buffer, size);
00650 
00651   // It's already GM, so dont convert
00652   XMIDI   midfile(mid_data, effects_conversion);
00653   
00654   delete mid_data;
00655   delete [] buffer;
00656 
00657   // Now give the xmidi object to the midi device
00658   XMIDIEventList *eventlist = midfile.GetEventList(0);
00659   if (eventlist) midi_device->start_sfx(eventlist);
00660   
00661 }
00662 
00663 void    MyMidiPlayer::stop_sound_effects()
00664 {
00665   if (midi_device)
00666     midi_device->stop_sfx();
00667 }
00668 
00669 OGG_MIDI::OGG_MIDI()
00670 {
00671   oggmusic = NULL;
00672   Mix_HookMusicFinished(music_complete_callback);
00673   Mix_VolumeMusic(MIX_MAX_VOLUME);
00674 }
00675 
00676 OGG_MIDI::~OGG_MIDI()
00677 {
00678   Mix_HaltMusic();
00679   if(oggmusic)
00680   {
00681     Mix_FreeMusic(oggmusic);
00682     oggmusic = NULL;
00683   }
00684 }
00685 
00686 //Clean up last track played, freeing memory each time
00687 void OGG_MIDI::music_complete_callback(void)
00688 {
00689   if(oggmusic)
00690   {
00691     Mix_FreeMusic(oggmusic);
00692     oggmusic = NULL;
00693   }
00694 }
00695 
00696 void OGG_MIDI::start_track(XMIDIEventList *, bool repeat)
00697 {
00698 }
00699 
00700 void OGG_MIDI::stop_track(void)
00701 {
00702   Mix_HaltMusic();
00703   if(oggmusic)
00704   {
00705     Mix_FreeMusic(oggmusic);
00706     oggmusic = NULL;
00707   }
00708 }
00709 
00710 bool OGG_MIDI::is_playing(void)
00711 {
00712   return Mix_PlayingMusic()!=0;
00713 }
00714 
00715 const char * OGG_MIDI::copyright(void)
00716 {
00717   return "Internal OGG digital music player";
00718 }
00719 
00720 

Generated on Mon Jul 9 14:42:40 2007 for ExultEngine by  doxygen 1.5.1