diff --git a/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj b/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj index 21bdeddf4..3b26ef20e 100644 --- a/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj +++ b/Frameworks/Dumb/Dumb.xcodeproj/project.pbxproj @@ -56,7 +56,7 @@ 8370B62C17F60FE2001A4D7A /* stack_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B62417F60FE2001A4D7A /* stack_alloc.h */; }; 8370B62D17F60FE2001A4D7A /* tarray.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B62517F60FE2001A4D7A /* tarray.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8370B63417F61001001A4D7A /* barray.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B62E17F61001001A4D7A /* barray.c */; }; - 8370B63617F61001001A4D7A /* sinc_resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63017F61001001A4D7A /* sinc_resampler.c */; }; + 8370B63617F61001001A4D7A /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63017F61001001A4D7A /* resampler.c */; }; 8370B63717F61001001A4D7A /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63117F61001001A4D7A /* lpc.c */; }; 8370B63817F61001001A4D7A /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63217F61001001A4D7A /* riff.c */; }; 8370B63917F61001001A4D7A /* tarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63317F61001001A4D7A /* tarray.c */; }; @@ -101,7 +101,7 @@ 8370B68917F61038001A4D7A /* readriff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66017F61038001A4D7A /* readriff.c */; }; 8370B68A17F61038001A4D7A /* readstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66117F61038001A4D7A /* readstm.c */; }; 8370B68B17F61038001A4D7A /* readstm2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66217F61038001A4D7A /* readstm2.c */; }; - 8370B7EA17F62A40001A4D7A /* sinc_resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B7E817F62A40001A4D7A /* sinc_resampler.h */; }; + 8370B7EA17F62A40001A4D7A /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B7E817F62A40001A4D7A /* resampler.h */; }; 83C8DF1D18C6B31400750AF7 /* blip_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C8DF1C18C6B31400750AF7 /* blip_buf.c */; }; 83C8DF1F18C6B32100750AF7 /* blip_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8DF1E18C6B32100750AF7 /* blip_buf.h */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; @@ -165,7 +165,7 @@ 8370B62417F60FE2001A4D7A /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = ""; }; 8370B62517F60FE2001A4D7A /* tarray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tarray.h; sourceTree = ""; }; 8370B62E17F61001001A4D7A /* barray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = barray.c; sourceTree = ""; }; - 8370B63017F61001001A4D7A /* sinc_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sinc_resampler.c; sourceTree = ""; }; + 8370B63017F61001001A4D7A /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = ""; }; 8370B63117F61001001A4D7A /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpc.c; sourceTree = ""; }; 8370B63217F61001001A4D7A /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = ""; }; 8370B63317F61001001A4D7A /* tarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tarray.c; sourceTree = ""; }; @@ -210,7 +210,7 @@ 8370B66017F61038001A4D7A /* readriff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readriff.c; sourceTree = ""; }; 8370B66117F61038001A4D7A /* readstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm.c; sourceTree = ""; }; 8370B66217F61038001A4D7A /* readstm2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm2.c; sourceTree = ""; }; - 8370B7E817F62A40001A4D7A /* sinc_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sinc_resampler.h; sourceTree = ""; }; + 8370B7E817F62A40001A4D7A /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; 83C8DF1C18C6B31400750AF7 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = ""; }; 83C8DF1E18C6B32100750AF7 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; @@ -308,7 +308,7 @@ isa = PBXGroup; children = ( 83C8DF1E18C6B32100750AF7 /* blip_buf.h */, - 8370B7E817F62A40001A4D7A /* sinc_resampler.h */, + 8370B7E817F62A40001A4D7A /* resampler.h */, 8370B61E17F60FE2001A4D7A /* barray.h */, 8370B62017F60FE2001A4D7A /* dumbfile.h */, 8370B62217F60FE2001A4D7A /* lpc.h */, @@ -356,7 +356,7 @@ children = ( 83C8DF1C18C6B31400750AF7 /* blip_buf.c */, 8370B62E17F61001001A4D7A /* barray.c */, - 8370B63017F61001001A4D7A /* sinc_resampler.c */, + 8370B63017F61001001A4D7A /* resampler.c */, 8370B63117F61001001A4D7A /* lpc.c */, 8370B63217F61001001A4D7A /* riff.c */, 8370B63317F61001001A4D7A /* tarray.c */, @@ -454,7 +454,7 @@ 8370B62617F60FE2001A4D7A /* barray.h in Headers */, 17C8F63E0CBEE797008D969D /* dumb.h in Headers */, 17C8F6400CBEE797008D969D /* it.h in Headers */, - 8370B7EA17F62A40001A4D7A /* sinc_resampler.h in Headers */, + 8370B7EA17F62A40001A4D7A /* resampler.h in Headers */, 17C8F63F0CBEE797008D969D /* dumb.h in Headers */, 8370B62B17F60FE2001A4D7A /* riff.h in Headers */, 8370B62A17F60FE2001A4D7A /* lpc.h in Headers */, @@ -567,7 +567,7 @@ 8370B66417F61038001A4D7A /* load6692.c in Sources */, 17C8F6560CBEE797008D969D /* itload.c in Sources */, 17C8F6570CBEE797008D969D /* itload2.c in Sources */, - 8370B63617F61001001A4D7A /* sinc_resampler.c in Sources */, + 8370B63617F61001001A4D7A /* resampler.c in Sources */, 17C8F6580CBEE797008D969D /* itmisc.c in Sources */, 8370B67517F61038001A4D7A /* loadriff.c in Sources */, 8370B66917F61038001A4D7A /* loadasy.c in Sources */, diff --git a/Frameworks/Dumb/dumb/include/internal/resampler.h b/Frameworks/Dumb/dumb/include/internal/resampler.h new file mode 100644 index 000000000..f3e7bf874 --- /dev/null +++ b/Frameworks/Dumb/dumb/include/internal/resampler.h @@ -0,0 +1,52 @@ +#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_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_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_LINEAR = 1, + RESAMPLER_QUALITY_CUBIC = 2, + RESAMPLER_QUALITY_SINC = 3, + RESAMPLER_QUALITY_MAX = 3 +}; + +void resampler_set_quality(void *, int quality); + +int resampler_get_free_count(void *); +void resampler_write_sample(void *, short sample); +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 *); +void resampler_remove_sample(void *); + +#endif diff --git a/Frameworks/Dumb/dumb/include/internal/sinc_resampler.h b/Frameworks/Dumb/dumb/include/internal/sinc_resampler.h deleted file mode 100644 index 4637dd1e3..000000000 --- a/Frameworks/Dumb/dumb/include/internal/sinc_resampler.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _SINC_RESAMPLER_H_ -#define _SINC_RESAMPLER_H_ - -// Ugglay -#ifdef SINC_DECORATE -#define PASTE(a,b) a ## b -#define EVALUATE(a,b) PASTE(a,b) -#define sinc_init EVALUATE(SINC_DECORATE,_sinc_init) -#define sinc_resampler_create EVALUATE(SINC_DECORATE,_sinc_resampler_create) -#define sinc_resampler_delete EVALUATE(SINC_DECORATE,_sinc_resampler_delete) -#define sinc_resampler_dup EVALUATE(SINC_DECORATE,_sinc_resampler_dup) -#define sinc_resampler_dup_inplace EVALUATE(SINC_DECORATE,_sinc_resampler_dup_inplace) -#define sinc_resampler_get_free_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_free_count) -#define sinc_resampler_write_sample EVALUATE(SINC_DECORATE,_sinc_resampler_write_sample) -#define sinc_resampler_set_rate EVALUATE(SINC_DECORATE,_sinc_resampler_set_rate) -#define sinc_resampler_ready EVALUATE(SINC_DECORATE,_sinc_resampler_ready) -#define sinc_resampler_clear EVALUATE(SINC_DECORATE,_sinc_resampler_clear) -#define sinc_resampler_get_sample_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample_count) -#define sinc_resampler_get_sample EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample) -#define sinc_resampler_remove_sample EVALUATE(SINC_DECORATE,_sinc_resampler_remove_sample) -#endif - -void sinc_init(void); - -void * sinc_resampler_create(void); -void sinc_resampler_delete(void *); -void * sinc_resampler_dup(const void *); -void sinc_resampler_dup_inplace(void *, const void *); - -int sinc_resampler_get_free_count(void *); -void sinc_resampler_write_sample(void *, short sample); -void sinc_resampler_set_rate( void *, double new_factor ); -int sinc_resampler_ready(void *); -void sinc_resampler_clear(void *); -int sinc_resampler_get_sample_count(void *); -int sinc_resampler_get_sample(void *); -void sinc_resampler_remove_sample(void *); - -#endif diff --git a/Frameworks/Dumb/dumb/src/helpers/resamp3.inc b/Frameworks/Dumb/dumb/src/helpers/resamp3.inc index 6f46a00f3..8da8410f5 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resamp3.inc +++ b/Frameworks/Dumb/dumb/src/helpers/resamp3.inc @@ -140,78 +140,24 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU MIX_ALIAS( todo ); done -= check; } - } else if (quality <= DUMB_RQ_LINEAR) { - /* Linear interpolation, backwards */ - SRCTYPE xbuf[3*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[1*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - COPYSRC(xbuf, 2, src, pos); - while (todo && x < &xbuf[3*SRC_CHANNELS]) { - HEAVYASSERT(pos >= resampler->start); - MIX_LINEAR(+=, 1, 0, -1); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - // TODO: use xstart for others too - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos >= resampler->start); - MIX_LINEAR(+=, 1, 1, 2); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else if (quality <= DUMB_RQ_CUBIC) { - /* Cubic interpolation, backwards */ - SRCTYPE xbuf[6*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[3*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 0); - COPYSRC(xbuf, 1, resampler->X, 1); - COPYSRC(xbuf, 2, resampler->X, 2); - COPYSRC(xbuf, 3, src, pos); - if (pos-1 >= resampler->start) COPYSRC(xbuf, 4, src, pos-1); - if (pos-2 >= resampler->start) COPYSRC(xbuf, 5, src, pos-2); - while (todo && x < &xbuf[6*SRC_CHANNELS]) { - HEAVYASSERT(pos >= resampler->start); - MIX_CUBIC(+=, 1, x, x, 0, -1, -2, -3); - subpos += dt; - pos += subpos >> 16; - x -= (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos >= resampler->start); - MIX_CUBIC(+=, 1, x, x, 0, 1, 2, 3); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); } else { /* FIR resampling, backwards */ SRCTYPE *x; if ( resampler->fir_resampler_ratio != delta ) { - sinc_resampler_set_rate( resampler->fir_resampler[0], delta ); - sinc_resampler_set_rate( resampler->fir_resampler[1], delta ); + resampler_set_rate( resampler->fir_resampler[0], delta ); + resampler_set_rate( resampler->fir_resampler[1], delta ); resampler->fir_resampler_ratio = delta; } x = &src[pos*SRC_CHANNELS]; while ( todo ) { - while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) && + while ( resampler_get_free_count( resampler->fir_resampler[0] ) && pos >= resampler->start ) { POKE_FIR(0); pos--; x -= SRC_CHANNELS; } - if ( !sinc_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; + if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; MIX_FIR; ADVANCE_FIR; --todo; @@ -273,77 +219,24 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU MIX_ALIAS( todo ); done -= check; } - } else if (quality <= DUMB_RQ_LINEAR) { - /* Linear interpolation, forwards */ - SRCTYPE xbuf[3*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[1*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 1); - COPYSRC(xbuf, 1, resampler->X, 2); - COPYSRC(xbuf, 2, src, pos); - while (todo && x < &xbuf[3*SRC_CHANNELS]) { - HEAVYASSERT(pos < resampler->end); - MIX_LINEAR(+=, 1, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos < resampler->end); - MIX_LINEAR(+=, 1, -2, -1); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); - } else if (quality <= DUMB_RQ_CUBIC) { - /* Cubic interpolation, forwards */ - SRCTYPE xbuf[6*SRC_CHANNELS]; - SRCTYPE *x = &xbuf[3*SRC_CHANNELS]; - COPYSRC(xbuf, 0, resampler->X, 0); - COPYSRC(xbuf, 1, resampler->X, 1); - COPYSRC(xbuf, 2, resampler->X, 2); - COPYSRC(xbuf, 3, src, pos); - if (pos+1 < resampler->end) COPYSRC(xbuf, 4, src, pos+1); - if (pos+2 < resampler->end) COPYSRC(xbuf, 5, src, pos+2); - while (todo && x < &xbuf[6*SRC_CHANNELS]) { - HEAVYASSERT(pos < resampler->end); - MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - todo--; - } - x = &src[pos*SRC_CHANNELS]; - LOOP4(todo, - HEAVYASSERT(pos < resampler->end); - MIX_CUBIC(+=, 1, x, x, -3, -2, -1, 0); - subpos += dt; - pos += subpos >> 16; - x += (subpos >> 16) * SRC_CHANNELS; - subpos &= 65535; - ); } else { /* FIR resampling, forwards */ SRCTYPE *x; if ( resampler->fir_resampler_ratio != delta ) { - sinc_resampler_set_rate( resampler->fir_resampler[0], delta ); - sinc_resampler_set_rate( resampler->fir_resampler[1], delta ); + resampler_set_rate( resampler->fir_resampler[0], delta ); + resampler_set_rate( resampler->fir_resampler[1], delta ); resampler->fir_resampler_ratio = delta; } x = &src[pos*SRC_CHANNELS]; while ( todo ) { - while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) && + while ( resampler_get_free_count( resampler->fir_resampler[0] ) && pos < resampler->end ) { POKE_FIR(0); pos++; x += SRC_CHANNELS; } - if ( !sinc_resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; + if ( !resampler_get_sample_count( resampler->fir_resampler[0] ) ) break; MIX_FIR; ADVANCE_FIR; --todo; @@ -409,12 +302,6 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE if (quality <= DUMB_RQ_ALIASING) { /* Aliasing, backwards */ PEEK_ALIAS; - } else if (quality <= DUMB_RQ_LINEAR) { - /* Linear interpolation, backwards */ - MIX_LINEAR(=, 0, 2, 1); - } else if (quality <= DUMB_RQ_CUBIC) { - /* Cubic interpolation, backwards */ - MIX_CUBIC(=, 0, src, x, pos, 2, 1, 0); } else { /* FIR resampling, backwards */ PEEK_FIR; @@ -424,12 +311,6 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE if (quality <= DUMB_RQ_ALIASING) { /* Aliasing */ PEEK_ALIAS; - } else if (quality <= DUMB_RQ_LINEAR) { - /* Linear interpolation, forwards */ - MIX_LINEAR(=, 0, 1, 2); - } else if (quality <= DUMB_RQ_CUBIC) { - /* Cubic interpolation, forwards */ - MIX_CUBIC(=, 0, x, src, 0, 1, 2, pos); } else { /* FIR resampling, forwards */ PEEK_FIR; diff --git a/Frameworks/Dumb/dumb/src/helpers/resample.c b/Frameworks/Dumb/dumb/src/helpers/resample.c index 5644ae2b9..15936ae94 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resample.c +++ b/Frameworks/Dumb/dumb/src/helpers/resample.c @@ -46,7 +46,7 @@ #include "dumb.h" #include "internal/blip_buf.h" -#include "internal/sinc_resampler.h" +#include "internal/resampler.h" @@ -171,7 +171,7 @@ void _dumb_init_cubic(void) cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14); } - sinc_init(); + resampler_init(); done = 1; } diff --git a/Frameworks/Dumb/dumb/src/helpers/resample.inc b/Frameworks/Dumb/dumb/src/helpers/resample.inc index 9d9e29c6f..01b2fcf8e 100644 --- a/Frameworks/Dumb/dumb/src/helpers/resample.inc +++ b/Frameworks/Dumb/dumb/src/helpers/resample.inc @@ -75,8 +75,10 @@ void dumb_reset_resampler(DUMB_RESAMPLER *resampler, SRCTYPE *src, int src_chann blip_clear(resampler->blip_buffer[0]); blip_clear(resampler->blip_buffer[1]); resampler->fir_resampler_ratio = 0; - sinc_resampler_clear(resampler->fir_resampler[0]); - sinc_resampler_clear(resampler->fir_resampler[1]); + resampler_clear(resampler->fir_resampler[0]); + resampler_clear(resampler->fir_resampler[1]); + resampler_set_quality(resampler->fir_resampler[0], resampler->quality); + resampler_set_quality(resampler->fir_resampler[1], resampler->quality); } @@ -158,15 +160,15 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l resampler->last_clock += inv_dt; \ } #define POKE_FIR(offset) { \ - sinc_resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \ + resampler_write_sample( resampler->fir_resampler[0], FIR(x[offset]) ); \ } #define MONO_DEST_PEEK_ALIAS *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), vol ) -#define MONO_DEST_PEEK_FIR *dst = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), vol ) +#define MONO_DEST_PEEK_FIR *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ) #define MONO_DEST_MIX_FIR { \ - *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), vol ); \ + *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), vol ); \ UPDATE_VOLUME( volume, vol ); \ } -#define ADVANCE_FIR sinc_resampler_remove_sample( resampler->fir_resampler[0] ) +#define ADVANCE_FIR resampler_remove_sample( resampler->fir_resampler[0] ) #define MONO_DEST_MIX_ALIAS(count) { \ int n = 0; \ resampler->last_clock -= count * 65536; \ @@ -184,12 +186,12 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l *dst++ = MULSC( sample, rvol ); \ } #define STEREO_DEST_PEEK_FIR { \ - int sample = sinc_resampler_get_sample( resampler->fir_resampler[0] ); \ + int sample = resampler_get_sample( resampler->fir_resampler[0] ); \ *dst++ = MULSC( sample, lvol ); \ *dst++ = MULSC( sample, rvol ); \ } #define STEREO_DEST_MIX_FIR { \ - int sample = sinc_resampler_get_sample( resampler->fir_resampler[0] ); \ + int sample = resampler_get_sample( resampler->fir_resampler[0] ); \ *dst++ += MULSC( sample, lvol ); \ *dst++ += MULSC( sample, rvol ); \ UPDATE_VOLUME( volume_left, lvol ); \ @@ -296,26 +298,26 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l resampler->last_clock += inv_dt; \ } #define POKE_FIR(offset) { \ - sinc_resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \ - sinc_resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \ + resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \ + resampler_write_sample( resampler->fir_resampler[1], FIR(x[(offset)*2+1]) ); \ } #define MONO_DEST_PEEK_ALIAS { \ *dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \ MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \ } #define MONO_DEST_PEEK_FIR { \ - *dst = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ - MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ + *dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ + MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ } #define MONO_DEST_MIX_FIR { \ - *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ - MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ + *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \ + MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ UPDATE_VOLUME( volume_left, lvol ); \ UPDATE_VOLUME( volume_right, rvol ); \ } #define ADVANCE_FIR { \ - sinc_resampler_remove_sample( resampler->fir_resampler[0] ); \ - sinc_resampler_remove_sample( resampler->fir_resampler[1] ); \ + resampler_remove_sample( resampler->fir_resampler[0] ); \ + resampler_remove_sample( resampler->fir_resampler[1] ); \ } #define MONO_DEST_MIX_ALIAS(count) { \ int n = 0; \ @@ -336,12 +338,12 @@ DUMB_RESAMPLER *dumb_start_resampler(SRCTYPE *src, int src_channels, long pos, l *dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \ } #define STEREO_DEST_PEEK_FIR { \ - *dst++ = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ - *dst++ = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ + *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ + *dst++ = MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ } #define STEREO_DEST_MIX_FIR { \ - *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ - *dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ + *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \ + *dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \ UPDATE_VOLUME( volume_left, lvol ); \ UPDATE_VOLUME( volume_right, rvol ); \ } diff --git a/Frameworks/Dumb/dumb/src/helpers/resampler.c b/Frameworks/Dumb/dumb/src/helpers/resampler.c new file mode 100644 index 000000000..fab589db9 --- /dev/null +++ b/Frameworks/Dumb/dumb/src/helpers/resampler.c @@ -0,0 +1,636 @@ +#include +#include +#define _USE_MATH_DEFINES +#include +#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) +#include +#define RESAMPLER_SSE +#endif + +#ifdef _MSC_VER +#define ALIGNED _declspec(align(16)) +#else +#define ALIGNED __attribute__((aligned(16))) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "resampler.h" + +enum { RESAMPLER_SHIFT = 13 }; +enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; +enum { SINC_WIDTH = 16 }; +enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; +enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; + +ALIGNED static float cubic_lut[CUBIC_SAMPLES]; + +static float sinc_lut[SINC_SAMPLES + 1]; + +enum { resampler_buffer_size = SINC_WIDTH * 4 }; + +static int fEqual(const float b, const float a) +{ + return fabs(a - b) < 1.0e-6; +} + +static float sinc(float x) +{ + return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); +} + +#ifdef RESAMPLER_SSE +#ifdef _MSC_VER +#include +#elif defined(__clang__) || defined(__GNUC__) +static inline void +__cpuid(int *data, int selector) +{ + asm("cpuid" + : "=a" (data[0]), + "=b" (data[1]), + "=c" (data[2]), + "=d" (data[3]) + : "a"(selector)); +} +#else +#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) +#endif + +static int query_cpu_feature_sse() { + int buffer[4]; + __cpuid(buffer,1); + if ((buffer[3]&(1<<25)) == 0) return 0; + return 1; +} + +static int resampler_has_sse = 0; +#endif + +void resampler_init(void) +{ + unsigned i; + double dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; + for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) + { + float y = x / SINC_WIDTH; +#if 1 + // Blackman + float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); +#elif 0 + // C.R.Helmrich's 2 term window + float window = 0.79445 * cos(0.5 * M_PI * y) + 0.20555 * cos(1.5 * M_PI * y); +#elif 0 + // Lanczos + float window = sinc(y); +#endif + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; + } + dx = 1.0 / (float)(RESAMPLER_RESOLUTION); + x = 0.0; + for (i = 0; i < RESAMPLER_RESOLUTION; ++i, x += dx) + { + cubic_lut[i*4] = (float)(-0.5 * x * x * x + x * x - 0.5 * x); + cubic_lut[i*4+1] = (float)( 1.5 * x * x * x - 2.5 * x * x + 1.0); + cubic_lut[i*4+2] = (float)(-1.5 * x * x * x + 2.0 * x * x + 0.5 * x); + cubic_lut[i*4+3] = (float)( 0.5 * x * x * x - 0.5 * x * x); + } +#ifdef RESAMPLER_SSE + resampler_has_sse = query_cpu_feature_sse(); +#endif +} + +typedef struct resampler +{ + int write_pos, write_filled; + int read_pos, read_filled; + unsigned short phase; + unsigned short phase_inc; + unsigned char quality; + float buffer_in[resampler_buffer_size * 2]; + float buffer_out[resampler_buffer_size + SINC_WIDTH * 2 - 1]; +} resampler; + +void * resampler_create(void) +{ + resampler * r = ( resampler * ) malloc( sizeof(resampler) ); + if ( !r ) return 0; + + r->write_pos = 0; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; + r->phase_inc = 0; + r->quality = RESAMPLER_QUALITY_MAX; + memset( r->buffer_in, 0, sizeof(r->buffer_in) ); + memset( r->buffer_out, 0, sizeof(r->buffer_out) ); + + return r; +} + +void resampler_delete(void * _r) +{ + free( _r ); +} + +void * resampler_dup(const void * _r) +{ + const resampler * r_in = ( const resampler * ) _r; + resampler * r_out = ( resampler * ) malloc( sizeof(resampler) ); + if ( !r_out ) return 0; + + r_out->write_pos = r_in->write_pos; + r_out->write_filled = r_in->write_filled; + r_out->read_pos = r_in->read_pos; + r_out->read_filled = r_in->read_filled; + r_out->phase = r_in->phase; + r_out->phase_inc = r_in->phase_inc; + r_out->quality = r_in->quality; + memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); + memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); + + return r_out; +} + +void resampler_dup_inplace(void *_d, const void *_s) +{ + const resampler * r_in = ( const resampler * ) _s; + resampler * r_out = ( resampler * ) _d; + + r_out->write_pos = r_in->write_pos; + r_out->write_filled = r_in->write_filled; + r_out->read_pos = r_in->read_pos; + r_out->read_filled = r_in->read_filled; + r_out->phase = r_in->phase; + r_out->phase_inc = r_in->phase_inc; + r_out->quality = r_in->quality; + memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); + memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); +} + +void resampler_set_quality(void *_r, int quality) +{ + resampler * r = ( resampler * ) _r; + if (quality < RESAMPLER_QUALITY_MIN) + quality = RESAMPLER_QUALITY_MIN; + else if (quality > RESAMPLER_QUALITY_MAX) + quality = RESAMPLER_QUALITY_MAX; + r->quality = (unsigned char)quality; +} + +int resampler_get_free_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + return resampler_buffer_size - r->write_filled; +} + +static int resampler_min_filled(resampler *r) +{ + switch (r->quality) + { + default: + case RESAMPLER_QUALITY_ZOH: + return 1; + + case RESAMPLER_QUALITY_LINEAR: + return 2; + + case RESAMPLER_QUALITY_CUBIC: + return 4; + + case RESAMPLER_QUALITY_SINC: + return SINC_WIDTH * 2; + } +} + +int resampler_ready(void *_r) +{ + resampler * r = ( resampler * ) _r; + return r->write_filled > resampler_min_filled(r); +} + +void resampler_clear(void *_r) +{ + resampler * r = ( resampler * ) _r; + r->write_pos = 0; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; +} + +void resampler_set_rate(void *_r, double new_factor) +{ + resampler * r = ( resampler * ) _r; + r->phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION ); +} + +void resampler_write_sample(void *_r, short s) +{ + resampler * r = ( resampler * ) _r; + + if ( r->write_filled < resampler_buffer_size ) + { + float s32 = s; + s32 *= (1.0 / 32768.0); + + r->buffer_in[ r->write_pos ] = s32; + r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32; + + ++r->write_filled; + + r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; + } +} + +static int resampler_run_zoh(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 1; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float sample; + + if ( out >= out_end ) + break; + + sample = *in; + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +static int resampler_run_linear(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float sample; + + if ( out >= out_end ) + break; + + sample = in[0] + (in[1] - in[0]) * ((float)phase / RESAMPLER_RESOLUTION); + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +static int resampler_run_cubic(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 4; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float * kernel; + int i; + float sample; + + if ( out >= out_end ) + break; + + kernel = cubic_lut + phase * 4; + + for (sample = 0, i = 0; i < 4; ++i) + sample += in[i] * kernel[i]; + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +#ifdef RESAMPLER_SSE +static int resampler_run_cubic_sse(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 4; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + __m128 temp1, temp2; + __m128 samplex = _mm_setzero_ps(); + + if ( out >= out_end ) + break; + + temp1 = _mm_loadu_ps( (const float *)( in ) ); + temp2 = _mm_load_ps( (const float *)( cubic_lut + phase * 4 ) ); + temp1 = _mm_mul_ps( temp1, temp2 ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = _mm_movehl_ps( temp1, samplex ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = samplex; + temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); + samplex = _mm_add_ps( samplex, temp1 ); + _mm_store_ss( out, samplex ); + ++out; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION - 1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} +#endif + +static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= SINC_WIDTH * 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + + do + { + float kernel[SINC_WIDTH * 2], kernel_sum = 0.0; + int i = SINC_WIDTH; + int phase_adj = phase * step / RESAMPLER_RESOLUTION; + float sample; + + if ( out >= out_end ) + break; + + for (; i >= -SINC_WIDTH + 1; --i) + { + int pos = i * step; + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + } + for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) + sample += in[i] * kernel[i]; + *out++ = (float)(sample / kernel_sum); + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +#ifdef RESAMPLER_SSE +static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= SINC_WIDTH * 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + + do + { + // accumulate in extended precision + float kernel_sum = 0.0; + __m128 kernel[SINC_WIDTH / 2]; + __m128 temp1, temp2; + __m128 samplex = _mm_setzero_ps(); + float *kernelf = (float*)(&kernel); + int i = SINC_WIDTH; + int phase_adj = phase * step / RESAMPLER_RESOLUTION; + + if ( out >= out_end ) + break; + + for (; i >= -SINC_WIDTH + 1; --i) + { + int pos = i * step; + kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + } + for (i = 0; i < SINC_WIDTH / 2; ++i) + { + temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) ); + temp2 = _mm_load_ps( (const float *)( kernel + i ) ); + temp1 = _mm_mul_ps( temp1, temp2 ); + samplex = _mm_add_ps( samplex, temp1 ); + } + kernel_sum = 1.0 / kernel_sum; + temp1 = _mm_movehl_ps( temp1, samplex ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = samplex; + temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = _mm_set_ss( kernel_sum ); + samplex = _mm_mul_ps( samplex, temp1 ); + _mm_store_ss( out, samplex ); + ++out; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION - 1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} +#endif + +static void resampler_fill(resampler * r) +{ + int min_filled = resampler_min_filled(r); + int quality = r->quality; + while ( r->write_filled > min_filled && + r->read_filled < resampler_buffer_size ) + { + int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size; + int write_size = resampler_buffer_size - write_pos; + float * out = r->buffer_out + write_pos; + if ( write_size > ( resampler_buffer_size - r->read_filled ) ) + write_size = resampler_buffer_size - r->read_filled; + switch (quality) + { + case RESAMPLER_QUALITY_ZOH: + resampler_run_zoh( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_LINEAR: + resampler_run_linear( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_CUBIC: +#ifdef RESAMPLER_SSE + if ( resampler_has_sse ) + resampler_run_cubic_sse( r, &out, out + write_size ); + else +#endif + resampler_run_cubic( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_SINC: +#ifdef RESAMPLER_SSE + if ( resampler_has_sse ) + resampler_run_sinc_sse( r, &out, out + write_size ); + else +#endif + resampler_run_sinc( r, &out, out + write_size ); + break; + } + r->read_filled += out - r->buffer_out - write_pos; + } +} + +int resampler_get_sample_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 ) + resampler_fill( r ); + return r->read_filled; +} + +int resampler_get_sample(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 ) + resampler_fill( r ); + if ( r->read_filled < 1 ) + return 0; + return (int)(r->buffer_out[ r->read_pos ] * 16777216.0); +} + +void resampler_remove_sample(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled > 0 ) + { + --r->read_filled; + r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size; + } +} diff --git a/Frameworks/Dumb/dumb/src/helpers/sinc_resampler.c b/Frameworks/Dumb/dumb/src/helpers/sinc_resampler.c deleted file mode 100644 index 3348ed82e..000000000 --- a/Frameworks/Dumb/dumb/src/helpers/sinc_resampler.c +++ /dev/null @@ -1,361 +0,0 @@ -#include -#include -#define _USE_MATH_DEFINES -#include -#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) -#include -#define SINC_SSE -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include "internal/sinc_resampler.h" - -enum { SINC_RESOLUTION = 8192 }; -enum { SINC_WIDTH = 16 }; -enum { SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH }; - -static float sinc_lut[SINC_SAMPLES + 1]; - -enum { sinc_buffer_size = SINC_WIDTH * 4 }; - -static int fEqual(const float b, const float a) -{ - return fabs(a - b) < 1.0e-6; -} - -static float sinc(float x) -{ - return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); -} - -#ifdef SINC_SSE -#ifdef _MSC_VER -#include -#elif defined(__clang__) || defined(__GNUC__) -static inline void -__cpuid(int *data, int selector) -{ - asm("cpuid" - : "=a" (data[0]), - "=b" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "a"(selector)); -} -#else -#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) -#endif - -static int query_cpu_feature_sse() { - int buffer[4]; - __cpuid(buffer,1); - if ((buffer[3]&(1<<25)) == 0) return 0; - return 1; -} - -static int sinc_has_sse = 0; -#endif - -void sinc_init(void) -{ - unsigned i; - float dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; - for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) - { - float y = x / SINC_WIDTH; - float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); - sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; - } -#ifdef SINC_SSE - sinc_has_sse = query_cpu_feature_sse(); -#endif -} - -typedef struct sinc_resampler -{ - int write_pos, write_filled; - int read_pos, read_filled; - unsigned short phase; - unsigned int phase_inc; - float buffer_in[sinc_buffer_size * 2]; - int buffer_out[sinc_buffer_size]; -} sinc_resampler; - -void * sinc_resampler_create(void) -{ - sinc_resampler * r = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) ); - if ( !r ) return 0; - - r->write_pos = 0; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase = 0; - r->phase_inc = 0; - memset( r->buffer_in, 0, sizeof(r->buffer_in) ); - memset( r->buffer_out, 0, sizeof(r->buffer_out) ); - - return r; -} - -void sinc_resampler_delete(void * _r) -{ - free( _r ); -} - -void * sinc_resampler_dup(const void * _r) -{ - const sinc_resampler * r_in = ( const sinc_resampler * ) _r; - sinc_resampler * r_out = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) ); - if ( !r_out ) return 0; - - r_out->write_pos = r_in->write_pos; - r_out->write_filled = r_in->write_filled; - r_out->read_pos = r_in->read_pos; - r_out->read_filled = r_in->read_filled; - r_out->phase = r_in->phase; - r_out->phase_inc = r_in->phase_inc; - memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); - memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); - - return r_out; -} - -void sinc_resampler_dup_inplace(void *_d, const void *_s) -{ - const sinc_resampler * r_in = ( const sinc_resampler * ) _s; - sinc_resampler * r_out = ( sinc_resampler * ) _d; - - r_out->write_pos = r_in->write_pos; - r_out->write_filled = r_in->write_filled; - r_out->read_pos = r_in->read_pos; - r_out->read_filled = r_in->read_filled; - r_out->phase = r_in->phase; - r_out->phase_inc = r_in->phase_inc; - memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); - memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); -} - -int sinc_resampler_get_free_count(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - return sinc_buffer_size - r->write_filled; -} - -int sinc_resampler_ready(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - return r->write_filled > (SINC_WIDTH * 2); -} - -void sinc_resampler_clear(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - r->write_pos = 0; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase = 0; -} - -void sinc_resampler_set_rate(void *_r, double new_factor) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - r->phase_inc = (int)( new_factor * SINC_RESOLUTION ); -} - -void sinc_resampler_write_sample(void *_r, short s) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - - if ( r->write_filled < sinc_buffer_size ) - { - float s32 = s; - - r->buffer_in[ r->write_pos ] = s32; - r->buffer_in[ r->write_pos + sinc_buffer_size ] = s32; - - ++r->write_filled; - - r->write_pos = ( r->write_pos + 1 ) % sinc_buffer_size; - } -} - -static int sinc_resampler_run(sinc_resampler * r, int ** out_, int * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - int* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - int phase = r->phase; - int phase_inc = r->phase_inc; - - int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel[SINC_WIDTH * 2], kernel_sum = 0.0; - int i = SINC_WIDTH; - int phase_adj = phase * step / SINC_RESOLUTION; - float sample; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; - } - for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) - sample += in[i] * kernel[i]; - *out++ = (int)(sample / kernel_sum * 256.0); - - phase += phase_inc; - - in += phase >> 13; - - phase &= 8191; - } - while ( in < in_end ); - - r->phase = (unsigned short) phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} - -#ifdef SINC_SSE -static int sinc_resampler_run_sse(sinc_resampler * r, int ** out_, int * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - int* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - int phase = r->phase; - int phase_inc = r->phase_inc; - - int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel_sum = 0.0; - __m128 kernel[SINC_WIDTH / 2]; - __m128 temp1, temp2; - __m128 samplex = _mm_setzero_ps(); - float *kernelf = (float*)(&kernel); - int i = SINC_WIDTH; - int phase_adj = phase * step / SINC_RESOLUTION; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; - } - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) ); - temp2 = _mm_load_ps( (const float *)( kernel + i ) ); - temp1 = _mm_mul_ps( temp1, temp2 ); - samplex = _mm_add_ps( samplex, temp1 ); - } - kernel_sum = 1.0 / kernel_sum * 256.0; - temp1 = _mm_movehl_ps( temp1, samplex ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = samplex; - temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = _mm_set_ss( kernel_sum ); - samplex = _mm_mul_ps( samplex, temp1 ); - *out++ = _mm_cvtss_si32( samplex ); - - phase += phase_inc; - - in += phase >> 13; - - phase &= 8191; - } - while ( in < in_end ); - - r->phase = (unsigned short) phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -static void sinc_resampler_fill(sinc_resampler * r) -{ - while ( r->write_filled > (SINC_WIDTH * 2) && - r->read_filled < sinc_buffer_size ) - { - int write_pos = ( r->read_pos + r->read_filled ) % sinc_buffer_size; - int write_size = sinc_buffer_size - write_pos; - int * out = r->buffer_out + write_pos; - if ( write_size > ( sinc_buffer_size - r->read_filled ) ) - write_size = sinc_buffer_size - r->read_filled; -#ifdef SINC_SSE - if ( sinc_has_sse ) - sinc_resampler_run_sse( r, &out, out + write_size ); - else -#endif - sinc_resampler_run( r, &out, out + write_size ); - r->read_filled += out - r->buffer_out - write_pos; - } -} - -int sinc_resampler_get_sample_count(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled < 1 ) - sinc_resampler_fill( r ); - return r->read_filled; -} - -int sinc_resampler_get_sample(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled < 1 ) - sinc_resampler_fill( r ); - if ( r->read_filled < 1 ) - return 0; - return r->buffer_out[ r->read_pos ]; -} - -void sinc_resampler_remove_sample(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled > 0 ) - { - --r->read_filled; - r->read_pos = ( r->read_pos + 1 ) % sinc_buffer_size; - } -} diff --git a/Frameworks/Dumb/dumb/src/it/itrender.c b/Frameworks/Dumb/dumb/src/it/itrender.c index 90341aa10..151c1430b 100644 --- a/Frameworks/Dumb/dumb/src/it/itrender.c +++ b/Frameworks/Dumb/dumb/src/it/itrender.c @@ -27,7 +27,7 @@ #include "internal/lpc.h" #include "internal/blip_buf.h" -#include "internal/sinc_resampler.h" +#include "internal/resampler.h" // #define BIT_ARRAY_BULLSHIT @@ -52,16 +52,16 @@ static IT_PLAYING *new_playing() blip_set_rates(r->resampler.blip_buffer[0], 65536, 1); blip_set_rates(r->resampler.blip_buffer[1], 65536, 1); r->resampler.fir_resampler_ratio = 0.0; - r->resampler.fir_resampler[0] = sinc_resampler_create(); + r->resampler.fir_resampler[0] = resampler_create(); if ( !r->resampler.fir_resampler[0] ) { free( r->resampler.blip_buffer[1] ); free( r->resampler.blip_buffer[0] ); free( r ); return NULL; } - r->resampler.fir_resampler[1] = sinc_resampler_create(); + r->resampler.fir_resampler[1] = resampler_create(); if ( !r->resampler.fir_resampler[1] ) { - sinc_resampler_delete( r->resampler.fir_resampler[0] ); + resampler_delete( r->resampler.fir_resampler[0] ); free( r->resampler.blip_buffer[1] ); free( r->resampler.blip_buffer[0] ); free( r ); @@ -73,8 +73,8 @@ static IT_PLAYING *new_playing() static void free_playing(IT_PLAYING * r) { - sinc_resampler_delete( r->resampler.fir_resampler[1] ); - sinc_resampler_delete( r->resampler.fir_resampler[0] ); + resampler_delete( r->resampler.fir_resampler[1] ); + resampler_delete( r->resampler.fir_resampler[0] ); blip_delete( r->resampler.blip_buffer[1] ); blip_delete( r->resampler.blip_buffer[0] ); free( r ); @@ -180,16 +180,16 @@ static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANN return NULL; } dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio; - dst->resampler.fir_resampler[0] = sinc_resampler_dup( src->resampler.fir_resampler[0] ); + dst->resampler.fir_resampler[0] = resampler_dup( src->resampler.fir_resampler[0] ); if ( !dst->resampler.fir_resampler[0] ) { blip_delete( dst->resampler.blip_buffer[1] ); blip_delete( dst->resampler.blip_buffer[0] ); free( dst ); return NULL; } - dst->resampler.fir_resampler[1] = sinc_resampler_dup( src->resampler.fir_resampler[1] ); + dst->resampler.fir_resampler[1] = resampler_dup( src->resampler.fir_resampler[1] ); if ( !dst->resampler.fir_resampler[1] ) { - sinc_resampler_delete( dst->resampler.fir_resampler[0] ); + resampler_delete( dst->resampler.fir_resampler[0] ); blip_delete( dst->resampler.blip_buffer[1] ); blip_delete( dst->resampler.blip_buffer[0] ); free( dst ); @@ -4660,6 +4660,8 @@ static long render_playing(DUMB_IT_SIGRENDERER *sigrenderer, IT_PLAYING *playing if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality) quality = playing->sample->max_resampling_quality; playing->resampler.quality = quality; + resampler_set_quality(playing->resampler.fir_resampler[0], quality); + resampler_set_quality(playing->resampler.fir_resampler[1], quality); } bits = playing->sample->flags & IT_SAMPLE_16BIT ? 16 : 8; @@ -5335,6 +5337,8 @@ void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quali IT_PLAYING * playing = sigrenderer->channel[i].playing; playing->resampling_quality = quality; playing->resampler.quality = quality; + resampler_set_quality(playing->resampler.fir_resampler[0], quality); + resampler_set_quality(playing->resampler.fir_resampler[1], quality); } } for (i = 0; i < DUMB_IT_N_NNA_CHANNELS; i++) { @@ -5342,6 +5346,8 @@ void dumb_it_set_resampling_quality(DUMB_IT_SIGRENDERER * sigrenderer, int quali IT_PLAYING * playing = sigrenderer->playing[i]; playing->resampling_quality = quality; playing->resampler.quality = quality; + resampler_set_quality(playing->resampler.fir_resampler[0], quality); + resampler_set_quality(playing->resampler.fir_resampler[1], quality); } } } diff --git a/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj b/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj index 68f916bde..c9144467d 100644 --- a/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj +++ b/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj @@ -112,7 +112,7 @@ - + @@ -209,7 +209,7 @@ - + diff --git a/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj.filters b/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj.filters index 24c786055..449103e42 100644 --- a/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj.filters +++ b/Frameworks/Dumb/dumb/vc6/dumb/dumb.vcxproj.filters @@ -282,7 +282,7 @@ src\it\readers - + src\helpers @@ -320,7 +320,7 @@ include\internal - + include\internal diff --git a/Frameworks/modplay/modplay.xcodeproj/project.pbxproj b/Frameworks/modplay/modplay.xcodeproj/project.pbxproj index 5c35e6022..ac2ea8abe 100644 --- a/Frameworks/modplay/modplay.xcodeproj/project.pbxproj +++ b/Frameworks/modplay/modplay.xcodeproj/project.pbxproj @@ -8,15 +8,17 @@ /* Begin PBXBuildFile section */ 835CBC8218DA95AC0087A03E /* ft2play.h in Headers */ = {isa = PBXBuildFile; fileRef = 839CAC3E18DA744700D67EA9 /* ft2play.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 838A72E618DEC9A1007C8A7D /* resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 838A72E418DEC9A1007C8A7D /* resampler.c */; }; + 838A72E718DEC9A1007C8A7D /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 838A72E518DEC9A1007C8A7D /* resampler.h */; }; 839CAC4018DA746000D67EA9 /* ft2play.c in Sources */ = {isa = PBXBuildFile; fileRef = 839CAC3F18DA746000D67EA9 /* ft2play.c */; }; 83F4D54818D82105009B2DE6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83F4D54618D82105009B2DE6 /* InfoPlist.strings */; }; 83F4D57718D821D2009B2DE6 /* st3play.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F4D57318D821D2009B2DE6 /* st3play.c */; }; 83F4D57818D821D2009B2DE6 /* st3play.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F4D57418D821D2009B2DE6 /* st3play.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 83F81CBB18DE4CEC0058B7C3 /* sinc_resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F81CB918DE4CEC0058B7C3 /* sinc_resampler.c */; }; - 83F81CBC18DE4CEC0058B7C3 /* sinc_resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F81CBA18DE4CEC0058B7C3 /* sinc_resampler.h */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 838A72E418DEC9A1007C8A7D /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = ""; }; + 838A72E518DEC9A1007C8A7D /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; 839CAC3E18DA744700D67EA9 /* ft2play.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ft2play.h; sourceTree = ""; }; 839CAC3F18DA746000D67EA9 /* ft2play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ft2play.c; sourceTree = ""; }; 83F4D53A18D82105009B2DE6 /* modplay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = modplay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -24,8 +26,6 @@ 83F4D54718D82105009B2DE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 83F4D57318D821D2009B2DE6 /* st3play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = st3play.c; sourceTree = ""; }; 83F4D57418D821D2009B2DE6 /* st3play.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = st3play.h; sourceTree = ""; }; - 83F81CB918DE4CEC0058B7C3 /* sinc_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sinc_resampler.c; sourceTree = ""; }; - 83F81CBA18DE4CEC0058B7C3 /* sinc_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sinc_resampler.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -74,8 +74,8 @@ 83F4D54318D82105009B2DE6 /* modplay */ = { isa = PBXGroup; children = ( - 83F81CB918DE4CEC0058B7C3 /* sinc_resampler.c */, - 83F81CBA18DE4CEC0058B7C3 /* sinc_resampler.h */, + 838A72E418DEC9A1007C8A7D /* resampler.c */, + 838A72E518DEC9A1007C8A7D /* resampler.h */, 83F4D57318D821D2009B2DE6 /* st3play.c */, 83F4D57418D821D2009B2DE6 /* st3play.h */, 839CAC3F18DA746000D67EA9 /* ft2play.c */, @@ -101,7 +101,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 83F81CBC18DE4CEC0058B7C3 /* sinc_resampler.h in Headers */, + 838A72E718DEC9A1007C8A7D /* resampler.h in Headers */, 835CBC8218DA95AC0087A03E /* ft2play.h in Headers */, 83F4D57818D821D2009B2DE6 /* st3play.h in Headers */, ); @@ -170,9 +170,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 838A72E618DEC9A1007C8A7D /* resampler.c in Sources */, 83F4D57718D821D2009B2DE6 /* st3play.c in Sources */, 839CAC4018DA746000D67EA9 /* ft2play.c in Sources */, - 83F81CBB18DE4CEC0058B7C3 /* sinc_resampler.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Frameworks/modplay/modplay/ft2play.c b/Frameworks/modplay/modplay/ft2play.c index a974c43e4..8c13d6ba5 100644 --- a/Frameworks/modplay/modplay/ft2play.c +++ b/Frameworks/modplay/modplay/ft2play.c @@ -29,7 +29,7 @@ #include #include -#include "sinc_resampler.h" +#include "resampler.h" #include "ft2play.h" @@ -297,7 +297,6 @@ typedef struct int32_t samplePosition; int32_t sampleLoopLength; int8_t interpolating; - int8_t oversampleCount; float incRate; float frac; @@ -2000,8 +1999,8 @@ static void MainPlayer(PLAYER *p) // periodically called from mixer p->voice[ch->Nr + 127] = p->voice[ch->Nr]; voiceSetVolume(p, ch->Nr, ch->FinalVol, ch->FinalPan, 1); voiceSetVolume(p, ch->Nr + 127, 0, ch->FinalPan, 1); - sinc_resampler_dup_inplace(p->resampler[ch->Nr + 127], p->resampler[ch->Nr]); - sinc_resampler_dup_inplace(p->resampler[ch->Nr + 127 + 254], p->resampler[ch->Nr + 254]); + resampler_dup_inplace(p->resampler[ch->Nr + 127], p->resampler[ch->Nr]); + resampler_dup_inplace(p->resampler[ch->Nr + 127 + 254], p->resampler[ch->Nr + 254]); #endif s = ch->InstrOfs; @@ -2682,16 +2681,15 @@ void voiceSetSource(PLAYER *p, uint8_t i, const int8_t *sampleData, p->voice[i].loopDir = 0; p->voice[i].stereo = stereo; p->voice[i].interpolating = 1; - p->voice[i].oversampleCount = 0; #ifdef USE_VOL_RAMP p->voice[i].rampTerminates = 0; #endif - sinc_resampler_clear(p->resampler[i]); + resampler_clear(p->resampler[i]); #ifdef USE_VOL_RAMP - sinc_resampler_clear(p->resampler[i+254]); + resampler_clear(p->resampler[i+254]); #else - sinc_resampler_clear(p->resampler[i+127]); + resampler_clear(p->resampler[i+127]); #endif } @@ -2705,13 +2703,12 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value) } p->voice[i].interpolating = 1; - p->voice[i].oversampleCount = 0; - sinc_resampler_clear(p->resampler[i]); + resampler_clear(p->resampler[i]); #ifdef USE_VOL_RAMP - sinc_resampler_clear(p->resampler[i+254]); + resampler_clear(p->resampler[i+254]); #else - sinc_resampler_clear(p->resampler[i+127]); + resampler_clear(p->resampler[i+127]); #endif } @@ -2764,8 +2761,6 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples) int8_t loopBidi; int8_t loopDir; - int32_t oversampleCount; - int32_t samplingInterpolation; int32_t interpolating; void * resampler; @@ -2778,30 +2773,21 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples) loopBidi = p->voice[ch].loopBidi; loopDir = p->voice[ch].loopDir; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; - - samplingInterpolation = p->samplingInterpolation ? 1 : 32; sampleData = p->voice[ch].sampleData; resampler = p->resampler[ch]; - sinc_resampler_set_rate(resampler, p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler, p->voice[ch].incRate ); for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) { p->voice[ch].busy = 1; samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler)) + while (interpolating && resampler_get_free_count(resampler)) { - for (;oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount) - sinc_resampler_write_sample(resampler, sampleData[samplePosition] * 256); - - if (oversampleCount < samplingInterpolation) - break; - - oversampleCount = 0; + resampler_write_sample(resampler, sampleData[samplePosition] * 256); if (loopDir == 1) { @@ -2850,9 +2836,8 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].loopDir = loopDir; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler) ) + if ( !resampler_ready(resampler) ) { p->voice[ch].sampleData = NULL; p->voice[ch].samplePosition = 0; @@ -2860,8 +2845,8 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples) break; } - sample = sinc_resampler_get_sample(resampler); - sinc_resampler_remove_sample(resampler); + sample = resampler_get_sample(resampler); + resampler_remove_sample(resampler); sampleL = (sample * p->voice[ch].volumeL); sampleR = (sample * p->voice[ch].volumeR); @@ -2925,8 +2910,6 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples) int8_t loopBidi; int8_t loopDir; - int32_t oversampleCount; - int32_t samplingInterpolation; int32_t interpolating; void * resampler[2]; @@ -2939,9 +2922,6 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples) loopBidi = p->voice[ch].loopBidi; loopDir = p->voice[ch].loopDir; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; - - samplingInterpolation = p->samplingInterpolation ? 1 : 32; sampleData = p->voice[ch].sampleData; @@ -2952,26 +2932,18 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples) resampler[1] = p->resampler[ch+127]; #endif - sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation); - sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler[0], p->voice[ch].incRate ); + resampler_set_rate(resampler[1], p->voice[ch].incRate ); for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) { p->voice[ch].busy = 1; samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler[0])) + while (interpolating && resampler_get_free_count(resampler[0])) { - for (;oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler[0]); ++oversampleCount) - { - sinc_resampler_write_sample(resampler[0], sampleData[samplePosition] * 256); - sinc_resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256); - } - - if (oversampleCount < samplingInterpolation) - break; - - oversampleCount = 0; + resampler_write_sample(resampler[0], sampleData[samplePosition] * 256); + resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256); if (loopDir == 1) { @@ -3020,9 +2992,8 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].loopDir = loopDir; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler[0]) ) + if ( !resampler_ready(resampler[0]) ) { p->voice[ch].sampleData = NULL; p->voice[ch].samplePosition = 0; @@ -3030,10 +3001,10 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples) break; } - sampleL = sinc_resampler_get_sample(resampler[0]); - sampleR = sinc_resampler_get_sample(resampler[1]); - sinc_resampler_remove_sample(resampler[0]); - sinc_resampler_remove_sample(resampler[1]); + sampleL = resampler_get_sample(resampler[0]); + sampleR = resampler_get_sample(resampler[1]); + resampler_remove_sample(resampler[0]); + resampler_remove_sample(resampler[1]); sampleL = (sampleL * p->voice[ch].volumeL); sampleR = (sampleR * p->voice[ch].volumeR); @@ -3098,8 +3069,6 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples) int8_t loopBidi; int8_t loopDir; - int32_t oversampleCount; - int32_t samplingInterpolation; int32_t interpolating; void * resampler; @@ -3112,30 +3081,21 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples) loopBidi = p->voice[ch].loopBidi; loopDir = p->voice[ch].loopDir; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; - - samplingInterpolation = p->samplingInterpolation ? 1 : 32; sampleData = (const int16_t *)(p->voice[ch].sampleData); resampler = p->resampler[ch]; - sinc_resampler_set_rate(resampler, p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler, p->voice[ch].incRate ); for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) { p->voice[ch].busy = 1; samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler)) + while (interpolating && resampler_get_free_count(resampler)) { - for (;oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount) - sinc_resampler_write_sample(resampler, sampleData[samplePosition]); - - if (oversampleCount < samplingInterpolation) - break; - - oversampleCount = 0; + resampler_write_sample(resampler, sampleData[samplePosition]); if (loopDir == 1) { @@ -3184,9 +3144,8 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].loopDir = loopDir; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler) ) + if ( !resampler_ready(resampler) ) { p->voice[ch].sampleData = NULL; p->voice[ch].samplePosition = 0; @@ -3194,8 +3153,8 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples) break; } - sample = sinc_resampler_get_sample(resampler); - sinc_resampler_remove_sample(resampler); + sample = resampler_get_sample(resampler); + resampler_remove_sample(resampler); sampleL = (sample * p->voice[ch].volumeL); sampleR = (sample * p->voice[ch].volumeR); @@ -3259,8 +3218,6 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples) int8_t loopBidi; int8_t loopDir; - int32_t oversampleCount; - int32_t samplingInterpolation; int32_t interpolating; void * resampler[2]; @@ -3273,9 +3230,6 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples) loopBidi = p->voice[ch].loopBidi; loopDir = p->voice[ch].loopDir; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; - - samplingInterpolation = p->samplingInterpolation ? 1 : 32; sampleData = (const int16_t *)(p->voice[ch].sampleData); @@ -3286,26 +3240,18 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples) resampler[1] = p->resampler[ch+127]; #endif - sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation); - sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler[0], p->voice[ch].incRate ); + resampler_set_rate(resampler[1], p->voice[ch].incRate ); for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j) { p->voice[ch].busy = 1; samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler[0])) + while (interpolating && resampler_get_free_count(resampler[0])) { - for (;oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler[0]); ++oversampleCount) - { - sinc_resampler_write_sample(resampler[0], sampleData[samplePosition]); - sinc_resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition]); - } - - if (oversampleCount < samplingInterpolation) - break; - - oversampleCount = 0; + resampler_write_sample(resampler[0], sampleData[samplePosition]); + resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition]); if (loopDir == 1) { @@ -3354,9 +3300,8 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].loopDir = loopDir; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler[0]) ) + if ( !resampler_ready(resampler[0]) ) { p->voice[ch].sampleData = NULL; p->voice[ch].samplePosition = 0; @@ -3364,10 +3309,10 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples) break; } - sampleL = sinc_resampler_get_sample(resampler[0]); - sampleR = sinc_resampler_get_sample(resampler[1]); - sinc_resampler_remove_sample(resampler[0]); - sinc_resampler_remove_sample(resampler[1]); + sampleL = resampler_get_sample(resampler[0]); + sampleR = resampler_get_sample(resampler[1]); + resampler_remove_sample(resampler[0]); + resampler_remove_sample(resampler[1]); sampleL = (sampleL * p->voice[ch].volumeL); sampleR = (sampleR * p->voice[ch].volumeR); @@ -3566,7 +3511,7 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation) p->samplingInterpolation = interpolation; - sinc_init(); + resampler_init(); #ifdef USE_VOL_RAMP for ( i = 0; i < 127 * 2 * 2; ++i ) @@ -3574,9 +3519,10 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation) for ( i = 0; i < 127 * 2; ++i ) #endif { - p->resampler[i] = sinc_resampler_create(); + p->resampler[i] = resampler_create(); if ( !p->resampler[i] ) goto error; + resampler_set_quality(p->resampler[i], interpolation); } // allocate memory for pointers @@ -3675,7 +3621,7 @@ void ft2play_Free(void *_p) #endif { if ( p->resampler[i] ) - sinc_resampler_delete( p->resampler[i] ); + resampler_delete( p->resampler[i] ); p->resampler[i] = NULL; } diff --git a/Frameworks/modplay/modplay/resampler.c b/Frameworks/modplay/modplay/resampler.c new file mode 100644 index 000000000..ac83dc9aa --- /dev/null +++ b/Frameworks/modplay/modplay/resampler.c @@ -0,0 +1,636 @@ +#include +#include +#define _USE_MATH_DEFINES +#include +#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) +#include +#define RESAMPLER_SSE +#endif + +#ifdef _MSC_VER +#define ALIGNED _declspec(align(16)) +#else +#define ALIGNED __attribute__((aligned(16))) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include "resampler.h" + +enum { RESAMPLER_SHIFT = 13 }; +enum { RESAMPLER_RESOLUTION = 1 << RESAMPLER_SHIFT }; +enum { SINC_WIDTH = 16 }; +enum { SINC_SAMPLES = RESAMPLER_RESOLUTION * SINC_WIDTH }; +enum { CUBIC_SAMPLES = RESAMPLER_RESOLUTION * 4 }; + +ALIGNED static float cubic_lut[CUBIC_SAMPLES]; + +static float sinc_lut[SINC_SAMPLES + 1]; + +enum { resampler_buffer_size = SINC_WIDTH * 4 }; + +static int fEqual(const float b, const float a) +{ + return fabs(a - b) < 1.0e-6; +} + +static float sinc(float x) +{ + return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); +} + +#ifdef RESAMPLER_SSE +#ifdef _MSC_VER +#include +#elif defined(__clang__) || defined(__GNUC__) +static inline void +__cpuid(int *data, int selector) +{ + asm("cpuid" + : "=a" (data[0]), + "=b" (data[1]), + "=c" (data[2]), + "=d" (data[3]) + : "a"(selector)); +} +#else +#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) +#endif + +static int query_cpu_feature_sse() { + int buffer[4]; + __cpuid(buffer,1); + if ((buffer[3]&(1<<25)) == 0) return 0; + return 1; +} + +static int resampler_has_sse = 0; +#endif + +void resampler_init(void) +{ + unsigned i; + double dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; + for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) + { + float y = x / SINC_WIDTH; +#if 1 + // Blackman + float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); +#elif 0 + // C.R.Helmrich's 2 term window + float window = 0.79445 * cos(0.5 * M_PI * y) + 0.20555 * cos(1.5 * M_PI * y); +#elif 0 + // Lanczos + float window = sinc(y); +#endif + sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; + } + dx = 1.0 / (float)(RESAMPLER_RESOLUTION); + x = 0.0; + for (i = 0; i < RESAMPLER_RESOLUTION; ++i, x += dx) + { + cubic_lut[i*4] = (float)(-0.5 * x * x * x + x * x - 0.5 * x); + cubic_lut[i*4+1] = (float)( 1.5 * x * x * x - 2.5 * x * x + 1.0); + cubic_lut[i*4+2] = (float)(-1.5 * x * x * x + 2.0 * x * x + 0.5 * x); + cubic_lut[i*4+3] = (float)( 0.5 * x * x * x - 0.5 * x * x); + } +#ifdef RESAMPLER_SSE + resampler_has_sse = query_cpu_feature_sse(); +#endif +} + +typedef struct resampler +{ + int write_pos, write_filled; + int read_pos, read_filled; + unsigned short phase; + unsigned short phase_inc; + unsigned char quality; + float buffer_in[resampler_buffer_size * 2]; + float buffer_out[resampler_buffer_size + SINC_WIDTH * 2 - 1]; +} resampler; + +void * resampler_create(void) +{ + resampler * r = ( resampler * ) malloc( sizeof(resampler) ); + if ( !r ) return 0; + + r->write_pos = 0; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; + r->phase_inc = 0; + r->quality = RESAMPLER_QUALITY_MAX; + memset( r->buffer_in, 0, sizeof(r->buffer_in) ); + memset( r->buffer_out, 0, sizeof(r->buffer_out) ); + + return r; +} + +void resampler_delete(void * _r) +{ + free( _r ); +} + +void * resampler_dup(const void * _r) +{ + const resampler * r_in = ( const resampler * ) _r; + resampler * r_out = ( resampler * ) malloc( sizeof(resampler) ); + if ( !r_out ) return 0; + + r_out->write_pos = r_in->write_pos; + r_out->write_filled = r_in->write_filled; + r_out->read_pos = r_in->read_pos; + r_out->read_filled = r_in->read_filled; + r_out->phase = r_in->phase; + r_out->phase_inc = r_in->phase_inc; + r_out->quality = r_in->quality; + memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); + memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); + + return r_out; +} + +void resampler_dup_inplace(void *_d, const void *_s) +{ + const resampler * r_in = ( const resampler * ) _s; + resampler * r_out = ( resampler * ) _d; + + r_out->write_pos = r_in->write_pos; + r_out->write_filled = r_in->write_filled; + r_out->read_pos = r_in->read_pos; + r_out->read_filled = r_in->read_filled; + r_out->phase = r_in->phase; + r_out->phase_inc = r_in->phase_inc; + r_out->quality = r_in->quality; + memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); + memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); +} + +void resampler_set_quality(void *_r, int quality) +{ + resampler * r = ( resampler * ) _r; + if (quality < RESAMPLER_QUALITY_MIN) + quality = RESAMPLER_QUALITY_MIN; + else if (quality > RESAMPLER_QUALITY_MAX) + quality = RESAMPLER_QUALITY_MAX; + r->quality = (unsigned char)quality; +} + +int resampler_get_free_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + return resampler_buffer_size - r->write_filled; +} + +static int resampler_min_filled(resampler *r) +{ + switch (r->quality) + { + default: + case RESAMPLER_QUALITY_ZOH: + return 1; + + case RESAMPLER_QUALITY_LINEAR: + return 2; + + case RESAMPLER_QUALITY_CUBIC: + return 4; + + case RESAMPLER_QUALITY_SINC: + return SINC_WIDTH * 2; + } +} + +int resampler_ready(void *_r) +{ + resampler * r = ( resampler * ) _r; + return r->write_filled > resampler_min_filled(r); +} + +void resampler_clear(void *_r) +{ + resampler * r = ( resampler * ) _r; + r->write_pos = 0; + r->write_filled = 0; + r->read_pos = 0; + r->read_filled = 0; + r->phase = 0; +} + +void resampler_set_rate(void *_r, double new_factor) +{ + resampler * r = ( resampler * ) _r; + r->phase_inc = (int)( new_factor * RESAMPLER_RESOLUTION ); +} + +void resampler_write_sample(void *_r, short s) +{ + resampler * r = ( resampler * ) _r; + + if ( r->write_filled < resampler_buffer_size ) + { + float s32 = s; + s32 *= (1.0 / 32768.0); + + r->buffer_in[ r->write_pos ] = s32; + r->buffer_in[ r->write_pos + resampler_buffer_size ] = s32; + + ++r->write_filled; + + r->write_pos = ( r->write_pos + 1 ) % resampler_buffer_size; + } +} + +static int resampler_run_zoh(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 1; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float sample; + + if ( out >= out_end ) + break; + + sample = *in; + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +static int resampler_run_linear(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float sample; + + if ( out >= out_end ) + break; + + sample = in[0] + (in[1] - in[0]) * ((float)phase / RESAMPLER_RESOLUTION); + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +static int resampler_run_cubic(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 4; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + float * kernel; + int i; + float sample; + + if ( out >= out_end ) + break; + + kernel = cubic_lut + phase * 4; + + for (sample = 0, i = 0; i < 4; ++i) + sample += in[i] * kernel[i]; + *out++ = sample; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +#ifdef RESAMPLER_SSE +static int resampler_run_cubic_sse(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= 4; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + do + { + __m128 temp1, temp2; + __m128 samplex = _mm_setzero_ps(); + + if ( out >= out_end ) + break; + + temp1 = _mm_loadu_ps( (const float *)( in ) ); + temp2 = _mm_load_ps( (const float *)( cubic_lut + phase * 4 ) ); + temp1 = _mm_mul_ps( temp1, temp2 ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = _mm_movehl_ps( temp1, samplex ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = samplex; + temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); + samplex = _mm_add_ps( samplex, temp1 ); + _mm_store_ss( out, samplex ); + ++out; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION - 1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} +#endif + +static int resampler_run_sinc(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= SINC_WIDTH * 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + + do + { + float kernel[SINC_WIDTH * 2], kernel_sum = 0.0; + int i = SINC_WIDTH; + int phase_adj = phase * step / RESAMPLER_RESOLUTION; + float sample; + + if ( out >= out_end ) + break; + + for (; i >= -SINC_WIDTH + 1; --i) + { + int pos = i * step; + kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + } + for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) + sample += in[i] * kernel[i]; + *out++ = (float)(sample / kernel_sum); + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION-1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} + +#ifdef RESAMPLER_SSE +static int resampler_run_sinc_sse(resampler * r, float ** out_, float * out_end) +{ + int in_size = r->write_filled; + float const* in_ = r->buffer_in + resampler_buffer_size + r->write_pos - r->write_filled; + int used = 0; + in_size -= SINC_WIDTH * 2; + if ( in_size > 0 ) + { + float* out = *out_; + float const* in = in_; + float const* const in_end = in + in_size; + int phase = r->phase; + int phase_inc = r->phase_inc; + + int step = phase_inc > RESAMPLER_RESOLUTION ? RESAMPLER_RESOLUTION * RESAMPLER_RESOLUTION / phase_inc : RESAMPLER_RESOLUTION; + + do + { + // accumulate in extended precision + float kernel_sum = 0.0; + __m128 kernel[SINC_WIDTH / 2]; + __m128 temp1, temp2; + __m128 samplex = _mm_setzero_ps(); + float *kernelf = (float*)(&kernel); + int i = SINC_WIDTH; + int phase_adj = phase * step / RESAMPLER_RESOLUTION; + + if ( out >= out_end ) + break; + + for (; i >= -SINC_WIDTH + 1; --i) + { + int pos = i * step; + kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; + } + for (i = 0; i < SINC_WIDTH / 2; ++i) + { + temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) ); + temp2 = _mm_load_ps( (const float *)( kernel + i ) ); + temp1 = _mm_mul_ps( temp1, temp2 ); + samplex = _mm_add_ps( samplex, temp1 ); + } + kernel_sum = 1.0 / kernel_sum; + temp1 = _mm_movehl_ps( temp1, samplex ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = samplex; + temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); + samplex = _mm_add_ps( samplex, temp1 ); + temp1 = _mm_set_ss( kernel_sum ); + samplex = _mm_mul_ps( samplex, temp1 ); + _mm_store_ss( out, samplex ); + ++out; + + phase += phase_inc; + + in += phase >> RESAMPLER_SHIFT; + + phase &= RESAMPLER_RESOLUTION - 1; + } + while ( in < in_end ); + + r->phase = (unsigned short) phase; + *out_ = out; + + used = (int)(in - in_); + + r->write_filled -= used; + } + + return used; +} +#endif + +static void resampler_fill(resampler * r) +{ + int min_filled = resampler_min_filled(r); + int quality = r->quality; + while ( r->write_filled > min_filled && + r->read_filled < resampler_buffer_size ) + { + int write_pos = ( r->read_pos + r->read_filled ) % resampler_buffer_size; + int write_size = resampler_buffer_size - write_pos; + float * out = r->buffer_out + write_pos; + if ( write_size > ( resampler_buffer_size - r->read_filled ) ) + write_size = resampler_buffer_size - r->read_filled; + switch (quality) + { + case RESAMPLER_QUALITY_ZOH: + resampler_run_zoh( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_LINEAR: + resampler_run_linear( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_CUBIC: +#ifdef RESAMPLER_SSE + if ( resampler_has_sse ) + resampler_run_cubic_sse( r, &out, out + write_size ); + else +#endif + resampler_run_cubic( r, &out, out + write_size ); + break; + + case RESAMPLER_QUALITY_SINC: +#ifdef RESAMPLER_SSE + if ( resampler_has_sse ) + resampler_run_sinc_sse( r, &out, out + write_size ); + else +#endif + resampler_run_sinc( r, &out, out + write_size ); + break; + } + r->read_filled += out - r->buffer_out - write_pos; + } +} + +int resampler_get_sample_count(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 ) + resampler_fill( r ); + return r->read_filled; +} + +float resampler_get_sample(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled < 1 ) + resampler_fill( r ); + if ( r->read_filled < 1 ) + return 0; + return r->buffer_out[ r->read_pos ]; +} + +void resampler_remove_sample(void *_r) +{ + resampler * r = ( resampler * ) _r; + if ( r->read_filled > 0 ) + { + --r->read_filled; + r->read_pos = ( r->read_pos + 1 ) % resampler_buffer_size; + } +} diff --git a/Frameworks/modplay/modplay/resampler.h b/Frameworks/modplay/modplay/resampler.h new file mode 100644 index 000000000..ca89b1db8 --- /dev/null +++ b/Frameworks/modplay/modplay/resampler.h @@ -0,0 +1,52 @@ +#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_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_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_LINEAR = 1, + RESAMPLER_QUALITY_CUBIC = 2, + RESAMPLER_QUALITY_SINC = 3, + RESAMPLER_QUALITY_MAX = 3 +}; + +void resampler_set_quality(void *, int quality); + +int resampler_get_free_count(void *); +void resampler_write_sample(void *, short sample); +void resampler_set_rate( void *, double new_factor ); +int resampler_ready(void *); +void resampler_clear(void *); +int resampler_get_sample_count(void *); +float resampler_get_sample(void *); +void resampler_remove_sample(void *); + +#endif diff --git a/Frameworks/modplay/modplay/sinc_resampler.c b/Frameworks/modplay/modplay/sinc_resampler.c deleted file mode 100644 index 9f7bdf9ce..000000000 --- a/Frameworks/modplay/modplay/sinc_resampler.c +++ /dev/null @@ -1,362 +0,0 @@ -#include -#include -#define _USE_MATH_DEFINES -#include -#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__)) -#include -#define SINC_SSE -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include "sinc_resampler.h" - -enum { SINC_RESOLUTION = 8192 }; -enum { SINC_WIDTH = 16 }; -enum { SINC_SAMPLES = SINC_RESOLUTION * SINC_WIDTH }; - -static float sinc_lut[SINC_SAMPLES + 1]; - -enum { sinc_buffer_size = SINC_WIDTH * 4 }; - -static int fEqual(const float b, const float a) -{ - return fabs(a - b) < 1.0e-6; -} - -static float sinc(float x) -{ - return fEqual(x, 0.0) ? 1.0 : sin(x * M_PI) / (x * M_PI); -} - -#ifdef SINC_SSE -#ifdef _MSC_VER -#include -#elif defined(__clang__) || defined(__GNUC__) -static inline void -__cpuid(int *data, int selector) -{ - asm("cpuid" - : "=a" (data[0]), - "=b" (data[1]), - "=c" (data[2]), - "=d" (data[3]) - : "a"(selector)); -} -#else -#define __cpuid(a,b) memset((a), 0, sizeof(int) * 4) -#endif - -static int query_cpu_feature_sse() { - int buffer[4]; - __cpuid(buffer,1); - if ((buffer[3]&(1<<25)) == 0) return 0; - return 1; -} - -static int sinc_has_sse = 0; -#endif - -void sinc_init(void) -{ - unsigned i; - float dx = (float)(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; - for (i = 0; i < SINC_SAMPLES + 1; ++i, x += dx) - { - float y = x / SINC_WIDTH; - float window = 0.42659 - 0.49656 * cos(M_PI + M_PI * y) + 0.076849 * cos(2.0 * M_PI * y); - sinc_lut[i] = fabs(x) < SINC_WIDTH ? sinc(x) * window : 0.0; - } -#ifdef SINC_SSE - sinc_has_sse = query_cpu_feature_sse(); -#endif -} - -typedef struct sinc_resampler -{ - int write_pos, write_filled; - int read_pos, read_filled; - unsigned short phase; - unsigned int phase_inc; - float buffer_in[sinc_buffer_size * 2]; - float buffer_out[sinc_buffer_size]; -} sinc_resampler; - -void * sinc_resampler_create(void) -{ - sinc_resampler * r = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) ); - if ( !r ) return 0; - - r->write_pos = 0; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase = 0; - r->phase_inc = 0; - memset( r->buffer_in, 0, sizeof(r->buffer_in) ); - memset( r->buffer_out, 0, sizeof(r->buffer_out) ); - - return r; -} - -void sinc_resampler_delete(void * _r) -{ - free( _r ); -} - -void * sinc_resampler_dup(const void * _r) -{ - const sinc_resampler * r_in = ( const sinc_resampler * ) _r; - sinc_resampler * r_out = ( sinc_resampler * ) malloc( sizeof(sinc_resampler) ); - if ( !r_out ) return 0; - - r_out->write_pos = r_in->write_pos; - r_out->write_filled = r_in->write_filled; - r_out->read_pos = r_in->read_pos; - r_out->read_filled = r_in->read_filled; - r_out->phase = r_in->phase; - r_out->phase_inc = r_in->phase_inc; - memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); - memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); - - return r_out; -} - -void sinc_resampler_dup_inplace(void *_d, const void *_s) -{ - const sinc_resampler * r_in = ( const sinc_resampler * ) _s; - sinc_resampler * r_out = ( sinc_resampler * ) _d; - - r_out->write_pos = r_in->write_pos; - r_out->write_filled = r_in->write_filled; - r_out->read_pos = r_in->read_pos; - r_out->read_filled = r_in->read_filled; - r_out->phase = r_in->phase; - r_out->phase_inc = r_in->phase_inc; - memcpy( r_out->buffer_in, r_in->buffer_in, sizeof(r_in->buffer_in) ); - memcpy( r_out->buffer_out, r_in->buffer_out, sizeof(r_in->buffer_out) ); -} - -int sinc_resampler_get_free_count(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - return sinc_buffer_size - r->write_filled; -} - -int sinc_resampler_ready(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - return r->write_filled > (SINC_WIDTH * 2); -} - -void sinc_resampler_clear(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - r->write_pos = 0; - r->write_filled = 0; - r->read_pos = 0; - r->read_filled = 0; - r->phase = 0; -} - -void sinc_resampler_set_rate(void *_r, double new_factor) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - r->phase_inc = (int)( new_factor * SINC_RESOLUTION ); -} - -void sinc_resampler_write_sample(void *_r, short s) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - - if ( r->write_filled < sinc_buffer_size ) - { - float s32 = s; - - r->buffer_in[ r->write_pos ] = s32; - r->buffer_in[ r->write_pos + sinc_buffer_size ] = s32; - - ++r->write_filled; - - r->write_pos = ( r->write_pos + 1 ) % sinc_buffer_size; - } -} - -static int sinc_resampler_run(sinc_resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - int phase = r->phase; - int phase_inc = r->phase_inc; - - int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel[SINC_WIDTH * 2], kernel_sum = 0.0; - int i = SINC_WIDTH; - int phase_adj = phase * step / SINC_RESOLUTION; - float sample; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - kernel_sum += kernel[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; - } - for (sample = 0, i = 0; i < SINC_WIDTH * 2; ++i) - sample += in[i] * kernel[i]; - *out++ = (float)(sample / kernel_sum * (1.0 / 32768.0)); - - phase += phase_inc; - - in += phase >> 13; - - phase &= 8191; - } - while ( in < in_end ); - - r->phase = (unsigned short) phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} - -#ifdef SINC_SSE -static int sinc_resampler_run_sse(sinc_resampler * r, float ** out_, float * out_end) -{ - int in_size = r->write_filled; - float const* in_ = r->buffer_in + sinc_buffer_size + r->write_pos - r->write_filled; - int used = 0; - in_size -= SINC_WIDTH * 2; - if ( in_size > 0 ) - { - float* out = *out_; - float const* in = in_; - float const* const in_end = in + in_size; - int phase = r->phase; - int phase_inc = r->phase_inc; - - int step = phase_inc > SINC_RESOLUTION ? SINC_RESOLUTION * SINC_RESOLUTION / phase_inc : SINC_RESOLUTION; - - do - { - // accumulate in extended precision - float kernel_sum = 0.0; - __m128 kernel[SINC_WIDTH / 2]; - __m128 temp1, temp2; - __m128 samplex = _mm_setzero_ps(); - float *kernelf = (float*)(&kernel); - int i = SINC_WIDTH; - int phase_adj = phase * step / SINC_RESOLUTION; - - if ( out >= out_end ) - break; - - for (; i >= -SINC_WIDTH + 1; --i) - { - int pos = i * step; - kernel_sum += kernelf[i + SINC_WIDTH - 1] = sinc_lut[abs(phase_adj - pos)]; - } - for (i = 0; i < SINC_WIDTH / 2; ++i) - { - temp1 = _mm_loadu_ps( (const float *)( in + i * 4 ) ); - temp2 = _mm_load_ps( (const float *)( kernel + i ) ); - temp1 = _mm_mul_ps( temp1, temp2 ); - samplex = _mm_add_ps( samplex, temp1 ); - } - kernel_sum = 1.0 / kernel_sum * (1.0 / 32768.0); - temp1 = _mm_movehl_ps( temp1, samplex ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = samplex; - temp1 = _mm_shuffle_ps( temp1, samplex, _MM_SHUFFLE(0, 0, 0, 1) ); - samplex = _mm_add_ps( samplex, temp1 ); - temp1 = _mm_set_ss( kernel_sum ); - samplex = _mm_mul_ps( samplex, temp1 ); - _mm_store_ss( out, samplex ); - ++out; - - phase += phase_inc; - - in += phase >> 13; - - phase &= 8191; - } - while ( in < in_end ); - - r->phase = (unsigned short) phase; - *out_ = out; - - used = (int)(in - in_); - - r->write_filled -= used; - } - - return used; -} -#endif - -static void sinc_resampler_fill(sinc_resampler * r) -{ - while ( r->write_filled > (SINC_WIDTH * 2) && - r->read_filled < sinc_buffer_size ) - { - int write_pos = ( r->read_pos + r->read_filled ) % sinc_buffer_size; - int write_size = sinc_buffer_size - write_pos; - float * out = r->buffer_out + write_pos; - if ( write_size > ( sinc_buffer_size - r->read_filled ) ) - write_size = sinc_buffer_size - r->read_filled; -#ifdef SINC_SSE - if ( sinc_has_sse ) - sinc_resampler_run_sse( r, &out, out + write_size ); - else -#endif - sinc_resampler_run( r, &out, out + write_size ); - r->read_filled += out - r->buffer_out - write_pos; - } -} - -int sinc_resampler_get_sample_count(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled < 1 ) - sinc_resampler_fill( r ); - return r->read_filled; -} - -float sinc_resampler_get_sample(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled < 1 ) - sinc_resampler_fill( r ); - if ( r->read_filled < 1 ) - return 0; - return r->buffer_out[ r->read_pos ]; -} - -void sinc_resampler_remove_sample(void *_r) -{ - sinc_resampler * r = ( sinc_resampler * ) _r; - if ( r->read_filled > 0 ) - { - --r->read_filled; - r->read_pos = ( r->read_pos + 1 ) % sinc_buffer_size; - } -} diff --git a/Frameworks/modplay/modplay/sinc_resampler.h b/Frameworks/modplay/modplay/sinc_resampler.h deleted file mode 100644 index 699a9b7e5..000000000 --- a/Frameworks/modplay/modplay/sinc_resampler.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _SINC_RESAMPLER_H_ -#define _SINC_RESAMPLER_H_ - -// Ugglay -#ifdef SINC_DECORATE -#define PASTE(a,b) a ## b -#define EVALUATE(a,b) PASTE(a,b) -#define sinc_init EVALUATE(SINC_DECORATE,_sinc_init) -#define sinc_resampler_create EVALUATE(SINC_DECORATE,_sinc_resampler_create) -#define sinc_resampler_delete EVALUATE(SINC_DECORATE,_sinc_resampler_delete) -#define sinc_resampler_dup EVALUATE(SINC_DECORATE,_sinc_resampler_dup) -#define sinc_resampler_dup_inplace EVALUATE(SINC_DECORATE,_sinc_resampler_dup_inplace) -#define sinc_resampler_get_free_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_free_count) -#define sinc_resampler_write_sample EVALUATE(SINC_DECORATE,_sinc_resampler_write_sample) -#define sinc_resampler_set_rate EVALUATE(SINC_DECORATE,_sinc_resampler_set_rate) -#define sinc_resampler_ready EVALUATE(SINC_DECORATE,_sinc_resampler_ready) -#define sinc_resampler_clear EVALUATE(SINC_DECORATE,_sinc_resampler_clear) -#define sinc_resampler_get_sample_count EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample_count) -#define sinc_resampler_get_sample EVALUATE(SINC_DECORATE,_sinc_resampler_get_sample) -#define sinc_resampler_remove_sample EVALUATE(SINC_DECORATE,_sinc_resampler_remove_sample) -#endif - -void sinc_init(void); - -void * sinc_resampler_create(void); -void sinc_resampler_delete(void *); -void * sinc_resampler_dup(const void *); -void sinc_resampler_dup_inplace(void *, const void *); - -int sinc_resampler_get_free_count(void *); -void sinc_resampler_write_sample(void *, short sample); -void sinc_resampler_set_rate( void *, double new_factor ); -int sinc_resampler_ready(void *); -void sinc_resampler_clear(void *); -int sinc_resampler_get_sample_count(void *); -float sinc_resampler_get_sample(void *); -void sinc_resampler_remove_sample(void *); - -#endif diff --git a/Frameworks/modplay/modplay/st3play.c b/Frameworks/modplay/modplay/st3play.c index 27c53e5e6..882e9b303 100644 --- a/Frameworks/modplay/modplay/st3play.c +++ b/Frameworks/modplay/modplay/st3play.c @@ -63,7 +63,7 @@ #define inline __forceinline #endif -#include "sinc_resampler.h" +#include "resampler.h" #include "st3play.h" @@ -136,7 +136,6 @@ typedef struct int8_t adpcm; int8_t mixing; int8_t interpolating; - int8_t oversampleCount; int32_t sampleLength; int32_t sampleLoopEnd; int32_t samplePosition; @@ -485,7 +484,7 @@ void * st3play_Alloc(uint32_t outputFreq, int8_t interpolation) if ( !p ) return 0; - sinc_init(); + resampler_init(); #ifdef USE_VOL_RAMP for (i = 0; i < 64 * 2; ++i) @@ -493,12 +492,13 @@ void * st3play_Alloc(uint32_t outputFreq, int8_t interpolation) for (i = 0; i < 64; ++i) #endif { - p->resampler[i] = sinc_resampler_create(); + p->resampler[i] = resampler_create(); if ( !p->resampler[i] ) { st3play_Free( p ); return 0; } + resampler_set_quality(p->resampler[i], interpolation); } p->soundBufferSize = _soundBufferSize; @@ -540,7 +540,7 @@ void st3play_Free(void *_p) #endif { if ( p->resampler[i] ) - sinc_resampler_delete( p->resampler[i] ); + resampler_delete( p->resampler[i] ); } if ( p->masterBufferL ) @@ -928,8 +928,8 @@ static inline void doamiga(PLAYER *p, uint8_t ch) #ifdef USE_VOL_RAMP p->voice[ch + 32] = p->voice[ch]; setvol(p, ch, 2); - sinc_resampler_dup_inplace(p->resampler[ch + 32], p->resampler[ch]); - sinc_resampler_dup_inplace(p->resampler[ch + 32 + 64], p->resampler[ch + 64]); + resampler_dup_inplace(p->resampler[ch + 32], p->resampler[ch]); + resampler_dup_inplace(p->resampler[ch + 32 + 64], p->resampler[ch + 64]); if (p->chn[ch].vol != 255) { if (p->chn[ch].vol <= 64) @@ -2620,7 +2620,6 @@ void voiceSetSource(PLAYER *p, uint8_t voiceNumber, const int8_t *sampleData, p->voice[voiceNumber].adpcm = adpcm; p->voice[voiceNumber].mixing = 1; p->voice[voiceNumber].interpolating = 1; - p->voice[voiceNumber].oversampleCount = 0; #ifdef USE_VOL_RAMP p->voice[voiceNumber].rampTerminates = 0; #endif @@ -2628,11 +2627,11 @@ void voiceSetSource(PLAYER *p, uint8_t voiceNumber, const int8_t *sampleData, if (p->voice[voiceNumber].samplePosition >= p->voice[voiceNumber].sampleLength) p->voice[voiceNumber].samplePosition = 0; - sinc_resampler_clear( p->resampler[voiceNumber] ); + resampler_clear( p->resampler[voiceNumber] ); #ifdef USE_VOL_RAMP - sinc_resampler_clear( p->resampler[voiceNumber+64] ); + resampler_clear( p->resampler[voiceNumber+64] ); #else - sinc_resampler_clear( p->resampler[voiceNumber+32] ); + resampler_clear( p->resampler[voiceNumber+32] ); #endif } @@ -2641,7 +2640,6 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value) p->voice[voiceNumber].samplePosition = value; p->voice[voiceNumber].mixing = 1; p->voice[voiceNumber].interpolating = 1; - p->voice[voiceNumber].oversampleCount = 0; if (p->voice[voiceNumber].loopEnabled) { @@ -2655,11 +2653,11 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value) p->voice[voiceNumber].samplePosition = 0; } - sinc_resampler_clear( p->resampler[voiceNumber] ); + resampler_clear( p->resampler[voiceNumber] ); #ifdef USE_VOL_RAMP - sinc_resampler_clear( p->resampler[voiceNumber+64] ); + resampler_clear( p->resampler[voiceNumber+64] ); #else - sinc_resampler_clear( p->resampler[voiceNumber+32] ); + resampler_clear( p->resampler[voiceNumber+32] ); #endif } @@ -2733,9 +2731,7 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples) int32_t sampleLoopEnd; int32_t sampleLoopLength; int32_t samplePosition; - int32_t samplingInterpolation; int32_t interpolating; - int32_t oversampleCount; uint32_t j; float volume; float sample; @@ -2751,29 +2747,22 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples) panningL = p->voice[ch].panningL; panningR = p->voice[ch].panningR; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; sampleData = p->voice[ch].sampleData; - samplingInterpolation = p->samplingInterpolation ? 1 : 32; resampler = p->resampler[ch]; - sinc_resampler_set_rate( resampler, p->voice[ch].incRate * (float)samplingInterpolation ); + resampler_set_rate( resampler, p->voice[ch].incRate ); for (j = 0; (j < samples) && sampleData; ++j) { samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler)) + while (interpolating && resampler_get_free_count(resampler)) { - for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount) - sinc_resampler_write_sample(resampler, sampleData[samplePosition] * 256); + resampler_write_sample(resampler, sampleData[samplePosition] * 256); - if (oversampleCount < samplingInterpolation) - break; - samplePosition++; - oversampleCount = 0; if (loopEnabled) { @@ -2792,16 +2781,15 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler) ) + if ( !resampler_ready(resampler) ) { p->voice[ch].mixing = 0; break; } - sample = sinc_resampler_get_sample(resampler); - sinc_resampler_remove_sample(resampler); + sample = resampler_get_sample(resampler); + resampler_remove_sample(resampler); sample *= volume; @@ -2868,9 +2856,7 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples) int32_t sampleLoopEnd; int32_t sampleLoopLength; int32_t samplePosition; - int32_t samplingInterpolation; int32_t interpolating; - int32_t oversampleCount; uint32_t j; float volume; float sampleL; @@ -2887,10 +2873,8 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples) panningL = p->voice[ch].panningL; panningR = p->voice[ch].panningR; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; sampleData = p->voice[ch].sampleData; - samplingInterpolation = p->samplingInterpolation ? 1 : 32; resampler[0] = p->resampler[ch]; #ifdef USE_VOL_RAMP @@ -2899,26 +2883,19 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples) resampler[1] = p->resampler[ch+32]; #endif - sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation); - sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler[0], p->voice[ch].incRate ); + resampler_set_rate(resampler[1], p->voice[ch].incRate ); for (j = 0; (j < samples) && sampleData; ++j) { samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler[0])) + while (interpolating && resampler_get_free_count(resampler[0])) { - for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler[0]); ++oversampleCount) - { - sinc_resampler_write_sample(resampler[0], sampleData[samplePosition] * 256); - sinc_resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256); - } - - if (oversampleCount < samplingInterpolation) - break; + resampler_write_sample(resampler[0], sampleData[samplePosition] * 256); + resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256); samplePosition++; - oversampleCount = 0; if (loopEnabled) { @@ -2937,18 +2914,17 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler[0]) ) + if ( !resampler_ready(resampler[0]) ) { p->voice[ch].mixing = 0; break; } - sampleL = sinc_resampler_get_sample(resampler[0]); - sampleR = sinc_resampler_get_sample(resampler[1]); - sinc_resampler_remove_sample(resampler[0]); - sinc_resampler_remove_sample(resampler[1]); + sampleL = resampler_get_sample(resampler[0]); + sampleR = resampler_get_sample(resampler[1]); + resampler_remove_sample(resampler[0]); + resampler_remove_sample(resampler[1]); sampleL *= volume; sampleR *= volume; @@ -3016,9 +2992,7 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples) int32_t sampleLoopEnd; int32_t sampleLoopLength; int32_t samplePosition; - int32_t samplingInterpolation; int32_t interpolating; - int32_t oversampleCount; uint32_t j; float volume; float sample; @@ -3034,29 +3008,22 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples) panningL = p->voice[ch].panningL; panningR = p->voice[ch].panningR; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; sampleData = (const int16_t*)(p->voice[ch].sampleData); - samplingInterpolation = p->samplingInterpolation ? 1 : 32; resampler = p->resampler[ch]; - sinc_resampler_set_rate( resampler, p->voice[ch].incRate * (float)samplingInterpolation ); + resampler_set_rate( resampler, p->voice[ch].incRate ); for (j = 0; (j < samples) && sampleData; ++j) { samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler)) + while (interpolating && resampler_get_free_count(resampler)) { - for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount) - sinc_resampler_write_sample(resampler, get_le16(&sampleData[samplePosition])); - - if (oversampleCount < samplingInterpolation) - break; + resampler_write_sample(resampler, get_le16(&sampleData[samplePosition])); samplePosition++; - oversampleCount = 0; if (loopEnabled) { @@ -3075,16 +3042,15 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler) ) + if ( !resampler_ready(resampler) ) { p->voice[ch].mixing = 0; break; } - sample = sinc_resampler_get_sample(resampler); - sinc_resampler_remove_sample(resampler); + sample = resampler_get_sample(resampler); + resampler_remove_sample(resampler); sample *= volume; @@ -3151,9 +3117,7 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples) int32_t sampleLoopEnd; int32_t sampleLoopLength; int32_t samplePosition; - int32_t samplingInterpolation; int32_t interpolating; - int32_t oversampleCount; uint32_t j; float volume; float sampleL; @@ -3170,10 +3134,8 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples) panningL = p->voice[ch].panningL; panningR = p->voice[ch].panningR; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; sampleData = (const int16_t*)(p->voice[ch].sampleData); - samplingInterpolation = p->samplingInterpolation ? 1 : 32; resampler[0] = p->resampler[ch]; #ifdef USE_VOL_RAMP @@ -3182,26 +3144,19 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples) resampler[1] = p->resampler[ch+32]; #endif - sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation); - sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation); + resampler_set_rate(resampler[0], p->voice[ch].incRate ); + resampler_set_rate(resampler[1], p->voice[ch].incRate ); for (j = 0; (j < samples) && sampleData; ++j) { samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler[0])) + while (interpolating && resampler_get_free_count(resampler[0])) { - for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler[0]); ++oversampleCount) - { - sinc_resampler_write_sample(resampler[0], get_le16(&sampleData[samplePosition])); - sinc_resampler_write_sample(resampler[1], get_le16(&sampleData[sampleLength + samplePosition])); - } - - if (oversampleCount < samplingInterpolation) - break; + resampler_write_sample(resampler[0], get_le16(&sampleData[samplePosition])); + resampler_write_sample(resampler[1], get_le16(&sampleData[sampleLength + samplePosition])); samplePosition++; - oversampleCount = 0; if (loopEnabled) { @@ -3220,18 +3175,17 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; - if ( !sinc_resampler_ready(resampler[0]) ) + if ( !resampler_ready(resampler[0]) ) { p->voice[ch].mixing = 0; break; } - sampleL = sinc_resampler_get_sample(resampler[0]); - sampleR = sinc_resampler_get_sample(resampler[1]); - sinc_resampler_remove_sample(resampler[0]); - sinc_resampler_remove_sample(resampler[1]); + sampleL = resampler_get_sample(resampler[0]); + sampleR = resampler_get_sample(resampler[1]); + resampler_remove_sample(resampler[0]); + resampler_remove_sample(resampler[1]); sampleL *= volume; sampleR *= volume; @@ -3307,10 +3261,8 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples) int32_t sampleLoopEnd; int32_t sampleLoopLength; int32_t samplePosition; - int32_t samplingInterpolation; int8_t lastDelta; int32_t interpolating; - int32_t oversampleCount; uint32_t j; float volume; float sample; @@ -3326,12 +3278,10 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples) panningL = p->voice[ch].panningL; panningR = p->voice[ch].panningR; interpolating = p->voice[ch].interpolating; - oversampleCount = p->voice[ch].oversampleCount; lastDelta = p->voice[ch].lastDelta; sampleDictionary = p->voice[ch].sampleData; sampleData = (uint8_t*)sampleDictionary + 16; - samplingInterpolation = p->samplingInterpolation ? 1 : 32; while (p->voice[ch].lastSamplePosition < p->voice[ch].samplePosition) { @@ -3343,27 +3293,22 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples) resampler = p->resampler[ch]; - sinc_resampler_set_rate( resampler, p->voice[ch].incRate * (float)samplingInterpolation ); + resampler_set_rate( resampler, p->voice[ch].incRate ); for (j = 0; (j < samples) && sampleData; ++j) { samplePosition = p->voice[ch].samplePosition; - while (interpolating && sinc_resampler_get_free_count(resampler)) + while (interpolating && resampler_get_free_count(resampler)) { int8_t nextDelta = lastDelta; int16_t sample = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &nextDelta) * 256; - for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount) - sinc_resampler_write_sample(resampler, sample); - - if (oversampleCount < samplingInterpolation) - break; + resampler_write_sample(resampler, sample); lastDelta = nextDelta; samplePosition++; - oversampleCount = 0; if (loopEnabled) { @@ -3389,17 +3334,16 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples) p->voice[ch].samplePosition = samplePosition; p->voice[ch].lastSamplePosition = samplePosition; p->voice[ch].interpolating = (int8_t)interpolating; - p->voice[ch].oversampleCount = (int8_t)oversampleCount; p->voice[ch].lastDelta = lastDelta; - if ( !sinc_resampler_ready(resampler) ) + if ( !resampler_ready(resampler) ) { p->voice[ch].mixing = 0; break; } - sample = sinc_resampler_get_sample(resampler); - sinc_resampler_remove_sample(resampler); + sample = resampler_get_sample(resampler); + resampler_remove_sample(resampler); sample *= volume;