aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorNorbert Lange2009-07-13 21:27:58 +0000
committerNorbert Lange2009-07-13 21:27:58 +0000
commit162c6a418ddd578214f48a889ae61f3b9efc8907 (patch)
tree389fd3bf6bc473893b30c6f46205a3689f494295 /sound
parent100d86ee4d3bc412ae61e890ca45b0e2a3d57895 (diff)
downloadscummvm-rg350-162c6a418ddd578214f48a889ae61f3b9efc8907.tar.gz
scummvm-rg350-162c6a418ddd578214f48a889ae61f3b9efc8907.tar.bz2
scummvm-rg350-162c6a418ddd578214f48a889ae61f3b9efc8907.zip
added routine pickvoice to dinamically choose a fitting channel
use similar FP-rounding as the original player svn-id: r42454
Diffstat (limited to 'sound')
-rw-r--r--sound/mods/maxtrax.cpp68
-rw-r--r--sound/mods/maxtrax.h1
2 files changed, 60 insertions, 9 deletions
diff --git a/sound/mods/maxtrax.cpp b/sound/mods/maxtrax.cpp
index b94f1fd4e5..271e0dc780 100644
--- a/sound/mods/maxtrax.cpp
+++ b/sound/mods/maxtrax.cpp
@@ -340,6 +340,50 @@ void MaxTrax::killVoice(byte num) {
Paula::setChannelVolume(num, 0);
}
+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;
+ const int leftBest = MIN(voices[0].status, voices[3].status);
+ const int rightBest = MIN(voices[1].status, voices[2].status);
+ const int sameSide = (leftSide) ? leftBest : rightBest;
+ const int otherSide = leftBest + rightBest - sameSide;
+
+ if (sameSide > VoiceContext::kStatusRelease && otherSide <= VoiceContext::kStatusRelease) {
+ pick ^= 1; // switches sides
+ }
+ }
+ pri &= ~kPrioFlagFixedSide;
+
+ for (int i = 1; i > 0; --i) {
+ const VoiceContext *voice = &voices[pick];
+ const VoiceContext *alternate = &voices[pick ^ 3];
+
+ if (voice->status > alternate->status
+ || (voice->status == alternate->status && voice->lastVolume > alternate->lastVolume)) {
+ // TODO: tiebreaking
+ pick ^= 3; // switch channels
+ const VoiceContext *tmp = voice;
+ voice = alternate;
+ alternate = tmp;
+ }
+
+ if ((voice->flags & VoiceContext::kFlagBlocked) != 0 || voice->priority > pri) {
+ pick ^= 3; // switch channels
+ if ((alternate->flags & VoiceContext::kFlagBlocked) != 0 || alternate->priority > pri) {
+ // if not already done, switch sides and try again
+ pick ^= 1;
+ continue;
+ }
+ }
+ // succeded
+ return (int8)pick;
+ }
+ // failed
+ return -1;
+}
+
int MaxTrax::calcNote(VoiceContext &voice) {
const ChannelContext &channel = *voice.channel;
voice.lastPeriod = 0;
@@ -381,9 +425,12 @@ int MaxTrax::calcNote(VoiceContext &voice) {
voice.periodOffset = octave << 16;
}
tone -= voice.periodOffset;
- if (tone >= PERIOD_LIMIT)
- // we need to scale with log(2)
- voice.lastPeriod = (uint16)expf((float)tone * (float)(0.69314718055994530942 / (1 << 16)));
+ if (tone >= PERIOD_LIMIT) {
+ // calculate 2^tone and round towards nearest integer
+ // 2*2^tone = exp((tone+1) * ln(2))
+ const uint16 periodX2 = (uint16)expf((float)(tone + (1 << 16)) * (float)(0.69314718055994530942 / (1 << 16)));
+ voice.lastPeriod = (periodX2 + 1) / 2;
+ }
return octave;
}
@@ -417,12 +464,9 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
return voiceNum;
}
} else {
- // TODO:
- // pickvoice based on channel.isRightChannel
- // return if no channel found
- voiceNum = (channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 0 : 1;
- static int c = 0;
- voiceNum = (&channel - _channelCtx) % 4;
+ voiceNum = pickvoice(_voiceCtx, (channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
+ if (voiceNum < 0)
+ return voiceNum;
}
assert(voiceNum >= 0 && voiceNum < ARRAYSIZE(_voiceCtx));
@@ -453,6 +497,7 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
if (!period)
period = 1000;
+ // TODO: since the original player is using the OS-functions, more than 1 sample could be queued up already
// get samplestart for the given octave
const int8 *samplePtr = patch.samplePtr + (patch.sampleTotalLen << useOctave) - patch.sampleTotalLen;
if (patch.sampleAttackLen) {
@@ -463,6 +508,11 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
Paula::enableChannel(voiceNum);
// wait for dma-clear
+ // FIXME: this is a workaround to enable oneshot-samples and it currently might crash Paula
+ if (patch.sampleTotalLen == patch.sampleAttackLen) {
+ Paula::setChannelSampleStart(voiceNum, 0);
+ Paula::setChannelSampleLen(voiceNum, 0);
+ }
}
if (patch.sampleTotalLen > patch.sampleAttackLen) {
diff --git a/sound/mods/maxtrax.h b/sound/mods/maxtrax.h
index cdfb614580..fddf005514 100644
--- a/sound/mods/maxtrax.h
+++ b/sound/mods/maxtrax.h
@@ -204,6 +204,7 @@ public:
void freeScores();
void resetChannel(ChannelContext &chan, bool rightChannel);
+ static int8 MaxTrax::pickvoice(const VoiceContext voice[4], uint pick, int16 pri);
int calcNote(VoiceContext &voice);
int8 noteOn(ChannelContext &channel, byte note, uint16 volume, uint16 pri);
void noteOff(ChannelContext &channel, byte note);