aboutsummaryrefslogtreecommitdiff
path: root/sound/mods
diff options
context:
space:
mode:
authorNorbert Lange2009-07-19 14:02:19 +0000
committerNorbert Lange2009-07-19 14:02:19 +0000
commitdbe300fc5303028af56a55efeecd99a0992a7928 (patch)
treea1132a076c484f95b0e596b350cbbe3c18c88251 /sound/mods
parent31b6767666c3ed5f3ef0660218941d26eccf2446 (diff)
downloadscummvm-rg350-dbe300fc5303028af56a55efeecd99a0992a7928.tar.gz
scummvm-rg350-dbe300fc5303028af56a55efeecd99a0992a7928.tar.bz2
scummvm-rg350-dbe300fc5303028af56a55efeecd99a0992a7928.zip
fixed retiring of external Notes
fixed/improved counting DMAs in Paula added flag for looping songs rearranged maxtrax.h a bit svn-id: r42613
Diffstat (limited to 'sound/mods')
-rw-r--r--sound/mods/maxtrax.cpp77
-rw-r--r--sound/mods/maxtrax.h73
-rw-r--r--sound/mods/paula.cpp31
3 files changed, 99 insertions, 82 deletions
diff --git a/sound/mods/maxtrax.cpp b/sound/mods/maxtrax.cpp
index 38327eda32..b09e2ea732 100644
--- a/sound/mods/maxtrax.cpp
+++ b/sound/mods/maxtrax.cpp
@@ -33,7 +33,7 @@
namespace Audio {
MaxTrax::MaxTrax(int rate, bool stereo)
- : Paula(stereo, rate, rate/50), _voiceCtx(), _patch(), _scores(), _numScores(), _microtonal() {
+ : Paula(stereo, rate, rate/50), _voiceCtx(), _patch(), _scores(), _numScores() {
_playerCtx.maxScoreNum = 128;
_playerCtx.vBlankFreq = 50;
_playerCtx.frameUnit = (uint16)((1000 * (1<<8)) / _playerCtx.vBlankFreq);
@@ -180,7 +180,7 @@ endOfEventLoop:
switch (voice.status) {
case VoiceContext::kStatusSustain:
- if (!channel.isAltered && !voice.hasPortamento && !channel.modulation)
+ if (!channel.isAltered && !voice.hasPortamento/* && !channel.modulation*/)
continue;
// Update Volume and Period
break;
@@ -277,7 +277,7 @@ endOfEventLoop:
voice.preCalcNote = precalcNote(voice.baseNote, patch.tune, voice.octave);
}
voice.lastPeriod = calcNote(voice);
- } else if (channel.isAltered || channel.modulation)
+ } else if (channel.isAltered/* || channel.modulation*/)
voice.lastPeriod = calcNote(voice);
}
@@ -288,8 +288,20 @@ endOfEventLoop:
for (ChannelContext *c = _channelCtx; c != &_channelCtx[ARRAYSIZE(_channelCtx)]; ++c)
c->isAltered = false;
-
//modulation stuff, sinevalue += tickunit
+
+ // we need to check if some voices have no sustainSample.
+ // in that case they are finished after the attackSample is done
+ for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
+ VoiceContext &voice = _voiceCtx[i];
+ if (voice.dmaOff && Paula::getChannelDmaCount((byte)i) >= voice.dmaOff ) {
+ voice.isBlocked = false;
+ voice.priority = 0;
+ voice.dmaOff = 0;
+ if (voice.status == VoiceContext::kStatusSustain)
+ voice.status = VoiceContext::kStatusRelease;
+ }
+ }
}
int32 MaxTrax::calcVolumeDelta(int32 delta, uint16 time) {
@@ -306,12 +318,12 @@ void MaxTrax::stopMusic() {
_playerCtx.nextEvent = 0;
}
-bool MaxTrax::doSong(int songIndex, int advance) {
+bool MaxTrax::playSong(int songIndex, bool loop, int advance) {
if (songIndex < 0 || songIndex >= _numScores)
return false;
Common::StackLock lock(_mutex);
_playerCtx.musicPlaying = false;
- _playerCtx.musicLoop = false;
+ _playerCtx.musicLoop = loop;
setTempo(_playerCtx.tempoInitial << 4);
_playerCtx.tempoTime = 0;
@@ -326,9 +338,9 @@ bool MaxTrax::doSong(int songIndex, int advance) {
const Event *cev = _scores[songIndex].events;
// Songs are special markers in the score
for (; advance > 0; --advance) {
- // TODO - check for boundaries
+ // TODO - check for boundaries
for(; cev->command != 0xFF && (cev->command != 0xA0 || (cev->stopTime >> 8) != 0x00); ++cev)
- ;
+ ; // no end_command or special_command + end
}
_playerCtx.nextEvent = cev;
_playerCtx.nextEventTime = cev->startTime;
@@ -345,9 +357,11 @@ void MaxTrax::killVoice(byte num) {
voice.channel = 0;
voice.envelope = 0;
voice.status = VoiceContext::kStatusFree;
- voice.flags = 0;
+ voice.isBlocked = false;
+ voice.hasDamper = false;
voice.hasPortamento = false;
voice.priority = 0;
+ voice.dmaOff = 0;
//voice.uinqueId = 0;
// "stop" voice, set period to 1, vol to 0
@@ -357,7 +371,6 @@ void MaxTrax::killVoice(byte num) {
}
int8 MaxTrax::pickvoice(const VoiceContext voices[4], uint pick, int16 pri) {
- pick &= 3;
enum { kPrioFlagFixedSide = 1 << 3 };
if ((pri & (kPrioFlagFixedSide)) == 0) {
const bool leftSide = (uint)(pick - 1) > 1;
@@ -366,17 +379,16 @@ int8 MaxTrax::pickvoice(const VoiceContext voices[4], uint pick, int16 pri) {
const int sameSide = (leftSide) ? leftBest : rightBest;
const int otherSide = leftBest + rightBest - sameSide;
- if (sameSide > VoiceContext::kStatusRelease && otherSide <= VoiceContext::kStatusRelease) {
+ if (sameSide > VoiceContext::kStatusRelease && otherSide <= VoiceContext::kStatusRelease)
pick ^= 1; // switches sides
- }
}
- pri &= ~kPrioFlagFixedSide;
+ pick &= 3;
- for (int i = 1; i > 0; --i) {
+ for (int i = 2; i > 0; --i) {
const VoiceContext *voice = &voices[pick];
const VoiceContext *alternate = &voices[pick ^ 3];
- if (voice->status > alternate->status
+ if (voice->status > alternate->status
|| (voice->status == alternate->status && voice->lastVolume > alternate->lastVolume)) {
// TODO: tiebreaking
pick ^= 3; // switch channels
@@ -385,9 +397,9 @@ int8 MaxTrax::pickvoice(const VoiceContext voices[4], uint pick, int16 pri) {
alternate = tmp;
}
- if ((voice->flags & VoiceContext::kFlagBlocked) != 0 || voice->priority > pri) {
+ if (voice->isBlocked || voice->priority > pri) {
pick ^= 3; // switch channels
- if ((alternate->flags & VoiceContext::kFlagBlocked) != 0 || alternate->priority > pri) {
+ if (alternate->isBlocked || alternate->priority > pri) {
// if not already done, switch sides and try again
pick ^= 1;
continue;
@@ -397,6 +409,7 @@ int8 MaxTrax::pickvoice(const VoiceContext voices[4], uint pick, int16 pri) {
return (int8)pick;
}
// failed
+ debug("Nopick");
return -1;
}
@@ -426,13 +439,13 @@ uint16 MaxTrax::calcNote(const VoiceContext &voice) {
}
int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, uint16 pri) {
- if (channel.microtonal >= 0)
- _microtonal[note % 127] = channel.microtonal;
+// if (channel.microtonal >= 0)
+// _microtonal[note % 127] = channel.microtonal;
if (!volume)
return -1;
const Patch &patch = *channel.patch;
- if (!patch.samplePtr)
+ if (!patch.samplePtr || patch.sampleTotalLen == 0)
return -1;
int8 voiceNum = -1;
if ((channel.flags & ChannelContext::kFlagMono) != 0 && channel.voicesActive) {
@@ -454,12 +467,11 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
voiceNum = pickvoice(_voiceCtx, (channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
if (voiceNum >= 0) {
VoiceContext &voice = _voiceCtx[voiceNum];
- voice.flags = 0;
+ voice.hasDamper = false;
+ voice.isBlocked = false;
voice.hasPortamento = false;
- if (voice.channel) {
+ if (voice.channel)
killVoice(voiceNum);
- voice.flags |= VoiceContext::kFlagStolen;
- }
voice.channel = &channel;
voice.patch = &patch;
voice.baseNote = note;
@@ -501,6 +513,8 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
if (patch.sampleTotalLen == patch.sampleAttackLen) {
Paula::setChannelSampleStart(voiceNum, 0);
Paula::setChannelSampleLen(voiceNum, 0);
+ Paula::setChannelDmaCount(voiceNum);
+ voice.dmaOff = 1;
}
}
@@ -543,7 +557,7 @@ void MaxTrax::noteOff(VoiceContext &voice, const byte note) {
assert(refNote == note);
if (refNote == note) {
if ((channel.flags & ChannelContext::kFlagDamper) != 0)
- voice.flags |= VoiceContext::kFlagDamper;
+ voice.hasDamper = true;
else
voice.status = VoiceContext::kStatusRelease;
}
@@ -551,9 +565,9 @@ void MaxTrax::noteOff(VoiceContext &voice, const byte note) {
}
void MaxTrax::resetChannel(ChannelContext &chan, bool rightChannel) {
- chan.modulation = 0;
- chan.modulationTime = 1000;
- chan.microtonal = -1;
+// chan.modulation = 0;
+// chan.modulationTime = 1000;
+// chan.microtonal = -1;
chan.portamentoTime = 500;
chan.pitchBend = 64 << 7;
chan.pitchReal = 0;
@@ -575,7 +589,7 @@ void MaxTrax::freeScores() {
_scores = 0;
}
_numScores = 0;
- memset(_microtonal, 0, sizeof(_microtonal));
+// memset(_microtonal, 0, sizeof(_microtonal));
}
void MaxTrax::freePatches() {
@@ -600,6 +614,7 @@ int MaxTrax::playNote(byte note, byte patch, uint16 duration, uint16 volume, boo
voice.stopEventCommand = note;
voice.stopEventParameter = kNumChannels;
voice.stopEventTime = duration << 8;
+ debug("Extranote: %d, stoptime: %d", voiceIndex, (voice.stopEventTime / (_playerCtx.frameUnit * 50)) );
}
return voiceIndex;
}
@@ -629,10 +644,10 @@ bool MaxTrax::load(Common::SeekableReadStream &musicData, bool loadScores, bool
if (flags & (1 << 15)) {
debug("Song has microtonal");
- if (loadScores) {
+/* if (loadScores) {
for (int i = 0; i < ARRAYSIZE(_microtonal); ++i)
_microtonal[i] = musicData.readUint16BE();
- } else
+ } else*/
musicData.skip(128 * 2);
}
diff --git a/sound/mods/maxtrax.h b/sound/mods/maxtrax.h
index 9fef3e68f0..65a504fcaf 100644
--- a/sound/mods/maxtrax.h
+++ b/sound/mods/maxtrax.h
@@ -35,18 +35,38 @@ public:
MaxTrax(int rate, bool stereo);
virtual ~MaxTrax();
+ bool load(Common::SeekableReadStream &musicData, bool loadScores = true, bool loadSamples = true);
+ bool playSong(int songIndex, bool loop = false, int advance = 0);
+ int playNote(byte note, byte patch, uint16 duration, uint16 volume, bool rightSide);
+ void setVolume(const byte volume) { _playerCtx.volume = volume; }
+ void setTempo(const uint16 tempo) {
+ _playerCtx.tickUnit = (int32)(((uint32)(tempo & 0xFFF0) << 8) / (uint16)(5 * _playerCtx.vBlankFreq));
+ }
+ void stopMusic();
+
protected:
void interrupt();
private:
-public:
-
enum { kNumPatches = 64, kNumVoices = 4, kNumChannels = 16, kNumExtraChannels = 1 };
enum { kPriorityScore, kPriorityNote, kPrioritySound };
- int16 _microtonal[128];
- struct Event;
+// int16 _microtonal[128];
- struct PlayerContext {
+ struct Event {
+ uint16 startTime;
+ uint16 stopTime;
+ byte command;
+ byte parameter;
+ };
+
+ struct Score {
+ const Event *events;
+ uint32 numEvents;
+ } *_scores;
+
+ int _numScores;
+
+ struct {
uint16 vBlankFreq;
int32 ticks;
int32 tickUnit;
@@ -93,20 +113,6 @@ public:
uint16 sampleOctaves;
} _patch[kNumPatches];
- struct Event {
- uint16 startTime;
- uint16 stopTime;
- byte command;
- byte parameter;
- };
-
- struct Score {
- const Event *events;
- uint32 numEvents;
- } *_scores;
-
- int _numScores;
-
struct ChannelContext {
const Patch *patch;
uint16 regParamNumber;
@@ -114,7 +120,7 @@ public:
uint16 modulation;
uint16 modulationTime;
- int16 microtonal;
+// int16 microtonal;
uint16 portamentoTime;
@@ -131,7 +137,7 @@ public:
kFlagPortamento = 1 << 1,
kFlagDamper = 1 << 2,
kFlagMono = 1 << 3,
- kFlagMicrotonal = 1 << 4,
+// kFlagMicrotonal = 1 << 4,
kFlagModVolume = 1 << 5//,
//kFlagAltered = 1 << 6
};
@@ -139,7 +145,7 @@ public:
bool isAltered;
uint8 lastNote;
- uint8 program;
+// uint8 program;
} _channelCtx[kNumChannels + kNumExtraChannels];
@@ -178,26 +184,17 @@ public:
kStatusStart
};
byte status;
- enum {
- kFlagStolen = 1 << 0,
- //kFlagPortamento = 1 << 1,
- kFlagDamper = 1 << 2,
- kFlagBlocked = 1 << 3,
- kFlagRecalc = 1 << 4
- };
- byte flags;
+ bool hasDamper;
+ bool isBlocked;
byte lastVolume;
bool hasPortamento;
+ byte dmaOff;
int32 stopEventTime;
byte stopEventCommand; // TODO: Remove?
byte stopEventParameter; // TODO: Remove?
} _voiceCtx[kNumVoices];
- bool load(Common::SeekableReadStream &musicData, bool loadScores = true, bool loadSamples = true);
- bool doSong(int songIndex, int advance = 0);
-
- void stopMusic();
void freePatches();
void freeScores();
void resetChannel(ChannelContext &chan, bool rightChannel);
@@ -208,14 +205,6 @@ public:
int8 noteOn(ChannelContext &channel, byte note, uint16 volume, uint16 pri);
void noteOff(VoiceContext &voice, byte note);
void killVoice(byte num);
- int playNote(byte note, byte patch, uint16 duration, uint16 volume, bool rightSide);
-
- void setVolume(const byte volume) {
- _playerCtx.volume = volume;
- }
- void setTempo(const uint16 tempo) {
- _playerCtx.tickUnit = (int32)(((uint32)(tempo & 0xFFF0) << 8) / (uint16)(5 * _playerCtx.vBlankFreq));
- }
static int32 precalcNote(byte baseNote, int16 tune, byte octave) {
return 0x9fd77 + 0x3C000 + (1 << 16) - ((baseNote << 14) + (tune << 11) / 3) / 3 - (octave << 16);
diff --git a/sound/mods/paula.cpp b/sound/mods/paula.cpp
index 2e19927d83..f801ecfc9f 100644
--- a/sound/mods/paula.cpp
+++ b/sound/mods/paula.cpp
@@ -130,41 +130,54 @@ int Paula::readBufferIntern(int16 *buffer, const int numSamples) {
int16 *p = buffer;
int end = 0;
int neededSamples = nSamples;
+ assert(offset < sLen);
// Compute the number of samples to generate; that is, either generate
// just as many as were requested, or until the buffer is used up.
// Note that dividing two frac_t yields an integer (as the denominators
// cancel out each other).
// Note that 'end' could be 0 here. No harm in that :-).
- end = MIN(neededSamples, (int)((sLen - offset + rate - 1) / rate));
+ const int leftSamples = (int)((sLen - offset + rate - 1) / rate);
+ end = MIN(neededSamples, leftSamples);
mixBuffer<stereo>(p, data, offset, rate, end, _voice[voice].volume, _voice[voice].panning);
neededSamples -= end;
- // If we have not yet generated enough samples, and looping is active: loop!
- if (neededSamples > 0 && _voice[voice].lengthRepeat > 2) {
- // At this point we know that we have used up all samples in the buffer, so reset it.
- _voice[voice].data = data = _voice[voice].dataRepeat;
+ if (leftSamples > 0 && end == leftSamples) {
+ dmaCount++;
+ data = _voice[voice].data = _voice[voice].dataRepeat;
_voice[voice].length = _voice[voice].lengthRepeat;
+ // TODO: offset -= sLen; but make sure there is no way offset >= 2*sLen
+ offset &= FRAC_LO_MASK;
+ }
+
+ // If we have not yet generated enough samples, and looping is active: loop!
+ if (neededSamples > 0 && _voice[voice].length > 2) {
sLen = intToFrac(_voice[voice].length);
// If the "rate" exceeds the sample rate, we would have to perform constant
// wrap arounds. So, apply the first step of the euclidean algorithm to
// achieve the same more efficiently: Take rate modulo sLen
- // TODO: This messes up dmaCount
+ // TODO: This messes up dmaCount and shouldnt happen?
if (sLen < rate)
- rate %= sLen;
+ warning("Paula: lenght %d is lesser than rate", _voice[voice].length);
+// rate %= sLen;
// Repeat as long as necessary.
while (neededSamples > 0) {
- // TODO offset -= sLen, but only if same rate otherwise need to scale first
+ // TODO: offset -= sLen; but make sure there is no way offset >= 2*sLen
offset &= FRAC_LO_MASK;
dmaCount++;
-
// Compute the number of samples to generate (see above) and mix 'em.
end = MIN(neededSamples, (int)((sLen - offset + rate - 1) / rate));
mixBuffer<stereo>(p, data, offset, rate, end, _voice[voice].volume, _voice[voice].panning);
neededSamples -= end;
}
+
+ if (offset < sLen)
+ dmaCount--;
+ else
+ offset &= FRAC_LO_MASK;
+
}
// Write back the cached data