00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022
00023 #ifdef USE_FMOPL_MIDI
00024
00025 #include <string>
00026
00027 #include "Audio.h"
00028 #include "fmopl_midi.h"
00029 #include "fmopldrv.h"
00030 #include "xmidi.h"
00031 #include "utils.h"
00032 #include "Configuration.h"
00033 #include "SDL_mixer.h"
00034
00035 extern Configuration *config;
00036
00037 #define FMOPL_MESSAGE_NO_MESSAGE 0
00038 #define FMOPL_MESSAGE_PLAY 1
00039 #define FMOPL_MESSAGE_PLAY_REPEAT 2
00040 #define FMOPL_MESSAGE_STOP 3
00041 #define FMOPL_MESSAGE_INIT 4
00042
00043 const unsigned short FMOpl_Midi::centre_value = 0x2000;
00044 const unsigned char FMOpl_Midi::fine_value = centre_value & 127;
00045 const unsigned char FMOpl_Midi::coarse_value = centre_value >> 7;
00046 const unsigned short FMOpl_Midi::combined_value = (coarse_value << 8) | fine_value;
00047
00048
00049
00050 #ifdef DO_SMP_TEST
00051 #define giveinfo() std::cerr << __FILE__ << ":" << __LINE__ << std::endl; std::cerr.flush();
00052 #else
00053 #define giveinfo()
00054 #endif
00055
00056 using std::string;
00057 using std::cout;
00058 using std::cerr;
00059 using std::endl;
00060
00061 class RingBuffer16
00062 {
00063 uint32 write_pos;
00064 uint32 read_pos;
00065 sint16 *buf;
00066 uint32 size;
00067 SDL_mutex *mutex;
00068
00069 public:
00070 void LockWrite(uint32 total, sint16 *&buf1, uint32 &size1, sint16 *&buf2, uint32 &size2);
00071 void LockRead(uint32 total, sint16 *&buf1, uint32 &size1, sint16 *&buf2, uint32 &size2);
00072 void Unlock();
00073
00074 RingBuffer16(uint32 s);
00075 ~RingBuffer16();
00076 };
00077
00078 RingBuffer16::RingBuffer16(uint32 s) : write_pos(0), read_pos(0), size(s)
00079 {
00080 buf = new sint16[size];
00081 std::memset(buf, 0, sizeof(sint16)*size);
00082 mutex = SDL_CreateMutex();
00083 }
00084
00085 RingBuffer16::~RingBuffer16()
00086 {
00087 SDL_DestroyMutex(mutex);
00088 delete [] buf;
00089 }
00090
00091 void RingBuffer16::Unlock()
00092 {
00093
00094 SDL_mutexV(mutex);
00095 }
00096
00097 void RingBuffer16::LockRead(uint32 total, sint16 *&buf1, uint32 &size1, sint16 *&buf2, uint32 &size2)
00098 {
00099
00100 SDL_mutexP(mutex);
00101
00102
00103 if (size < total) {
00104 size1 = 0;
00105 buf1 = 0;
00106 size2 = 0;
00107 buf2 = 0;
00108 return;
00109 }
00110
00111
00112 if (read_pos + total >= size) {
00113
00114
00115 buf1 = buf + read_pos;
00116 size1 = size - read_pos;
00117
00118
00119 read_pos += total;
00120 read_pos -= size;
00121
00122
00123 buf2 = buf;
00124 size2 = read_pos;
00125
00126 return;
00127 }
00128
00129
00130 buf1 = buf + read_pos;
00131 size1 = total;
00132 buf2 = 0;
00133 size2 = 0;
00134 read_pos += total;
00135
00136 }
00137
00138 void RingBuffer16::LockWrite(uint32 total, sint16 *&buf1, uint32 &size1, sint16 *&buf2, uint32 &size2)
00139 {
00140
00141 SDL_mutexP(mutex);
00142
00143
00144 if (size < total) {
00145 size1 = 0;
00146 buf1 = 0;
00147 size2 = 0;
00148 buf2 = 0;
00149 return;
00150 }
00151
00152
00153 if (write_pos + total >= size) {
00154
00155
00156 buf1 = buf + write_pos;
00157 size1 = size - write_pos;
00158
00159
00160 write_pos += total;
00161 write_pos -= size;
00162
00163
00164 buf2 = buf;
00165 size2 = write_pos;
00166
00167 return;
00168 }
00169
00170
00171 buf1 = buf + write_pos;
00172 size1 = total;
00173 buf2 = 0;
00174 size2 = 0;
00175 write_pos += total;
00176 }
00177
00178 FMOpl_Midi::FMOpl_Midi()
00179 {
00180 giveinfo();
00181 playing = false;
00182 is_available = false;
00183 giveinfo();
00184 init_device();
00185 giveinfo();
00186 }
00187
00188 FMOpl_Midi::~FMOpl_Midi()
00189 {
00190 giveinfo();
00191 if (!is_available) return;
00192
00193 deinit_device();
00194 }
00195
00196 void FMOpl_Midi::deinit_device()
00197 {
00198
00199 is_available = false;
00200 Mix_HookMusic (NULL, NULL);
00201 #ifdef PENTAGRAM
00202 Mix_CloseAudio();
00203 #endif
00204
00205
00206 SDL_Delay(10);
00207
00208
00209 SDL_mutexP(mutex);
00210
00211
00212 if (evntlist) evntlist->DecerementCounter();
00213 evntlist = NULL;
00214
00215
00216 if (new_list) new_list->DecerementCounter();
00217 new_list = NULL;
00218 comMessage_priv = FMOPL_MESSAGE_NO_MESSAGE;
00219
00220
00221 repeat = false;
00222 aim = 0;
00223 diff = 0;
00224 last_tick = 0;
00225 evntlist = NULL;
00226 event = NULL;
00227 notes_on.clear();
00228 loop_num = -1;
00229 std::memset(volumes, 64, sizeof(volumes));
00230 std::memset(balances, 64, sizeof(balances));
00231 generate_rem = 0;
00232 total_sample_ticks = 0;
00233
00234
00235 delete opl;
00236 opl = 0;
00237 delete buffer;
00238 buffer = 0;
00239
00240
00241 delete opl_right;
00242 opl_right = 0;
00243 delete buffer_right;
00244 buffer_right = 0;
00245
00246
00247 SDL_mutexV(mutex);
00248
00249
00250 SDL_DestroyMutex(mutex);
00251 SDL_DestroyMutex(comMutex);
00252 mutex = NULL;
00253 comMutex = NULL;
00254 }
00255
00256 void FMOpl_Midi::init_device()
00257 {
00258 string s;
00259
00260 Audio *audio = Audio::get_ptr();
00261
00262
00263 if (audio->is_stereo())
00264 {
00265 config->value("config/audio/midi/dual_opl",s,"yes");
00266 if (s == "yes") dual = true;
00267 else {
00268 s = "no";
00269 dual = false;
00270 }
00271
00272 std::cout << "Dual OPL mode: " << s << endl;
00273
00274
00275 config->set("config/audio/midi/dual_opl",s,true);
00276 }
00277 else
00278 {
00279 dual = false;
00280 }
00281
00282
00283 playing = false;
00284 generate_rem = 0;
00285 is_available = true;
00286 comMessage_priv = FMOPL_MESSAGE_NO_MESSAGE;
00287 new_list = NULL;
00288
00289
00290 buffer = new RingBuffer16(44096);
00291 opl = new OplDriver;
00292 opl->open(audio->get_sample_rate());
00293
00294
00295 if (dual) {
00296 buffer_right = new RingBuffer16(44096);
00297 opl_right = new OplDriver;
00298 opl_right->open(audio->get_sample_rate());
00299 }
00300 else {
00301 opl_right = 0;
00302 buffer_right = 0;
00303 }
00304
00305
00306 repeat = false;
00307 aim = 0;
00308 diff = 0;
00309 last_tick = 0;
00310 evntlist = NULL;
00311 event = NULL;
00312 notes_on.clear();
00313 loop_num = -1;
00314 std::memset(volumes, 64, sizeof(volumes));
00315 std::memset(balances, 64, sizeof(balances));
00316
00317 generate_rem = 0;
00318 total_sample_ticks = 0;
00319 global_volume = 255;
00320
00321
00322 mutex = SDL_CreateMutex();
00323 comMutex = SDL_CreateMutex();
00324
00325
00326 #ifdef PENTAGRAM
00327 Mix_OpenAudio(audio->get_sample_rate(), AUDIO_S16SYS, 2, 4096);
00328 #endif
00329 Mix_HookMusic (mixer_hook_static, (void*) this);
00330 }
00331
00332 inline void FMOpl_Midi::send_vol_or_balance(uint32 chan) {
00333
00334
00335 if (!dual) return;
00336
00337 int left = volumes[chan];
00338 int right = volumes[chan];
00339
00340
00341 if (balances[chan] < 64) {
00342 right *= balances[chan];
00343 right >>= 6;
00344 }
00345
00346 else if (balances[chan] > 64) {
00347 left *= 127 - balances[chan];
00348 left >>= 6;
00349 }
00350
00351 opl->send(chan | (MIDI_STATUS_CONTROLLER << 4)|(7 << 8) | (left<<16));
00352 opl_right->send(chan | (MIDI_STATUS_CONTROLLER << 4)|(7 << 8) | (right<<16));
00353 }
00354
00355 inline void FMOpl_Midi::send(uint32 b) {
00356
00357
00358 if (dual && (b&0xFFF0) == ((MIDI_STATUS_CONTROLLER << 4)|(7 << 8)))
00359 {
00360 int chan = b&0xF;
00361 volumes[chan] = (b >> 16) & 0x7F;
00362 send_vol_or_balance(chan);
00363 }
00364
00365 else if (dual && (b&0xFFF0) == ((MIDI_STATUS_CONTROLLER << 4)|(10 << 8)))
00366 {
00367 int chan = b&0xF;
00368 balances[chan] = (b >> 16) & 0x7F;
00369 send_vol_or_balance(chan);
00370 }
00371 else {
00372 opl->send(b);
00373 if (opl_right) opl_right->send(b);
00374 }
00375 }
00376
00377 uint32 FMOpl_Midi::GenerateSamples(uint32 count_required, uint32 sample_rate) {
00378
00379 uint32 amount_generated = 0;
00380
00381 uint32 inc = 1;
00382 uint32 gen = OPL_NUM_SAMPLES_PER_PASS;
00383
00384 if (sample_rate == 44100) gen *= 2;
00385 else if (sample_rate == 11025) inc *= 2;
00386 else if (sample_rate != 22050)
00387 {
00388
00389 inc = 6;
00390 gen = (OPL_TIME_PER_PASS*sample_rate)/(120*OPL_TICK_MULTIPLIER*inc);
00391 }
00392
00393 while (amount_generated < count_required) {
00394
00395 HandleStop();
00396 PlayNotes();
00397 HandlePlay();
00398
00399 GetSamples(gen);
00400 amount_generated += gen;
00401 wmoClockIncTime(inc);
00402 }
00403
00404 return amount_generated - count_required;
00405 }
00406
00407 void FMOpl_Midi::PlayNotes()
00408 {
00409
00410 while (midi_event *note = notes_on.PopTime(wmoGetRealTime()))
00411 send(note->status | (note->data[0] << 8));
00412
00413 while (event)
00414 {
00415 aim = (event->time-last_tick)*OPL_TICK_MULTIPLIER;
00416
00417
00418
00419 diff = aim - wmoGetTime ();
00420
00421 if (diff > 0) break;
00422
00423 last_tick = event->time;
00424 wmoAddOffset(aim);
00425
00426
00427 if ((event->status >> 4) == MIDI_STATUS_CONTROLLER && event->data[0] == XMIDI_CONTROLLER_FOR_LOOP)
00428 {
00429 if (loop_num < XMIDI_MAX_FOR_LOOP_COUNT) loop_num++;
00430
00431 loop_count[loop_num] = event->data[1];
00432 loop_event[loop_num] = event;
00433
00434 }
00435 else if ((event->status >> 4) == MIDI_STATUS_CONTROLLER && event->data[0] == XMIDI_CONTROLLER_NEXT_BREAK)
00436 {
00437 if (loop_num != -1)
00438 {
00439 if (event->data[1] < 64)
00440 {
00441 loop_num--;
00442 }
00443 }
00444 event = NULL;
00445
00446 }
00447 else if ((event->status >> 4) == MIDI_STATUS_CONTROLLER && event->data[0] == XMIDI_CONTROLLER_CALLBACK_TRIG)
00448 {
00449
00450 }
00451 else if (event->status < 0xF0)
00452 {
00453 int type = event->status >> 4;
00454
00455 if ((type != MIDI_STATUS_NOTE_ON || event->data[1]) && type != MIDI_STATUS_NOTE_OFF) {
00456 if (type == MIDI_STATUS_NOTE_ON) {
00457 notes_on.Remove(event);
00458 notes_on.Push (event, event->duration * OPL_TICK_MULTIPLIER + wmoGetStart());
00459 }
00460
00461 send(event->status | (event->data[0] << 8) | (event->data[1] << 16));
00462 }
00463 }
00464
00465 if (event) event = event->next;
00466
00467
00468 int &comMessage = LockComs();
00469
00470 if (!event || comMessage != FMOPL_MESSAGE_NO_MESSAGE)
00471 {
00472 bool clean = !repeat || (comMessage != FMOPL_MESSAGE_NO_MESSAGE) || last_tick == 0;
00473
00474 if (clean)
00475 {
00476 playing = false;
00477 if (comMessage == FMOPL_MESSAGE_STOP)
00478 comMessage = FMOPL_MESSAGE_NO_MESSAGE;
00479
00480
00481 while (midi_event *note = notes_on.Pop())
00482 send(note->status | (note->data[0] << 8));
00483
00484
00485 for (int i = 0; i < 16; i++) reset_channel (i);
00486
00487 if (evntlist) evntlist->DecerementCounter();
00488 evntlist = NULL;
00489 event = NULL;
00490
00491 loop_num = -1;
00492 wmoInitClock ();
00493 }
00494
00495 last_tick = 0;
00496
00497 if (evntlist)
00498 {
00499 if (loop_num == -1) event = evntlist->events;
00500 else
00501 {
00502 event = loop_event[loop_num]->next;
00503 last_tick = loop_event[loop_num]->time;
00504
00505 if (loop_count[loop_num])
00506 if (!--loop_count[loop_num])
00507 loop_num--;
00508 }
00509 }
00510 }
00511
00512
00513 UnlockComs();
00514 }
00515
00516 }
00517
00518 void FMOpl_Midi::HandlePlay()
00519 {
00520
00521 int &comMessage = LockComs();
00522
00523
00524
00525 if (comMessage == FMOPL_MESSAGE_PLAY || comMessage == FMOPL_MESSAGE_PLAY_REPEAT)
00526 {
00527
00528 while (midi_event *note = notes_on.Pop())
00529 send(note->status | (note->data[0] << 8));
00530
00531
00532 giveinfo();
00533 for (int i = 0; i < 16; i++) reset_channel (i);
00534
00535 if (evntlist) evntlist->DecerementCounter();
00536 evntlist = NULL;
00537 event = NULL;
00538 playing = false;
00539
00540
00541 giveinfo();
00542 evntlist = new_list;
00543 repeat = (comMessage == FMOPL_MESSAGE_PLAY_REPEAT);
00544
00545 giveinfo();
00546 new_list = NULL;
00547 giveinfo();
00548 comMessage = FMOPL_MESSAGE_NO_MESSAGE;
00549
00550 giveinfo();
00551 if (evntlist) event = evntlist->events;
00552 else event = 0;
00553
00554 giveinfo();
00555 last_tick = 0;
00556
00557 giveinfo();
00558 wmoInitClock ();
00559
00560
00561 loop_num = -1;
00562
00563 giveinfo();
00564 playing = true;
00565 }
00566
00567
00568 UnlockComs();
00569 }
00570
00571 void FMOpl_Midi::HandleStop()
00572 {
00573
00574 int &comMessage = LockComs();
00575
00576 if (comMessage == FMOPL_MESSAGE_STOP)
00577 {
00578 giveinfo();
00579 playing = false;
00580 comMessage = FMOPL_MESSAGE_NO_MESSAGE;
00581
00582
00583 while (midi_event *note = notes_on.Pop())
00584 send(note->status | (note->data[0] << 8));
00585
00586 giveinfo();
00587
00588 for (int i = 0; i < 16; i++) reset_channel (i);
00589
00590 giveinfo();
00591 if (evntlist) evntlist->DecerementCounter();
00592 giveinfo();
00593 evntlist = NULL;
00594 event = NULL;
00595 giveinfo();
00596
00597
00598
00599 loop_num = -1;
00600
00601 wmoInitClock ();
00602 last_tick = 0;
00603 }
00604
00605
00606 UnlockComs();
00607 }
00608
00609 void FMOpl_Midi::reset_channel (int i)
00610 {
00611
00612 send(i | (MIDI_STATUS_CONTROLLER << 4) | (0 << 8) | (127 << 16));
00613
00614
00615 send(i | (MIDI_STATUS_CONTROLLER << 4) | (1 << 8) | (coarse_value << 16));
00616
00617
00618 send(i | (MIDI_STATUS_CONTROLLER << 4) | (7 << 8) | (coarse_value << 16));
00619
00620
00621 send(i | (MIDI_STATUS_CONTROLLER << 4) | (10 << 8) | (coarse_value << 16));
00622
00623
00624 send(i | (MIDI_STATUS_CONTROLLER << 4) | (11 << 8) | (127 << 16));
00625
00626
00627 send(i | (MIDI_STATUS_CONTROLLER << 4) | (XMIDI_CONTROLLER_BANK_CHANGE << 8) | (0 << 16));
00628
00629
00630 send(i | (MIDI_STATUS_CONTROLLER << 4) | (123 << 8));
00631
00632
00633 send(i | (MIDI_STATUS_PROG_CHANGE << 4) | (0 << 8));
00634
00635
00636 send(i | (MIDI_STATUS_PITCH_WHEEL << 4) | (combined_value << 8));
00637
00638 }
00639
00640
00641 int &FMOpl_Midi::LockComs()
00642 {
00643 SDL_mutexP(comMutex);
00644 return comMessage_priv;
00645 }
00646
00647
00648 void FMOpl_Midi::UnlockComs()
00649 {
00650 SDL_mutexV(comMutex);
00651 }
00652
00653
00654 void FMOpl_Midi::ClearComs()
00655 {
00656 comMessage_priv = FMOPL_MESSAGE_NO_MESSAGE;
00657
00658
00659 if (new_list) new_list->DecerementCounter();
00660 new_list = NULL;
00661 }
00662
00663 void FMOpl_Midi::start_track (XMIDIEventList *xmidi, bool repeat)
00664 {
00665 giveinfo();
00666 if (!is_available)
00667 init_device();
00668
00669 giveinfo();
00670 if (!is_available)
00671 return;
00672
00673 giveinfo();
00674
00675
00676 int &comMessage = LockComs();
00677 ClearComs();
00678
00679
00680 giveinfo();
00681 xmidi->IncerementCounter();
00682 new_list = xmidi;
00683
00684
00685 if (repeat) comMessage = FMOPL_MESSAGE_PLAY_REPEAT;
00686 else comMessage = FMOPL_MESSAGE_PLAY;
00687
00688
00689 UnlockComs();
00690 }
00691
00692 void FMOpl_Midi::stop_track(void)
00693 {
00694 giveinfo();
00695 if (!is_available) return;
00696
00697 giveinfo();
00698
00699
00700 int &comMessage = LockComs();
00701 ClearComs();
00702
00703
00704 if (playing) comMessage = FMOPL_MESSAGE_STOP;
00705
00706
00707 UnlockComs();
00708 }
00709
00710 bool FMOpl_Midi::is_playing(void)
00711 {
00712 giveinfo();
00713
00714 int &comMessage = LockComs();
00715
00716
00717
00718 bool ret = playing && comMessage != FMOPL_MESSAGE_STOP;
00719
00720 UnlockComs();
00721
00722 return ret;
00723 }
00724
00725 const char *FMOpl_Midi::copyright(void)
00726 {
00727 giveinfo();
00728 return "Internal Emulated FM Opl Midi Synth.";
00729 }
00730
00731 void FMOpl_Midi::mixer_hook_static(void *udata, Uint8 *stream, int len)
00732 {
00733 ((FMOpl_Midi *)udata)->mixer_hook(stream, len);
00734 }
00735
00736 void FMOpl_Midi::mixer_hook(Uint8 *stream, int len)
00737 {
00738
00739 SDL_mutexP(mutex);
00740
00741
00742 if (!is_available) return;
00743
00744 Audio *audio = Audio::get_ptr();
00745
00746
00747 if (audio->is_stereo())
00748 generate_rem = GenerateSamples(len/4-generate_rem, audio->get_sample_rate());
00749 else
00750 generate_rem = GenerateSamples(len/2-generate_rem, audio->get_sample_rate());
00751
00752
00753 sint16* stream16 = (sint16*) stream;
00754
00755 sint16* b1 = 0;
00756 sint16* b2 = 0;
00757 uint32 size1 = 0;
00758 uint32 size2 = 0;
00759 int i = 0;
00760
00761
00762 if (audio->is_stereo())
00763 buffer->LockRead(len/4, b1, size1, b2, size2);
00764 else
00765 buffer->LockRead(len/2, b1, size1, b2, size2);
00766
00767 sint16* b1_r = b1;
00768 sint16* b2_r = b2;
00769 uint32 size1_r = size1;
00770 uint32 size2_r = size2;
00771
00772
00773 if (dual) buffer_right->LockRead(len/4, b1_r, size1_r, b2_r, size2_r);
00774
00775
00776 if (global_volume >= 255) {
00777
00778 if (audio->is_stereo()) {
00779
00780 for (i = 0; i < size1; ++i) {
00781 stream16[i<<1] = b1[i];
00782 stream16[(i<<1)+1] = b1_r[i];
00783 }
00784
00785 for (i = 0; i < size2; ++i) {
00786 stream16[(i+size1)<<1] = b2[i];
00787 stream16[((i+size1)<<1)+1] = b2_r[i];
00788 }
00789 }
00790 else {
00791
00792 for (i = 0; i < size1; ++i) {
00793 stream16[i] = b1[i];
00794 }
00795
00796 for (i = 0; i < size2; ++i) {
00797 stream16[i+size1] = b2[i];
00798 }
00799 }
00800 }
00801 else if (global_volume && dual) {
00802 for (i = 0; i < size1; ++i) {
00803 stream16[i<<1] = (b1[i]*global_volume)/255;
00804 stream16[(i<<1)+1] = (b1_r[i]*global_volume)/255;
00805 }
00806
00807 for (i = 0; i < size2; ++i) {
00808 stream16[(i+size1)<<1] = (b2[i]*global_volume)/255;
00809 stream16[((i+size1)<<1)+1] = (b2_r[i]*global_volume)/255;
00810 }
00811 }
00812 else if (global_volume) {
00813 if (audio->is_stereo()) {
00814
00815 for (i = 0; i < size1; ++i) {
00816 stream16[(i<<1)+1] = stream16[i<<1] = (b1[i]*global_volume)/255;
00817 }
00818
00819 for (i = 0; i < size2; ++i) {
00820 stream16[((i+size1)<<1)+1] = stream16[(i+size1)<<1] = (b2[i]*global_volume)/255;
00821 }
00822 }
00823 else {
00824
00825 for (i = 0; i < size1; ++i) {
00826 stream16[i] = (b1[i]*global_volume)/255;
00827 }
00828
00829 for (i = 0; i < size2; ++i) {
00830 stream16[i+size1] = (b2[i]*global_volume)/255;
00831 }
00832 }
00833 }
00834
00835
00836 if (dual) buffer_right->Unlock();
00837
00838
00839 buffer->Unlock();
00840
00841
00842 SDL_mutexV(mutex);
00843
00844 }
00845
00846 void FMOpl_Midi::GetSamples(uint32 samples)
00847 {
00848
00849 if (samples) {
00850
00851
00852 sint16* b1 = 0;
00853 sint16* b2 = 0;
00854 uint32 size1 = 0;
00855 uint32 size2 = 0;
00856
00857
00858 buffer->LockWrite(samples, b1, size1, b2, size2);
00859
00860
00861
00862 if (size1 && b1) opl->generate_samples(b1, size1);
00863 if (size2 && b2) opl->generate_samples(b2, size2);
00864
00865 if (dual) {
00866
00867 buffer_right->LockWrite(samples, b1, size1, b2, size2);
00868
00869 if (size1 && b1) opl_right->generate_samples(b1, size1);
00870 if (size2 && b2) opl_right->generate_samples(b2, size2);
00871
00872
00873 buffer_right->Unlock();
00874 }
00875
00876
00877 buffer->Unlock();
00878
00879 }
00880 }
00881
00882 void FMOpl_Midi::load_patches(bool force_xmidi)
00883 {
00884
00885 SDL_mutexP(mutex);
00886
00887 if (opl) opl->LoadMT32Bank(force_xmidi);
00888 if (opl_right) opl_right->LoadMT32Bank(force_xmidi);
00889
00890
00891 SDL_mutexV(mutex);
00892 }
00893
00894 bool FMOpl_Midi::is_fm_synth()
00895 {
00896 return true;
00897 }
00898
00899 bool FMOpl_Midi::use_gs127()
00900 {
00901 return true;
00902 }
00903
00904
00905
00906
00907
00908 int FMOpl_Midi::max_streams()
00909 {
00910 return 1;
00911 }
00912
00913 void FMOpl_Midi::start_stream(int str_num, XMIDIEventList *eventlist, bool repeat, bool activate, int vol)
00914 {
00915 stop_track();
00916 set_volume(0, vol);
00917 start_track(eventlist, repeat);
00918 }
00919
00920 void FMOpl_Midi::activate_stream(int str_num)
00921 {
00922
00923 }
00924
00925 void FMOpl_Midi::stop_stream(int str_num)
00926 {
00927 stop_track();
00928 }
00929
00930 void FMOpl_Midi::set_volume(int str_num, int level)
00931 {
00932 if (!is_available) return;
00933
00934
00935 SDL_mutexP(mutex);
00936
00937
00938 global_volume = level;
00939
00940
00941 SDL_mutexV(mutex);
00942 }
00943
00944 bool FMOpl_Midi::is_playing(int str_num)
00945 {
00946 return is_playing();
00947 }
00948
00949 int FMOpl_Midi::get_active()
00950 {
00951 return 0;
00952 }
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010 #endif //USE_FMOPL_MIDI