[Scummvm-git-logs] scummvm master -> a4c247a1b54e6b73d245f91e7a33203041c36963
bluegr
noreply at scummvm.org
Thu Sep 12 22:04:57 UTC 2024
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
7dec8d50d9 SCI: (PCJr sound driver) - major cleanup
a4c247a1b5 SCI: (PCJr sound driver) - add pitch bend support
Commit: 7dec8d50d9c0011462c9477a6b257ba88d149028
https://github.com/scummvm/scummvm/commit/7dec8d50d9c0011462c9477a6b257ba88d149028
Author: athrxx (athrxx at scummvm.org)
Date: 2024-09-13T01:04:53+03:00
Commit Message:
SCI: (PCJr sound driver) - major cleanup
The code style was outdated and unpleasant.
I put all the channel code into sub classes and
improved the compliance with our coding
conventions,
Changed paths:
engines/sci/sound/drivers/pcjr.cpp
diff --git a/engines/sci/sound/drivers/pcjr.cpp b/engines/sci/sound/drivers/pcjr.cpp
index 1bb304fca61..f2db992a1f0 100644
--- a/engines/sci/sound/drivers/pcjr.cpp
+++ b/engines/sci/sound/drivers/pcjr.cpp
@@ -29,43 +29,381 @@
namespace Sci {
-#define VOLUME_SHIFT 3
-
-#define BASE_NOTE 129 // A10
-#define BASE_OCTAVE 10 // A10, as I said
-
-static const int freq_table[12] = { // A4 is 440Hz, halftone map is x |-> ** 2^(x/12)
- 28160, // A10
- 29834,
- 31608,
- 33488,
- 35479,
- 37589,
- 39824,
- 42192,
- 44701,
- 47359,
- 50175,
- 53159
+class SoundHWChannel {
+public:
+ SoundHWChannel(const uint16 *&_smpVolTable, const byte &masterVol, int outputRate);
+ virtual ~SoundHWChannel() {}
+
+ virtual void reset();
+ virtual void updateChannelVolume() = 0;
+ virtual void processEnvelope() = 0;
+ void recalcSample();
+
+ void setPart(byte number) { _partMapping = number; }
+
+ virtual void noteOn(byte note, byte velocity) = 0;
+ virtual void noteOff(byte sustain) = 0;
+ virtual void chanOff();
+ virtual void sustainOff() {}
+ void setVolume(byte volume) { _ctrlVolume = volume; }
+
+ int16 currentSample() const { return _curSample; }
+ bool isMappedToPart(byte part) const { return _partMapping == part; }
+ bool hasNote(byte note) const { return _note == note; }
+ bool isPlaying() const { return _note != 0xFF; }
+ virtual bool isSustained() const { return false; }
+ virtual uint16 getDuration() const { return 0; }
+
+protected:
+ byte _partMapping;
+ byte _ctrlVolume;
+ byte _velocity;
+ int8 _envVolume;
+ byte _note;
+ byte _envState;
+ byte _envCount;
+ int8 _envAttn;
+ int _freqCount;
+ uint16 _smpAmplitude;
+ int16 _curSample;
+
+ const int _outputRate;
+ const byte &_masterVolume;
+ const uint16 *&_smpVolTable;
+
+private:
+ int getFrequency() const;
+};
+
+class SoundChannel_PCSpeaker : public SoundHWChannel {
+public:
+ SoundChannel_PCSpeaker(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(smpVolTable, masterVol, outputRate) {}
+ ~SoundChannel_PCSpeaker() override {}
+
+ void reset() override;
+ void updateChannelVolume() override;
+ void processEnvelope() override {}
+
+ void noteOn(byte note, byte velocity) override;
+ void noteOff(byte) override;
+};
+
+class SoundChannel_PCJr_SCI0 : public SoundHWChannel {
+public:
+ SoundChannel_PCJr_SCI0(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(smpVolTable, masterVol, outputRate) {}
+ ~SoundChannel_PCJr_SCI0() override {}
+
+ void reset() override;
+ void updateChannelVolume() override;
+ void processEnvelope() override;
+
+ void noteOn(byte note, byte velocity) override;
+ void noteOff(byte) override;
+
+private:
+ void envAT();
+ void envST();
+ void envRL();
+
+ byte _envCount2;
};
-static inline int get_freq(int note) {
- int halftone_delta = note - BASE_NOTE;
- int oct_diff = ((halftone_delta + BASE_OCTAVE * 12) / 12) - BASE_OCTAVE;
- int halftone_index = (halftone_delta + (12 * 100)) % 12;
- int freq = (!note) ? 0 : freq_table[halftone_index] / (1 << (-oct_diff));
+class SoundChannel_PCJr_SCI1 : public SoundHWChannel {
+public:
+ SoundChannel_PCJr_SCI1(const uint16 *&smpVolTable, const byte &masterVol, int outputRate, const uint16 *&instrumentOffsets, const byte *&instrumentData, byte *&program) :
+ SoundHWChannel(smpVolTable, masterVol, outputRate), _instrumentOffsets(instrumentOffsets), _instrumentData(instrumentData), _program(program) {}
+ ~SoundChannel_PCJr_SCI1() override {}
+
+ void reset() override;
+ void updateChannelVolume() override;
+ void processEnvelope() override;
+
+ void noteOn(byte note, byte velocity) override;
+ void noteOff(byte sustain) override;
+ void chanOff() override;
+ void sustainOff() override;
+
+ bool isSustained() const override { return _sustain != 0; }
+ uint16 getDuration() const override { return _releaseDuration ? _releaseDuration + 0x8000 : _duration; }
+
+private:
+ void processInstrument();
+
+ uint16 _duration;
+ uint16 _releaseDuration;
+ byte _sustain;
+ byte _release;
+ byte *&_program;
+ const byte *_envData;
+ const uint16 *&_instrumentOffsets;
+ const byte *&_instrumentData;
+};
+
+SoundHWChannel::SoundHWChannel(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : _smpVolTable(smpVolTable), _masterVolume(masterVol), _outputRate(outputRate) {
+ reset();
+}
+
+void SoundHWChannel::reset() {
+ _partMapping = _note = 0xFF;
+ _ctrlVolume = _velocity = 0;
+ _envVolume = 0;
+ _envAttn = 0;
+ _envState = _envCount = 0;
+ _freqCount = 0;
+ _smpAmplitude = 0;
+ _curSample = 0;
+}
+
+void SoundHWChannel::recalcSample() {
+ int freq = getFrequency();
+ _freqCount += freq;
+
+ while (_freqCount >= (_outputRate << 1))
+ _freqCount -= (_outputRate << 1);
+
+ if (_freqCount - freq < 0) {
+ // Unclean rising edge
+ int l = _smpAmplitude << 1;
+ _curSample = (int16)~_smpAmplitude + (l * _freqCount) / freq;
+ } else if (_freqCount >= _outputRate && _freqCount - freq < _outputRate) {
+ // Unclean falling edge
+ int l = _smpAmplitude << 1;
+ _curSample = _smpAmplitude - (l * (_freqCount - _outputRate)) / freq;
+ } else {
+ if (_freqCount < _outputRate)
+ _curSample = _smpAmplitude;
+ else
+ _curSample = (int16)~_smpAmplitude;
+ }
+}
+
+void SoundHWChannel::chanOff() {
+ _note = 0xFF;
+ _envState = 0;
+ _envAttn = 0;
+ _envVolume = 0;
+ _envCount = 0;
+}
+
+#define SCI_PCJR_BASE_NOTE 129 // A10
+#define SCI_PCJR_BASE_OCTAVE 10 // A10, as I said
+
+int SoundHWChannel::getFrequency() const {
+ static const uint16 freqTable[12] = { // A4 is 440Hz, halftone map is x |-> ** 2^(x/12)
+ 28160, // A10
+ 29834,
+ 31608,
+ 33488,
+ 35479,
+ 37589,
+ 39824,
+ 42192,
+ 44701,
+ 47359,
+ 50175,
+ 53159
+ };
+
+ assert(_note != 0xFF);
+
+ int halftoneDelta = _note - SCI_PCJR_BASE_NOTE;
+ int octDiff = ((halftoneDelta + SCI_PCJR_BASE_OCTAVE * 12) / 12) - SCI_PCJR_BASE_OCTAVE;
+ int halftoneIndex = (halftoneDelta + (12 * 100)) % 12;
+ int freq = (!_note) ? 0 : freqTable[halftoneIndex] / (1 << (-octDiff));
return freq;
}
+#undef SCI_PCJR_BASE_NOTE
+#undef SCI_PCJR_BASE_OCTAVE
+
+void SoundChannel_PCSpeaker::reset() {
+ SoundHWChannel::reset();
+ updateChannelVolume();
+}
+
+void SoundChannel_PCSpeaker::updateChannelVolume() {
+ // The PC speaker has a fixed volume level. The original will turn it off if the volume is zero
+ // or otherwise turn it on. We just use the PCJr volume table for the master volume, so that our
+ // volume controls still work.
+ _smpAmplitude = _smpVolTable[15 - _masterVolume];
+}
+
+void SoundChannel_PCSpeaker::noteOn(byte note, byte velocity) {
+ _note = note;
+}
+
+void SoundChannel_PCSpeaker::noteOff(byte) {
+ chanOff();
+}
+
+void SoundChannel_PCJr_SCI0::reset() {
+ SoundHWChannel::reset();
+ _ctrlVolume = 96;
+ updateChannelVolume();
+}
+
+void SoundChannel_PCJr_SCI0::updateChannelVolume() {
+ int veloAttn = 3 - (_velocity >> 5);
+ int volAttn = 15 - (_ctrlVolume >> 3);
+ int attn = volAttn + veloAttn + _envVolume;
+ if (attn >= 15) {
+ attn = 15;
+ if (_envState >= 2)
+ chanOff();
+ } else if (attn < 0) {
+ attn = 0;
+ }
+ attn = CLIP<int>(attn + (15 - _masterVolume), volAttn, 15);
+ _smpAmplitude = _smpVolTable[attn];
+}
+
+void SoundChannel_PCJr_SCI0::processEnvelope() {
+ switch (_envState) {
+ case 1:
+ envAT();
+ break;
+ case 2:
+ envST();
+ break;
+ case 3:
+ envRL();
+ break;
+ default:
+ break;
+ }
+}
+
+void SoundChannel_PCJr_SCI0::noteOn(byte note, byte velocity) {
+ _note = note;
+ _velocity = velocity;
+ _envState = 1;
+ _envCount = 0;
+ envAT();
+}
+
+void SoundChannel_PCJr_SCI0::noteOff(byte) {
+ _envState = 3;
+ _envCount = 0;
+ envRL();
+}
+
+void SoundChannel_PCJr_SCI0::envAT() {
+ static const int8 envTable[] = { 0, -2, -3, -2, -1, 0, 127 };
+ byte c = _envCount++;
+ if (envTable[c] == 127) {
+ _envState++;
+ _envCount = 0;
+ _envCount2 = 20;
+ envST();
+ } else {
+ _envVolume = _envAttn = envTable[c];
+ updateChannelVolume();
+ }
+}
+
+void SoundChannel_PCJr_SCI0::envST() {
+ if (!_envCount2 || --_envCount2)
+ return;
+ _envVolume = ++_envAttn;
+ _envCount2 = 20;
+ updateChannelVolume();
+}
+
+void SoundChannel_PCJr_SCI0::envRL() {
+ static const byte envTable[] = { 1, 1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 7, 8, 9, 10, 11, 12, 127 };
+ byte c = _envCount++;
+ _envVolume = (envTable[c] == 127) ? 15 : _envAttn + envTable[c];
+ updateChannelVolume();
+}
+
+void SoundChannel_PCJr_SCI1::reset() {
+ SoundHWChannel::reset();
+ _duration = _releaseDuration = 0;
+ _sustain = _release = 0;
+ _ctrlVolume = _envVolume = 15;
+ _envData = nullptr;
+ updateChannelVolume();
+}
+
+void SoundChannel_PCJr_SCI1::updateChannelVolume() {
+ static const byte veloTable[16] = { 0x01, 0x03, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F };
+ int velo = _velocity ? veloTable[_velocity >> 3] : 0;
+ int vol = _ctrlVolume ? MAX<int>(1, _ctrlVolume >> 3) : 0;
+ int tl = ((vol * velo / 15) * _envVolume / 15) * _masterVolume;
+ if (tl > 0 && tl < 15)
+ tl = 15;
+ int attn = 15 - tl / 15;
+ _smpAmplitude = _smpVolTable[attn];
+}
+
+void SoundChannel_PCJr_SCI1::processEnvelope() {
+ ++_duration;
+ if (_release)
+ ++_releaseDuration;
+ processInstrument();
+ updateChannelVolume();
+}
+
+void SoundChannel_PCJr_SCI1::noteOn(byte note, byte velocity) {
+ _note = note;
+ _velocity = velocity;
+ _envState = 0;
+ _envCount = 0;
+ _duration = 0;
+ _releaseDuration = 0;
+ _release = 0;
+ _sustain = 0;
+
+ assert(_instrumentOffsets);
+ assert(_instrumentData);
+ _envData = &_instrumentData[_instrumentOffsets[_program[_partMapping]]];
+}
+
+void SoundChannel_PCJr_SCI1::noteOff(byte sustain) {
+ byte &dest = sustain ? _sustain : _release;
+ dest = 1;
+}
+
+void SoundChannel_PCJr_SCI1::chanOff() {
+ SoundHWChannel::chanOff();
+ _duration = 0;
+ _releaseDuration = 0;
+ _sustain = 0;
+ _release = 0;
+}
+
+void SoundChannel_PCJr_SCI1::sustainOff() {
+ _sustain = 0;
+ _release = 1;
+}
+
+void SoundChannel_PCJr_SCI1::processInstrument() {
+ if (_envCount == 0xFE) {
+ if (_release)
+ _envCount = 0;
+ else
+ return;
+ }
+
+ if (_envCount == 0) {
+ byte a = _envData[_envState << 1];
+ if (a == 0xFF) {
+ chanOff();
+ _envCount = 0;
+ } else {
+ _envCount = _envData[(_envState << 1) + 1];
+ _envVolume = a;
+ ++_envState;
+ }
+ } else {
+ --_envCount;
+ }
+}
+
class MidiDriver_PCJr : public MidiDriver_Emulated {
public:
friend class MidiPlayer_PCJr;
-
- enum {
- kMaxChannels = 3
- };
-
enum Properties {
kPropNone = 0,
kPropVolume
@@ -92,15 +430,7 @@ public:
private:
bool loadInstruments(Resource &resource);
- void updateChannelVolume(int chan);
- void updateSounds();
-
- void envAT(byte chan);
- void envST(byte chan);
- void envRL(byte chan);
- void envINST(byte chan);
- void chanNoteOn(byte chan, byte note, byte velocity);
- void chanOff(byte chan);
+ void processEnvelopes();
void noteOn(byte part, byte note, byte velocity);
void noteOff(byte part, byte note);
@@ -115,34 +445,23 @@ private:
void assignFreeChannels(byte part);
byte allocateChannel(byte part);
- byte _globalVolume; // Base volume
- byte _chanVolume[kMaxChannels];
- byte _chanVelocity[kMaxChannels];
- int8 _chanEnvVolume[kMaxChannels];
- uint16 _smpVolume[kMaxChannels];
- byte _notes[kMaxChannels]; // Current halftone, or 0 if off
- byte _envState[kMaxChannels];
- byte _envCount[kMaxChannels];
- byte _envCount2[kMaxChannels];
- const byte *_envData[kMaxChannels];
- int8 _envAttn[kMaxChannels];
- int _freq_count[kMaxChannels];
- byte _partMapping[kMaxChannels];
- uint16 _duration[kMaxChannels];
- uint16 _releaseDuration[kMaxChannels];
- byte _chanSustain[kMaxChannels];
- byte _chanRelease[kMaxChannels];
- byte _chanMapping[16];
- byte _chanMissing[16];
- byte _program[16];
- byte _partSustain[16];
+ byte _masterVolume;
+ byte *_chanMapping;
+ byte *_chanMissing;
+ byte *_program;
+ byte *_sustain;
+
uint32 _sndUpdateSmpQty;
uint32 _sndUpdateSmpQtyRem;
uint32 _sndUpdateCountDown;
uint32 _sndUpdateCountDownRem;
- const uint16 *_smpVolTable;
+
+ SoundHWChannel **_channels;
+
const uint16 *_instrumentOffsets;
- const uint8 *_instrumentData;
+ const byte *_instrumentData;
+
+ const uint16 *_smpVolTable;
const SciVersion _version;
const byte _numChannels;
const bool _pcsMode;
@@ -185,11 +504,11 @@ uint32 MidiDriver_PCJr::property(int prop, uint32 value) {
switch (prop) {
case kPropVolume:
- res = _globalVolume;
+ res = _masterVolume;
if (value != 0xffff) {
- _globalVolume = value;
+ _masterVolume = value;
for (int i = 0; i < _numChannels; ++i)
- updateChannelVolume(i);
+ _channels[i]->updateChannelVolume();
}
break;
default:
@@ -208,23 +527,15 @@ void MidiDriver_PCJr::initTrack(SciSpan<const byte> &header) {
if (caps != 0 && caps != 2)
return;
- for (int i = 0; i < _numChannels; ++i) {
- _smpVolume[i] = 0;
- _chanVolume[i] = 96;
- _chanVelocity[i] = 0;
- _notes[i] = 0xFF;
- _partMapping[i] = 0x10;
- _envState[i] = 0;
- _envCount[i] = 0;
- updateChannelVolume(i);
- }
+ for (int i = 0; i < _numChannels; ++i)
+ _channels[i]->reset();
if (_version == SCI_VERSION_0_EARLY) {
byte chanFlag = _pcsMode ? 0x04 : 0x02;
for (int i = 0, numAssigned = 0; i < 16 && numAssigned < _numChannels; ++i) {
uint8 f = header.getInt8At(++readPos);
if ((!(f & 8) || (f & 1)) && (f & chanFlag))
- _partMapping[numAssigned++] = i;
+ _channels[numAssigned++]->setPart(i);
}
} else {
byte chanFlag = _pcsMode ? 0x20 : 0x10;
@@ -232,18 +543,12 @@ void MidiDriver_PCJr::initTrack(SciSpan<const byte> &header) {
uint8 f = header.getInt8At(++readPos);
readPos++;
if (f & chanFlag)
- _partMapping[numAssigned++] = i;
+ _channels[numAssigned++]->setPart(i);
}
}
}
void MidiDriver_PCJr::generateSamples(int16 *data, int len) {
- int freq[kMaxChannels];
- int frequency = getRate();
-
- for (int chan = 0; chan < _numChannels; chan++)
- freq[chan] = get_freq(_notes[chan]);
-
for (int i = 0; i < len; i++) {
if (!--_sndUpdateCountDown) {
_sndUpdateCountDown = _sndUpdateSmpQty;
@@ -252,100 +557,80 @@ void MidiDriver_PCJr::generateSamples(int16 *data, int len) {
_sndUpdateCountDownRem -= (_sndUpdateSmpQty << 16);
++_sndUpdateCountDown;
}
- updateSounds();
+ processEnvelopes();
}
int16 result = 0;
- for (int chan = 0; chan < _numChannels; chan++)
- if (_notes[chan] != 0xFF) {
- uint16 volume = _smpVolume[chan];
- _freq_count[chan] += freq[chan];
- while (_freq_count[chan] >= (frequency << 1))
- _freq_count[chan] -= (frequency << 1);
-
- if (_freq_count[chan] - freq[chan] < 0) {
- // Unclean rising edge
- int l = volume << 1;
- result += (int16)~volume + (l * _freq_count[chan]) / freq[chan];
- } else if (_freq_count[chan] >= frequency && _freq_count[chan] - freq[chan] < frequency) {
- // Unclean falling edge
- int l = volume << 1;
- result += volume - (l * (_freq_count[chan] - frequency)) / freq[chan];
- } else {
- if (_freq_count[chan] < frequency)
- result += volume;
- else
- result += (int16)~volume;
- }
- }
+ for (int chan = 0; chan < _numChannels; chan++) {
+ if (!_channels[chan]->isPlaying())
+ continue;
+ _channels[chan]->recalcSample();
+ result += _channels[chan]->currentSample();
+ }
data[i] = result;
}
}
-MidiDriver_PCJr::MidiDriver_PCJr(Audio::Mixer *mixer, SciVersion version, bool pcsMode) : MidiDriver_Emulated(mixer), _version(version), _pcsMode(pcsMode),
- _numChannels(pcsMode ? 1 : 3), _globalVolume(0), _instrumentOffsets(nullptr), _instrumentData(nullptr), _smpVolTable(nullptr) {
- for (int i = 0; i < kMaxChannels; ++i) {
- _chanVolume[i] = 0;
- _chanVelocity[i] = 0;
- _chanEnvVolume[i] = 0;
- _smpVolume[i] = 0;
- _notes[i] = 0;
- _envState[i] = 0;
- _envCount[i] = 0;
- _envCount2[i] = 0;
- _envAttn[i] = 0;
- _freq_count[i] = 0;
- _partMapping[i] = 0;
- _duration[i] = 0;
- _releaseDuration[i] = 0;
- _chanSustain[i] = 0;
- _chanRelease[i] = 0;
- _envData[i] = nullptr;
- }
-
- for (int i = 0; i < 16; ++i) {
- _chanMapping[i] = 0;
- _chanMissing[i] = 0;
- _program[i] = 0;
- _partSustain[i] = 0;
- }
+MidiDriver_PCJr::MidiDriver_PCJr(Audio::Mixer *mixer, SciVersion version, bool pcsMode) : MidiDriver_Emulated(mixer), _version(version), _pcsMode(pcsMode), _numChannels(pcsMode ? 1 : 3),
+ _masterVolume(0), _channels(nullptr), _instrumentOffsets(nullptr), _instrumentData(nullptr) {
uint16 *smpVolTable = new uint16[16]();
for (int i = 0; i < 15; ++i) // The last entry is left at zero.
smpVolTable[i] = (double)((32767 & ~_numChannels) / _numChannels) / pow(10.0, (double)i / 10.0);
_smpVolTable = smpVolTable;
+ assert(_smpVolTable);
+
+ _chanMapping = new byte[16]();
+ _chanMissing = new byte[16]();
+ _program = new byte[16]();
+ _sustain = new byte[16]();
+
+ assert(_chanMapping);
+ assert(_chanMissing);
+ assert(_program);
+ assert(_sustain);
+
+ _channels = new SoundHWChannel*[_numChannels]();
+ assert(_channels);
+ for (int i = 0; i < _numChannels; ++i) {
+ if (pcsMode)
+ _channels[i] = new SoundChannel_PCSpeaker(_smpVolTable, _masterVolume, getRate());
+ else if (version <= SCI_VERSION_0_LATE)
+ _channels[i] = new SoundChannel_PCJr_SCI0(_smpVolTable, _masterVolume, getRate());
+ else
+ _channels[i] = new SoundChannel_PCJr_SCI1(_smpVolTable, _masterVolume, getRate(), _instrumentOffsets, _instrumentData, _program);
+ }
_sndUpdateSmpQty = (mixer->getOutputRate() << 16) / 0x3C0000;
_sndUpdateSmpQtyRem = (mixer->getOutputRate() << 16) % 0x3C0000;
_sndUpdateCountDown = _sndUpdateSmpQty;
_sndUpdateCountDownRem = 0;
-};
+}
MidiDriver_PCJr::~MidiDriver_PCJr() {
close();
+ if (_channels) {
+ for (int i = 0; i < _numChannels; ++i)
+ delete _channels[i];
+ delete[] _channels;
+ }
delete[] _smpVolTable;
delete[] _instrumentOffsets;
delete[] _instrumentData;
+ delete[] _chanMapping;
+ delete[] _chanMissing;
+ delete[] _program;
+ delete[] _sustain;
}
int MidiDriver_PCJr::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- _globalVolume = 15;
- for (int i = 0; i < _numChannels; i++) {
- _smpVolume[i] = 0;
- _chanVolume[i] = 15;
- _chanVelocity[i] = 0;
- _chanEnvVolume[i] = 15;
- _partMapping[i] = 0xFF;
- _notes[i] = 0xFF;
- _freq_count[i] = 0;
- _envState[i] = 0;
- _envCount[i] = 0;
- updateChannelVolume(i);
- }
+ _masterVolume = 15;
+ for (int i = 0; i < _numChannels; i++)
+ _channels[i]->reset();
if (_version > SCI_VERSION_0_LATE && !_pcsMode) {
ResourceManager *resMan = g_sci->getResMan();
@@ -402,202 +687,44 @@ bool MidiDriver_PCJr::loadInstruments(Resource &resource) {
return true;
}
-void MidiDriver_PCJr::updateChannelVolume(int chan) {
- assert(chan >= 0 && chan < kMaxChannels);
- int attn = 0;
-
- if (_pcsMode) {
- // The PC speaker has a fixed volume level. The original will turn it off if the volume is zero
- // or otherwise turn it on. We just use the PCJr volume table for the master volume, so that our
- // volume controls still work.
- attn = 15 - _globalVolume;
- } else if (_version <= SCI_VERSION_0_LATE) {
- int veloAttn = 3 - (_chanVelocity[chan] >> 5);
- int volAttn = 15 - (_chanVolume[chan] >> 3);
- attn = volAttn + veloAttn + _chanEnvVolume[chan];
- if (attn >= 15) {
- attn = 15;
- if (_envState[chan] >= 2)
- chanOff(chan);
- } else if (attn < 0) {
- attn = 0;
- }
- attn = CLIP<int>(attn + (15 - _globalVolume), volAttn, 15);
- } else {
- static const byte veloTable[16] = { 0x01, 0x03, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F };
- int velo = _chanVelocity[chan] ? veloTable[_chanVelocity[chan] >> 3] : 0;
- int vol = _chanVolume[chan] ? MAX<int>(1, _chanVolume[chan] >> 3) : 0;
- int tl = ((vol * velo / 15) * _chanEnvVolume[chan] / 15) * _globalVolume;
- if (tl > 0 && tl < 15)
- tl = 15;
- attn = 15 - tl / 15;
- }
-
- _smpVolume[chan] = _smpVolTable[attn];
-}
-
-void MidiDriver_PCJr::updateSounds() {
- if (_pcsMode)
- return;
-
+void MidiDriver_PCJr::processEnvelopes() {
for (int i = 0; i < _numChannels; i++) {
- if (_notes[i] == 0xFF)
- continue;
-
- if (_version > SCI_VERSION_0_LATE) {
- ++_duration[i];
- if (_chanRelease[i])
- ++_releaseDuration[i];
- envINST(i);
- updateChannelVolume(i);
- } else {
- switch (_envState[i]) {
- case 1:
- envAT(i);
- break;
- case 2:
- envST(i);
- break;
- case 3:
- envRL(i);
- break;
- default:
- break;
- }
- }
- }
-}
-
-void MidiDriver_PCJr::envAT(byte chan) {
- static const int8 envTable[] = { 0, -2, -3, -2, -1, 0, 127 };
- byte c = _envCount[chan]++;
- if (envTable[c] == 127) {
- _envState[chan]++;
- _envCount[chan] = 0;
- _envCount2[chan] = 20;
- envST(chan);
- } else {
- _chanEnvVolume[chan] = _envAttn[chan] = envTable[c];
- updateChannelVolume(chan);
- }
-}
-
-void MidiDriver_PCJr::envST(byte chan) {
- if (!_envCount2[chan] || --_envCount2[chan])
- return;
- _chanEnvVolume[chan] = ++_envAttn[chan];
- _envCount2[chan] = 20;
- updateChannelVolume(chan);
-}
-
-void MidiDriver_PCJr::envRL(byte chan) {
- static const byte envTable[] = { 1, 1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 7, 8, 9, 10, 11, 12, 127 };
- byte c = _envCount[chan]++;
- _chanEnvVolume[chan] = (envTable[c] == 127) ? 15 : _envAttn[chan] + envTable[c];
- updateChannelVolume(chan);
-}
-
-void MidiDriver_PCJr::envINST(byte chan) {
- if (_envCount[chan] == 0xFE) {
- if (_chanRelease[chan])
- _envCount[chan] = 0;
- else
- return;
- }
-
- if (_envCount[chan] == 0) {
- byte a = _envData[chan][_envState[chan] << 1];
- if (a == 0xFF) {
- chanOff(chan);
- _envCount[chan] = 0;
- } else {
- _envCount[chan] = _envData[chan][(_envState[chan] << 1) + 1];
- _chanEnvVolume[chan] = a;
- ++_envState[chan];
- }
- } else {
- --_envCount[chan];
+ if (_channels[i]->isPlaying())
+ _channels[i]->processEnvelope();
}
}
-void MidiDriver_PCJr::chanNoteOn(byte chan, byte note, byte velocity) {
- _notes[chan] = note;
- _chanVelocity[chan] = velocity;
- _envState[chan] = _version > SCI_VERSION_0_LATE ? 0 : 1;
- _envCount[chan] = 0;
- _duration[chan] = 0;
- _releaseDuration[chan] = 0;
- _chanRelease[chan] = 0;
- _chanSustain[chan] = 0;
-
- if (_pcsMode)
- return;
-
- if (_version <= SCI_VERSION_0_LATE) {
- envAT(chan);
- } else {
- assert(_instrumentOffsets);
- assert(_instrumentData);
- _envData[chan] = &_instrumentData[_instrumentOffsets[_program[_partMapping[chan]]]];
- }
-}
-
-void MidiDriver_PCJr::chanOff(byte chan) {
- _notes[chan] = 0xFF;
- _duration[chan] = 0;
- _releaseDuration[chan] = 0;
- _chanSustain[chan] = 0;
- _chanRelease[chan] = 0;
- _envState[chan] = 0;
- _envAttn[chan] = 0;
- _chanEnvVolume[chan] = 0;
- _envCount[chan] = 0;
-}
-
void MidiDriver_PCJr::noteOn(byte part, byte note, byte velocity) {
if (_pcsMode) {
- if (_partMapping[0] != part)
- return;
- chanOff(0);
- if (note < 24 || note > 119)
+ if (!_channels[0]->isMappedToPart(part))
return;
- chanNoteOn(0, note, velocity);
+ _channels[0]->chanOff();
+ if (note >= 24 && note <= 119)
+ _channels[0]->noteOn(note, velocity);
return;
} else if (_version > SCI_VERSION_0_LATE) {
if (note < 21 || note > 116)
return;
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] != part || _notes[i] != note)
+ if (!_channels[i]->isMappedToPart(part) || !_channels[i]->hasNote(note))
continue;
- chanOff(i);
- chanNoteOn(i, note, velocity);
+ _channels[i]->chanOff();
+ _channels[i]->noteOn(note, velocity);
return;
}
}
byte c = allocateChannel(part);
if (c != 0xFF)
- chanNoteOn(c, note, velocity);
+ _channels[c]->noteOn(note, velocity);
}
void MidiDriver_PCJr::noteOff(byte part, byte note) {
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] != part || _notes[i] != note)
+ if (!_channels[i]->isMappedToPart(part) || !_channels[i]->hasNote(note))
continue;
-
- if (_pcsMode) {
- chanOff(i);
- } else if (_version > SCI_VERSION_0_LATE) {
- if (_partSustain[part])
- _chanSustain[i] = 1;
- else
- _chanRelease[i] = 1;
- } else {
- _envState[i] = 3;
- _envCount[i] = 0;
- envRL(i);
- }
+ _channels[i]->noteOff(_sustain[part]);
}
}
@@ -605,8 +732,8 @@ void MidiDriver_PCJr::controlChange(byte part, byte controller, byte value) {
switch (controller) {
case 7:
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] == part)
- _chanVolume[i] = value;
+ if (_channels[i]->isMappedToPart(part))
+ _channels[i]->setVolume(value);
}
break;
case 64:
@@ -618,8 +745,8 @@ void MidiDriver_PCJr::controlChange(byte part, byte controller, byte value) {
case SCI_MIDI_CHANNEL_NOTES_OFF:
case SCI_MIDI_CHANNEL_SOUND_OFF:
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] == part)
- chanOff(i);
+ if (_channels[i]->isMappedToPart(part))
+ _channels[i]->chanOff();
}
break;
default:
@@ -639,15 +766,13 @@ void MidiDriver_PCJr::controlChangeSustain(byte part, byte sus) {
if (_version <= SCI_VERSION_0_LATE || _pcsMode)
return;
- _partSustain[part] = sus;
+ _sustain[part] = sus;
if (sus)
return;
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] != part || !_chanSustain[i])
- continue;
- _chanSustain[i] = 0;
- _chanRelease[i] = 1;
+ if (_channels[i]->isMappedToPart(part) && _channels[i]->isSustained())
+ _channels[i]->sustainOff();
}
}
@@ -656,15 +781,15 @@ void MidiDriver_PCJr::controlChangePolyphony(byte part, byte numChan) {
return;
if (_pcsMode) {
- if (numChan == 0 || _partMapping[0] != part)
- chanOff(0);
- _partMapping[0] = numChan ? part : 0xFF;
+ if (numChan == 0 || !_channels[0]->isMappedToPart(part))
+ _channels[0]->chanOff();
+ _channels[0]->setPart(numChan ? part : 0xFF);
return;
}
uint8 numAssigned = 0;
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] == part)
+ if (_channels[i]->isMappedToPart(part))
numAssigned++;
}
@@ -679,12 +804,12 @@ void MidiDriver_PCJr::controlChangePolyphony(byte part, byte numChan) {
void MidiDriver_PCJr::addChannels(byte part, byte num) {
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] != 0xFF)
+ if (!_channels[i]->isMappedToPart(0xFF))
continue;
- _partMapping[i] = part;
+ _channels[i]->setPart(part);
- if (_notes[i] != 0xFF)
- chanOff(i);
+ if (_channels[i]->isPlaying())
+ _channels[i]->chanOff();
if (!--num)
break;
@@ -705,9 +830,9 @@ void MidiDriver_PCJr::dropChannels(byte part, byte num) {
_chanMissing[part] = 0;
for (int i = 0; i < _numChannels; i++) {
- if (_partMapping[i] != part || _notes[i] != 0xFF)
+ if (!_channels[i]->isMappedToPart(part) || _channels[i]->isPlaying())
continue;
- _partMapping[i] = 0xFF;
+ _channels[i]->setPart(0xFF);
if (!--num)
return;
}
@@ -716,10 +841,10 @@ void MidiDriver_PCJr::dropChannels(byte part, byte num) {
uint16 oldest = 0;
byte dropCh = 0;
for (int i = 0; i < _numChannels; i++) {
- if (_partMapping[i] != part)
+ if (!_channels[i]->isMappedToPart(part))
continue;
- uint16 ct = _releaseDuration[i] ? _releaseDuration[i] + 0x8000 : _duration[i];
+ uint16 ct = _channels[i]->getDuration();
if (ct >= oldest) {
dropCh = i;
@@ -727,15 +852,15 @@ void MidiDriver_PCJr::dropChannels(byte part, byte num) {
}
}
- chanOff(dropCh);
- _partMapping[dropCh] = 0xFF;
+ _channels[dropCh]->chanOff();
+ _channels[dropCh]->setPart(0xFF);
} while (--num);
}
void MidiDriver_PCJr::assignFreeChannels(byte part) {
uint8 freeChan = 0;
for (int i = 0; i < _numChannels; i++) {
- if (_partMapping[i] == 0xff)
+ if (_channels[i]->isMappedToPart(0xFF))
freeChan++;
}
@@ -761,7 +886,7 @@ byte MidiDriver_PCJr::allocateChannel(byte part) {
byte res = 0xFF;
if (_version <= SCI_VERSION_0_LATE) {
for (int i = 0; i < _numChannels; ++i) {
- if (_partMapping[i] == part)
+ if (_channels[i]->isMappedToPart(part))
res = i;
}
return res;
@@ -775,15 +900,15 @@ byte MidiDriver_PCJr::allocateChannel(byte part) {
if (c == _chanMapping[part])
loop = false;
- if (_partMapping[c] != part)
+ if (!_channels[c]->isMappedToPart(part))
continue;
- if (_notes[c] == 0xFF) {
+ if (!_channels[c]->isPlaying()) {
_chanMapping[part] = c;
return c;
}
- uint16 ct = _releaseDuration[c] ? _releaseDuration[c] + 0x8000 : _duration[c];
+ uint16 ct = _channels[c]->getDuration();
if (ct < oldest)
continue;
@@ -793,7 +918,7 @@ byte MidiDriver_PCJr::allocateChannel(byte part) {
if (oldest != 0) {
_chanMapping[part] = res;
- chanOff(res);
+ _channels[res]->chanOff();
}
return res;
@@ -823,7 +948,7 @@ byte MidiPlayer_PCJr::getPlayId() const {
void MidiPlayer_PCJr::initTrack(SciSpan<const byte> &trackData) {
if (_driver)
static_cast<MidiDriver_PCJr*>(_driver)->initTrack(trackData);
-};
+}
MidiPlayer *MidiPlayer_PCJr_create(SciVersion version) {
return new MidiPlayer_PCJr(version, false);
Commit: a4c247a1b54e6b73d245f91e7a33203041c36963
https://github.com/scummvm/scummvm/commit/a4c247a1b54e6b73d245f91e7a33203041c36963
Author: athrxx (athrxx at scummvm.org)
Date: 2024-09-13T01:04:53+03:00
Commit Message:
SCI: (PCJr sound driver) - add pitch bend support
Changed paths:
engines/sci/sound/drivers/pcjr.cpp
diff --git a/engines/sci/sound/drivers/pcjr.cpp b/engines/sci/sound/drivers/pcjr.cpp
index f2db992a1f0..948c835f136 100644
--- a/engines/sci/sound/drivers/pcjr.cpp
+++ b/engines/sci/sound/drivers/pcjr.cpp
@@ -31,7 +31,7 @@ namespace Sci {
class SoundHWChannel {
public:
- SoundHWChannel(const uint16 *&_smpVolTable, const byte &masterVol, int outputRate);
+ SoundHWChannel(const Common::SharedPtr<const uint16> &freqTable, const Common::SharedPtr<const uint16> &smpVolTable, const byte &masterVol, int outputRate);
virtual ~SoundHWChannel() {}
virtual void reset();
@@ -45,6 +45,7 @@ public:
virtual void noteOff(byte sustain) = 0;
virtual void chanOff();
virtual void sustainOff() {}
+ void pitchBend(uint16 pb);
void setVolume(byte volume) { _ctrlVolume = volume; }
int16 currentSample() const { return _curSample; }
@@ -60,24 +61,28 @@ protected:
byte _velocity;
int8 _envVolume;
byte _note;
+ byte _pbDiv;
byte _envState;
byte _envCount;
int8 _envAttn;
- int _freqCount;
uint16 _smpAmplitude;
- int16 _curSample;
const int _outputRate;
const byte &_masterVolume;
- const uint16 *&_smpVolTable;
+ const Common::SharedPtr<const uint16> _freqTable;
+ const Common::SharedPtr<const uint16> _smpVolTable;
private:
int getFrequency() const;
+
+ int16 _pitchBend;
+ int16 _curSample;
+ int _freqCount;
};
class SoundChannel_PCSpeaker : public SoundHWChannel {
public:
- SoundChannel_PCSpeaker(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(smpVolTable, masterVol, outputRate) {}
+ SoundChannel_PCSpeaker(const Common::SharedPtr<const uint16> &freqTable, const Common::SharedPtr<const uint16> &smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(freqTable, smpVolTable, masterVol, outputRate) {}
~SoundChannel_PCSpeaker() override {}
void reset() override;
@@ -90,7 +95,7 @@ public:
class SoundChannel_PCJr_SCI0 : public SoundHWChannel {
public:
- SoundChannel_PCJr_SCI0(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(smpVolTable, masterVol, outputRate) {}
+ SoundChannel_PCJr_SCI0(const Common::SharedPtr<const uint16> &freqTable, const Common::SharedPtr<const uint16> &smpVolTable, const byte &masterVol, int outputRate) : SoundHWChannel(freqTable, smpVolTable, masterVol, outputRate), _envCount2(0) {}
~SoundChannel_PCJr_SCI0() override {}
void reset() override;
@@ -110,8 +115,9 @@ private:
class SoundChannel_PCJr_SCI1 : public SoundHWChannel {
public:
- SoundChannel_PCJr_SCI1(const uint16 *&smpVolTable, const byte &masterVol, int outputRate, const uint16 *&instrumentOffsets, const byte *&instrumentData, byte *&program) :
- SoundHWChannel(smpVolTable, masterVol, outputRate), _instrumentOffsets(instrumentOffsets), _instrumentData(instrumentData), _program(program) {}
+ SoundChannel_PCJr_SCI1(const Common::SharedPtr<const uint16> &freqTable, const Common::SharedPtr<const uint16> &smpVolTable, const byte &masterVol, int outputRate, const uint16 *&instrumentOffsets, const byte *&instrumentData, byte *&program) :
+ SoundHWChannel(freqTable, smpVolTable, masterVol, outputRate), _instrumentOffsets(instrumentOffsets), _instrumentData(instrumentData), _program(program), _duration(0), _releaseDuration(0), _sustain(0),
+ _release(0), _envData(nullptr) {}
~SoundChannel_PCJr_SCI1() override {}
void reset() override;
@@ -139,7 +145,7 @@ private:
const byte *&_instrumentData;
};
-SoundHWChannel::SoundHWChannel(const uint16 *&smpVolTable, const byte &masterVol, int outputRate) : _smpVolTable(smpVolTable), _masterVolume(masterVol), _outputRate(outputRate) {
+SoundHWChannel::SoundHWChannel(const Common::SharedPtr<const uint16> &freqTable, const Common::SharedPtr<const uint16> &smpVolTable, const byte &masterVol, int outputRate) : _freqTable(freqTable), _smpVolTable(smpVolTable), _masterVolume(masterVol), _outputRate(outputRate) {
reset();
}
@@ -152,6 +158,7 @@ void SoundHWChannel::reset() {
_freqCount = 0;
_smpAmplitude = 0;
_curSample = 0;
+ _pitchBend = 0;
}
void SoundHWChannel::recalcSample() {
@@ -185,31 +192,21 @@ void SoundHWChannel::chanOff() {
_envCount = 0;
}
+void SoundHWChannel::pitchBend(uint16 pb) {
+ _pitchBend = ((pb < 0x2000) ? -(0x2000 - pb) : pb - 0x2000) / _pbDiv;
+}
+
#define SCI_PCJR_BASE_NOTE 129 // A10
#define SCI_PCJR_BASE_OCTAVE 10 // A10, as I said
int SoundHWChannel::getFrequency() const {
- static const uint16 freqTable[12] = { // A4 is 440Hz, halftone map is x |-> ** 2^(x/12)
- 28160, // A10
- 29834,
- 31608,
- 33488,
- 35479,
- 37589,
- 39824,
- 42192,
- 44701,
- 47359,
- 50175,
- 53159
- };
+ if (_note == 0xFF)
+ return 0;
- assert(_note != 0xFF);
-
- int halftoneDelta = _note - SCI_PCJR_BASE_NOTE;
- int octDiff = ((halftoneDelta + SCI_PCJR_BASE_OCTAVE * 12) / 12) - SCI_PCJR_BASE_OCTAVE;
- int halftoneIndex = (halftoneDelta + (12 * 100)) % 12;
- int freq = (!_note) ? 0 : freqTable[halftoneIndex] / (1 << (-octDiff));
+ int halftoneDelta = (_note - SCI_PCJR_BASE_NOTE) * 4 + _pitchBend;
+ int octDiff = ((halftoneDelta + SCI_PCJR_BASE_OCTAVE * 48) / 48) - SCI_PCJR_BASE_OCTAVE;
+ int halftoneIndex = (halftoneDelta + (48 * 100)) % 48;
+ int freq = _freqTable.get()[halftoneIndex] / (1 << (-octDiff));
return freq;
}
@@ -219,6 +216,7 @@ int SoundHWChannel::getFrequency() const {
void SoundChannel_PCSpeaker::reset() {
SoundHWChannel::reset();
+ _pbDiv = 171;
updateChannelVolume();
}
@@ -226,7 +224,7 @@ void SoundChannel_PCSpeaker::updateChannelVolume() {
// The PC speaker has a fixed volume level. The original will turn it off if the volume is zero
// or otherwise turn it on. We just use the PCJr volume table for the master volume, so that our
// volume controls still work.
- _smpAmplitude = _smpVolTable[15 - _masterVolume];
+ _smpAmplitude = _smpVolTable.get()[15 - _masterVolume];
}
void SoundChannel_PCSpeaker::noteOn(byte note, byte velocity) {
@@ -240,6 +238,7 @@ void SoundChannel_PCSpeaker::noteOff(byte) {
void SoundChannel_PCJr_SCI0::reset() {
SoundHWChannel::reset();
_ctrlVolume = 96;
+ _pbDiv = 171;
updateChannelVolume();
}
@@ -255,7 +254,7 @@ void SoundChannel_PCJr_SCI0::updateChannelVolume() {
attn = 0;
}
attn = CLIP<int>(attn + (15 - _masterVolume), volAttn, 15);
- _smpAmplitude = _smpVolTable[attn];
+ _smpAmplitude = _smpVolTable.get()[attn];
}
void SoundChannel_PCJr_SCI0::processEnvelope() {
@@ -323,6 +322,7 @@ void SoundChannel_PCJr_SCI1::reset() {
_sustain = _release = 0;
_ctrlVolume = _envVolume = 15;
_envData = nullptr;
+ _pbDiv = 170;
updateChannelVolume();
}
@@ -334,7 +334,7 @@ void SoundChannel_PCJr_SCI1::updateChannelVolume() {
if (tl > 0 && tl < 15)
tl = 15;
int attn = 15 - tl / 15;
- _smpAmplitude = _smpVolTable[attn];
+ _smpAmplitude = _smpVolTable.get()[attn];
}
void SoundChannel_PCJr_SCI1::processEnvelope() {
@@ -461,7 +461,6 @@ private:
const uint16 *_instrumentOffsets;
const byte *_instrumentData;
- const uint16 *_smpVolTable;
const SciVersion _version;
const byte _numChannels;
const bool _pcsMode;
@@ -490,7 +489,7 @@ void MidiDriver_PCJr::send(uint32 b) {
programChange(part, op1);
break;
case 0xe0:
- pitchBend(part, op1 | (op2 << 7));
+ pitchBend(part, (op1 & 0x7f) | ((op2 & 0x7f) << 7));
break;
default:
debug(2, "Unused MIDI command %02x %02x %02x", command, op1, op2);
@@ -578,8 +577,13 @@ MidiDriver_PCJr::MidiDriver_PCJr(Audio::Mixer *mixer, SciVersion version, bool p
uint16 *smpVolTable = new uint16[16]();
for (int i = 0; i < 15; ++i) // The last entry is left at zero.
smpVolTable[i] = (double)((32767 & ~_numChannels) / _numChannels) / pow(10.0, (double)i / 10.0);
- _smpVolTable = smpVolTable;
- assert(_smpVolTable);
+ Common::SharedPtr<const uint16> smpVolTablePtr(smpVolTable, Common::ArrayDeleter<const uint16>());
+
+ uint16 *freqTable = new uint16[48]();
+ assert(freqTable);
+ for (int i = 0; i < 48; ++i)
+ freqTable[i] = pow(2, (double)(288 + i) / 48.0) * 440.0;
+ Common::SharedPtr<const uint16> freqTablePtr(freqTable, Common::ArrayDeleter<const uint16>());
_chanMapping = new byte[16]();
_chanMissing = new byte[16]();
@@ -595,11 +599,11 @@ MidiDriver_PCJr::MidiDriver_PCJr(Audio::Mixer *mixer, SciVersion version, bool p
assert(_channels);
for (int i = 0; i < _numChannels; ++i) {
if (pcsMode)
- _channels[i] = new SoundChannel_PCSpeaker(_smpVolTable, _masterVolume, getRate());
+ _channels[i] = new SoundChannel_PCSpeaker(freqTablePtr, smpVolTablePtr, _masterVolume, getRate());
else if (version <= SCI_VERSION_0_LATE)
- _channels[i] = new SoundChannel_PCJr_SCI0(_smpVolTable, _masterVolume, getRate());
+ _channels[i] = new SoundChannel_PCJr_SCI0(freqTablePtr, smpVolTablePtr, _masterVolume, getRate());
else
- _channels[i] = new SoundChannel_PCJr_SCI1(_smpVolTable, _masterVolume, getRate(), _instrumentOffsets, _instrumentData, _program);
+ _channels[i] = new SoundChannel_PCJr_SCI1(freqTablePtr, smpVolTablePtr, _masterVolume, getRate(), _instrumentOffsets, _instrumentData, _program);
}
_sndUpdateSmpQty = (mixer->getOutputRate() << 16) / 0x3C0000;
@@ -615,7 +619,7 @@ MidiDriver_PCJr::~MidiDriver_PCJr() {
delete _channels[i];
delete[] _channels;
}
- delete[] _smpVolTable;
+
delete[] _instrumentOffsets;
delete[] _instrumentData;
delete[] _chanMapping;
@@ -713,6 +717,8 @@ void MidiDriver_PCJr::noteOn(byte part, byte note, byte velocity) {
_channels[i]->noteOn(note, velocity);
return;
}
+ } else if (note == 0) {
+ return;
}
byte c = allocateChannel(part);
@@ -760,6 +766,10 @@ void MidiDriver_PCJr::programChange(byte part, byte program) {
}
void MidiDriver_PCJr::pitchBend(byte part, uint16 value) {
+ for (int i = 0; i < _numChannels; ++i) {
+ if (_channels[i]->isMappedToPart(part))
+ _channels[i]->pitchBend(value);
+ }
}
void MidiDriver_PCJr::controlChangeSustain(byte part, byte sus) {
More information about the Scummvm-git-logs
mailing list