Updated modplay, bringing volume ramping to st3play
parent
bdd43b2a4b
commit
a567183510
|
@ -3563,7 +3563,11 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation)
|
||||||
|
|
||||||
lanczos_init();
|
lanczos_init();
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
for ( i = 0; i < 127 * 2 * 2; ++i )
|
for ( i = 0; i < 127 * 2 * 2; ++i )
|
||||||
|
#else
|
||||||
|
for ( i = 0; i < 127 * 2; ++i )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
p->resampler[i] = lanczos_resampler_create();
|
p->resampler[i] = lanczos_resampler_create();
|
||||||
if ( !p->resampler[i] )
|
if ( !p->resampler[i] )
|
||||||
|
@ -3659,7 +3663,11 @@ void ft2play_Free(void *_p)
|
||||||
if (p->linearPeriods) free(p->linearPeriods); p->linearPeriods = NULL;
|
if (p->linearPeriods) free(p->linearPeriods); p->linearPeriods = NULL;
|
||||||
if (p->NilPatternLine) free(p->NilPatternLine); p->NilPatternLine = NULL;
|
if (p->NilPatternLine) free(p->NilPatternLine); p->NilPatternLine = NULL;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
for ( i = 0; i < 127 * 2 * 2; ++i )
|
for ( i = 0; i < 127 * 2 * 2; ++i )
|
||||||
|
#else
|
||||||
|
for ( i = 0; i < 127 * 2; ++i )
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if ( p->resampler[i] )
|
if ( p->resampler[i] )
|
||||||
lanczos_resampler_delete( p->resampler[i] );
|
lanczos_resampler_delete( p->resampler[i] );
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
** * Middle-C speeds beyond 65535
|
** * Middle-C speeds beyond 65535
|
||||||
** * Process the last 16 channels as PCM
|
** * Process the last 16 channels as PCM
|
||||||
** * Process 8 octaves instead of 7
|
** * Process 8 octaves instead of 7
|
||||||
|
** * Compile-time optional volume ramping
|
||||||
**
|
**
|
||||||
** - Effects:
|
** - Effects:
|
||||||
** * Command S9x (sound control - only S91/S90 so far)
|
** * Command S9x (sound control - only S91/S90 so far)
|
||||||
|
@ -66,6 +67,8 @@
|
||||||
|
|
||||||
#include "st3play.h"
|
#include "st3play.h"
|
||||||
|
|
||||||
|
#define USE_VOL_RAMP
|
||||||
|
|
||||||
// TRACKER ID
|
// TRACKER ID
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -148,6 +151,16 @@ typedef struct
|
||||||
float panningL;
|
float panningL;
|
||||||
float panningR;
|
float panningR;
|
||||||
float orgPanR;
|
float orgPanR;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
float targetVol;
|
||||||
|
float targetPanL;
|
||||||
|
float targetPanR;
|
||||||
|
float volDelta;
|
||||||
|
float panDeltaL;
|
||||||
|
float panDeltaR;
|
||||||
|
int8_t rampTerminates;
|
||||||
|
#endif
|
||||||
} VOICE;
|
} VOICE;
|
||||||
|
|
||||||
// VARIABLES / STATE
|
// VARIABLES / STATE
|
||||||
|
@ -177,13 +190,24 @@ typedef struct
|
||||||
int32_t soundBufferSize;
|
int32_t soundBufferSize;
|
||||||
uint32_t outputFreq;
|
uint32_t outputFreq;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
VOICE voice[32*2];
|
||||||
|
|
||||||
|
void *resampler[64*2];
|
||||||
|
#else
|
||||||
VOICE voice[32];
|
VOICE voice[32];
|
||||||
|
|
||||||
void *resampler[64];
|
void *resampler[64];
|
||||||
|
#endif
|
||||||
|
|
||||||
float f_outputFreq;
|
float f_outputFreq;
|
||||||
float f_masterVolume;
|
float f_masterVolume;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
float f_samplesPerFrame;
|
||||||
|
float f_samplesPerFrameSharp;
|
||||||
|
#endif
|
||||||
|
|
||||||
// pre-initialized variables
|
// pre-initialized variables
|
||||||
int8_t samplingInterpolation;// = 1;
|
int8_t samplingInterpolation;// = 1;
|
||||||
float *masterBufferL;// = NULL;
|
float *masterBufferL;// = NULL;
|
||||||
|
@ -301,7 +325,7 @@ static void voiceSetSource(PLAYER *, uint8_t voiceNumber, const int8_t *sampleDa
|
||||||
int32_t sampleLength, int32_t sampleLoopLength, int32_t sampleLoopEnd,
|
int32_t sampleLength, int32_t sampleLoopLength, int32_t sampleLoopEnd,
|
||||||
int8_t loopEnabled, int8_t sixteenbit, int8_t stereo, int8_t adpcm);
|
int8_t loopEnabled, int8_t sixteenbit, int8_t stereo, int8_t adpcm);
|
||||||
static void voiceSetSamplePosition(PLAYER *, uint8_t voiceNumber, uint16_t value);
|
static void voiceSetSamplePosition(PLAYER *, uint8_t voiceNumber, uint16_t value);
|
||||||
static void voiceSetVolume(PLAYER *, uint8_t voiceNumber, float volume);
|
static void voiceSetVolume(PLAYER *, uint8_t voiceNumber, float volume, uint8_t sharp);
|
||||||
static void voiceSetSurround(PLAYER *, uint8_t voiceNumber, int8_t surround);
|
static void voiceSetSurround(PLAYER *, uint8_t voiceNumber, int8_t surround);
|
||||||
static void voiceSetPanning(PLAYER *, uint8_t voiceNumber, uint16_t pan);
|
static void voiceSetPanning(PLAYER *, uint8_t voiceNumber, uint16_t pan);
|
||||||
static void voiceSetSamplingFrequency(PLAYER *, uint8_t voiceNumber, float samplingFrequency);
|
static void voiceSetSamplingFrequency(PLAYER *, uint8_t voiceNumber, float samplingFrequency);
|
||||||
|
@ -463,7 +487,11 @@ void * st3play_Alloc(uint32_t outputFreq, int8_t interpolation)
|
||||||
|
|
||||||
lanczos_init();
|
lanczos_init();
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
for (i = 0; i < 64 * 2; ++i)
|
||||||
|
#else
|
||||||
for (i = 0; i < 64; ++i)
|
for (i = 0; i < 64; ++i)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
p->resampler[i] = lanczos_resampler_create();
|
p->resampler[i] = lanczos_resampler_create();
|
||||||
if ( !p->resampler[i] )
|
if ( !p->resampler[i] )
|
||||||
|
@ -505,7 +533,11 @@ void st3play_Free(void *_p)
|
||||||
|
|
||||||
FreeSong(p);
|
FreeSong(p);
|
||||||
|
|
||||||
for (i = 0; i < 64; ++i)
|
#ifdef USE_VOL_RAMP
|
||||||
|
for (i = 0; i < 64 * 2; ++i)
|
||||||
|
#else
|
||||||
|
for (i = 0; i < 64; ++i)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if ( p->resampler[i] )
|
if ( p->resampler[i] )
|
||||||
lanczos_resampler_delete( p->resampler[i] );
|
lanczos_resampler_delete( p->resampler[i] );
|
||||||
|
@ -597,10 +629,14 @@ static inline void setspd(PLAYER *p, uint8_t ch)
|
||||||
voiceSetSamplingFrequency(p, ch, 14317056.0f / (float)tmpspd);
|
voiceSetSamplingFrequency(p, ch, 14317056.0f / (float)tmpspd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setvol(PLAYER *p, uint8_t ch)
|
static inline void setvol(PLAYER *p, uint8_t ch, uint8_t sharp)
|
||||||
{
|
{
|
||||||
p->chn[ch].achannelused |= 0x80;
|
p->chn[ch].achannelused |= 0x80;
|
||||||
voiceSetVolume(p, ch, ((float)(p->chn[ch].avol) / 63.0f) * ((float)(p->chn[ch].chanvol) / 64.0f) * ((float)(p->globalvol) / 64.0f));
|
#ifdef USE_VOL_RAMP
|
||||||
|
voiceSetVolume(p, ch + ((sharp == 2) ? 32 : 0), (sharp == 2) ? 0.0f : ((float)(p->chn[ch].avol) / 63.0f) * ((float)(p->chn[ch].chanvol) / 64.0f) * ((float)(p->globalvol) / 64.0f), sharp);
|
||||||
|
#else
|
||||||
|
voiceSetVolume(p, ch, ((float)(p->chn[ch].avol) / 63.0f) * ((float)(p->chn[ch].chanvol) / 64.0f) * ((float)(p->globalvol) / 64.0f), sharp);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setpan(PLAYER *p, uint8_t ch)
|
static inline void setpan(PLAYER *p, uint8_t ch)
|
||||||
|
@ -841,6 +877,9 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
uint32_t insrepbeg;
|
uint32_t insrepbeg;
|
||||||
uint32_t insrepend;
|
uint32_t insrepend;
|
||||||
int8_t shift;
|
int8_t shift;
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
uint8_t volassigned = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (p->chn[ch].ins)
|
if (p->chn[ch].ins)
|
||||||
{
|
{
|
||||||
|
@ -861,7 +900,6 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
if (p->chn[ch].avol > 63) p->chn[ch].avol = 63;
|
if (p->chn[ch].avol > 63) p->chn[ch].avol = 63;
|
||||||
|
|
||||||
p->chn[ch].aorgvol = p->chn[ch].avol;
|
p->chn[ch].aorgvol = p->chn[ch].avol;
|
||||||
setvol(p, ch);
|
|
||||||
|
|
||||||
insoffs = (uint32_t)(((uint32_t)(insdat[0x0D])<<16)|((uint16_t)(insdat[0x0F])<<8)|insdat[0x0E])<<4;
|
insoffs = (uint32_t)(((uint32_t)(insdat[0x0D])<<16)|((uint16_t)(insdat[0x0F])<<8)|insdat[0x0E])<<4;
|
||||||
|
|
||||||
|
@ -887,6 +925,30 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
if ((insdat[0x1F] & 1) && inslen && (insrepend > insrepbeg))
|
if ((insdat[0x1F] & 1) && inslen && (insrepend > insrepbeg))
|
||||||
loop = 1;
|
loop = 1;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch + 32] = p->voice[ch];
|
||||||
|
setvol(p, ch, 2);
|
||||||
|
lanczos_resampler_dup_inplace(p->resampler[ch + 32], p->resampler[ch]);
|
||||||
|
lanczos_resampler_dup_inplace(p->resampler[ch + 32 + 64], p->resampler[ch + 64]);
|
||||||
|
if (p->chn[ch].vol != 255)
|
||||||
|
{
|
||||||
|
if (p->chn[ch].vol <= 64)
|
||||||
|
{
|
||||||
|
p->chn[ch].avol = p->chn[ch].vol;
|
||||||
|
p->chn[ch].aorgvol = p->chn[ch].vol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// NON-ST3
|
||||||
|
if ((p->chn[ch].vol >= 128) && (p->chn[ch].vol <= 192))
|
||||||
|
{
|
||||||
|
p->chn[ch].apanpos = (p->chn[ch].vol - 128) << 2;
|
||||||
|
setpan(p, ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
volassigned = 1;
|
||||||
|
#endif
|
||||||
|
setvol(p, ch, 1);
|
||||||
|
|
||||||
voiceSetSource(p, ch, (const int8_t *)(&p->mseg[insoffs]), inslen,
|
voiceSetSource(p, ch, (const int8_t *)(&p->mseg[insoffs]), inslen,
|
||||||
insrepend - insrepbeg, insrepend, loop,
|
insrepend - insrepbeg, insrepend, loop,
|
||||||
insdat[0x1F] & 4, insdat[0x1F] & 2, insdat[0x1E] == 4);
|
insdat[0x1F] & 4, insdat[0x1F] & 2, insdat[0x1E] == 4);
|
||||||
|
@ -924,7 +986,7 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
p->chn[ch].asldspd = 65535;
|
p->chn[ch].asldspd = 65535;
|
||||||
|
|
||||||
setspd(p, ch);
|
setspd(p, ch);
|
||||||
setvol(p, ch);
|
setvol(p, ch, 0);
|
||||||
|
|
||||||
// shutdown channel
|
// shutdown channel
|
||||||
voiceSetSource(p, ch, NULL, 0, 0, 0, 0, 0, 0, 0);
|
voiceSetSource(p, ch, NULL, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
@ -951,14 +1013,18 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
if (p->chn[ch].vol != 255 && !volassigned)
|
||||||
|
#else
|
||||||
if (p->chn[ch].vol != 255)
|
if (p->chn[ch].vol != 255)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (p->chn[ch].vol <= 64)
|
if (p->chn[ch].vol <= 64)
|
||||||
{
|
{
|
||||||
p->chn[ch].avol = p->chn[ch].vol;
|
p->chn[ch].avol = p->chn[ch].vol;
|
||||||
p->chn[ch].aorgvol = p->chn[ch].vol;
|
p->chn[ch].aorgvol = p->chn[ch].vol;
|
||||||
|
|
||||||
setvol(p, ch);
|
setvol(p, ch, 0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1647,7 +1713,7 @@ static void s_volslide(PLAYER *p, chn_t *ch)
|
||||||
if (ch->avol < 0) ch->avol = 0;
|
if (ch->avol < 0) ch->avol = 0;
|
||||||
if (ch->avol > 63) ch->avol = 63;
|
if (ch->avol > 63) ch->avol = 63;
|
||||||
|
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
|
|
||||||
if (p->volslidetype == 1)
|
if (p->volslidetype == 1)
|
||||||
s_vibrato(p, ch);
|
s_vibrato(p, ch);
|
||||||
|
@ -1890,7 +1956,7 @@ static void s_tremor(PLAYER *p, chn_t *ch)
|
||||||
ch->atreon = 0;
|
ch->atreon = 0;
|
||||||
|
|
||||||
ch->avol = 0;
|
ch->avol = 0;
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
|
|
||||||
ch->atremor = ch->info & 0x0F;
|
ch->atremor = ch->info & 0x0F;
|
||||||
}
|
}
|
||||||
|
@ -1899,7 +1965,7 @@ static void s_tremor(PLAYER *p, chn_t *ch)
|
||||||
ch->atreon = 1;
|
ch->atreon = 1;
|
||||||
|
|
||||||
ch->avol = ch->aorgvol;
|
ch->avol = ch->aorgvol;
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
|
|
||||||
ch->atremor = ch->info >> 4;
|
ch->atremor = ch->info >> 4;
|
||||||
}
|
}
|
||||||
|
@ -1988,7 +2054,7 @@ static void s_chanvolslide(PLAYER *p, chn_t *ch) // NON-ST3
|
||||||
if (ch->chanvol < 0) ch->chanvol = 0;
|
if (ch->chanvol < 0) ch->chanvol = 0;
|
||||||
if (ch->chanvol > 64) ch->chanvol = 64;
|
if (ch->chanvol > 64) ch->chanvol = 64;
|
||||||
|
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2077,7 +2143,7 @@ static void s_retrig(PLAYER *p, chn_t *ch)
|
||||||
if (ch->avol > 63) ch->avol = 63;
|
if (ch->avol > 63) ch->avol = 63;
|
||||||
if (ch->avol < 0) ch->avol = 0;
|
if (ch->avol < 0) ch->avol = 0;
|
||||||
|
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
|
|
||||||
ch->atrigcnt++; // probably a mistake? Keep it anyways.
|
ch->atrigcnt++; // probably a mistake? Keep it anyways.
|
||||||
}
|
}
|
||||||
|
@ -2172,7 +2238,7 @@ static void s_tremolo(PLAYER *p, chn_t *ch)
|
||||||
if (dat < 0) dat = 0;
|
if (dat < 0) dat = 0;
|
||||||
|
|
||||||
ch->avol = (int8_t)(dat);
|
ch->avol = (int8_t)(dat);
|
||||||
setvol(p, ch->channelnum);
|
setvol(p, ch->channelnum, 0);
|
||||||
|
|
||||||
ch->avibcnt = (cnt + ((ch->info >> 4) << 1)) & 0x7E;
|
ch->avibcnt = (cnt + ((ch->info >> 4) << 1)) & 0x7E;
|
||||||
}
|
}
|
||||||
|
@ -2376,7 +2442,7 @@ static void s_globvolslide(PLAYER *p, chn_t *ch) // NON-ST3
|
||||||
if (p->globalvol > 64) p->globalvol = 64;
|
if (p->globalvol > 64) p->globalvol = 64;
|
||||||
|
|
||||||
// update all channels now
|
// update all channels now
|
||||||
for (i = 0; i < (p->lastachannelused + 1); ++i) setvol(p, i);
|
for (i = 0; i < (p->lastachannelused + 1); ++i) setvol(p, i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2507,6 +2573,11 @@ static void s_panbrello(PLAYER *p, chn_t *ch) // NON-ST3
|
||||||
void setSamplesPerFrame(PLAYER *p, uint32_t val)
|
void setSamplesPerFrame(PLAYER *p, uint32_t val)
|
||||||
{
|
{
|
||||||
p->samplesPerFrame = val;
|
p->samplesPerFrame = val;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->f_samplesPerFrame = 1.0f / ((float)(val) / 4.0f);
|
||||||
|
p->f_samplesPerFrameSharp = 1.0f / (p->f_outputFreq / 1000.0f); // 1ms
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSamplingInterpolation(PLAYER *p, int8_t value)
|
void setSamplingInterpolation(PLAYER *p, int8_t value)
|
||||||
|
@ -2550,12 +2621,19 @@ void voiceSetSource(PLAYER *p, uint8_t voiceNumber, const int8_t *sampleData,
|
||||||
p->voice[voiceNumber].mixing = 1;
|
p->voice[voiceNumber].mixing = 1;
|
||||||
p->voice[voiceNumber].interpolating = 1;
|
p->voice[voiceNumber].interpolating = 1;
|
||||||
p->voice[voiceNumber].oversampleCount = 0;
|
p->voice[voiceNumber].oversampleCount = 0;
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[voiceNumber].rampTerminates = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (p->voice[voiceNumber].samplePosition >= p->voice[voiceNumber].sampleLength)
|
if (p->voice[voiceNumber].samplePosition >= p->voice[voiceNumber].sampleLength)
|
||||||
p->voice[voiceNumber].samplePosition = 0;
|
p->voice[voiceNumber].samplePosition = 0;
|
||||||
|
|
||||||
lanczos_resampler_clear( p->resampler[voiceNumber] );
|
lanczos_resampler_clear( p->resampler[voiceNumber] );
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
lanczos_resampler_clear( p->resampler[voiceNumber+64] );
|
||||||
|
#else
|
||||||
lanczos_resampler_clear( p->resampler[voiceNumber+32] );
|
lanczos_resampler_clear( p->resampler[voiceNumber+32] );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value)
|
void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value)
|
||||||
|
@ -2578,30 +2656,67 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value)
|
||||||
}
|
}
|
||||||
|
|
||||||
lanczos_resampler_clear( p->resampler[voiceNumber] );
|
lanczos_resampler_clear( p->resampler[voiceNumber] );
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
lanczos_resampler_clear( p->resampler[voiceNumber+64] );
|
||||||
|
#else
|
||||||
lanczos_resampler_clear( p->resampler[voiceNumber+32] );
|
lanczos_resampler_clear( p->resampler[voiceNumber+32] );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void voiceSetVolume(PLAYER *p, uint8_t voiceNumber, float volume)
|
void voiceSetVolume(PLAYER *p, uint8_t voiceNumber, float volume, uint8_t sharp)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
const float rampRate = sharp ? p->f_samplesPerFrameSharp : p->f_samplesPerFrame;
|
||||||
|
if (sharp)
|
||||||
|
{
|
||||||
|
if (volume)
|
||||||
|
p->voice[voiceNumber].volume = 0.0f;
|
||||||
|
else
|
||||||
|
p->voice[voiceNumber].rampTerminates = 1;
|
||||||
|
}
|
||||||
|
p->voice[voiceNumber].targetVol = volume;
|
||||||
|
p->voice[voiceNumber].volDelta = (p->voice[voiceNumber].targetVol - p->voice[voiceNumber].volume) * rampRate;
|
||||||
|
#else
|
||||||
p->voice[voiceNumber].volume = volume;
|
p->voice[voiceNumber].volume = volume;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void voiceSetSurround(PLAYER *p, uint8_t voiceNumber, int8_t surround)
|
void voiceSetSurround(PLAYER *p, uint8_t voiceNumber, int8_t surround)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
const float rampRate = p->f_samplesPerFrameSharp;
|
||||||
|
if (surround)
|
||||||
|
p->voice[voiceNumber].targetPanR = -p->voice[voiceNumber].orgPanR;
|
||||||
|
else
|
||||||
|
p->voice[voiceNumber].targetPanR = p->voice[voiceNumber].orgPanR;
|
||||||
|
p->voice[voiceNumber].panDeltaR = (p->voice[voiceNumber].targetPanR - p->voice[voiceNumber].panningR) * rampRate;
|
||||||
|
#else
|
||||||
if (surround)
|
if (surround)
|
||||||
p->voice[voiceNumber].panningR = -p->voice[voiceNumber].orgPanR;
|
p->voice[voiceNumber].panningR = -p->voice[voiceNumber].orgPanR;
|
||||||
else
|
else
|
||||||
p->voice[voiceNumber].panningR = p->voice[voiceNumber].orgPanR;
|
p->voice[voiceNumber].panningR = p->voice[voiceNumber].orgPanR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void voiceSetPanning(PLAYER *p, uint8_t voiceNumber, uint16_t pan)
|
void voiceSetPanning(PLAYER *p, uint8_t voiceNumber, uint16_t pan)
|
||||||
{
|
{
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
const float rampRate = p->f_samplesPerFrameSharp;
|
||||||
|
#endif
|
||||||
|
|
||||||
float pf;
|
float pf;
|
||||||
|
|
||||||
pf = (float)(pan) / 256.0f;
|
pf = (float)(pan) / 256.0f;
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[voiceNumber].targetPanL = 1.0f - pf;
|
||||||
|
p->voice[voiceNumber].targetPanR = pf;
|
||||||
|
p->voice[voiceNumber].panDeltaL = (p->voice[voiceNumber].targetPanL - p->voice[voiceNumber].panningL) * rampRate;
|
||||||
|
p->voice[voiceNumber].panDeltaR = (p->voice[voiceNumber].targetPanR - p->voice[voiceNumber].panningR) * rampRate;
|
||||||
|
#else
|
||||||
p->voice[voiceNumber].panningL = 1.0f - pf;
|
p->voice[voiceNumber].panningL = 1.0f - pf;
|
||||||
p->voice[voiceNumber].panningR = pf;
|
p->voice[voiceNumber].panningR = pf;
|
||||||
|
#endif
|
||||||
p->voice[voiceNumber].orgPanR = pf;
|
p->voice[voiceNumber].orgPanR = pf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2692,7 +2807,57 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
|
||||||
p->masterBufferL[j] += (sample * panningL);
|
p->masterBufferL[j] += (sample * panningL);
|
||||||
p->masterBufferR[j] += (sample * panningR);
|
p->masterBufferR[j] += (sample * panningR);
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
volume += p->voice[ch].volDelta;
|
||||||
|
panningL += p->voice[ch].panDeltaL;
|
||||||
|
panningR += p->voice[ch].panDeltaR;
|
||||||
|
|
||||||
|
if (p->voice[ch].volDelta >= 0.0f)
|
||||||
|
{
|
||||||
|
if (volume > p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (volume < p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaL >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningL > p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningL < p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaR >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningR > p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningR < p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].rampTerminates && !volume)
|
||||||
|
{
|
||||||
|
p->voice[ch].mixing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch].volume = volume;
|
||||||
|
p->voice[ch].panningL = panningL;
|
||||||
|
p->voice[ch].panningR = panningR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
@ -2728,7 +2893,11 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
||||||
|
|
||||||
resampler[0] = p->resampler[ch];
|
resampler[0] = p->resampler[ch];
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
resampler[1] = p->resampler[ch+64];
|
||||||
|
#else
|
||||||
resampler[1] = p->resampler[ch+32];
|
resampler[1] = p->resampler[ch+32];
|
||||||
|
#endif
|
||||||
|
|
||||||
lanczos_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
lanczos_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
||||||
lanczos_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
lanczos_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
||||||
|
@ -2786,7 +2955,57 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
|
||||||
p->masterBufferL[j] += (sampleL * panningL);
|
p->masterBufferL[j] += (sampleL * panningL);
|
||||||
p->masterBufferR[j] += (sampleR * panningR);
|
p->masterBufferR[j] += (sampleR * panningR);
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
volume += p->voice[ch].volDelta;
|
||||||
|
panningL += p->voice[ch].panDeltaL;
|
||||||
|
panningR += p->voice[ch].panDeltaR;
|
||||||
|
|
||||||
|
if (p->voice[ch].volDelta >= 0.0f)
|
||||||
|
{
|
||||||
|
if (volume > p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (volume < p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaL >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningL > p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningL < p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaR >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningR > p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningR < p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].rampTerminates && !volume)
|
||||||
|
{
|
||||||
|
p->voice[ch].mixing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch].volume = volume;
|
||||||
|
p->voice[ch].panningL = panningL;
|
||||||
|
p->voice[ch].panningR = panningR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
|
static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
@ -2871,7 +3090,57 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
|
||||||
p->masterBufferL[j] += (sample * panningL);
|
p->masterBufferL[j] += (sample * panningL);
|
||||||
p->masterBufferR[j] += (sample * panningR);
|
p->masterBufferR[j] += (sample * panningR);
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
volume += p->voice[ch].volDelta;
|
||||||
|
panningL += p->voice[ch].panDeltaL;
|
||||||
|
panningR += p->voice[ch].panDeltaR;
|
||||||
|
|
||||||
|
if (p->voice[ch].volDelta >= 0.0f)
|
||||||
|
{
|
||||||
|
if (volume > p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (volume < p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaL >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningL > p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningL < p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaR >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningR > p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningR < p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].rampTerminates && !volume)
|
||||||
|
{
|
||||||
|
p->voice[ch].mixing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch].volume = volume;
|
||||||
|
p->voice[ch].panningL = panningL;
|
||||||
|
p->voice[ch].panningR = panningR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
@ -2907,7 +3176,11 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
||||||
|
|
||||||
resampler[0] = p->resampler[ch];
|
resampler[0] = p->resampler[ch];
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
resampler[1] = p->resampler[ch+64];
|
||||||
|
#else
|
||||||
resampler[1] = p->resampler[ch+32];
|
resampler[1] = p->resampler[ch+32];
|
||||||
|
#endif
|
||||||
|
|
||||||
lanczos_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
lanczos_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
||||||
lanczos_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
lanczos_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
||||||
|
@ -2965,7 +3238,57 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
|
||||||
p->masterBufferL[j] += (sampleL * panningL);
|
p->masterBufferL[j] += (sampleL * panningL);
|
||||||
p->masterBufferR[j] += (sampleR * panningR);
|
p->masterBufferR[j] += (sampleR * panningR);
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
volume += p->voice[ch].volDelta;
|
||||||
|
panningL += p->voice[ch].panDeltaL;
|
||||||
|
panningR += p->voice[ch].panDeltaR;
|
||||||
|
|
||||||
|
if (p->voice[ch].volDelta >= 0.0f)
|
||||||
|
{
|
||||||
|
if (volume > p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (volume < p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaL >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningL > p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningL < p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaR >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningR > p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningR < p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].rampTerminates && !volume)
|
||||||
|
{
|
||||||
|
p->voice[ch].mixing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch].volume = volume;
|
||||||
|
p->voice[ch].panningL = panningL;
|
||||||
|
p->voice[ch].panningR = panningR;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int8_t get_adpcm_sample(const int8_t *sampleDictionary, const uint8_t *sampleData, int32_t samplePosition, int8_t *lastDelta)
|
static inline int8_t get_adpcm_sample(const int8_t *sampleDictionary, const uint8_t *sampleData, int32_t samplePosition, int8_t *lastDelta)
|
||||||
|
@ -3082,6 +3405,79 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
|
|
||||||
p->masterBufferL[j] += (sample * panningL);
|
p->masterBufferL[j] += (sample * panningL);
|
||||||
p->masterBufferR[j] += (sample * panningR);
|
p->masterBufferR[j] += (sample * panningR);
|
||||||
|
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
volume += p->voice[ch].volDelta;
|
||||||
|
panningL += p->voice[ch].panDeltaL;
|
||||||
|
panningR += p->voice[ch].panDeltaR;
|
||||||
|
|
||||||
|
if (p->voice[ch].volDelta >= 0.0f)
|
||||||
|
{
|
||||||
|
if (volume > p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (volume < p->voice[ch].targetVol)
|
||||||
|
volume = p->voice[ch].targetVol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaL >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningL > p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningL < p->voice[ch].targetPanL)
|
||||||
|
panningL = p->voice[ch].targetPanL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].panDeltaR >= 0.0f)
|
||||||
|
{
|
||||||
|
if (panningR > p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panningR < p->voice[ch].targetPanR)
|
||||||
|
panningR = p->voice[ch].targetPanR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->voice[ch].rampTerminates && !volume)
|
||||||
|
{
|
||||||
|
p->voice[ch].mixing = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef USE_VOL_RAMP
|
||||||
|
p->voice[ch].volume = volume;
|
||||||
|
p->voice[ch].panningL = panningL;
|
||||||
|
p->voice[ch].panningR = panningR;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mixChannel(PLAYER *p, uint8_t i, uint32_t sampleBlockLength)
|
||||||
|
{
|
||||||
|
if (p->voice[i].incRate && p->voice[i].mixing)
|
||||||
|
{
|
||||||
|
if (p->voice[i].stereo)
|
||||||
|
{
|
||||||
|
if (p->voice[i].sixteenBit)
|
||||||
|
mix16bstereo(p, i, sampleBlockLength);
|
||||||
|
else
|
||||||
|
mix8bstereo(p, i, sampleBlockLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p->voice[i].sixteenBit)
|
||||||
|
mix16b(p, i, sampleBlockLength);
|
||||||
|
else if (p->voice[i].adpcm)
|
||||||
|
mixadpcm(p, i, sampleBlockLength);
|
||||||
|
else
|
||||||
|
mix8b(p, i, sampleBlockLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3103,25 +3499,10 @@ void mixSampleBlock(PLAYER *p, float *outputStream, uint32_t sampleBlockLength)
|
||||||
{
|
{
|
||||||
if (p->muted[i / 8] & (1 << (i % 8)))
|
if (p->muted[i / 8] & (1 << (i % 8)))
|
||||||
continue;
|
continue;
|
||||||
if (p->voice[i].incRate && p->voice[i].mixing)
|
mixChannel(p, i, sampleBlockLength);
|
||||||
{
|
#ifdef USE_VOL_RAMP
|
||||||
if (p->voice[i].stereo)
|
mixChannel(p, i + 32, sampleBlockLength);
|
||||||
{
|
#endif
|
||||||
if (p->voice[i].sixteenBit)
|
|
||||||
mix16bstereo(p, i, sampleBlockLength);
|
|
||||||
else
|
|
||||||
mix8bstereo(p, i, sampleBlockLength);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (p->voice[i].sixteenBit)
|
|
||||||
mix16b(p, i, sampleBlockLength);
|
|
||||||
else if (p->voice[i].adpcm)
|
|
||||||
mixadpcm(p, i, sampleBlockLength);
|
|
||||||
else
|
|
||||||
mix8b(p, i, sampleBlockLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < sampleBlockLength; ++j)
|
for (j = 0; j < sampleBlockLength; ++j)
|
||||||
|
@ -3226,18 +3607,18 @@ void FreeSong(PLAYER *p)
|
||||||
p->ModuleLoaded = 0;
|
p->ModuleLoaded = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void st3play_Mute(void *_p, int8_t channel, int8_t mute)
|
void st3play_Mute(void *_p, int8_t channel, int8_t mute)
|
||||||
{
|
{
|
||||||
PLAYER * p = (PLAYER *)_p;
|
PLAYER * p = (PLAYER *)_p;
|
||||||
int8_t mask = 1 << (channel % 8);
|
int8_t mask = 1 << (channel % 8);
|
||||||
if (channel > 31)
|
if (channel > 31)
|
||||||
return;
|
return;
|
||||||
if (mute)
|
if (mute)
|
||||||
p->muted[channel / 8] |= mask;
|
p->muted[channel / 8] |= mask;
|
||||||
else
|
else
|
||||||
p->muted[channel / 8] &= ~mask;
|
p->muted[channel / 8] &= ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t st3play_GetLoopCount(void *_p)
|
int32_t st3play_GetLoopCount(void *_p)
|
||||||
{
|
{
|
||||||
PLAYER * p = (PLAYER *)_p;
|
PLAYER * p = (PLAYER *)_p;
|
||||||
|
|
Loading…
Reference in New Issue