1 /* ScummVM - Graphic Adventure Engine
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
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.
25 #include "common/scummsys.h"
29 #include "sound/softsynth/mt32/mt32emu.h"
31 #include "sound/softsynth/emumidi.h"
32 #include "sound/musicplugin.h"
33 #include "sound/mpu401.h"
35 #include "common/config-manager.h"
36 #include "common/debug.h"
37 #include "common/events.h"
38 #include "common/file.h"
39 #include "common/system.h"
40 #include "common/util.h"
42 #include "graphics/fontman.h"
43 #include "graphics/surface.h"
45 class MidiChannel_MT32
: public MidiChannel_MPU401
{
46 void effectLevel(byte value
) { }
47 void chorusLevel(byte value
) { }
50 class MidiDriver_MT32
: public MidiDriver_Emulated
{
52 Audio::SoundHandle _handle
;
53 MidiChannel_MT32 _midiChannels
[16];
55 MT32Emu::Synth
*_synth
;
60 void generateSamples(int16
*buf
, int len
);
65 MidiDriver_MT32(Audio::Mixer
*mixer
);
66 virtual ~MidiDriver_MT32();
71 void setPitchBendRange (byte channel
, uint range
);
72 void sysEx(const byte
*msg
, uint16 length
);
74 uint32
property(int prop
, uint32 param
);
75 MidiChannel
*allocateChannel();
76 MidiChannel
*getPercussionChannel();
79 bool isStereo() const { return true; }
80 int getRate() const { return _outputRate
; }
83 class MT32File
: public MT32Emu::File
{
85 Common::DumpFile _out
;
87 bool open(const char *filename
, OpenMode mode
) {
88 if (mode
== OpenMode_read
)
89 return _in
.open(filename
);
91 return _out
.open(filename
);
97 size_t read(void *in
, size_t size
) {
98 return _in
.read(in
, size
);
100 bool readBit8u(MT32Emu::Bit8u
*in
) {
101 byte b
= _in
.readByte();
107 size_t write(const void *in
, size_t size
) {
108 return _out
.write(in
, size
);
110 bool writeBit8u(MT32Emu::Bit8u out
) {
115 return _in
.isOpen() && _in
.eos();
119 static int eatSystemEvents() {
121 Common::EventManager
*eventMan
= g_system
->getEventManager();
122 while (eventMan
->pollEvent(event
)) {
123 switch (event
.type
) {
124 case Common::EVENT_QUIT
:
133 static void drawProgress(float progress
) {
134 const Graphics::Font
&font(*FontMan
.getFontByUsage(Graphics::FontManager::kOSDFont
));
135 Graphics::Surface surf
;
136 uint32 borderColor
= 0x2;
137 uint32 fillColor
= 0x4;
138 surf
.w
= g_system
->getWidth() / 7 * 5;
139 surf
.h
= font
.getFontHeight();
140 int x
= g_system
->getWidth() / 7;
141 int y
= g_system
->getHeight() / 2 - surf
.h
/ 2;
143 surf
.bytesPerPixel
= 1;
144 surf
.pixels
= calloc(surf
.w
, surf
.h
);
145 Common::Rect
r(surf
.w
, surf
.h
);
146 surf
.frameRect(r
, borderColor
);
148 r
.right
= r
.left
+ (uint16
)(r
.width() * progress
);
149 surf
.fillRect(r
, fillColor
);
150 g_system
->copyRectToScreen((byte
*)surf
.pixels
, surf
.pitch
, x
, y
, surf
.w
, surf
.h
);
151 g_system
->updateScreen();
155 static void drawMessage(int offset
, const Common::String
&text
) {
156 const Graphics::Font
&font(*FontMan
.getFontByUsage(Graphics::FontManager::kOSDFont
));
157 Graphics::Surface surf
;
159 surf
.w
= g_system
->getWidth();
160 surf
.h
= font
.getFontHeight();
162 surf
.bytesPerPixel
= 1;
163 surf
.pixels
= calloc(surf
.w
, surf
.h
);
164 font
.drawString(&surf
, text
, 0, 0, surf
.w
, color
, Graphics::kTextAlignCenter
);
165 int y
= g_system
->getHeight() / 2 - font
.getFontHeight() / 2 + offset
* (font
.getFontHeight() + 1);
166 g_system
->copyRectToScreen((byte
*)surf
.pixels
, surf
.pitch
, 0, y
, surf
.w
, surf
.h
);
167 g_system
->updateScreen();
171 static MT32Emu::File
*MT32_OpenFile(void *userData
, const char *filename
, MT32Emu::File::OpenMode mode
) {
172 MT32File
*file
= new MT32File();
173 if (!file
->open(filename
, mode
)) {
180 static void MT32_PrintDebug(void *userData
, const char *fmt
, va_list list
) {
182 if (((MidiDriver_MT32
*)userData
)->_initialising
) {
183 vsnprintf(buf
, 512, fmt
, list
);
184 buf
[70] = 0; // Truncate to a reasonable length
187 //vdebug(0, fmt, list); // FIXME: Use a higher debug level
190 static int MT32_Report(void *userData
, MT32Emu::ReportType type
, const void *reportData
) {
192 case MT32Emu::ReportType_lcdMessage
:
193 g_system
->displayMessageOnOSD((const char *)reportData
);
195 case MT32Emu::ReportType_errorControlROM
:
196 error("Failed to load MT32_CONTROL.ROM");
198 case MT32Emu::ReportType_errorPCMROM
:
199 error("Failed to load MT32_PCM.ROM");
201 case MT32Emu::ReportType_progressInit
:
202 if (((MidiDriver_MT32
*)userData
)->_initialising
) {
203 drawProgress(*((const float *)reportData
));
204 return eatSystemEvents();
207 case MT32Emu::ReportType_availableSSE
:
208 debug(1, "MT32emu: SSE is available");
210 case MT32Emu::ReportType_usingSSE
:
211 debug(1, "MT32emu: using SSE");
213 case MT32Emu::ReportType_available3DNow
:
214 debug(1, "MT32emu: 3DNow! is available");
216 case MT32Emu::ReportType_using3DNow
:
217 debug(1, "MT32emu: using 3DNow!");
225 ////////////////////////////////////////
229 ////////////////////////////////////////
231 MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer
*mixer
) : MidiDriver_Emulated(mixer
) {
232 _channelMask
= 0xFFFF; // Permit all 16 channels by default
234 for (i
= 0; i
< ARRAYSIZE(_midiChannels
); ++i
) {
235 _midiChannels
[i
].init(this, i
);
238 // A higher baseFreq reduces the length used in generateSamples(),
239 // and means that the timer callback will be called more often.
240 // That results in more accurate timing.
242 // Unfortunately bugs in the emulator cause inaccurate tuning
243 // at rates other than 32KHz, thus we produce data at 32KHz and
244 // rely on Mixer to convert.
245 _outputRate
= 32000; //_mixer->getOutputRate();
246 _initialising
= false;
249 MidiDriver_MT32::~MidiDriver_MT32() {
254 int MidiDriver_MT32::open() {
255 MT32Emu::SynthProperties prop
;
258 return MERR_ALREADY_OPEN
;
260 MidiDriver_Emulated::open();
262 memset(&prop
, 0, sizeof(prop
));
263 prop
.sampleRate
= getRate();
264 prop
.useReverb
= true;
265 prop
.useDefaultReverb
= false;
268 prop
.reverbLevel
= 3;
269 prop
.userData
= this;
270 prop
.printDebug
= MT32_PrintDebug
;
271 prop
.report
= MT32_Report
;
272 prop
.openFile
= MT32_OpenFile
;
273 _synth
= new MT32Emu::Synth();
274 _initialising
= true;
275 const byte dummy_palette
[] = {
283 g_system
->setPalette(dummy_palette
, 0, 5);
284 drawMessage(-1, "Initialising MT-32 Emulator");
285 if (!_synth
->open(prop
))
286 return MERR_DEVICE_NOT_AVAILABLE
;
287 _initialising
= false;
288 g_system
->fillScreen(0);
289 g_system
->updateScreen();
290 _mixer
->playInputStream(Audio::Mixer::kSFXSoundType
, &_handle
, this, -1, 255, 0, false, true);
294 void MidiDriver_MT32::send(uint32 b
) {
298 void MidiDriver_MT32::setPitchBendRange(byte channel
, uint range
) {
300 printf("setPitchBendRange() called with range > 24: %d", range
);
302 byte benderRangeSysex
[9];
303 benderRangeSysex
[0] = 0x41; // Roland
304 benderRangeSysex
[1] = channel
;
305 benderRangeSysex
[2] = 0x16; // MT-32
306 benderRangeSysex
[3] = 0x12; // Write
307 benderRangeSysex
[4] = 0x00;
308 benderRangeSysex
[5] = 0x00;
309 benderRangeSysex
[6] = 0x04;
310 benderRangeSysex
[7] = (byte
)range
;
311 benderRangeSysex
[8] = MT32Emu::Synth::calcSysexChecksum(&benderRangeSysex
[4], 4, 0);
312 sysEx(benderRangeSysex
, 9);
315 void MidiDriver_MT32::sysEx(const byte
*msg
, uint16 length
) {
316 if (msg
[0] == 0xf0) {
317 _synth
->playSysex(msg
, length
);
319 _synth
->playSysexWithoutFraming(msg
, length
);
323 void MidiDriver_MT32::close() {
328 // Detach the player callback handler
329 setTimerCallback(NULL
, NULL
);
330 // Detach the mixer callback handler
331 _mixer
->stopHandle(_handle
);
338 void MidiDriver_MT32::generateSamples(int16
*data
, int len
) {
339 _synth
->render(data
, len
);
342 uint32
MidiDriver_MT32::property(int prop
, uint32 param
) {
344 case PROP_CHANNEL_MASK
:
345 _channelMask
= param
& 0xFFFF;
352 MidiChannel
*MidiDriver_MT32::allocateChannel() {
353 MidiChannel_MT32
*chan
;
356 for (i
= 0; i
< ARRAYSIZE(_midiChannels
); ++i
) {
357 if (i
== 9 || !(_channelMask
& (1 << i
)))
359 chan
= &_midiChannels
[i
];
360 if (chan
->allocate()) {
367 MidiChannel
*MidiDriver_MT32::getPercussionChannel() {
368 return &_midiChannels
[9];
371 // This code should be used when calling the timer callback from the mixer thread is undesirable.
372 // Note that it results in less accurate timing.
374 class MidiEvent_MT32
{
376 MidiEvent_MT32
*_next
;
377 uint32 _msg
; // 0xFFFFFFFF indicates a sysex message
381 MidiEvent_MT32(uint32 msg
, byte
*data
, uint32 len
) {
384 _data
= new byte
[len
];
385 memcpy(_data
, data
, len
);
397 class MidiDriver_ThreadedMT32
: public MidiDriver_MT32
{
399 OSystem::Mutex _eventMutex
;
400 MidiEvent_MT32
*_events
;
401 TimerManager::TimerProc _timer_proc
;
403 void pushMidiEvent(MidiEvent_MT32
*event
);
404 MidiEvent_MT32
*popMidiEvent();
408 void sysEx(const byte
*msg
, uint16 length
);
411 MidiDriver_ThreadedMT32(Audio::Mixer
*mixer
);
415 void setTimerCallback(void *timer_param
, TimerManager::TimerProc timer_proc
);
419 MidiDriver_ThreadedMT32::MidiDriver_ThreadedMT32(Audio::Mixer
*mixer
) : MidiDriver_MT32(mixer
) {
424 void MidiDriver_ThreadedMT32::close() {
425 MidiDriver_MT32::close();
426 while ((popMidiEvent() != NULL
)) {
427 // Just eat any leftover events
431 void MidiDriver_ThreadedMT32::setTimerCallback(void *timer_param
, TimerManager::TimerProc timer_proc
) {
432 if (!_timer_proc
|| !timer_proc
) {
434 _vm
->_timer
->removeTimerProc(_timer_proc
);
435 _timer_proc
= timer_proc
;
437 _vm
->_timer
->installTimerProc(timer_proc
, getBaseTempo(), timer_param
);
441 void MidiDriver_ThreadedMT32::pushMidiEvent(MidiEvent_MT32
*event
) {
442 Common::StackLock
lock(_eventMutex
);
443 if (_events
== NULL
) {
446 MidiEvent_MT32
*last
= _events
;
447 while (last
->_next
!= NULL
)
453 MidiEvent_MT32
*MidiDriver_ThreadedMT32::popMidiEvent() {
454 Common::StackLock
lock(_eventMutex
);
455 MidiEvent_MT32
*event
;
458 _events
= event
->_next
;
462 void MidiDriver_ThreadedMT32::send(uint32 b
) {
463 MidiEvent_MT32
*event
= new MidiEvent_MT32(b
, NULL
, 0);
464 pushMidiEvent(event
);
467 void MidiDriver_ThreadedMT32::sysEx(const byte
*msg
, uint16 length
) {
468 MidiEvent_MT32
*event
= new MidiEvent_MT32(0xFFFFFFFF, msg
, length
);
469 pushMidiEvent(event
);
472 void MidiDriver_ThreadedMT32::onTimer() {
473 MidiEvent_MT32
*event
;
474 while ((event
= popMidiEvent()) != NULL
) {
475 if (event
->_msg
== 0xFFFFFFFF) {
476 MidiDriver_MT32::sysEx(event
->_data
, event
->_len
);
478 MidiDriver_MT32::send(event
->_msg
);
488 class MT32EmuMusicPlugin
: public MusicPluginObject
{
490 const char *getName() const {
491 return "MT-32 Emulator";
494 const char *getId() const {
498 MusicDevices
getDevices() const;
499 Common::Error
createInstance(Audio::Mixer
*mixer
, MidiDriver
**mididriver
) const;
502 MusicDevices
MT32EmuMusicPlugin::getDevices() const {
503 MusicDevices devices
;
504 devices
.push_back(MusicDevice(this, "", MT_MT32
));
508 Common::Error
MT32EmuMusicPlugin::createInstance(Audio::Mixer
*mixer
, MidiDriver
**mididriver
) const {
509 *mididriver
= new MidiDriver_MT32(mixer
);
511 return Common::kNoError
;
514 MidiDriver
*MidiDriver_MT32_create(Audio::Mixer
*mixer
) {
515 // HACK: It will stay here until engine plugin loader overhaul
516 if (ConfMan
.hasKey("extrapath"))
517 Common::File::addDefaultDirectory(ConfMan
.get("extrapath"));
519 MidiDriver
*mididriver
;
521 MT32EmuMusicPlugin p
;
522 p
.createInstance(mixer
, &mididriver
);
527 //#if PLUGIN_ENABLED_DYNAMIC(MT32)
528 //REGISTER_PLUGIN_DYNAMIC(MT32, PLUGIN_TYPE_MUSIC, MT32EmuMusicPlugin);
530 REGISTER_PLUGIN_STATIC(MT32
, PLUGIN_TYPE_MUSIC
, MT32EmuMusicPlugin
);