TSAGE: Beginnings of SoundBlaster sound driver

This commit is contained in:
Paul Gilbert 2011-07-02 10:39:57 +10:00
parent 925347bd4d
commit ab7fdccc3b
2 changed files with 123 additions and 211 deletions

View File

@ -126,7 +126,10 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
assert(__sndmgrReady);
_availableDrivers.clear();
// Build up a list of available drivers. Currently we only implement an Adlib driver
// Build up a list of available drivers. Currently we only implement an Adlib music
// and SoundBlaster FX driver
// Adlib driver
SoundDriverEntry sd;
sd.driverNum = ADLIB_DRIVER_NUM;
sd.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
@ -136,12 +139,23 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) {
sd.longDescription = "3812fm";
_availableDrivers.push_back(sd);
// SoundBlaster entry
SoundDriverEntry sdFx;
sdFx.driverNum = SBLASTER_DRIVER_NUM;
sdFx.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED;
sdFx.field2 = 0;
sdFx.field6 = 15000;
sdFx.shortDescription = "SndBlast";
sdFx.longDescription = "SoundBlaster";
_availableDrivers.push_back(sdFx);
_driversDetected = true;
return _availableDrivers;
}
void SoundManager::installConfigDrivers() {
installDriver(ADLIB_DRIVER_NUM);
installDriver(SBLASTER_DRIVER_NUM);
}
Common::List<SoundDriverEntry> &SoundManager::getDriverList(bool detectFlag) {
@ -2125,7 +2139,7 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice
vtStruct->_entries[entryIndex]._type1._field4 = v0;
vtStruct->_entries[entryIndex]._type1._field5 = 0;
driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1);
driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1);
}
}
@ -2143,8 +2157,9 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice
vtStruct->_entries[entryIndex]._type1._field4 = v0;
vtStruct->_entries[entryIndex]._type1._field5 = 0;
driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F);
driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0);
int v1, v2;
driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F);
driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0, &v1, &v2);
}
break;
}
@ -2271,11 +2286,33 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) {
vtStruct->_entries[entryIndex]._type1._field4 = *(channelData + 1);
vtStruct->_entries[entryIndex]._type1._field5 = 0;
driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f);
int v1, v2;
driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f);
driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), _loop ? 1 : 0,
&v1, &v2);
}
} else {
int channel = 0; // Is this correct?!
for (uint entryIndex = 0; entryIndex < vtStruct->_entries.size(); ++entryIndex) {
VoiceStructEntry &vte = vtStruct->_entries[entryIndex];
VoiceStructEntryType1 &vse = vte._type1;
if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == vtStruct->_total)) {
SoundDriver *driver = vte._driver;
int v1, v2;
driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &v1, &v2);
if (v2) {
_trkState[trackIndex] = 0;
} else if (vtStruct->_total) {
_timer = 0;
}
}
}
_trkState[trackIndex] = 0;
}
} else {
_trkState[trackIndex] = 0;
}
}
}
@ -2511,7 +2548,7 @@ int AdlibSoundDriver::setMasterVolume(int volume) {
return oldVolume;
}
void AdlibSoundDriver::proc32(int channel, int program, int v0, int v1) {
void AdlibSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) {
if (program == -1)
return;
@ -2735,7 +2772,7 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() {
_maxVersion = 0x10A;
_masterVolume = 0;
_groupData.groupMask = 9;
_groupData.groupMask = 1;
_groupData.v1 = 0x3E;
_groupData.v2 = 0;
_groupData.pData = &adlib_group_data[0];
@ -2765,31 +2802,25 @@ AdlibFxSoundDriver::~AdlibFxSoundDriver() {
}
bool AdlibFxSoundDriver::open() {
write209();
write(64);
write(165);
// for (int idx = 0; idx < 5000 * 16; ++idx) al = port[21h]
write(1, 0x20);
if (!reset())
return false;
// _v45071 = 1;
// _v4506F = 0;
write(8, 0);
for (int idx = 0x20; idx < 0xF6; ++idx)
write(idx, 0);
write(0xBD, 0);
return true;
}
void AdlibFxSoundDriver::close() {
for (int idx = 0xB0; idx < 0xB8; ++idx)
write(idx, _portContents[idx] & 0xDF);
for (int idx = 0x40; idx < 0x55; ++idx)
write(idx, 0x3F);
reset();
write(208);
write211();
}
bool AdlibFxSoundDriver::reset() {
write(1, 0x20);
write(1, 0x20);
return true;
}
@ -2798,77 +2829,72 @@ const GroupData *AdlibFxSoundDriver::getGroupData() {
return &_groupData;
}
void AdlibFxSoundDriver::poll() {
if (!_masterVolume || !_channelVolume) {
if (_v45046)
write211();
} else {
if (!_v45046)
write209();
}
}
int AdlibFxSoundDriver::setMasterVolume(int volume) {
int oldVolume = _masterVolume;
_masterVolume = volume;
for (int channelNum = 0; channelNum < ADLIB_CHANNEL_COUNT; ++channelNum)
updateChannelVolume(channelNum);
return oldVolume;
}
void AdlibFxSoundDriver::proc32(int channel, int program, int v0, int v1) {
void AdlibFxSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) {
if (program == -1)
return;
/*
int offset = READ_LE_UINT16(_patchData + program * 2);
if (offset) {
const byte *dataP = _patchData + offset;
int id;
for (offset = 2, id = 0; id != READ_LE_UINT16(dataP); offset += 30, ++id) {
if ((dataP[offset] <= v0) && (dataP[offset + 1] >= v0)) {
if (dataP[offset + 2] != 0xff)
v0 = dataP[offset + 2];
if (_sound)
updateVoice(channel);
_v4409E[channel] = dataP + offset - _patchData;
// TODO: Stuff
// Set sustain/release
int portNum = v440C2[v440B0[channel]] + 0x80;
write(portNum, (_portContents[portNum] & 0xF0) | 0xF);
portNum = v440C2[v440B9[channel]] + 0x80;
write(portNum, (_portContents[portNum] & 0xF0) | 0xF);
if (_channelVoiced[channel])
clearVoice(channel);
_v44067[channel] = v0;
_v4405E[channel] = v1;
updateChannel(channel);
setFrequency(channel);
updateChannelVolume(channel);
setVoice(channel);
break;
}
}
}
*/
}
void AdlibFxSoundDriver::updateVoice(int channel) {
if (_channelVoiced[channel])
clearVoice(channel);
if (_sound) {
write(208);
_sound = NULL;
_v45062 = 0;
_v45066 = 0;
_v45068 = 0;
}
}
void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) {
if (cmd == 7) {
// Set channel volume
_channelVolume[channel] = value;
updateChannelVolume(channel);
_channelVolume = value;
}
}
void AdlibFxSoundDriver::setPitch(int channel, int pitchBlend) {
_pitchBlend[channel] = pitchBlend;
setFrequency(channel);
void AdlibFxSoundDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) {
_v4506A = value;
*v1 = _v4506B;
*v2 = 0;
_v4506B = 0;
if (!_sound)
*v2 = 1;
}
void AdlibFxSoundDriver::write(byte reg, byte value) {
_portContents[reg] = value;
_queue.push(RegisterValue(reg, value));
void AdlibFxSoundDriver::write(int v) {
/*
port[adlib_port + 12] = v;
for (int i = 0; i < 100; ++i) {
if (!port[adlib_port + 12] & 0x80)
break;
}
*/
}
void AdlibFxSoundDriver::flush() {
@ -2880,127 +2906,7 @@ void AdlibFxSoundDriver::flush() {
}
}
void AdlibFxSoundDriver::updateChannelVolume(int channelNum) {
int volume = (_masterVolume * _channelVolume[channelNum] / 127 * _v4405E[channelNum] / 127) / 2;
int level2 = 63 - v44134[volume * _v44079[channelNum] / 63];
int level1 = !_v44082[channelNum] ? 63 - _v44070[channelNum] :
63 - v44134[volume * _v44070[channelNum] / 63];
int portNum = v440C2[v440B0[channelNum]] + 0x40;
write(portNum, (_portContents[portNum] & 0x80) | level1);
portNum = v440C2[v440B9[channelNum]] + 0x40;
write(portNum, (_portContents[portNum] & 0x80) | level2);
}
void AdlibFxSoundDriver::setVoice(int channel) {
int portNum = 0xB0 + channel;
write(portNum, _portContents[portNum] | 0x20);
_channelVoiced[channel] = true;
}
void AdlibFxSoundDriver::clearVoice(int channel) {
write(0xB0 + channel, _portContents[0xB0 + channel] & ~0x20);
_channelVoiced[channel] = false;
}
void AdlibFxSoundDriver::updateChannel(int channel) {
/*
const byte *dataP = _patchData + _v4409E[channel];
int portOffset = v440C2[v440B0[channel]];
int portNum = portOffset + 0x20;
int portValue = 0;
if (*(dataP + 4))
portValue |= 0x80;
if (*(dataP + 5))
portValue |= 0x40;
if (*(dataP + 8))
portValue |= 0x20;
if (*(dataP + 6))
portValue |= 0x10;
portValue |= *(dataP + 7);
write(portNum, portValue);
portValue = (_portContents[0x40 + portOffset] & 0x3F) | (*(dataP + 9) << 6);
write(0x40 + portOffset, portValue);
_v44070[channel] = 63 - *(dataP + 10);
write(0x60 + portOffset, *(dataP + 12) | (*(dataP + 11) << 4));
write(0x80 + portOffset, *(dataP + 14) | (*(dataP + 13) << 4));
write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 15));
portOffset = v440C2[v440B9[channel]];
portNum = portOffset + 0x20;
portValue = 0;
if (*(dataP + 17))
portValue |= 0x80;
if (*(dataP + 18))
portValue |= 0x40;
if (*(dataP + 21))
portValue |= 0x20;
if (*(dataP + 19))
portValue |= 0x10;
portValue |= *(dataP + 20);
write(portNum, portValue);
write(0x40 + portOffset, (_portContents[0x40 + portOffset] & 0x3f) | (*(dataP + 22) << 6));
_v44079[channel] = 0x3F - *(dataP + 23);
write(0x60 + portOffset, *(dataP + 25) | (*(dataP + 24) << 4));
write(0x80 + portOffset, *(dataP + 27) | (*(dataP + 26) << 4));
write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 28));
write(0xC0 + channel, (_portContents[0xC0 + channel] & 0xF0)
| (*(dataP + 16) << 1) | *(dataP + 3));
_v44082[channel] = *(dataP + 3);
*/
}
void AdlibFxSoundDriver::setFrequency(int channel) {
int offset, ch;
int v = _pitchBlend[channel];
if (v == 0x2000) {
offset = 0;
ch = _v44067[channel];
} else if (v > 0x2000) {
ch = _v44067[channel];
v -= 0x2000;
if (v == 0x1fff)
v = 0x2000;
offset = (v / 170) & 3;
ch += (v / 170) >> 2;
if (ch >= 128)
ch = 127;
} else {
ch = _v44067[channel];
int tempVal = (0x2000 - v) / 170;
int tempVal2 = 4 - (tempVal & 3);
if (tempVal2 == 4)
offset = 0;
else {
offset = tempVal2;
--ch;
}
ch -= tempVal >> 2;
if (ch < 0)
ch = 0;
}
int var2 = ch / 12;
if (var2)
--var2;
int dataWord = v440D4[((ch % 12) << 2) + offset];
write(0xA0 + channel, dataWord & 0xff);
write(0xB0 + channel, (_portContents[0xB0 + channel] & 0xE0) |
((dataWord >> 8) & 3) | (var2 << 2));
}
int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) {
update(buffer, numSamples);
@ -3025,4 +2931,14 @@ void AdlibFxSoundDriver::update(int16 *buf, int len) {
}
}
void AdlibFxSoundDriver::write209() {
write(209);
_v45046 = true;
}
void AdlibFxSoundDriver::write211() {
write(211);
_v45046 = false;
}
} // End of namespace tSage

View File

@ -40,6 +40,7 @@ class Sound;
#define SOUND_ARR_SIZE 16
#define ROLAND_DRIVER_NUM 2
#define ADLIB_DRIVER_NUM 3
#define SBLASTER_DRIVER_NUM 4
struct trackInfoStruct {
int _numTracks;
@ -106,12 +107,12 @@ public:
virtual void setProgram(int channel, int program) {} // Method #13
virtual void setVolume1(int channel, int v2, int v3, int volume) {}
virtual void setPitchBlend(int channel, int pitchBlend) {} // Method #15
virtual void proc32(int channel, int program, int v0, int v1) {}// Method #16
virtual void proc32(Sound *sound, int channel, int program, int v0, int v1) {}// Method #16
virtual void updateVoice(int channel) {} // Method #17
virtual void proc36() {} // Method #18
virtual void proc38(int channel, int cmd, int value) {} // Method #19
virtual void setPitch(int channel, int pitchBlend) {} // Method #20
virtual void proc42(int channel, int v0, int v1) {} // Method #21
virtual void proc42(int channel, int cmd, int value, int *v1, int *v2) {} // Method #21
};
struct VoiceStructEntryType0 {
@ -439,7 +440,7 @@ public:
virtual const GroupData *getGroupData();
virtual void installPatch(const byte *data, int size);
virtual int setMasterVolume(int volume);
virtual void proc32(int channel, int program, int v0, int v1);
virtual void proc32(Sound *sound, int channel, int program, int v0, int v1);
virtual void updateVoice(int channel);
virtual void proc38(int channel, int cmd, int value);
virtual void setPitch(int channel, int pitchBlend);
@ -455,33 +456,28 @@ public:
class AdlibFxSoundDriver: public SoundDriver, Audio::AudioStream {
private:
Common::Queue<RegisterValue> _queue;
GroupData _groupData;
Audio::Mixer *_mixer;
FM_OPL *_opl;
Audio::SoundHandle _soundHandle;
int _sampleRate;
byte _portContents[256];
int _masterVolume;
Common::Queue<RegisterValue> _queue;
bool _channelVoiced[ADLIB_CHANNEL_COUNT];
int _channelVolume[ADLIB_CHANNEL_COUNT];
int _v4405E[ADLIB_CHANNEL_COUNT];
int _v44067[ADLIB_CHANNEL_COUNT];
int _v44070[ADLIB_CHANNEL_COUNT];
int _v44079[ADLIB_CHANNEL_COUNT];
int _v44082[ADLIB_CHANNEL_COUNT + 1];
int _pitchBlend[ADLIB_CHANNEL_COUNT];
int _v4409E[ADLIB_CHANNEL_COUNT];
int _v45062;
int _v45066;
int _v45068;
int _v4506A;
int _v4506B;
bool _v45046;
byte _masterVolume;
byte _channelVolume;
Sound *_sound;
void write(byte reg, byte value);
void write(int v);
void flush();
void updateChannelVolume(int channel);
void setVoice(int channel);
void clearVoice(int channel);
void updateChannel(int channel);
void setFrequency(int channel);
void sub_4556E();
void write209();
void write211();
public:
AdlibFxSoundDriver();
virtual ~AdlibFxSoundDriver();
@ -490,12 +486,12 @@ public:
virtual void close();
virtual bool reset();
virtual const GroupData *getGroupData();
virtual void installPatch(const byte *data, int size) {}
virtual void poll();
virtual int setMasterVolume(int volume);
virtual void proc32(int channel, int program, int v0, int v1);
virtual void proc32(Sound *sound, int channel, int program, int v0, int v1);
virtual void updateVoice(int channel);
virtual void proc38(int channel, int cmd, int value);
virtual void setPitch(int channel, int pitchBlend);
virtual void proc42(int channel, int cmd, int value, int *v1, int *v2);
// AudioStream interface
virtual int readBuffer(int16 *buffer, const int numSamples);