From 7a0aea53dd9a5065226ec2e627089475ca84867f Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 28 Mar 2014 17:53:08 -0700 Subject: [PATCH] Made DUMB and modplay volume ramping more sensitive when transititioning to or from zero volume, and implemented Modplug ADPCM sample support into ft2play --- Frameworks/Dumb/dumb/src/it/itrender.c | 8 +++- Frameworks/modplay/modplay/ft2play.c | 62 +++++++++++++++++++++++--- Frameworks/modplay/modplay/st3play.c | 7 ++- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/Frameworks/Dumb/dumb/src/it/itrender.c b/Frameworks/Dumb/dumb/src/it/itrender.c index 57e5c55a0..9cb9837ed 100644 --- a/Frameworks/Dumb/dumb/src/it/itrender.c +++ b/Frameworks/Dumb/dumb/src/it/itrender.c @@ -3905,6 +3905,13 @@ static void playing_volume_setup(DUMB_IT_SIGRENDERER * sigrenderer, IT_PLAYING * vol = calculate_volume(sigrenderer, playing, 1.0f); playing->float_volume[0] *= vol; playing->float_volume[1] *= vol; + + rampScale = 4; + + if (ramp_style > 0 && playing->declick_stage == 2) { + if ((playing->ramp_volume[0] == 0 && playing->ramp_volume[1] == 0) || vol == 0) + rampScale = 48; + } if (ramp_style == 0 || (ramp_style < 2 && playing->declick_stage == 2)) { if (playing->declick_stage <= 2) { @@ -3921,7 +3928,6 @@ static void playing_volume_setup(DUMB_IT_SIGRENDERER * sigrenderer, IT_PLAYING * playing->ramp_delta[0] = 0; playing->ramp_delta[1] = 0; } else { - rampScale = 4; if (playing->declick_stage == 0) { playing->ramp_volume[0] = 0; playing->ramp_volume[1] = 0; diff --git a/Frameworks/modplay/modplay/ft2play.c b/Frameworks/modplay/modplay/ft2play.c index cb05fd723..ebfcf6714 100644 --- a/Frameworks/modplay/modplay/ft2play.c +++ b/Frameworks/modplay/modplay/ft2play.c @@ -81,6 +81,7 @@ typedef struct SampleHeaderTyp_t uint8_t Typ; uint8_t Pan; int8_t RelTon; + uint8_t Junk; } #ifdef __GNUC__ __attribute__ ((packed)) @@ -171,6 +172,7 @@ typedef struct SampleTyp_t uint8_t Typ; uint8_t Pan; int8_t RelTon; + uint8_t Junk; int8_t *Pek; } SampleTyp; @@ -2251,7 +2253,7 @@ static int8_t LoadInstrHeader(PLAYER *p, MEM *buf, uint16_t i) } if ((ih.SampleSize == 0) || (ih.SampleSize > 40)) ih.SampleSize = 40; // default - ih.SampleSize -= (1 + 22); // skip junk + name + ih.SampleSize -= (22); // skip name if (ih.AntSamp > 32) return (0); @@ -2264,9 +2266,9 @@ static int8_t LoadInstrHeader(PLAYER *p, MEM *buf, uint16_t i) for (j = 0; j < ih.AntSamp; ++j) { - mread(&ih.Samp[j], 17, 1, buf); - mseek(buf, 1 + 22, SEEK_CUR); // skip junk + name - memcpy(&p->Instr[i]->Samp[j], &ih.Samp[j], 17); + mread(&ih.Samp[j], 18, 1, buf); + mseek(buf, 22, SEEK_CUR); // skip junk + name + memcpy(&p->Instr[i]->Samp[j], &ih.Samp[j], 18); // non-FT2 fix: Force loop flags off if loop length is 0 if (p->Instr[i]->Samp[j].RepL == 0) @@ -2292,6 +2294,40 @@ static void CheckSampleRepeat(PLAYER *p, uint16_t ins, uint8_t smp) } } +static inline int8_t get_adpcm_sample(const int8_t *sampleDictionary, const uint8_t *sampleData, int32_t samplePosition, int8_t *lastDelta) +{ + uint8_t byte = sampleData[samplePosition / 2]; + byte = (samplePosition & 1) ? byte >> 4 : byte & 15; + return *lastDelta += sampleDictionary[byte]; +} + +static void Adpcm2Samp(uint8_t * sample, uint32_t length) +{ + const int8_t *sampleDictionary; + const uint8_t *sampleData; + + uint32_t samplePosition; + int8_t lastDelta; + + uint8_t * sampleDataOut = (uint8_t *) malloc(length); + if (!sampleDataOut) + return; + + sampleDictionary = (const int8_t *)sample; + sampleData = (uint8_t*)sampleDictionary + 16; + + samplePosition = 0; + lastDelta = 0; + + while (samplePosition < length) + { + sampleDataOut[samplePosition] = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &lastDelta); + samplePosition++; + } + + memcpy(sample, sampleDataOut, length); +} + static int8_t LoadInstrSample(PLAYER *p, MEM *buf, uint16_t i) { uint16_t j; @@ -2301,9 +2337,13 @@ static int8_t LoadInstrSample(PLAYER *p, MEM *buf, uint16_t i) { for (j = 1; j <= p->Instr[i]->AntSamp; ++j) { + int adpcm = 0; p->Instr[i]->Samp[j - 1].Pek = NULL; l = p->Instr[i]->Samp[j - 1].Len; + if (p->Instr[i]->Samp[j - 1].Junk == 0xAD && + !(p->Instr[i]->Samp[j - 1].Typ & (16|32))) + adpcm = (((l + 1) / 2) + 16); if (l > 0) { p->Instr[i]->Samp[j - 1].Pek = (int8_t *)(malloc(l)); @@ -2313,8 +2353,11 @@ static int8_t LoadInstrSample(PLAYER *p, MEM *buf, uint16_t i) return (0); } - mread(p->Instr[i]->Samp[j - 1].Pek, l, 1, buf); - Delta2Samp(p->Instr[i]->Samp[j - 1].Pek, l, p->Instr[i]->Samp[j - 1].Typ); + mread(p->Instr[i]->Samp[j - 1].Pek, adpcm ? adpcm : l, 1, buf); + if (!adpcm) + Delta2Samp(p->Instr[i]->Samp[j - 1].Pek, l, p->Instr[i]->Samp[j - 1].Typ); + else + Adpcm2Samp(p->Instr[i]->Samp[j - 1].Pek, l); } CheckSampleRepeat(p, i, (uint8_t)(j) - 1); @@ -2721,6 +2764,11 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value) void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t pan, uint8_t sharp) { #ifdef USE_VOL_RAMP + if (p->rampStyle > 0 && !sharp) + { + if ((p->voice[i].volumeL == 0 && p->voice[i].volumeR == 0) || vol == 0) + sharp = 3; + } if (p->rampStyle > 1 || (p->rampStyle > 0 && sharp)) { const float rampRate = sharp ? p->f_samplesPerFrameSharp : p->f_samplesPerFrame; @@ -2731,7 +2779,7 @@ void voiceSetVolume(PLAYER *p, uint8_t i, float vol, uint8_t pan, uint8_t sharp) p->voice[i].volumeL = 0.0f; p->voice[i].volumeR = 0.0f; } - else + else if (sharp != 3) p->voice[i].rampTerminates = 1; } diff --git a/Frameworks/modplay/modplay/st3play.c b/Frameworks/modplay/modplay/st3play.c index 4925274f6..32d9b24e6 100644 --- a/Frameworks/modplay/modplay/st3play.c +++ b/Frameworks/modplay/modplay/st3play.c @@ -2683,6 +2683,11 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value) void voiceSetVolume(PLAYER *p, uint8_t voiceNumber, float volume, uint8_t sharp) { #ifdef USE_VOL_RAMP + if (p->rampStyle > 0 && !sharp) + { + if (p->voice[voiceNumber].volume == 0 || volume == 0) + sharp = 3; + } if (p->rampStyle > 1 || (p->rampStyle > 0 && sharp != 0)) { const float rampRate = sharp ? p->f_samplesPerFrameSharp : p->f_samplesPerFrame; @@ -2690,7 +2695,7 @@ void voiceSetVolume(PLAYER *p, uint8_t voiceNumber, float volume, uint8_t sharp) { if (volume) p->voice[voiceNumber].volume = 0.0f; - else + else if (sharp != 3) p->voice[voiceNumber].rampTerminates = 1; } p->voice[voiceNumber].targetVol = volume;