Major overhaul of module playback routines, including a new band-limited linear interpolation mode, softer default pan separation, and better band-limited synthesis for MOD files

CQTexperiment
Chris Moeller 2015-01-10 23:07:51 -08:00
parent 9c54354c44
commit 1950124506
33 changed files with 3196 additions and 688 deletions

View File

@ -676,9 +676,10 @@ void dumb_destroy_click_remover_array(int n, DUMB_CLICK_REMOVER **cr);
#define DUMB_RQ_ALIASING 0
#define DUMB_RQ_BLEP 1
#define DUMB_RQ_LINEAR 2
#define DUMB_RQ_CUBIC 3
#define DUMB_RQ_FIR 4
#define DUMB_RQ_N_LEVELS 5
#define DUMB_RQ_BLAM 3
#define DUMB_RQ_CUBIC 4
#define DUMB_RQ_FIR 5
#define DUMB_RQ_N_LEVELS 6
extern int dumb_resampling_quality; /* This specifies the default */
void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quality); /* This overrides it */
@ -767,6 +768,11 @@ void dumb_resample_get_current_sample_n_2_1(int n, DUMB_RESAMPLER *resampler, DU
void dumb_resample_get_current_sample_n_2_2(int n, DUMB_RESAMPLER *resampler, DUMB_VOLUME_RAMP_INFO * volume_left, DUMB_VOLUME_RAMP_INFO * volume_right, sample_t *dst);
void dumb_end_resampler_n(int n, DUMB_RESAMPLER *resampler);
/* This sets the default panning separation for hard panned formats,
or for formats with default panning information. This must be set
before using any readers or loaders, and is not really thread safe. */
extern int dumb_it_default_panning_separation; /* in percent, default 25 */
/* DUH Construction */

View File

@ -36,9 +36,10 @@ enum
RESAMPLER_QUALITY_ZOH = 0,
RESAMPLER_QUALITY_BLEP = 1,
RESAMPLER_QUALITY_LINEAR = 2,
RESAMPLER_QUALITY_CUBIC = 3,
RESAMPLER_QUALITY_SINC = 4,
RESAMPLER_QUALITY_MAX = 4
RESAMPLER_QUALITY_BLAM = 3,
RESAMPLER_QUALITY_CUBIC = 4,
RESAMPLER_QUALITY_SINC = 5,
RESAMPLER_QUALITY_MAX = 5
};
void resampler_set_quality(void *, int quality);
@ -52,6 +53,6 @@ void resampler_clear(void *);
int resampler_get_sample_count(void *);
int resampler_get_sample(void *);
float resampler_get_sample_float(void *);
void resampler_remove_sample(void *);
void resampler_remove_sample(void *, int decay);
#endif

View File

@ -114,8 +114,12 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU
}
x = &src[pos*SRC_CHANNELS];
while ( todo ) {
while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
pos >= resampler->start )
while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) ||
(!resampler_get_sample_count( resampler->fir_resampler[0] )
#if SRC_CHANNELS == 2
&& !resampler_get_sample_count( resampler->fir_resampler[1] )
#endif
) ) && pos >= resampler->start )
{
POKE_FIR(0);
pos--;
@ -159,8 +163,12 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU
}
x = &src[pos*SRC_CHANNELS];
while ( todo ) {
while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
pos < resampler->end )
while ( ( resampler_get_free_count( resampler->fir_resampler[0] ) ||
(!resampler_get_sample_count( resampler->fir_resampler[0] )
#if SRC_CHANNELS == 2
&& !resampler_get_sample_count( resampler->fir_resampler[1] )
#endif
) ) && pos < resampler->end )
{
POKE_FIR(0);
pos++;

View File

@ -74,13 +74,14 @@
* 0 - DUMB_RQ_ALIASING - fastest
* 1 - DUMB_RQ_BLEP - nicer than aliasing, but slower
* 2 - DUMB_RQ_LINEAR
* 3 - DUMB_RQ_CUBIC
* 4 - DUMB_RQ_FIR - nicest
* 3 - DUMB_RQ_BLAM - band-limited linear interpolation, nice but slower
* 4 - DUMB_RQ_CUBIC
* 5 - DUMB_RQ_FIR - nicest
*
* Values outside the range 0-4 will behave the same as the nearest
* value within the range.
*/
int dumb_resampling_quality = DUMB_RQ_CUBIC;
int dumb_resampling_quality = DUMB_RQ_BLAM;

View File

@ -141,7 +141,7 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ); \
UPDATE_VOLUME( volume, vol ); \
}
#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0] )
#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0], 1 )
#define STEREO_DEST_PEEK_FIR { \
int sample = resampler_get_sample( resampler->fir_resampler[0] ); \
*dst++ = MULSC( sample, lvol ); \
@ -225,8 +225,8 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l
UPDATE_VOLUME( volume_right, rvol ); \
}
#define ADVANCE_FIR { \
resampler_remove_sample( resampler->fir_resampler[0] ); \
resampler_remove_sample( resampler->fir_resampler[1] ); \
resampler_remove_sample( resampler->fir_resampler[0], 1 ); \
resampler_remove_sample( resampler->fir_resampler[1], 1 ); \
}
#define STEREO_DEST_PEEK_FIR { \
*dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
#include "internal/it.h"
int dumb_it_default_panning_separation = 25;
DUMB_IT_SIGDATA *duh_get_it_sigdata(DUH *duh)
{

View File

@ -3976,7 +3976,7 @@ static void process_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playin
playing->sample_vibrato_time += playing->sample->vibrato_speed;
}
#ifdef _MSC_VER
#if defined(_MSC_VER) && _MSC_VER < 1800
static float log2(float x) {return (float)log(x)/(float)log(2.0f);}
#endif

View File

@ -413,8 +413,9 @@ static DUMB_IT_SIGDATA *it_669_load_sigdata(DUMBFILE *f, int * ext)
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 2) {
sigdata->channel_pan[i+0] = 48;
sigdata->channel_pan[i+1] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i+0] = 32 + sep;
sigdata->channel_pan[i+1] = 32 - sep;
}
_dumb_it_fix_invalid_orders(sigdata);

View File

@ -347,10 +347,11 @@ static DUMB_IT_SIGDATA *it_riff_amff_load_sigdata( DUMBFILE * f, struct riff * s
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )
@ -578,10 +579,11 @@ static DUMB_IT_SIGDATA *it_riff_am_load_sigdata( DUMBFILE * f, struct riff * str
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )

View File

@ -334,8 +334,9 @@ static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version)
}
}
else {
int sep = 32 * dumb_it_default_panning_separation / 100;
for ( i = 0; i < 16; i++ ) {
sigdata->channel_pan[ i ] = ( dumbfile_getc( f ) & 1 ) ? 16 : 48;
sigdata->channel_pan[ i ] = ( dumbfile_getc( f ) & 1 ) ? 32 - sep : 32 + sep;
}
}

View File

@ -303,10 +303,11 @@ static DUMB_IT_SIGDATA *it_asy_load_sigdata(DUMBFILE *f)
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
sigdata->channel_pan[i+0] = 16;
sigdata->channel_pan[i+1] = 48;
sigdata->channel_pan[i+2] = 48;
sigdata->channel_pan[i+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i+0] = 32 - sep;
sigdata->channel_pan[i+1] = 32 + sep;
sigdata->channel_pan[i+2] = 32 + sep;
sigdata->channel_pan[i+3] = 32 - sep;
}
_dumb_it_fix_invalid_orders(sigdata);

View File

@ -272,10 +272,11 @@ static DUMB_IT_SIGDATA *it_riff_dsmf_load_sigdata( DUMBFILE * f, struct riff * s
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for ( n = 0; (unsigned)n < stream->chunk_count; ++n )

View File

@ -596,10 +596,11 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int restrict_)
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (i = 0; i < DUMB_IT_N_CHANNELS; i += 4) {
sigdata->channel_pan[i+0] = 16;
sigdata->channel_pan[i+1] = 48;
sigdata->channel_pan[i+2] = 48;
sigdata->channel_pan[i+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[i+0] = 32 - sep;
sigdata->channel_pan[i+1] = 32 + sep;
sigdata->channel_pan[i+2] = 32 + sep;
sigdata->channel_pan[i+3] = 32 - sep;
}
_dumb_it_fix_invalid_orders(sigdata);

View File

@ -229,10 +229,11 @@ static DUMB_IT_SIGDATA *it_mtm_load_sigdata(DUMBFILE *f, int * version)
}
for (n = 32; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
sigdata->sample = malloc(sigdata->n_samples * sizeof(*sigdata->sample));

View File

@ -598,10 +598,11 @@ static DUMB_IT_SIGDATA *it_old_psm_load_sigdata(DUMBFILE *f)
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for (n = 0; n < n_components; n++)

View File

@ -659,10 +659,11 @@ static DUMB_IT_SIGDATA *it_psm_load_sigdata(DUMBFILE *f, int * ver, int subsong)
memset(sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS);
for (n = 0; n < DUMB_IT_N_CHANNELS; n += 4) {
sigdata->channel_pan[n ] = 16;
sigdata->channel_pan[n+1] = 48;
sigdata->channel_pan[n+2] = 48;
sigdata->channel_pan[n+3] = 16;
int sep = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[n ] = 32 - sep;
sigdata->channel_pan[n+1] = 32 + sep;
sigdata->channel_pan[n+2] = 32 + sep;
sigdata->channel_pan[n+3] = 32 - sep;
}
for (n = 0; n < n_song_chunks; n++) {

View File

@ -557,12 +557,13 @@ static DUMB_IT_SIGDATA *it_s3m_load_sigdata(DUMBFILE *f, int * cwtv)
/* Channel settings for 32 channels, 255=unused, +128=disabled */
{
int i;
int sep = (7 * dumb_it_default_panning_separation + 50) / 100;
for (i = 0; i < 32; i++) {
int c = dumbfile_getc(f);
if (!(c & (128 | 16))) { /* +128=disabled, +16=Adlib */
if (sigdata->n_pchannels < i + 1) sigdata->n_pchannels = i + 1;
sigdata->channel_volume[i] = 64;
sigdata->channel_pan[i] = c & 8 ? 12 : 3;
sigdata->channel_pan[i] = c & 8 ? 7 + sep : 7 - sep;
/** WARNING: ah, but it should be 7 for mono... */
} else {
/** WARNING: this could be improved if we support channel muting... */

View File

@ -61,6 +61,7 @@ static int it_stm_read_sample_header( IT_SAMPLE *sample, DUMBFILE *f, unsigned s
/* Looks like no-existy. */
sample->flags &= ~IT_SAMPLE_EXISTS;
sample->length = 0;
*offset = 0;
return dumbfile_error( f );
}
@ -278,10 +279,11 @@ static DUMB_IT_SIGDATA *it_stm_load_sigdata(DUMBFILE *f, int * version)
}
memset( sigdata->channel_volume, 64, 4 );
sigdata->channel_pan[ 0 ] = 48;
sigdata->channel_pan[ 1 ] = 16;
sigdata->channel_pan[ 2 ] = 48;
sigdata->channel_pan[ 3 ] = 16;
n = 32 * dumb_it_default_panning_separation / 100;
sigdata->channel_pan[ 0 ] = 32 + n;
sigdata->channel_pan[ 1 ] = 32 - n;
sigdata->channel_pan[ 2 ] = 32 + n;
sigdata->channel_pan[ 3 ] = 32 - n;
for ( n = 0; n < sigdata->n_samples; ++n ) {
if ( it_stm_read_sample_header( &sigdata->sample[ n ], f, &sample_offset[ n ] ) ) {

View File

@ -3030,7 +3030,8 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler))
while (interpolating && (resampler_get_free_count(resampler) ||
!resampler_get_sample_count(resampler)))
{
resampler_write_sample_fixed(resampler, sampleData[samplePosition], 8);
@ -3085,7 +3086,7 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
}
sample = resampler_get_sample_float(resampler);
resampler_remove_sample(resampler);
resampler_remove_sample(resampler, 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3193,7 +3194,9 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler[0]))
while (interpolating && (resampler_get_free_count(resampler[0]) ||
(!resampler_get_sample_count(resampler[0]) &&
!resampler_get_sample_count(resampler[1]))))
{
resampler_write_sample_fixed(resampler[0], sampleData[samplePosition], 8);
resampler_write_sample_fixed(resampler[1], sampleData[sampleLength + samplePosition], 8);
@ -3250,8 +3253,8 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
sampleL = resampler_get_sample_float(resampler[0]);
sampleR = resampler_get_sample_float(resampler[1]);
resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]);
resampler_remove_sample(resampler[0], 1);
resampler_remove_sample(resampler[1], 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3359,7 +3362,8 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler))
while (interpolating && (resampler_get_free_count(resampler) ||
!resampler_get_sample_count(resampler)))
{
resampler_write_sample_fixed(resampler, sampleData[samplePosition], 16);
@ -3414,7 +3418,7 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
}
sample = resampler_get_sample_float(resampler);
resampler_remove_sample(resampler);
resampler_remove_sample(resampler, 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3522,7 +3526,9 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler[0]))
while (interpolating && (resampler_get_free_count(resampler[0]) ||
(!resampler_get_sample_count(resampler[0]) &&
!resampler_get_sample_count(resampler[1]))))
{
resampler_write_sample_fixed(resampler[0], sampleData[samplePosition], 16);
resampler_write_sample_fixed(resampler[1], sampleData[sampleLength + samplePosition], 16);
@ -3579,8 +3585,8 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
sampleL = resampler_get_sample_float(resampler[0]);
sampleR = resampler_get_sample_float(resampler[1]);
resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]);
resampler_remove_sample(resampler[0], 1);
resampler_remove_sample(resampler[1], 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)

File diff suppressed because it is too large Load Diff

View File

@ -36,9 +36,10 @@ enum
RESAMPLER_QUALITY_ZOH = 0,
RESAMPLER_QUALITY_BLEP = 1,
RESAMPLER_QUALITY_LINEAR = 2,
RESAMPLER_QUALITY_CUBIC = 3,
RESAMPLER_QUALITY_SINC = 4,
RESAMPLER_QUALITY_MAX = 4
RESAMPLER_QUALITY_BLAM = 3,
RESAMPLER_QUALITY_CUBIC = 4,
RESAMPLER_QUALITY_SINC = 5,
RESAMPLER_QUALITY_MAX = 5
};
void resampler_set_quality(void *, int quality);
@ -52,6 +53,6 @@ void resampler_clear(void *);
int resampler_get_sample_count(void *);
int resampler_get_sample(void *);
float resampler_get_sample_float(void *);
void resampler_remove_sample(void *);
void resampler_remove_sample(void *, int decay);
#endif

View File

@ -2947,7 +2947,8 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler))
while (interpolating && (resampler_get_free_count(resampler) ||
!resampler_get_sample_count(resampler)))
{
resampler_write_sample_fixed(resampler, sampleData[samplePosition], 8);
@ -2976,7 +2977,7 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
}
sample = resampler_get_sample_float(resampler);
resampler_remove_sample(resampler);
resampler_remove_sample(resampler, 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -2991,7 +2992,8 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
{
v->fader = v->faderDest;
resampler_clear(resampler);
p->voice[ch].mixing = 0;
v->mixing = 0;
sampleData = 0;
}
sample *= v->fader;
@ -3099,7 +3101,9 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler[0]))
while (interpolating && (resampler_get_free_count(resampler[0]) ||
(!resampler_get_sample_count(resampler[0]) &&
!resampler_get_sample_count(resampler[1]))))
{
resampler_write_sample_fixed(resampler[0], sampleData[samplePosition], 8);
resampler_write_sample_fixed(resampler[1], sampleData[sampleLength + samplePosition], 8);
@ -3131,8 +3135,8 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
sampleL = resampler_get_sample_float(resampler[0]);
sampleR = resampler_get_sample_float(resampler[1]);
resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]);
resampler_remove_sample(resampler[0], 1);
resampler_remove_sample(resampler[1], 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3148,6 +3152,7 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
v->fader = v->faderDest;
resampler_clear(resampler);
v->mixing = 0;
sampleData = 0;
}
sampleL *= v->fader;
@ -3250,7 +3255,8 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler))
while (interpolating && (resampler_get_free_count(resampler) ||
!resampler_get_sample_count(resampler)))
{
resampler_write_sample_fixed(resampler, (int16_t)get_le16(&sampleData[samplePosition]), 16);
@ -3279,7 +3285,7 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
}
sample = resampler_get_sample_float(resampler);
resampler_remove_sample(resampler);
resampler_remove_sample(resampler, 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3295,6 +3301,7 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
v->fader = v->faderDest;
resampler_clear(resampler);
v->mixing = 0;
sampleData = 0;
}
sample *= v->fader;
@ -3402,7 +3409,9 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler[0]))
while (interpolating && (resampler_get_free_count(resampler[0]) ||
(!resampler_get_sample_count(resampler[0]) &&
!resampler_get_sample_count(resampler[1]))))
{
resampler_write_sample_fixed(resampler[0], (int16_t)get_le16(&sampleData[samplePosition]), 16);
resampler_write_sample_fixed(resampler[1], (int16_t)get_le16(&sampleData[sampleLength + samplePosition]), 16);
@ -3434,8 +3443,8 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
sampleL = resampler_get_sample_float(resampler[0]);
sampleR = resampler_get_sample_float(resampler[1]);
resampler_remove_sample(resampler[0]);
resampler_remove_sample(resampler[1]);
resampler_remove_sample(resampler[0], 1);
resampler_remove_sample(resampler[1], 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3451,6 +3460,7 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
v->fader = v->faderDest;
resampler_clear(resampler);
v->mixing = 0;
sampleData = 0;
}
sampleL *= v->fader;
@ -3572,7 +3582,8 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
{
samplePosition = v->samplePosition;
while (interpolating && resampler_get_free_count(resampler))
while (interpolating && (resampler_get_free_count(resampler) ||
!resampler_get_sample_count(resampler)))
{
int8_t nextDelta = lastDelta;
int16_t sample = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &nextDelta);
@ -3614,7 +3625,7 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
}
sample = resampler_get_sample_float(resampler);
resampler_remove_sample(resampler);
resampler_remove_sample(resampler, 1);
#ifdef USE_VOL_RAMP
if (rampStyle > 0)
@ -3630,6 +3641,7 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
v->fader = v->faderDest;
resampler_clear(resampler);
v->mixing = 0;
sampleData = 0;
}
sample *= v->fader;
@ -3773,7 +3785,7 @@ static void st3play_AdlibMix(PLAYER *p, float *buffer, int32_t count)
for (i = 0; i < outbuffer_avail; ++i)
{
float sample = resampler_get_sample_float( p->fmResampler );
resampler_remove_sample( p->fmResampler );
resampler_remove_sample( p->fmResampler, 1 );
buffer[i * 2 + 0] += sample;
buffer[i * 2 + 1] += sample;

View File

@ -7,16 +7,16 @@
objects = {
/* Begin PBXBuildFile section */
83304C9B1A5F9A1C0066CDDA /* pt_blep.c in Sources */ = {isa = PBXBuildFile; fileRef = 83304C991A5F9A1C0066CDDA /* pt_blep.c */; };
83304C9C1A5F9A1C0066CDDA /* pt_blep.h in Headers */ = {isa = PBXBuildFile; fileRef = 83304C9A1A5F9A1C0066CDDA /* pt_blep.h */; };
832127D71A622EEC00979C39 /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 832127D51A622EEC00979C39 /* resampler.h */; };
832127D81A622EEC00979C39 /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 832127D61A622EEC00979C39 /* resampler.c */; };
83A0F4A61816CEAD00119DB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83A0F4A41816CEAD00119DB4 /* InfoPlist.strings */; };
83A0F4D51816CF9500119DB4 /* playptmod.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A0F4D11816CF9500119DB4 /* playptmod.c */; };
83A0F4D61816CF9500119DB4 /* playptmod.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A0F4D21816CF9500119DB4 /* playptmod.h */; settings = {ATTRIBUTES = (Public, ); }; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
83304C991A5F9A1C0066CDDA /* pt_blep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pt_blep.c; sourceTree = "<group>"; };
83304C9A1A5F9A1C0066CDDA /* pt_blep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pt_blep.h; sourceTree = "<group>"; };
832127D51A622EEC00979C39 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
832127D61A622EEC00979C39 /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = "<group>"; };
83A0F4981816CEAD00119DB4 /* playptmod.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = playptmod.framework; sourceTree = BUILT_PRODUCTS_DIR; };
83A0F4A31816CEAD00119DB4 /* playptmod-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "playptmod-Info.plist"; sourceTree = "<group>"; };
83A0F4A51816CEAD00119DB4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@ -70,8 +70,8 @@
83A0F4A11816CEAD00119DB4 /* playptmod */ = {
isa = PBXGroup;
children = (
83304C991A5F9A1C0066CDDA /* pt_blep.c */,
83304C9A1A5F9A1C0066CDDA /* pt_blep.h */,
832127D51A622EEC00979C39 /* resampler.h */,
832127D61A622EEC00979C39 /* resampler.c */,
83A0F4D11816CF9500119DB4 /* playptmod.c */,
83A0F4D21816CF9500119DB4 /* playptmod.h */,
83A0F4A21816CEAD00119DB4 /* Supporting Files */,
@ -95,8 +95,8 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
832127D71A622EEC00979C39 /* resampler.h in Headers */,
83A0F4D61816CF9500119DB4 /* playptmod.h in Headers */,
83304C9C1A5F9A1C0066CDDA /* pt_blep.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -163,8 +163,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
83304C9B1A5F9A1C0066CDDA /* pt_blep.c in Sources */,
83A0F4D51816CF9500119DB4 /* playptmod.c in Sources */,
832127D81A622EEC00979C39 /* resampler.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -29,7 +29,7 @@
#define _USE_MATH_DEFINES // visual studio
#include "playptmod.h"
#include "pt_blep.h"
#include "resampler.h"
#include <stdio.h>
#include <string.h> // memcpy()
@ -185,8 +185,8 @@ typedef struct voice_data
int panR;
int step;
int newStep;
float frac;
float rate;
int interpolating;
int mute;
} Voice;
@ -241,8 +241,8 @@ typedef struct
FilterC filterC;
float *mixBufferL;
float *mixBufferR;
BLEP blep[MAX_CHANNELS];
BLEP blepVol[MAX_CHANNELS];
void * blep[MAX_CHANNELS];
void * blepVol[MAX_CHANNELS];
unsigned int orderPlayed[256];
MODULE *source;
} player;
@ -437,6 +437,7 @@ static void mixerSwapChSource(player *p, int ch, const signed char *src, int len
v->newLoopBegin = loopStart;
v->newLoopEnd = loopStart + loopLength;
v->newStep = step;
v->interpolating = 1;
// if the mixer was already shut down because of a short non-loop sample, force swap
if (v->data == NULL)
@ -446,7 +447,6 @@ static void mixerSwapChSource(player *p, int ch, const signed char *src, int len
v->loopFlag = v->newLoopFlag;
v->data = v->newData;
v->length = v->newLength;
v->frac = 0.0f;
v->step = v->newStep;
// for safety, shut down voice if the sample position is overriding the length
@ -464,12 +464,12 @@ static void mixerSetChSource(player *p, int ch, const signed char *src, int leng
v->swapSampleFlag = false;
v->data = src;
v->index = offset;
v->frac = 0.0f;
v->length = length;
v->loopFlag = loopLength > (2 * step);
v->loopBegin = loopStart;
v->loopEnd = loopStart + loopLength;
v->step = step;
v->interpolating = 1;
// Check external 9xx usage (Set Sample Offset)
if (v->loopFlag)
@ -525,8 +525,8 @@ static void mixerCutChannels(player *p)
memset(p->v, 0, sizeof (p->v));
for (i = 0; i < MAX_CHANNELS; ++i)
{
memset(&p->blep[i], 0, sizeof(BLEP));
memset(&p->blepVol[i], 0, sizeof(BLEP));
resampler_clear(p->blep[i]);
resampler_clear(p->blepVol[i]);
}
memset(&p->filter, 0, sizeof (p->filter));
@ -545,7 +545,7 @@ static void mixerCutChannels(player *p)
static void mixerSetChRate(player *p, int ch, float rate)
{
p->v[ch].rate = rate;
p->v[ch].rate = 1.0f / rate;
}
static void outputAudio(player *p, int *target, int numSamples)
@ -556,6 +556,7 @@ static void outputAudio(player *p, int *target, int numSamples)
int step;
int tempVolume;
int delta;
int interpolating;
unsigned int i;
unsigned int j;
float L;
@ -565,8 +566,8 @@ static void outputAudio(player *p, int *target, int numSamples)
float downscale;
Voice *v;
BLEP *bSmp;
BLEP *bVol;
void *bSmp;
void *bVol;
memset(p->mixBufferL, 0, numSamples * sizeof (float));
memset(p->mixBufferR, 0, numSamples * sizeof (float));
@ -576,27 +577,99 @@ static void outputAudio(player *p, int *target, int numSamples)
j = 0;
v = &p->v[i];
bSmp = &p->blep[i];
bVol = &p->blepVol[i];
bSmp = p->blep[i];
bVol = p->blepVol[i];
if (v->data && v->rate)
{
step = v->step;
interpolating = v->interpolating;
resampler_set_rate(bSmp, v->rate);
resampler_set_rate(bVol, v->rate);
for (j = 0; j < numSamples;)
{
tempSample = (v->data ? (step == 2 ? (v->data[v->index] + v->data[v->index + 1] * 0x100) : v->data[v->index] * 0x100) : 0);
tempVolume = (v->data && !v->mute ? v->vol : 0);
while (j < numSamples && (!v->data || v->frac >= 1.0f))
while (interpolating && (resampler_get_free_count(bSmp) ||
!resampler_get_sample_count(bSmp)))
{
t_vol = 0.0f;
t_smp = 0.0f;
tempSample = (v->data ? (step == 2 ? (v->data[v->index] + v->data[v->index + 1] * 0x100) : v->data[v->index] * 0x100) : 0);
resampler_write_sample_fixed(bSmp, tempSample, 1);
resampler_write_sample_fixed(bVol, tempVolume, 1);
if (v->data)
v->frac -= 1.0f;
t_vol += blepRun(bVol);
t_smp += blepRun(bSmp);
{
v->index += step;
if (v->loopFlag)
{
if (v->index >= v->loopEnd)
{
if (v->swapSampleFlag)
{
v->swapSampleFlag = false;
if (!v->newLoopFlag)
{
interpolating = 0;
break;
}
v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag;
v->data = v->newData;
v->length = v->newLength;
v->step = v->newStep;
v->index = v->loopBegin;
}
else
{
v->index = v->loopBegin;
}
}
}
else if (v->index >= v->length)
{
if (v->swapSampleFlag)
{
v->swapSampleFlag = false;
if (!v->newLoopFlag)
{
interpolating = 0;
break;
}
v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag;
v->data = v->newData;
v->length = v->newLength;
v->step = v->newStep;
v->index = v->loopBegin;
}
else
{
interpolating = 0;
break;
}
}
}
}
v->interpolating = interpolating;
while (j < numSamples && resampler_get_sample_count(bSmp))
{
t_vol = resampler_get_sample_float(bVol);
t_smp = resampler_get_sample_float(bSmp);
resampler_remove_sample(bVol, 0);
resampler_remove_sample(bSmp, 1);
t_smp *= t_vol;
i_smp = (signed int)t_smp;
@ -606,108 +679,12 @@ static void outputAudio(player *p, int *target, int numSamples)
j++;
}
if (j >= numSamples)
if (!interpolating && j < numSamples)
{
v->data = NULL;
break;
if (tempSample != bSmp->lastInput && v->frac >= 0.0f && v->frac < 1.0f)
{
delta = tempSample - bSmp->lastInput;
bSmp->lastInput = tempSample;
blepAdd(bSmp, v->frac, delta);
}
if (tempVolume != bVol->lastInput)
{
delta = tempVolume - bVol->lastInput;
bVol->lastInput = tempVolume;
blepAdd(bVol, 0, delta);
}
if (v->data)
{
v->index += step;
v->frac += v->rate;
if (v->loopFlag)
{
if (v->index >= v->loopEnd)
{
if (v->swapSampleFlag)
{
v->swapSampleFlag = false;
if (!v->newLoopFlag)
{
v->data = NULL;
continue;
}
v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag;
v->data = v->newData;
v->length = v->newLength;
v->frac = 0.0f;
v->step = v->newStep;
while (v->index >= v->loopEnd)
v->index = v->loopBegin + (v->index - v->loopEnd);
}
else
{
while (v->index >= v->loopEnd)
v->index = v->loopBegin + (v->index - v->loopEnd);
}
}
}
else if (v->index >= v->length)
{
if (v->swapSampleFlag)
{
v->swapSampleFlag = false;
if (!v->newLoopFlag)
{
v->data = NULL;
continue;
}
v->loopBegin = v->newLoopBegin;
v->loopEnd = v->newLoopEnd;
v->loopFlag = v->newLoopFlag;
v->data = v->newData;
v->length = v->newLength;
v->frac = 0.0f;
v->step = v->newStep;
while (v->index >= v->loopEnd)
v->index = v->loopBegin + (v->index - v->loopEnd);
}
else
{
v->data = NULL;
}
}
}
}
}
if ((j < numSamples) && (v->data == NULL))
{
for (; j < numSamples; ++j)
{
tempVolume = 0.0f;
tempSample = 0.0f;
tempVolume += blepRun(bVol);
tempSample += blepRun(bSmp);
tempSample *= tempVolume;
i_smp = (signed int)tempSample;
p->mixBufferL[j] += i_smp * v->panL;
p->mixBufferR[j] += i_smp * v->panR;
}
}
}
@ -2787,6 +2764,8 @@ void *playptmod_Create(int samplingFrequency)
player *p = (player *) calloc(1, sizeof (player));
int i, j;
resampler_init();
p->tempoTimerVal = (samplingFrequency * 125) / 50;
@ -2820,8 +2799,20 @@ void *playptmod_Create(int samplingFrequency)
p->useLEDFilter = false;
for (i = 0; i < MAX_CHANNELS; ++i)
{
p->blep[i] = resampler_create();
resampler_set_quality(p->blep[i], RESAMPLER_QUALITY_BLEP);
}
for (i = 0; i < MAX_CHANNELS; ++i)
{
p->blepVol[i] = resampler_create();
resampler_set_quality(p->blepVol[i], RESAMPLER_QUALITY_BLEP);
}
mixerCutChannels(p);
return p;
}
@ -2953,6 +2944,12 @@ void playptmod_Free(void *_p)
p->extendedFrequencyTable = NULL;
}
for (i = 0; i < MAX_CHANNELS; ++i)
{
resampler_delete(p->blep[i]);
resampler_delete(p->blepVol[i]);
}
free(p);
}

View File

@ -1,93 +0,0 @@
/*
** This file is part of the ProTracker 2.3D port/clone
** project by Olav "8bitbubsy" Sorensen.
**
** It contains unstructured and unclean code, but I care
** more about how the program works than how the source
** code looks. Although, I do respect coders that can
** master the art of writing clean and structured code.
** I know I can't.
**
** All of the files are considered 'public domain',
** do whatever you want with it.
**
*/
#include <stdint.h>
#include "pt_blep.h"
#define _LERP(I, F) ((I[0]) + ((I[1]) - (I[0])) * (F))
static const uint32_t blepData[48] =
{
0x3F7FE1F1, 0x3F7FD548, 0x3F7FD6A3, 0x3F7FD4E3,
0x3F7FAD85, 0x3F7F2152, 0x3F7DBFAE, 0x3F7ACCDF,
0x3F752F1E, 0x3F6B7384, 0x3F5BFBCB, 0x3F455CF2,
0x3F26E524, 0x3F0128C4, 0x3EACC7DC, 0x3E29E86B,
0x3C1C1D29, 0xBDE4BBE6, 0xBE3AAE04, 0xBE48DEDD,
0xBE22AD7E, 0xBDB2309A, 0xBB82B620, 0x3D881411,
0x3DDADBF3, 0x3DE2C81D, 0x3DAAA01F, 0x3D1E769A,
0xBBC116D7, 0xBD1402E8, 0xBD38A069, 0xBD0C53BB,
0xBC3FFB8C, 0x3C465FD2, 0x3CEA5764, 0x3D0A51D6,
0x3CEAE2D5, 0x3C92AC5A, 0x3BE4CBF7, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
void blepAdd(BLEP *b, float offset, float amplitude)
{
int8_t n;
uint32_t i;
const float *src;
float f;
float a;
float k[NS];
n = NS;
i = (uint32_t)(offset * SP);
src = (const float *)(blepData) + i + OS;
f = (offset * SP) - i;
i = b->index;
a = 0.0f;
while (n--)
{
a += k[n] = _LERP(src, f);
src += SP;
}
n = NS;
a = 1.0f / a;
while (n--)
{
b->buffer[i] += (amplitude * k[n]) * a;
i++;
i &= RNS;
}
b->samplesLeft = NS;
}
float blepRun(BLEP *b)
{
float output;
output = b->buffer[b->index];
b->buffer[b->index] = 0.0f;
b->index++;
b->index &= RNS;
b->samplesLeft--;
output += b->lastOutput;
b->lastOutput = output;
return (output);
}

View File

@ -1,55 +0,0 @@
/*
** This file is part of the ProTracker 2.3D port/clone
** project by Olav "8bitbubsy" Sorensen.
**
** It contains unstructured and unclean code, but I care
** more about how the program works than how the source
** code looks. Although, I do respect coders that can
** master the art of writing clean and structured code.
** I know I can't.
**
** All of the files are considered 'public domain',
** do whatever you want with it.
**
*/
#ifndef __PT_BLEP_H
#define __PT_BLEP_H
#include <stdint.h>
// thanks to aciddose/ad/adejr for the blep/cutoff/filter stuff!
// information on blep variables
//
// ZC = zero crossings, the number of ripples in the impulse
// OS = oversampling, how many samples per zero crossing are taken
// SP = step size per output sample, used to lower the cutoff (play the impulse slower)
// NS = number of samples of impulse to insert
// RNS = the lowest power of two greater than NS, minus one (used to wrap output buffer)
//
// ZC and OS are here only for reference, they depend upon the data in the table and can't be changed.
// SP, the step size can be any number lower or equal to OS, as long as the result NS remains an integer.
// for example, if ZC=8,OS=5, you can set SP=1, the result is NS=40, and RNS must then be 63.
// the result of that is the filter cutoff is set at nyquist * (SP/OS), in this case nyquist/5.
#define ZC 8
#define OS 5
#define SP 5
#define NS (ZC * OS / SP)
#define RNS 7 // RNS = (2^ > NS) - 1
typedef struct blep_data
{
int32_t index;
int32_t samplesLeft;
float buffer[RNS + 1];
float lastInput;
float lastOutput;
} BLEP;
void blepAdd(BLEP *b, float offset, float amplitude);
float blepRun(BLEP *b);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
#ifndef _RESAMPLER_H_
#define _RESAMPLER_H_
// Ugglay
#ifdef RESAMPLER_DECORATE
#define PASTE(a,b) a ## b
#define EVALUATE(a,b) PASTE(a,b)
#define resampler_init EVALUATE(RESAMPLER_DECORATE,_resampler_init)
#define resampler_create EVALUATE(RESAMPLER_DECORATE,_resampler_create)
#define resampler_delete EVALUATE(RESAMPLER_DECORATE,_resampler_delete)
#define resampler_dup EVALUATE(RESAMPLER_DECORATE,_resampler_dup)
#define resampler_dup_inplace EVALUATE(RESAMPLER_DECORATE,_resampler_dup_inplace)
#define resampler_set_quality EVALUATE(RESAMPLER_DECORATE,_resampler_set_quality)
#define resampler_get_free_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_free_count)
#define resampler_write_sample EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample)
#define resampler_write_sample_fixed EVALUATE(RESAMPLER_DECORATE,_resampler_write_sample_fixed)
#define resampler_set_rate EVALUATE(RESAMPLER_DECORATE,_resampler_set_rate)
#define resampler_ready EVALUATE(RESAMPLER_DECORATE,_resampler_ready)
#define resampler_clear EVALUATE(RESAMPLER_DECORATE,_resampler_clear)
#define resampler_get_sample_count EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_count)
#define resampler_get_sample EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample)
#define resampler_get_sample_float EVALUATE(RESAMPLER_DECORATE,_resampler_get_sample_float)
#define resampler_remove_sample EVALUATE(RESAMPLER_DECORATE,_resampler_remove_sample)
#endif
void resampler_init(void);
void * resampler_create(void);
void resampler_delete(void *);
void * resampler_dup(const void *);
void resampler_dup_inplace(void *, const void *);
enum
{
RESAMPLER_QUALITY_MIN = 0,
RESAMPLER_QUALITY_ZOH = 0,
RESAMPLER_QUALITY_BLEP = 1,
RESAMPLER_QUALITY_LINEAR = 2,
RESAMPLER_QUALITY_BLAM = 3,
RESAMPLER_QUALITY_CUBIC = 4,
RESAMPLER_QUALITY_SINC = 5,
RESAMPLER_QUALITY_MAX = 5
};
void resampler_set_quality(void *, int quality);
int resampler_get_free_count(void *);
void resampler_write_sample(void *, short sample);
void resampler_write_sample_fixed(void *, int sample, unsigned char depth);
void resampler_set_rate( void *, double new_factor );
int resampler_ready(void *);
void resampler_clear(void *);
int resampler_get_sample_count(void *);
int resampler_get_sample(void *);
float resampler_get_sample_float(void *);
void resampler_remove_sample(void *, int decay);
#endif

View File

@ -106,6 +106,8 @@ static void SyncProc( HSYNC handle, DWORD channel, DWORD data, void *user )
resampling_int = 0;
else if ([resampling isEqualToString:@"linear"])
resampling_int = 1;
else if ([resampling isEqualToString:@"blam"])
resampling_int = 1;
else if ([resampling isEqualToString:@"cubic"])
resampling_int = 1;
else if ([resampling isEqualToString:@"sinc"])

View File

@ -205,10 +205,12 @@ int callbackLoop(void *data)
resampling_int = 1;
else if ([resampling isEqualToString:@"linear"])
resampling_int = 2;
else if ([resampling isEqualToString:@"cubic"])
else if ([resampling isEqualToString:@"blam"])
resampling_int = 3;
else if ([resampling isEqualToString:@"sinc"])
else if ([resampling isEqualToString:@"cubic"])
resampling_int = 4;
else if ([resampling isEqualToString:@"sinc"])
resampling_int = 5;
dumb_it_set_resampling_quality( itsr, resampling_int );
dumb_it_set_ramp_style(itsr, 2);

View File

@ -190,10 +190,12 @@ BOOL xm_probe_length( unsigned long * intro_length, unsigned long * loop_length,
resampling_int = 1;
else if ([resampling isEqualToString:@"linear"])
resampling_int = 2;
else if ([resampling isEqualToString:@"cubic"])
else if ([resampling isEqualToString:@"blam"])
resampling_int = 3;
else if ([resampling isEqualToString:@"sinc"])
else if ([resampling isEqualToString:@"cubic"])
resampling_int = 4;
else if ([resampling isEqualToString:@"sinc"])
resampling_int = 5;
if ( type == TYPE_S3M )
{

View File

@ -28,6 +28,11 @@
NSLocalizedStringFromTableInBundle(@"Linear Interpolation", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
@"linear", @"preference",nil]];
[self addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedStringFromTableInBundle(@"Blam Synthesis", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
@"blam", @"preference",nil]];
[self addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedStringFromTableInBundle(@"Cubic Interpolation", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",