SCI: Add driver for Yamaha FB-01. Cleanup.
svn-id: r47571
This commit is contained in:
parent
d6bb432a92
commit
9861b04b93
16 changed files with 743 additions and 66 deletions
|
@ -61,8 +61,9 @@ MODULE_OBJS := \
|
||||||
sound/iterator/songlib.o \
|
sound/iterator/songlib.o \
|
||||||
sound/drivers/adlib.o \
|
sound/drivers/adlib.o \
|
||||||
sound/drivers/amiga.o \
|
sound/drivers/amiga.o \
|
||||||
sound/drivers/pcjr.o \
|
sound/drivers/fb01.o \
|
||||||
sound/drivers/midi.o \
|
sound/drivers/midi.o \
|
||||||
|
sound/drivers/pcjr.o \
|
||||||
video/seq_decoder.o \
|
video/seq_decoder.o \
|
||||||
video/vmd_decoder.o
|
video/vmd_decoder.o
|
||||||
|
|
||||||
|
|
|
@ -2152,4 +2152,18 @@ int SoundResource::getChannelFilterMask(int hardwareMask, bool wantsRhythm) {
|
||||||
return channelMask;
|
return channelMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte SoundResource::getInitialVoiceCount(byte channel) {
|
||||||
|
byte *data = _innerResource->data;
|
||||||
|
|
||||||
|
if (_soundVersion > SCI_VERSION_0_LATE)
|
||||||
|
return 0; // TODO
|
||||||
|
|
||||||
|
data++; // Skip over digital sample flag
|
||||||
|
|
||||||
|
if (_soundVersion == SCI_VERSION_0_EARLY)
|
||||||
|
return data[channel] >> 4;
|
||||||
|
else
|
||||||
|
return data[channel * 2];
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -475,6 +475,7 @@ public:
|
||||||
Track *getTrackByType(byte type);
|
Track *getTrackByType(byte type);
|
||||||
Track *getDigitalTrack();
|
Track *getDigitalTrack();
|
||||||
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
|
int getChannelFilterMask(int hardwareMask, bool wantsRhythm);
|
||||||
|
byte getInitialVoiceCount(byte channel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SciVersion _soundVersion;
|
SciVersion _soundVersion;
|
||||||
|
|
|
@ -101,6 +101,10 @@ SciEngine::~SciEngine() {
|
||||||
Common::Error SciEngine::run() {
|
Common::Error SciEngine::run() {
|
||||||
// FIXME/TODO: Move some of the stuff below to init()
|
// FIXME/TODO: Move some of the stuff below to init()
|
||||||
|
|
||||||
|
// Assign default values to the config manager, in case settings are missing
|
||||||
|
ConfMan.registerDefault("undither", "true");
|
||||||
|
ConfMan.registerDefault("enable_fb01", "false");
|
||||||
|
|
||||||
_resMan = new ResourceManager();
|
_resMan = new ResourceManager();
|
||||||
|
|
||||||
if (!_resMan) {
|
if (!_resMan) {
|
||||||
|
@ -168,8 +172,6 @@ Common::Error SciEngine::run() {
|
||||||
|
|
||||||
_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
|
_gamestate->_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, soundVersion);
|
||||||
|
|
||||||
// Assign default values to the config manager, in case settings are missing
|
|
||||||
ConfMan.registerDefault("undither", "true");
|
|
||||||
screen->unditherSetState(ConfMan.getBool("undither"));
|
screen->unditherSetState(ConfMan.getBool("undither"));
|
||||||
|
|
||||||
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
||||||
|
|
|
@ -41,8 +41,6 @@ struct ADGameDescription;
|
||||||
*/
|
*/
|
||||||
namespace Sci {
|
namespace Sci {
|
||||||
|
|
||||||
// Uncomment this to include old graphics code
|
|
||||||
//#define INCLUDE_OLDGFX
|
|
||||||
// Uncomment this to use old music functions
|
// Uncomment this to use old music functions
|
||||||
//#define USE_OLD_MUSIC_FUNCTIONS
|
//#define USE_OLD_MUSIC_FUNCTIONS
|
||||||
// Uncomment this to use old pathfinding code
|
// Uncomment this to use old pathfinding code
|
||||||
|
|
|
@ -160,7 +160,7 @@ private:
|
||||||
|
|
||||||
class MidiPlayer_AdLib : public MidiPlayer {
|
class MidiPlayer_AdLib : public MidiPlayer {
|
||||||
public:
|
public:
|
||||||
MidiPlayer_AdLib() { _driver = new MidiDriver_AdLib(g_system->getMixer()); }
|
MidiPlayer_AdLib(SciVersion soundVersion) : MidiPlayer(soundVersion) { _driver = new MidiDriver_AdLib(g_system->getMixer()); }
|
||||||
~MidiPlayer_AdLib() {
|
~MidiPlayer_AdLib() {
|
||||||
delete _driver;
|
delete _driver;
|
||||||
_driver = 0;
|
_driver = 0;
|
||||||
|
@ -169,7 +169,7 @@ public:
|
||||||
int open(ResourceManager *resMan);
|
int open(ResourceManager *resMan);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
byte getPlayId(SciVersion soundVersion);
|
byte getPlayId();
|
||||||
int getPolyphony() const { return MidiDriver_AdLib::kVoices; }
|
int getPolyphony() const { return MidiDriver_AdLib::kVoices; }
|
||||||
bool hasRhythmChannel() const { return false; }
|
bool hasRhythmChannel() const { return false; }
|
||||||
void setVolume(byte volume) { static_cast<MidiDriver_AdLib *>(_driver)->setVolume(volume); }
|
void setVolume(byte volume) { static_cast<MidiDriver_AdLib *>(_driver)->setVolume(volume); }
|
||||||
|
@ -814,7 +814,7 @@ int MidiPlayer_AdLib::open(ResourceManager *resMan) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<MidiDriver_AdLib *>(_driver)->open(getSciVersion() <= SCI_VERSION_0_LATE);
|
return static_cast<MidiDriver_AdLib *>(_driver)->open(_version <= SCI_VERSION_0_LATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MidiPlayer_AdLib::close() {
|
void MidiPlayer_AdLib::close() {
|
||||||
|
@ -823,8 +823,8 @@ void MidiPlayer_AdLib::close() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte MidiPlayer_AdLib::getPlayId(SciVersion soundVersion) {
|
byte MidiPlayer_AdLib::getPlayId() {
|
||||||
switch (soundVersion) {
|
switch (_version) {
|
||||||
case SCI_VERSION_0_EARLY:
|
case SCI_VERSION_0_EARLY:
|
||||||
return 0x01;
|
return 0x01;
|
||||||
case SCI_VERSION_0_LATE:
|
case SCI_VERSION_0_LATE:
|
||||||
|
@ -834,8 +834,8 @@ byte MidiPlayer_AdLib::getPlayId(SciVersion soundVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiPlayer *MidiPlayer_AdLib_create() {
|
MidiPlayer *MidiPlayer_AdLib_create(SciVersion _soundVersion) {
|
||||||
return new MidiPlayer_AdLib();
|
return new MidiPlayer_AdLib(_soundVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -653,8 +653,8 @@ void MidiDriver_Amiga::generateSamples(int16 *data, int len) {
|
||||||
|
|
||||||
class MidiPlayer_Amiga : public MidiPlayer {
|
class MidiPlayer_Amiga : public MidiPlayer {
|
||||||
public:
|
public:
|
||||||
MidiPlayer_Amiga() { _driver = new MidiDriver_Amiga(g_system->getMixer()); }
|
MidiPlayer_Amiga(SciVersion version) : MidiPlayer(version) { _driver = new MidiDriver_Amiga(g_system->getMixer()); }
|
||||||
byte getPlayId(SciVersion soundVersion);
|
byte getPlayId();
|
||||||
int getPolyphony() const { return MidiDriver_Amiga::kVoices; }
|
int getPolyphony() const { return MidiDriver_Amiga::kVoices; }
|
||||||
bool hasRhythmChannel() const { return false; }
|
bool hasRhythmChannel() const { return false; }
|
||||||
void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); }
|
void setVolume(byte volume) { static_cast<MidiDriver_Amiga *>(_driver)->setVolume(volume); }
|
||||||
|
@ -662,12 +662,12 @@ public:
|
||||||
void loadInstrument(int idx, byte *data);
|
void loadInstrument(int idx, byte *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
MidiPlayer *MidiPlayer_Amiga_create() {
|
MidiPlayer *MidiPlayer_Amiga_create(SciVersion version) {
|
||||||
return new MidiPlayer_Amiga();
|
return new MidiPlayer_Amiga(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte MidiPlayer_Amiga::getPlayId(SciVersion soundVersion) {
|
byte MidiPlayer_Amiga::getPlayId() {
|
||||||
if (soundVersion != SCI_VERSION_0_LATE)
|
if (_version != SCI_VERSION_0_LATE)
|
||||||
error("Amiga sound support not available for this SCI version");
|
error("Amiga sound support not available for this SCI version");
|
||||||
|
|
||||||
return 0x40;
|
return 0x40;
|
||||||
|
|
648
engines/sci/sound/drivers/fb01.cpp
Normal file
648
engines/sci/sound/drivers/fb01.cpp
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sci/sci.h"
|
||||||
|
|
||||||
|
#include "sci/resource.h"
|
||||||
|
#include "sci/sound/drivers/mididriver.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
|
||||||
|
static byte volumeTable[64] = {
|
||||||
|
0x00, 0x10, 0x14, 0x18, 0x1f, 0x26, 0x2a, 0x2e,
|
||||||
|
0x2f, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35, 0x36,
|
||||||
|
0x36, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39,
|
||||||
|
0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b,
|
||||||
|
0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
|
||||||
|
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e,
|
||||||
|
0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||||
|
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f
|
||||||
|
};
|
||||||
|
|
||||||
|
class MidiPlayer_Fb01 : public MidiPlayer {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
kVoices = 8,
|
||||||
|
kMaxSysExSize = 264
|
||||||
|
};
|
||||||
|
|
||||||
|
MidiPlayer_Fb01(SciVersion version);
|
||||||
|
virtual ~MidiPlayer_Fb01();
|
||||||
|
|
||||||
|
int open(ResourceManager *resMan);
|
||||||
|
void close();
|
||||||
|
void send(uint32 b);
|
||||||
|
void sysEx(const byte *msg, uint16 length);
|
||||||
|
bool hasRhythmChannel() const { return false; }
|
||||||
|
byte getPlayId();
|
||||||
|
int getPolyphony() const { return kVoices; } // 9 in SCI1?
|
||||||
|
void setVolume(byte volume);
|
||||||
|
int getVolume();
|
||||||
|
void playSwitch(bool play);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void noteOn(int channel, int note, int velocity);
|
||||||
|
void noteOff(int channel, int note);
|
||||||
|
void setPatch(int channel, int patch);
|
||||||
|
void controlChange(int channel, int control, int value);
|
||||||
|
|
||||||
|
void setVoiceParam(byte voice, byte param, byte value);
|
||||||
|
void setSystemParam(byte sysChan, byte param, byte value);
|
||||||
|
void sendVoiceData(byte instrument, const byte *data);
|
||||||
|
void sendBanks(const byte *data, int size);
|
||||||
|
void storeVoiceData(byte instrument, byte bank, byte index);
|
||||||
|
void initVoices();
|
||||||
|
|
||||||
|
void voiceOn(int voice, int note, int velocity);
|
||||||
|
void voiceOff(int voice);
|
||||||
|
int findVoice(int channel);
|
||||||
|
void voiceMapping(int channel, int voices);
|
||||||
|
void assignVoices(int channel, int voices);
|
||||||
|
void releaseVoices(int channel, int voices);
|
||||||
|
void donateVoices();
|
||||||
|
void sendToChannel(byte channel, byte command, byte op1, byte op2);
|
||||||
|
|
||||||
|
struct Channel {
|
||||||
|
uint8 patch; // Patch setting
|
||||||
|
uint8 volume; // Channel volume (0-63)
|
||||||
|
uint8 pan; // Pan setting (0-127, 64 is center)
|
||||||
|
uint8 holdPedal; // Hold pedal setting (0 to 63 is off, 127 to 64 is on)
|
||||||
|
uint8 extraVoices; // The number of additional voices this channel optimally needs
|
||||||
|
uint16 pitchWheel; // Pitch wheel setting (0-16383, 8192 is center)
|
||||||
|
uint8 lastVoice; // Last voice used for this MIDI channel
|
||||||
|
bool enableVelocity; // Enable velocity control (SCI0)
|
||||||
|
|
||||||
|
Channel() : patch(0), volume(127), pan(64), holdPedal(0), extraVoices(0),
|
||||||
|
pitchWheel(8192), lastVoice(0), enableVelocity(false) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Voice {
|
||||||
|
int8 channel; // MIDI channel that this voice is assigned to or -1
|
||||||
|
int8 note; // Currently playing MIDI note or -1
|
||||||
|
int bank; // Current bank setting or -1
|
||||||
|
int patch; // Currently playing patch or -1
|
||||||
|
uint8 velocity; // Note velocity
|
||||||
|
bool isSustained; // Flag indicating a note that is being sustained by the hold pedal
|
||||||
|
uint16 age; // Age of the current note
|
||||||
|
|
||||||
|
Voice() : channel(-1), note(-1), bank(-1), patch(-1), velocity(0), isSustained(false), age(0) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool _playSwitch;
|
||||||
|
int _masterVolume;
|
||||||
|
|
||||||
|
Channel _channels[16];
|
||||||
|
Voice _voices[kVoices];
|
||||||
|
|
||||||
|
Common::TimerManager::TimerProc _timerProc;
|
||||||
|
void *_timerParam;
|
||||||
|
static void midiTimerCallback(void *p);
|
||||||
|
void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
|
||||||
|
|
||||||
|
byte _sysExBuf[kMaxSysExSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
MidiPlayer_Fb01::MidiPlayer_Fb01(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _timerParam(NULL), _timerProc(NULL) {
|
||||||
|
MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
|
||||||
|
_driver = createMidi(midiType);
|
||||||
|
|
||||||
|
_sysExBuf[0] = 0x43;
|
||||||
|
_sysExBuf[1] = 0x75;
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiPlayer_Fb01::~MidiPlayer_Fb01() {
|
||||||
|
delete _driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::voiceMapping(int channel, int voices) {
|
||||||
|
int curVoices = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < kVoices; i++)
|
||||||
|
if (_voices[i].channel == channel)
|
||||||
|
curVoices++;
|
||||||
|
|
||||||
|
curVoices += _channels[channel].extraVoices;
|
||||||
|
|
||||||
|
if (curVoices < voices) {
|
||||||
|
debug(3, "FB-01: assigning %i additional voices to channel %i", voices - curVoices, channel);
|
||||||
|
assignVoices(channel, voices - curVoices);
|
||||||
|
} else if (curVoices > voices) {
|
||||||
|
debug(3, "FB-01: releasing %i voices from channel %i", curVoices - voices, channel);
|
||||||
|
releaseVoices(channel, curVoices - voices);
|
||||||
|
donateVoices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::assignVoices(int channel, int voices) {
|
||||||
|
assert(voices > 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
if (_voices[i].channel == -1) {
|
||||||
|
_voices[i].channel = channel;
|
||||||
|
if (--voices == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_channels[channel].extraVoices += voices;
|
||||||
|
setPatch(channel, _channels[channel].patch);
|
||||||
|
sendToChannel(channel, 0xe0, _channels[channel].pitchWheel & 0x7f, _channels[channel].pitchWheel >> 7);
|
||||||
|
controlChange(channel, 0x07, _channels[channel].volume);
|
||||||
|
controlChange(channel, 0x0a, _channels[channel].pan);
|
||||||
|
controlChange(channel, 0x40, _channels[channel].holdPedal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::releaseVoices(int channel, int voices) {
|
||||||
|
if (_channels[channel].extraVoices >= voices) {
|
||||||
|
_channels[channel].extraVoices -= voices;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
voices -= _channels[channel].extraVoices;
|
||||||
|
_channels[channel].extraVoices = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
if ((_voices[i].channel == channel) && (_voices[i].note == -1)) {
|
||||||
|
_voices[i].channel = -1;
|
||||||
|
if (--voices == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
if (_voices[i].channel == channel) {
|
||||||
|
voiceOff(i);
|
||||||
|
_voices[i].channel = -1;
|
||||||
|
if (--voices == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::donateVoices() {
|
||||||
|
int freeVoices = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < kVoices; i++)
|
||||||
|
if (_voices[i].channel == -1)
|
||||||
|
freeVoices++;
|
||||||
|
|
||||||
|
if (freeVoices == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < MIDI_CHANNELS; i++) {
|
||||||
|
if (_channels[i].extraVoices >= freeVoices) {
|
||||||
|
assignVoices(i, freeVoices);
|
||||||
|
_channels[i].extraVoices -= freeVoices;
|
||||||
|
return;
|
||||||
|
} else if (_channels[i].extraVoices > 0) {
|
||||||
|
assignVoices(i, _channels[i].extraVoices);
|
||||||
|
freeVoices -= _channels[i].extraVoices;
|
||||||
|
_channels[i].extraVoices = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MidiPlayer_Fb01::findVoice(int channel) {
|
||||||
|
int voice = -1;
|
||||||
|
int oldestVoice = -1;
|
||||||
|
uint32 oldestAge = 0;
|
||||||
|
|
||||||
|
// Try to find a voice assigned to this channel that is free (round-robin)
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
int v = (_channels[channel].lastVoice + i + 1) % kVoices;
|
||||||
|
|
||||||
|
if (_voices[v].channel == channel) {
|
||||||
|
if (_voices[v].note == -1) {
|
||||||
|
voice = v;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We also keep track of the oldest note in case the search fails
|
||||||
|
// Notes started in the current time slice will not be selected
|
||||||
|
if (_voices[v].age > oldestAge) {
|
||||||
|
oldestAge = _voices[v].age;
|
||||||
|
oldestVoice = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (voice == -1) {
|
||||||
|
if (oldestVoice != -1) {
|
||||||
|
voiceOff(oldestVoice);
|
||||||
|
voice = oldestVoice;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_channels[channel].lastVoice = voice;
|
||||||
|
return voice;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::sendToChannel(byte channel, byte command, byte op1, byte op2) {
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
// Send command to all voices assigned to this channel
|
||||||
|
if (_voices[i].channel == channel)
|
||||||
|
_driver->send(command | i, op1, op2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::setPatch(int channel, int patch) {
|
||||||
|
int bank = 0;
|
||||||
|
|
||||||
|
_channels[channel].patch = patch;
|
||||||
|
|
||||||
|
if (patch >= 48) {
|
||||||
|
patch -= 48;
|
||||||
|
bank = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int voice = 0; voice < kVoices; voice++) {
|
||||||
|
if (_voices[voice].channel == channel) {
|
||||||
|
if (_voices[voice].bank != bank) {
|
||||||
|
_voices[voice].bank = bank;
|
||||||
|
setVoiceParam(voice, 4, bank);
|
||||||
|
}
|
||||||
|
_driver->send(0xc0 | voice, patch, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::voiceOn(int voice, int note, int velocity) {
|
||||||
|
if (_playSwitch) {
|
||||||
|
_voices[voice].note = note;
|
||||||
|
_voices[voice].age = 0;
|
||||||
|
_driver->send(0x90 | voice, note, velocity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::voiceOff(int voice) {
|
||||||
|
_voices[voice].note = -1;
|
||||||
|
_driver->send(0xb0 | voice, 0x7b, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::noteOff(int channel, int note) {
|
||||||
|
int voice;
|
||||||
|
for (voice = 0; voice < kVoices; voice++) {
|
||||||
|
if ((_voices[voice].channel == channel) && (_voices[voice].note == note)) {
|
||||||
|
voiceOff(voice);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::noteOn(int channel, int note, int velocity) {
|
||||||
|
if (velocity == 0)
|
||||||
|
return noteOff(channel, note);
|
||||||
|
|
||||||
|
if (_version > SCI_VERSION_0_LATE)
|
||||||
|
velocity = volumeTable[velocity >> 1] << 1;
|
||||||
|
|
||||||
|
int voice;
|
||||||
|
for (voice = 0; voice < kVoices; voice++) {
|
||||||
|
if ((_voices[voice].channel == channel) && (_voices[voice].note == note)) {
|
||||||
|
voiceOff(voice);
|
||||||
|
voiceOn(voice, note, velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
voice = findVoice(channel);
|
||||||
|
|
||||||
|
if (voice == -1) {
|
||||||
|
debug(3, "FB-01: failed to find free voice assigned to channel %i", channel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
voiceOn(voice, note, velocity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::controlChange(int channel, int control, int value) {
|
||||||
|
switch (control) {
|
||||||
|
case 0x07: {
|
||||||
|
_channels[channel].volume = value;
|
||||||
|
|
||||||
|
if (_version > SCI_VERSION_0_LATE)
|
||||||
|
value = volumeTable[value >> 1] << 1;
|
||||||
|
|
||||||
|
byte vol = _masterVolume;
|
||||||
|
|
||||||
|
if (vol > 0)
|
||||||
|
vol = CLIP<byte>(vol + 3, 0, 15);
|
||||||
|
|
||||||
|
sendToChannel(channel, 0xb0, control, (value * vol / 15) & 0x7f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0a:
|
||||||
|
_channels[channel].pan = value;
|
||||||
|
sendToChannel(channel, 0xb0, control, value);
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
_channels[channel].holdPedal = value;
|
||||||
|
sendToChannel(channel, 0xb0, control, value);
|
||||||
|
break;
|
||||||
|
case 0x4b:
|
||||||
|
// In early SCI0, voice count 15 signifies that the channel should be ignored
|
||||||
|
// for this song. Assuming that there are no embedded voice count commands in
|
||||||
|
// the MIDI stream, we should be able to get away with simply setting the voice
|
||||||
|
// count for this channel to 0.
|
||||||
|
voiceMapping(channel, (value != 15 ? value : 0));
|
||||||
|
break;
|
||||||
|
case 0x7b:
|
||||||
|
for (int i = 0; i < kVoices; i++)
|
||||||
|
if ((_voices[i].channel == channel) && (_voices[i].note != -1))
|
||||||
|
voiceOff(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::send(uint32 b) {
|
||||||
|
byte command = b & 0xf0;
|
||||||
|
byte channel = b & 0xf;
|
||||||
|
byte op1 = (b >> 8) & 0x7f;
|
||||||
|
byte op2 = (b >> 16) & 0x7f;
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case 0x80:
|
||||||
|
noteOff(channel, op1);
|
||||||
|
break;
|
||||||
|
case 0x90:
|
||||||
|
noteOn(channel, op1, op2);
|
||||||
|
break;
|
||||||
|
case 0xb0:
|
||||||
|
controlChange(channel, op1, op2);
|
||||||
|
break;
|
||||||
|
case 0xc0:
|
||||||
|
setPatch(channel, op1);
|
||||||
|
break;
|
||||||
|
case 0xe0:
|
||||||
|
_channels[channel].pitchWheel = (op1 & 0x7f) | ((op2 & 0x7f) << 7);
|
||||||
|
sendToChannel(channel, command, op1, op2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warning("FB-01: Ignoring MIDI event %02x %02x %02x", command | channel, op1, op2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::setVolume(byte volume) {
|
||||||
|
_masterVolume = volume;
|
||||||
|
|
||||||
|
for (uint i = 0; i < MIDI_CHANNELS; i++)
|
||||||
|
controlChange(i, 0x07, _channels[i].volume & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MidiPlayer_Fb01::getVolume() {
|
||||||
|
return _masterVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::playSwitch(bool play) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::midiTimerCallback(void *p) {
|
||||||
|
MidiPlayer_Fb01 *m = (MidiPlayer_Fb01 *)p;
|
||||||
|
|
||||||
|
// Increase the age of the notes
|
||||||
|
for (int i = 0; i < kVoices; i++) {
|
||||||
|
if (m->_voices[i].note != -1)
|
||||||
|
m->_voices[i].age++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m->_timerProc)
|
||||||
|
m->_timerProc(m->_timerParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
|
||||||
|
_driver->setTimerCallback(NULL, NULL);
|
||||||
|
|
||||||
|
_timerParam = timer_param;
|
||||||
|
_timerProc = timer_proc;
|
||||||
|
|
||||||
|
_driver->setTimerCallback(this, midiTimerCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::sendBanks(const byte *data, int size) {
|
||||||
|
if (size < 3072)
|
||||||
|
error("Failed to read FB-01 patch");
|
||||||
|
|
||||||
|
// SSCI sends bank dumps containing 48 instruments at once. We cannot do that
|
||||||
|
// due to the limited maximum SysEx length. Instead we send the instruments
|
||||||
|
// one by one and store them in the banks.
|
||||||
|
for (int i = 0; i < 48; i++) {
|
||||||
|
sendVoiceData(0, data + i * 64);
|
||||||
|
storeVoiceData(0, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send second bank if available
|
||||||
|
if ((size >= 6146) && (READ_BE_UINT16(data + 3072) == 0xabcd)) {
|
||||||
|
for (int i = 0; i < 48; i++) {
|
||||||
|
sendVoiceData(0, data + 3074 + i * 64);
|
||||||
|
storeVoiceData(0, 1, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MidiPlayer_Fb01::open(ResourceManager *resMan) {
|
||||||
|
assert(resMan != NULL);
|
||||||
|
|
||||||
|
int retval = _driver->open();
|
||||||
|
if (retval != 0) {
|
||||||
|
warning("Failed to open MIDI driver");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set system channel to 0. We send this command over all 16 system channels
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
setSystemParam(i, 0x20, 0);
|
||||||
|
|
||||||
|
// Turn off memory protection
|
||||||
|
setSystemParam(0, 0x21, 0);
|
||||||
|
|
||||||
|
Resource *res = resMan->findResource(ResourceId(kResourceTypePatch, 2), 0);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
sendBanks(res->data, res->size);
|
||||||
|
} else {
|
||||||
|
warning("FB-01 patch file not found, attempting to load sound bank from IMF.DRV");
|
||||||
|
// Try to load sound bank from IMF.DRV
|
||||||
|
Common::File f;
|
||||||
|
|
||||||
|
if (f.open("IMF.DRV")) {
|
||||||
|
int size = f.size();
|
||||||
|
byte *buf = new byte[size];
|
||||||
|
|
||||||
|
f.read(buf, size);
|
||||||
|
|
||||||
|
// Search for start of sound bank
|
||||||
|
int offset;
|
||||||
|
for (offset = 0; offset < size; ++offset) {
|
||||||
|
if (!strncmp((char *)buf + offset, "SIERRA ", 7))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip to voice data
|
||||||
|
offset += 0x20;
|
||||||
|
|
||||||
|
if (offset >= size)
|
||||||
|
error("Failed to locate start of FB-01 sound bank");
|
||||||
|
|
||||||
|
sendBanks(buf + offset, size - offset);
|
||||||
|
|
||||||
|
delete[] buf;
|
||||||
|
} else
|
||||||
|
error("Failed to open IMF.DRV");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up voices to use MIDI channels 0 - 7
|
||||||
|
for (int i = 0; i < kVoices; i++)
|
||||||
|
setVoiceParam(i, 1, i);
|
||||||
|
|
||||||
|
initVoices();
|
||||||
|
|
||||||
|
// Set master volume
|
||||||
|
setSystemParam(0, 0x24, 0x7f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::close() {
|
||||||
|
_driver->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::setVoiceParam(byte voice, byte param, byte value) {
|
||||||
|
_sysExBuf[2] = 0x00;
|
||||||
|
_sysExBuf[3] = 0x18 | voice;
|
||||||
|
_sysExBuf[4] = param;
|
||||||
|
_sysExBuf[5] = value;
|
||||||
|
|
||||||
|
_driver->sysEx(_sysExBuf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::setSystemParam(byte sysChan, byte param, byte value) {
|
||||||
|
_sysExBuf[2] = sysChan;
|
||||||
|
_sysExBuf[3] = 0x10;
|
||||||
|
_sysExBuf[4] = param;
|
||||||
|
_sysExBuf[5] = value;
|
||||||
|
|
||||||
|
sysEx(_sysExBuf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::sendVoiceData(byte instrument, const byte *data) {
|
||||||
|
_sysExBuf[2] = 0x00;
|
||||||
|
_sysExBuf[3] = 0x08 | instrument;
|
||||||
|
_sysExBuf[4] = 0x00;
|
||||||
|
_sysExBuf[5] = 0x00;
|
||||||
|
_sysExBuf[6] = 0x01;
|
||||||
|
_sysExBuf[7] = 0x00;
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
_sysExBuf[8 + i * 2] = data[i] & 0xf;
|
||||||
|
_sysExBuf[8 + i * 2 + 1] = data[i] >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte checksum = 0;
|
||||||
|
for (int i = 8; i < 136; i++)
|
||||||
|
checksum += _sysExBuf[i];
|
||||||
|
|
||||||
|
_sysExBuf[136] = (-checksum) & 0x7f;
|
||||||
|
|
||||||
|
sysEx(_sysExBuf, 137);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::storeVoiceData(byte instrument, byte bank, byte index) {
|
||||||
|
_sysExBuf[2] = 0x00;
|
||||||
|
_sysExBuf[3] = 0x28 | instrument;
|
||||||
|
_sysExBuf[4] = 0x40;
|
||||||
|
_sysExBuf[5] = (bank > 0 ? 48 : 0) + index;
|
||||||
|
|
||||||
|
sysEx(_sysExBuf, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::initVoices() {
|
||||||
|
int i = 2;
|
||||||
|
_sysExBuf[i++] = 0x70;
|
||||||
|
|
||||||
|
// Set all MIDI channels to 0 voices
|
||||||
|
for (int j = 0; j < MIDI_CHANNELS; j++) {
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x00;
|
||||||
|
_sysExBuf[i++] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the 8 MIDI channels we will be using
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
// One voice
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x00;
|
||||||
|
_sysExBuf[i++] = 0x01;
|
||||||
|
|
||||||
|
// Full range of keys
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x02;
|
||||||
|
_sysExBuf[i++] = 0x7f;
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x03;
|
||||||
|
_sysExBuf[i++] = 0x00;
|
||||||
|
|
||||||
|
// Voice bank 0
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x04;
|
||||||
|
_sysExBuf[i++] = 0x00;
|
||||||
|
|
||||||
|
// Voice 10
|
||||||
|
_sysExBuf[i++] = 0x70 | j;
|
||||||
|
_sysExBuf[i++] = 0x05;
|
||||||
|
_sysExBuf[i++] = 0x0a;
|
||||||
|
}
|
||||||
|
|
||||||
|
sysEx(_sysExBuf, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiPlayer_Fb01::sysEx(const byte *msg, uint16 length) {
|
||||||
|
_driver->sysEx(msg, length);
|
||||||
|
|
||||||
|
// Wait the time it takes to send the SysEx data
|
||||||
|
uint32 delay = (length + 2) * 1000 / 3125;
|
||||||
|
|
||||||
|
delay += 10;
|
||||||
|
|
||||||
|
g_system->delayMillis(delay);
|
||||||
|
g_system->updateScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte MidiPlayer_Fb01::getPlayId() {
|
||||||
|
switch (_version) {
|
||||||
|
case SCI_VERSION_0_EARLY:
|
||||||
|
return 0x01;
|
||||||
|
case SCI_VERSION_0_LATE:
|
||||||
|
return 0x02;
|
||||||
|
default:
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiPlayer *MidiPlayer_Fb01_create(SciVersion version) {
|
||||||
|
return new MidiPlayer_Fb01(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Sci
|
|
@ -43,7 +43,7 @@ public:
|
||||||
kMaxSysExSize = 264
|
kMaxSysExSize = 264
|
||||||
};
|
};
|
||||||
|
|
||||||
MidiPlayer_Midi();
|
MidiPlayer_Midi(SciVersion version);
|
||||||
virtual ~MidiPlayer_Midi();
|
virtual ~MidiPlayer_Midi();
|
||||||
|
|
||||||
int open(ResourceManager *resMan);
|
int open(ResourceManager *resMan);
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
void send(uint32 b);
|
void send(uint32 b);
|
||||||
void sysEx(const byte *msg, uint16 length);
|
void sysEx(const byte *msg, uint16 length);
|
||||||
bool hasRhythmChannel() const { return true; }
|
bool hasRhythmChannel() const { return true; }
|
||||||
byte getPlayId(SciVersion soundVersion);
|
byte getPlayId();
|
||||||
int getPolyphony() const { return kVoices; }
|
int getPolyphony() const { return kVoices; }
|
||||||
void setVolume(byte volume);
|
void setVolume(byte volume);
|
||||||
int getVolume();
|
int getVolume();
|
||||||
|
@ -116,7 +116,7 @@ private:
|
||||||
byte _sysExBuf[kMaxSysExSize];
|
byte _sysExBuf[kMaxSysExSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
MidiPlayer_Midi::MidiPlayer_Midi() : _playSwitch(true), _masterVolume(15), _isMt32(false), _hasReverb(false), _isOldPatchFormat(true) {
|
MidiPlayer_Midi::MidiPlayer_Midi(SciVersion version) : MidiPlayer(version), _playSwitch(true), _masterVolume(15), _isMt32(false), _hasReverb(false), _isOldPatchFormat(true) {
|
||||||
MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
|
MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
|
||||||
_driver = createMidi(midiType);
|
_driver = createMidi(midiType);
|
||||||
|
|
||||||
|
@ -847,8 +847,8 @@ void MidiPlayer_Midi::sysEx(const byte *msg, uint16 length) {
|
||||||
g_system->updateScreen();
|
g_system->updateScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
byte MidiPlayer_Midi::getPlayId(SciVersion soundVersion) {
|
byte MidiPlayer_Midi::getPlayId() {
|
||||||
switch (soundVersion) {
|
switch (_version) {
|
||||||
case SCI_VERSION_0_EARLY:
|
case SCI_VERSION_0_EARLY:
|
||||||
case SCI_VERSION_0_LATE:
|
case SCI_VERSION_0_LATE:
|
||||||
return 0x01;
|
return 0x01;
|
||||||
|
@ -860,8 +860,8 @@ byte MidiPlayer_Midi::getPlayId(SciVersion soundVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiPlayer *MidiPlayer_Midi_create() {
|
MidiPlayer *MidiPlayer_Midi_create(SciVersion version) {
|
||||||
return new MidiPlayer_Midi();
|
return new MidiPlayer_Midi(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -70,7 +70,7 @@ protected:
|
||||||
byte _reverb;
|
byte _reverb;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MidiPlayer() : _reverb(0) { }
|
MidiPlayer(SciVersion version) : _reverb(0), _version(version) { }
|
||||||
|
|
||||||
int open() {
|
int open() {
|
||||||
ResourceManager *resMan = ((SciEngine *)g_engine)->getResourceManager(); // HACK
|
ResourceManager *resMan = ((SciEngine *)g_engine)->getResourceManager(); // HACK
|
||||||
|
@ -83,9 +83,9 @@ public:
|
||||||
virtual bool hasRhythmChannel() const = 0;
|
virtual bool hasRhythmChannel() const = 0;
|
||||||
MidiChannel *allocateChannel() { return _driver->allocateChannel(); }
|
MidiChannel *allocateChannel() { return _driver->allocateChannel(); }
|
||||||
MidiChannel *getPercussionChannel() { return _driver->getPercussionChannel(); }
|
MidiChannel *getPercussionChannel() { return _driver->getPercussionChannel(); }
|
||||||
void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { _driver->setTimerCallback(timer_param, timer_proc); }
|
virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { _driver->setTimerCallback(timer_param, timer_proc); }
|
||||||
|
|
||||||
virtual byte getPlayId(SciVersion soundVersion) = 0;
|
virtual byte getPlayId() = 0;
|
||||||
virtual int getPolyphony() const = 0;
|
virtual int getPolyphony() const = 0;
|
||||||
|
|
||||||
virtual void setVolume(byte volume) {
|
virtual void setVolume(byte volume) {
|
||||||
|
@ -107,13 +107,17 @@ public:
|
||||||
_driver->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
|
_driver->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SciVersion _version;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MidiPlayer *MidiPlayer_AdLib_create();
|
extern MidiPlayer *MidiPlayer_AdLib_create(SciVersion version);
|
||||||
extern MidiPlayer *MidiPlayer_Amiga_create();
|
extern MidiPlayer *MidiPlayer_Amiga_create(SciVersion version);
|
||||||
extern MidiPlayer *MidiPlayer_PCJr_create();
|
extern MidiPlayer *MidiPlayer_PCJr_create(SciVersion version);
|
||||||
extern MidiPlayer *MidiPlayer_PCSpeaker_create();
|
extern MidiPlayer *MidiPlayer_PCSpeaker_create(SciVersion version);
|
||||||
extern MidiPlayer *MidiPlayer_Midi_create();
|
extern MidiPlayer *MidiPlayer_Midi_create(SciVersion version);
|
||||||
|
extern MidiPlayer *MidiPlayer_Fb01_create(SciVersion version);
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
||||||
|
|
|
@ -230,16 +230,16 @@ void MidiDriver_PCJr::close() {
|
||||||
|
|
||||||
class MidiPlayer_PCJr : public MidiPlayer {
|
class MidiPlayer_PCJr : public MidiPlayer {
|
||||||
public:
|
public:
|
||||||
MidiPlayer_PCJr() { _driver = new MidiDriver_PCJr(g_system->getMixer()); }
|
MidiPlayer_PCJr(SciVersion version) : MidiPlayer(version) { _driver = new MidiDriver_PCJr(g_system->getMixer()); }
|
||||||
int open(ResourceManager *resMan) { return static_cast<MidiDriver_PCJr *>(_driver)->open(getPolyphony()); }
|
int open(ResourceManager *resMan) { return static_cast<MidiDriver_PCJr *>(_driver)->open(getPolyphony()); }
|
||||||
byte getPlayId(SciVersion soundVersion);
|
byte getPlayId();
|
||||||
int getPolyphony() const { return 3; }
|
int getPolyphony() const { return 3; }
|
||||||
bool hasRhythmChannel() const { return false; }
|
bool hasRhythmChannel() const { return false; }
|
||||||
void setVolume(byte volume) { static_cast<MidiDriver_PCJr *>(_driver)->_global_volume = volume; }
|
void setVolume(byte volume) { static_cast<MidiDriver_PCJr *>(_driver)->_global_volume = volume; }
|
||||||
};
|
};
|
||||||
|
|
||||||
byte MidiPlayer_PCJr::getPlayId(SciVersion soundVersion) {
|
byte MidiPlayer_PCJr::getPlayId() {
|
||||||
switch (soundVersion) {
|
switch (_version) {
|
||||||
case SCI_VERSION_0_EARLY:
|
case SCI_VERSION_0_EARLY:
|
||||||
return 0x02;
|
return 0x02;
|
||||||
case SCI_VERSION_0_LATE:
|
case SCI_VERSION_0_LATE:
|
||||||
|
@ -249,18 +249,20 @@ byte MidiPlayer_PCJr::getPlayId(SciVersion soundVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiPlayer *MidiPlayer_PCJr_create() {
|
MidiPlayer *MidiPlayer_PCJr_create(SciVersion version) {
|
||||||
return new MidiPlayer_PCJr();
|
return new MidiPlayer_PCJr(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MidiPlayer_PCSpeaker : public MidiPlayer_PCJr {
|
class MidiPlayer_PCSpeaker : public MidiPlayer_PCJr {
|
||||||
public:
|
public:
|
||||||
byte getPlayId(SciVersion soundVersion);
|
MidiPlayer_PCSpeaker(SciVersion version) : MidiPlayer_PCJr(version) { }
|
||||||
|
|
||||||
|
byte getPlayId();
|
||||||
int getPolyphony() const { return 1; }
|
int getPolyphony() const { return 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
byte MidiPlayer_PCSpeaker::getPlayId(SciVersion soundVersion) {
|
byte MidiPlayer_PCSpeaker::getPlayId() {
|
||||||
switch (soundVersion) {
|
switch (_version) {
|
||||||
case SCI_VERSION_0_EARLY:
|
case SCI_VERSION_0_EARLY:
|
||||||
return 0x04;
|
return 0x04;
|
||||||
case SCI_VERSION_0_LATE:
|
case SCI_VERSION_0_LATE:
|
||||||
|
@ -270,8 +272,8 @@ byte MidiPlayer_PCSpeaker::getPlayId(SciVersion soundVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MidiPlayer *MidiPlayer_PCSpeaker_create() {
|
MidiPlayer *MidiPlayer_PCSpeaker_create(SciVersion version) {
|
||||||
return new MidiPlayer_PCSpeaker();
|
return new MidiPlayer_PCSpeaker(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // End of namespace Sci
|
} // End of namespace Sci
|
||||||
|
|
|
@ -229,15 +229,15 @@ Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) {
|
||||||
case MD_ADLIB:
|
case MD_ADLIB:
|
||||||
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
|
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
|
||||||
if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga)
|
if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga)
|
||||||
_mididrv = MidiPlayer_Amiga_create();
|
_mididrv = MidiPlayer_Amiga_create(_soundVersion);
|
||||||
else
|
else
|
||||||
_mididrv = MidiPlayer_AdLib_create();
|
_mididrv = MidiPlayer_AdLib_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
case MD_PCJR:
|
case MD_PCJR:
|
||||||
_mididrv = MidiPlayer_PCJr_create();
|
_mididrv = MidiPlayer_PCJr_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
case MD_PCSPK:
|
case MD_PCSPK:
|
||||||
_mididrv = MidiPlayer_PCSpeaker_create();
|
_mididrv = MidiPlayer_PCSpeaker_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -261,7 +261,7 @@ Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) {
|
||||||
|
|
||||||
Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) {
|
Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) {
|
||||||
Common::StackLock lock(_mutex);
|
Common::StackLock lock(_mutex);
|
||||||
SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId(_soundVersion)));
|
SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId()));
|
||||||
SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
|
SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
|
||||||
|
|
||||||
if (_iterator == NULL) {
|
if (_iterator == NULL) {
|
||||||
|
|
|
@ -87,6 +87,16 @@ bool MidiParser_SCI::loadMusic(SoundResource::Track *track, MusicEntry *psnd, in
|
||||||
_loopTick = 0;
|
_loopTick = 0;
|
||||||
_channelsUsed = 0;
|
_channelsUsed = 0;
|
||||||
|
|
||||||
|
if (_soundVersion <= SCI_VERSION_0_LATE) {
|
||||||
|
// Set initial voice count
|
||||||
|
for (int i = 0; i < 16; ++i) {
|
||||||
|
byte voiceCount = 0;
|
||||||
|
if (channelFilterMask & (1 << i))
|
||||||
|
voiceCount = psnd->soundRes->getInitialVoiceCount(i);
|
||||||
|
_driver->send(0xB0 | i, 0x4B, voiceCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Send a velocity off signal to all channels
|
// Send a velocity off signal to all channels
|
||||||
for (int i = 0; i < 16; ++i) {
|
for (int i = 0; i < 16; ++i) {
|
||||||
_driver->send(0xB0 | i, 0x4E, 0); // Reset velocity
|
_driver->send(0xB0 | i, 0x4E, 0); // Reset velocity
|
||||||
|
|
|
@ -67,18 +67,21 @@ void SciMusic::init() {
|
||||||
case MD_ADLIB:
|
case MD_ADLIB:
|
||||||
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
|
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
|
||||||
if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga)
|
if (((SciEngine *)g_engine)->getPlatform() == Common::kPlatformAmiga)
|
||||||
_pMidiDrv = MidiPlayer_Amiga_create();
|
_pMidiDrv = MidiPlayer_Amiga_create(_soundVersion);
|
||||||
else
|
else
|
||||||
_pMidiDrv = MidiPlayer_AdLib_create();
|
_pMidiDrv = MidiPlayer_AdLib_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
case MD_PCJR:
|
case MD_PCJR:
|
||||||
_pMidiDrv = MidiPlayer_PCJr_create();
|
_pMidiDrv = MidiPlayer_PCJr_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
case MD_PCSPK:
|
case MD_PCSPK:
|
||||||
_pMidiDrv = MidiPlayer_PCSpeaker_create();
|
_pMidiDrv = MidiPlayer_PCSpeaker_create(_soundVersion);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_pMidiDrv = MidiPlayer_Midi_create();
|
if (ConfMan.getBool("enable_fb01"))
|
||||||
|
_pMidiDrv = MidiPlayer_Fb01_create(_soundVersion);
|
||||||
|
else
|
||||||
|
_pMidiDrv = MidiPlayer_Midi_create(_soundVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pMidiDrv) {
|
if (_pMidiDrv) {
|
||||||
|
@ -165,7 +168,7 @@ void SciMusic::sortPlayList() {
|
||||||
}
|
}
|
||||||
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
||||||
int channelFilterMask = 0;
|
int channelFilterMask = 0;
|
||||||
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion));
|
SoundResource::Track *track = pSnd->soundRes->getTrackByType(_pMidiDrv->getPlayId());
|
||||||
|
|
||||||
if (track) {
|
if (track) {
|
||||||
// If MIDI device is selected but there is no digital track in sound resource
|
// If MIDI device is selected but there is no digital track in sound resource
|
||||||
|
@ -202,7 +205,7 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
|
||||||
pSnd->pauseCounter = 0;
|
pSnd->pauseCounter = 0;
|
||||||
|
|
||||||
// Find out what channels to filter for SCI0
|
// Find out what channels to filter for SCI0
|
||||||
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(_soundVersion), _pMidiDrv->hasRhythmChannel());
|
channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(), _pMidiDrv->hasRhythmChannel());
|
||||||
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
|
pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
|
||||||
|
|
||||||
// Fast forward to the last position and perform associated events when loading
|
// Fast forward to the last position and perform associated events when loading
|
||||||
|
@ -394,7 +397,7 @@ void SciMusic::printSongInfo(reg_t obj, Console *con) {
|
||||||
if (song->pMidiParser) {
|
if (song->pMidiParser) {
|
||||||
con->DebugPrintf("Type: MIDI\n");
|
con->DebugPrintf("Type: MIDI\n");
|
||||||
if (song->soundRes) {
|
if (song->soundRes) {
|
||||||
SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion));
|
SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId());
|
||||||
con->DebugPrintf("Channels: %d\n", track->channelCount);
|
con->DebugPrintf("Channels: %d\n", track->channelCount);
|
||||||
}
|
}
|
||||||
} else if (song->pStreamAud || song->pLoopStream) {
|
} else if (song->pStreamAud || song->pLoopStream) {
|
||||||
|
@ -403,7 +406,7 @@ void SciMusic::printSongInfo(reg_t obj, Console *con) {
|
||||||
_pMixer->isSoundHandleActive(song->hCurrentAud) ? "yes" : "no");
|
_pMixer->isSoundHandleActive(song->hCurrentAud) ? "yes" : "no");
|
||||||
if (song->soundRes) {
|
if (song->soundRes) {
|
||||||
con->DebugPrintf("Sound resource information:\n");
|
con->DebugPrintf("Sound resource information:\n");
|
||||||
SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId(_soundVersion));
|
SoundResource::Track *track = song->soundRes->getTrackByType(_pMidiDrv->getPlayId());
|
||||||
if (track && track->digitalChannelNr != -1) {
|
if (track && track->digitalChannelNr != -1) {
|
||||||
con->DebugPrintf("Sample size: %d, sample rate: %d, channels: %d, digital channel number: %d\n",
|
con->DebugPrintf("Sample size: %d, sample rate: %d, channels: %d, digital channel number: %d\n",
|
||||||
track->digitalSampleSize, track->digitalSampleRate, track->channelCount, track->digitalChannelNr);
|
track->digitalSampleSize, track->digitalSampleRate, track->channelCount, track->digitalChannelNr);
|
||||||
|
|
|
@ -41,14 +41,6 @@
|
||||||
|
|
||||||
namespace Sci {
|
namespace Sci {
|
||||||
|
|
||||||
enum TrackType {
|
|
||||||
kTrackAdLib = 0,
|
|
||||||
kTrackGameBlaster = 9,
|
|
||||||
kTrackMT32 = 12,
|
|
||||||
kTrackSpeaker = 18,
|
|
||||||
kTrackTandy = 19
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SoundStatus {
|
enum SoundStatus {
|
||||||
kSoundStopped = 0,
|
kSoundStopped = 0,
|
||||||
kSoundInitialized = 1,
|
kSoundInitialized = 1,
|
||||||
|
|
|
@ -209,7 +209,9 @@ SoundCommandParser::~SoundCommandParser() {
|
||||||
for (SoundCommandContainer::iterator i = _soundCommands.begin(); i != _soundCommands.end(); ++i)
|
for (SoundCommandContainer::iterator i = _soundCommands.begin(); i != _soundCommands.end(); ++i)
|
||||||
delete *i;
|
delete *i;
|
||||||
|
|
||||||
|
#ifndef USE_OLD_MUSIC_FUNCTIONS
|
||||||
delete _music;
|
delete _music;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t SoundCommandParser::parseCommand(int argc, reg_t *argv, reg_t acc) {
|
reg_t SoundCommandParser::parseCommand(int argc, reg_t *argv, reg_t acc) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue