Updated DUMB and modplay
This commit is contained in:
parent
93b427ae4e
commit
46815ba392
18 changed files with 1539 additions and 1185 deletions
|
@ -56,7 +56,7 @@
|
||||||
8370B62C17F60FE2001A4D7A /* stack_alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 8370B62417F60FE2001A4D7A /* stack_alloc.h */; };
|
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, ); }; };
|
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 */; };
|
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 */; };
|
8370B63717F61001001A4D7A /* lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63117F61001001A4D7A /* lpc.c */; };
|
||||||
8370B63817F61001001A4D7A /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63217F61001001A4D7A /* riff.c */; };
|
8370B63817F61001001A4D7A /* riff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63217F61001001A4D7A /* riff.c */; };
|
||||||
8370B63917F61001001A4D7A /* tarray.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B63317F61001001A4D7A /* tarray.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 */; };
|
8370B68917F61038001A4D7A /* readriff.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66017F61038001A4D7A /* readriff.c */; };
|
||||||
8370B68A17F61038001A4D7A /* readstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66117F61038001A4D7A /* readstm.c */; };
|
8370B68A17F61038001A4D7A /* readstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66117F61038001A4D7A /* readstm.c */; };
|
||||||
8370B68B17F61038001A4D7A /* readstm2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8370B66217F61038001A4D7A /* readstm2.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 */; };
|
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 */; };
|
83C8DF1F18C6B32100750AF7 /* blip_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C8DF1E18C6B32100750AF7 /* blip_buf.h */; };
|
||||||
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
|
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 = "<group>"; };
|
8370B62417F60FE2001A4D7A /* stack_alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stack_alloc.h; sourceTree = "<group>"; };
|
||||||
8370B62517F60FE2001A4D7A /* tarray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tarray.h; sourceTree = "<group>"; };
|
8370B62517F60FE2001A4D7A /* tarray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tarray.h; sourceTree = "<group>"; };
|
||||||
8370B62E17F61001001A4D7A /* barray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = barray.c; sourceTree = "<group>"; };
|
8370B62E17F61001001A4D7A /* barray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = barray.c; sourceTree = "<group>"; };
|
||||||
8370B63017F61001001A4D7A /* sinc_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sinc_resampler.c; sourceTree = "<group>"; };
|
8370B63017F61001001A4D7A /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = "<group>"; };
|
||||||
8370B63117F61001001A4D7A /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpc.c; sourceTree = "<group>"; };
|
8370B63117F61001001A4D7A /* lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lpc.c; sourceTree = "<group>"; };
|
||||||
8370B63217F61001001A4D7A /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
|
8370B63217F61001001A4D7A /* riff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = riff.c; sourceTree = "<group>"; };
|
||||||
8370B63317F61001001A4D7A /* tarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tarray.c; sourceTree = "<group>"; };
|
8370B63317F61001001A4D7A /* tarray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tarray.c; sourceTree = "<group>"; };
|
||||||
|
@ -210,7 +210,7 @@
|
||||||
8370B66017F61038001A4D7A /* readriff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readriff.c; sourceTree = "<group>"; };
|
8370B66017F61038001A4D7A /* readriff.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readriff.c; sourceTree = "<group>"; };
|
||||||
8370B66117F61038001A4D7A /* readstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm.c; sourceTree = "<group>"; };
|
8370B66117F61038001A4D7A /* readstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm.c; sourceTree = "<group>"; };
|
||||||
8370B66217F61038001A4D7A /* readstm2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm2.c; sourceTree = "<group>"; };
|
8370B66217F61038001A4D7A /* readstm2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = readstm2.c; sourceTree = "<group>"; };
|
||||||
8370B7E817F62A40001A4D7A /* sinc_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sinc_resampler.h; sourceTree = "<group>"; };
|
8370B7E817F62A40001A4D7A /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
|
||||||
83C8DF1C18C6B31400750AF7 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = "<group>"; };
|
83C8DF1C18C6B31400750AF7 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = "<group>"; };
|
||||||
83C8DF1E18C6B32100750AF7 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = "<group>"; };
|
83C8DF1E18C6B32100750AF7 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = "<group>"; };
|
||||||
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
@ -308,7 +308,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
83C8DF1E18C6B32100750AF7 /* blip_buf.h */,
|
83C8DF1E18C6B32100750AF7 /* blip_buf.h */,
|
||||||
8370B7E817F62A40001A4D7A /* sinc_resampler.h */,
|
8370B7E817F62A40001A4D7A /* resampler.h */,
|
||||||
8370B61E17F60FE2001A4D7A /* barray.h */,
|
8370B61E17F60FE2001A4D7A /* barray.h */,
|
||||||
8370B62017F60FE2001A4D7A /* dumbfile.h */,
|
8370B62017F60FE2001A4D7A /* dumbfile.h */,
|
||||||
8370B62217F60FE2001A4D7A /* lpc.h */,
|
8370B62217F60FE2001A4D7A /* lpc.h */,
|
||||||
|
@ -356,7 +356,7 @@
|
||||||
children = (
|
children = (
|
||||||
83C8DF1C18C6B31400750AF7 /* blip_buf.c */,
|
83C8DF1C18C6B31400750AF7 /* blip_buf.c */,
|
||||||
8370B62E17F61001001A4D7A /* barray.c */,
|
8370B62E17F61001001A4D7A /* barray.c */,
|
||||||
8370B63017F61001001A4D7A /* sinc_resampler.c */,
|
8370B63017F61001001A4D7A /* resampler.c */,
|
||||||
8370B63117F61001001A4D7A /* lpc.c */,
|
8370B63117F61001001A4D7A /* lpc.c */,
|
||||||
8370B63217F61001001A4D7A /* riff.c */,
|
8370B63217F61001001A4D7A /* riff.c */,
|
||||||
8370B63317F61001001A4D7A /* tarray.c */,
|
8370B63317F61001001A4D7A /* tarray.c */,
|
||||||
|
@ -454,7 +454,7 @@
|
||||||
8370B62617F60FE2001A4D7A /* barray.h in Headers */,
|
8370B62617F60FE2001A4D7A /* barray.h in Headers */,
|
||||||
17C8F63E0CBEE797008D969D /* dumb.h in Headers */,
|
17C8F63E0CBEE797008D969D /* dumb.h in Headers */,
|
||||||
17C8F6400CBEE797008D969D /* it.h in Headers */,
|
17C8F6400CBEE797008D969D /* it.h in Headers */,
|
||||||
8370B7EA17F62A40001A4D7A /* sinc_resampler.h in Headers */,
|
8370B7EA17F62A40001A4D7A /* resampler.h in Headers */,
|
||||||
17C8F63F0CBEE797008D969D /* dumb.h in Headers */,
|
17C8F63F0CBEE797008D969D /* dumb.h in Headers */,
|
||||||
8370B62B17F60FE2001A4D7A /* riff.h in Headers */,
|
8370B62B17F60FE2001A4D7A /* riff.h in Headers */,
|
||||||
8370B62A17F60FE2001A4D7A /* lpc.h in Headers */,
|
8370B62A17F60FE2001A4D7A /* lpc.h in Headers */,
|
||||||
|
@ -567,7 +567,7 @@
|
||||||
8370B66417F61038001A4D7A /* load6692.c in Sources */,
|
8370B66417F61038001A4D7A /* load6692.c in Sources */,
|
||||||
17C8F6560CBEE797008D969D /* itload.c in Sources */,
|
17C8F6560CBEE797008D969D /* itload.c in Sources */,
|
||||||
17C8F6570CBEE797008D969D /* itload2.c in Sources */,
|
17C8F6570CBEE797008D969D /* itload2.c in Sources */,
|
||||||
8370B63617F61001001A4D7A /* sinc_resampler.c in Sources */,
|
8370B63617F61001001A4D7A /* resampler.c in Sources */,
|
||||||
17C8F6580CBEE797008D969D /* itmisc.c in Sources */,
|
17C8F6580CBEE797008D969D /* itmisc.c in Sources */,
|
||||||
8370B67517F61038001A4D7A /* loadriff.c in Sources */,
|
8370B67517F61038001A4D7A /* loadriff.c in Sources */,
|
||||||
8370B66917F61038001A4D7A /* loadasy.c in Sources */,
|
8370B66917F61038001A4D7A /* loadasy.c in Sources */,
|
||||||
|
|
52
Frameworks/Dumb/dumb/include/internal/resampler.h
Normal file
52
Frameworks/Dumb/dumb/include/internal/resampler.h
Normal file
|
@ -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
|
|
@ -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
|
|
|
@ -140,78 +140,24 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU
|
||||||
MIX_ALIAS( todo );
|
MIX_ALIAS( todo );
|
||||||
done -= check;
|
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 {
|
} else {
|
||||||
/* FIR resampling, backwards */
|
/* FIR resampling, backwards */
|
||||||
SRCTYPE *x;
|
SRCTYPE *x;
|
||||||
if ( resampler->fir_resampler_ratio != delta ) {
|
if ( resampler->fir_resampler_ratio != delta ) {
|
||||||
sinc_resampler_set_rate( resampler->fir_resampler[0], delta );
|
resampler_set_rate( resampler->fir_resampler[0], delta );
|
||||||
sinc_resampler_set_rate( resampler->fir_resampler[1], delta );
|
resampler_set_rate( resampler->fir_resampler[1], delta );
|
||||||
resampler->fir_resampler_ratio = delta;
|
resampler->fir_resampler_ratio = delta;
|
||||||
}
|
}
|
||||||
x = &src[pos*SRC_CHANNELS];
|
x = &src[pos*SRC_CHANNELS];
|
||||||
while ( todo ) {
|
while ( todo ) {
|
||||||
while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) &&
|
while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
|
||||||
pos >= resampler->start )
|
pos >= resampler->start )
|
||||||
{
|
{
|
||||||
POKE_FIR(0);
|
POKE_FIR(0);
|
||||||
pos--;
|
pos--;
|
||||||
x -= SRC_CHANNELS;
|
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;
|
MIX_FIR;
|
||||||
ADVANCE_FIR;
|
ADVANCE_FIR;
|
||||||
--todo;
|
--todo;
|
||||||
|
@ -273,77 +219,24 @@ long dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, long dst_size, VOLU
|
||||||
MIX_ALIAS( todo );
|
MIX_ALIAS( todo );
|
||||||
done -= check;
|
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 {
|
} else {
|
||||||
/* FIR resampling, forwards */
|
/* FIR resampling, forwards */
|
||||||
SRCTYPE *x;
|
SRCTYPE *x;
|
||||||
if ( resampler->fir_resampler_ratio != delta ) {
|
if ( resampler->fir_resampler_ratio != delta ) {
|
||||||
sinc_resampler_set_rate( resampler->fir_resampler[0], delta );
|
resampler_set_rate( resampler->fir_resampler[0], delta );
|
||||||
sinc_resampler_set_rate( resampler->fir_resampler[1], delta );
|
resampler_set_rate( resampler->fir_resampler[1], delta );
|
||||||
resampler->fir_resampler_ratio = delta;
|
resampler->fir_resampler_ratio = delta;
|
||||||
}
|
}
|
||||||
x = &src[pos*SRC_CHANNELS];
|
x = &src[pos*SRC_CHANNELS];
|
||||||
while ( todo ) {
|
while ( todo ) {
|
||||||
while ( sinc_resampler_get_free_count( resampler->fir_resampler[0] ) &&
|
while ( resampler_get_free_count( resampler->fir_resampler[0] ) &&
|
||||||
pos < resampler->end )
|
pos < resampler->end )
|
||||||
{
|
{
|
||||||
POKE_FIR(0);
|
POKE_FIR(0);
|
||||||
pos++;
|
pos++;
|
||||||
x += SRC_CHANNELS;
|
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;
|
MIX_FIR;
|
||||||
ADVANCE_FIR;
|
ADVANCE_FIR;
|
||||||
--todo;
|
--todo;
|
||||||
|
@ -409,12 +302,6 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
||||||
if (quality <= DUMB_RQ_ALIASING) {
|
if (quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing, backwards */
|
/* Aliasing, backwards */
|
||||||
PEEK_ALIAS;
|
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 {
|
} else {
|
||||||
/* FIR resampling, backwards */
|
/* FIR resampling, backwards */
|
||||||
PEEK_FIR;
|
PEEK_FIR;
|
||||||
|
@ -424,12 +311,6 @@ void dumb_resample_get_current_sample(DUMB_RESAMPLER *resampler, VOLUME_PARAMETE
|
||||||
if (quality <= DUMB_RQ_ALIASING) {
|
if (quality <= DUMB_RQ_ALIASING) {
|
||||||
/* Aliasing */
|
/* Aliasing */
|
||||||
PEEK_ALIAS;
|
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 {
|
} else {
|
||||||
/* FIR resampling, forwards */
|
/* FIR resampling, forwards */
|
||||||
PEEK_FIR;
|
PEEK_FIR;
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
#include "dumb.h"
|
#include "dumb.h"
|
||||||
|
|
||||||
#include "internal/blip_buf.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);
|
cubicA1[t] = (int)(3*t*t*t >> 17) - (int)(5*t*t >> 7) + (int)(1 << 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
sinc_init();
|
resampler_init();
|
||||||
|
|
||||||
done = 1;
|
done = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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[0]);
|
||||||
blip_clear(resampler->blip_buffer[1]);
|
blip_clear(resampler->blip_buffer[1]);
|
||||||
resampler->fir_resampler_ratio = 0;
|
resampler->fir_resampler_ratio = 0;
|
||||||
sinc_resampler_clear(resampler->fir_resampler[0]);
|
resampler_clear(resampler->fir_resampler[0]);
|
||||||
sinc_resampler_clear(resampler->fir_resampler[1]);
|
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; \
|
resampler->last_clock += inv_dt; \
|
||||||
}
|
}
|
||||||
#define POKE_FIR(offset) { \
|
#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_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 { \
|
#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 ); \
|
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) { \
|
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||||
int n = 0; \
|
int n = 0; \
|
||||||
resampler->last_clock -= count * 65536; \
|
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 ); \
|
*dst++ = MULSC( sample, rvol ); \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_PEEK_FIR { \
|
#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, lvol ); \
|
||||||
*dst++ = MULSC( sample, rvol ); \
|
*dst++ = MULSC( sample, rvol ); \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_MIX_FIR { \
|
#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, lvol ); \
|
||||||
*dst++ += MULSC( sample, rvol ); \
|
*dst++ += MULSC( sample, rvol ); \
|
||||||
UPDATE_VOLUME( volume_left, lvol ); \
|
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; \
|
resampler->last_clock += inv_dt; \
|
||||||
}
|
}
|
||||||
#define POKE_FIR(offset) { \
|
#define POKE_FIR(offset) { \
|
||||||
sinc_resampler_write_sample( resampler->fir_resampler[0], FIR(x[(offset)*2+0]) ); \
|
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[1], FIR(x[(offset)*2+1]) ); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_PEEK_ALIAS { \
|
#define MONO_DEST_PEEK_ALIAS { \
|
||||||
*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
|
*dst = MULSC( blip_peek_sample( resampler->blip_buffer[0] ), lvol ) + \
|
||||||
MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_PEEK_FIR { \
|
#define MONO_DEST_PEEK_FIR { \
|
||||||
*dst = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
*dst = MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
||||||
MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_MIX_FIR { \
|
#define MONO_DEST_MIX_FIR { \
|
||||||
*dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
*dst++ += MULSC( resampler_get_sample( resampler->fir_resampler[0] ), lvol ) + \
|
||||||
MULSC( sinc_resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
MULSC( resampler_get_sample( resampler->fir_resampler[1] ), rvol ); \
|
||||||
UPDATE_VOLUME( volume_left, lvol ); \
|
UPDATE_VOLUME( volume_left, lvol ); \
|
||||||
UPDATE_VOLUME( volume_right, rvol ); \
|
UPDATE_VOLUME( volume_right, rvol ); \
|
||||||
}
|
}
|
||||||
#define ADVANCE_FIR { \
|
#define ADVANCE_FIR { \
|
||||||
sinc_resampler_remove_sample( resampler->fir_resampler[0] ); \
|
resampler_remove_sample( resampler->fir_resampler[0] ); \
|
||||||
sinc_resampler_remove_sample( resampler->fir_resampler[1] ); \
|
resampler_remove_sample( resampler->fir_resampler[1] ); \
|
||||||
}
|
}
|
||||||
#define MONO_DEST_MIX_ALIAS(count) { \
|
#define MONO_DEST_MIX_ALIAS(count) { \
|
||||||
int n = 0; \
|
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 ); \
|
*dst++ = MULSC( blip_peek_sample( resampler->blip_buffer[1] ), rvol ); \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_PEEK_FIR { \
|
#define STEREO_DEST_PEEK_FIR { \
|
||||||
*dst++ = MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
|
*dst++ = MULSC( 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[1] ), rvol ); \
|
||||||
}
|
}
|
||||||
#define STEREO_DEST_MIX_FIR { \
|
#define STEREO_DEST_MIX_FIR { \
|
||||||
*dst++ += MULSC( sinc_resampler_get_sample( resampler->fir_resampler[0] ), lvol ); \
|
*dst++ += MULSC( 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[1] ), rvol ); \
|
||||||
UPDATE_VOLUME( volume_left, lvol ); \
|
UPDATE_VOLUME( volume_left, lvol ); \
|
||||||
UPDATE_VOLUME( volume_right, rvol ); \
|
UPDATE_VOLUME( volume_right, rvol ); \
|
||||||
}
|
}
|
||||||
|
|
636
Frameworks/Dumb/dumb/src/helpers/resampler.c
Normal file
636
Frameworks/Dumb/dumb/src/helpers/resampler.c
Normal file
|
@ -0,0 +1,636 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#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 <intrin.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,361 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#define _USE_MATH_DEFINES
|
|
||||||
#include <math.h>
|
|
||||||
#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
#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 <intrin.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include "internal/lpc.h"
|
#include "internal/lpc.h"
|
||||||
|
|
||||||
#include "internal/blip_buf.h"
|
#include "internal/blip_buf.h"
|
||||||
#include "internal/sinc_resampler.h"
|
#include "internal/resampler.h"
|
||||||
|
|
||||||
// #define BIT_ARRAY_BULLSHIT
|
// #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[0], 65536, 1);
|
||||||
blip_set_rates(r->resampler.blip_buffer[1], 65536, 1);
|
blip_set_rates(r->resampler.blip_buffer[1], 65536, 1);
|
||||||
r->resampler.fir_resampler_ratio = 0.0;
|
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] ) {
|
if ( !r->resampler.fir_resampler[0] ) {
|
||||||
free( r->resampler.blip_buffer[1] );
|
free( r->resampler.blip_buffer[1] );
|
||||||
free( r->resampler.blip_buffer[0] );
|
free( r->resampler.blip_buffer[0] );
|
||||||
free( r );
|
free( r );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
r->resampler.fir_resampler[1] = sinc_resampler_create();
|
r->resampler.fir_resampler[1] = resampler_create();
|
||||||
if ( !r->resampler.fir_resampler[1] ) {
|
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[1] );
|
||||||
free( r->resampler.blip_buffer[0] );
|
free( r->resampler.blip_buffer[0] );
|
||||||
free( r );
|
free( r );
|
||||||
|
@ -73,8 +73,8 @@ static IT_PLAYING *new_playing()
|
||||||
|
|
||||||
static void free_playing(IT_PLAYING * r)
|
static void free_playing(IT_PLAYING * r)
|
||||||
{
|
{
|
||||||
sinc_resampler_delete( r->resampler.fir_resampler[1] );
|
resampler_delete( r->resampler.fir_resampler[1] );
|
||||||
sinc_resampler_delete( r->resampler.fir_resampler[0] );
|
resampler_delete( r->resampler.fir_resampler[0] );
|
||||||
blip_delete( r->resampler.blip_buffer[1] );
|
blip_delete( r->resampler.blip_buffer[1] );
|
||||||
blip_delete( r->resampler.blip_buffer[0] );
|
blip_delete( r->resampler.blip_buffer[0] );
|
||||||
free( r );
|
free( r );
|
||||||
|
@ -180,16 +180,16 @@ static IT_PLAYING *dup_playing(IT_PLAYING *src, IT_CHANNEL *dstchannel, IT_CHANN
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dst->resampler.fir_resampler_ratio = src->resampler.fir_resampler_ratio;
|
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] ) {
|
if ( !dst->resampler.fir_resampler[0] ) {
|
||||||
blip_delete( dst->resampler.blip_buffer[1] );
|
blip_delete( dst->resampler.blip_buffer[1] );
|
||||||
blip_delete( dst->resampler.blip_buffer[0] );
|
blip_delete( dst->resampler.blip_buffer[0] );
|
||||||
free( dst );
|
free( dst );
|
||||||
return NULL;
|
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] ) {
|
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[1] );
|
||||||
blip_delete( dst->resampler.blip_buffer[0] );
|
blip_delete( dst->resampler.blip_buffer[0] );
|
||||||
free( dst );
|
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)
|
if (playing->sample->max_resampling_quality >= 0 && quality > playing->sample->max_resampling_quality)
|
||||||
quality = playing->sample->max_resampling_quality;
|
quality = playing->sample->max_resampling_quality;
|
||||||
playing->resampler.quality = 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;
|
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;
|
IT_PLAYING * playing = sigrenderer->channel[i].playing;
|
||||||
playing->resampling_quality = quality;
|
playing->resampling_quality = quality;
|
||||||
playing->resampler.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++) {
|
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];
|
IT_PLAYING * playing = sigrenderer->playing[i];
|
||||||
playing->resampling_quality = quality;
|
playing->resampling_quality = quality;
|
||||||
playing->resampler.quality = quality;
|
playing->resampler.quality = quality;
|
||||||
|
resampler_set_quality(playing->resampler.fir_resampler[0], quality);
|
||||||
|
resampler_set_quality(playing->resampler.fir_resampler[1], quality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
<ClCompile Include="..\..\src\helpers\blip_buf.c" />
|
<ClCompile Include="..\..\src\helpers\blip_buf.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\clickrem.c" />
|
<ClCompile Include="..\..\src\helpers\clickrem.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\fir_resampler.c" />
|
<ClCompile Include="..\..\src\helpers\fir_resampler.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\sinc_resampler.c" />
|
<ClCompile Include="..\..\src\helpers\resampler.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\lpc.c" />
|
<ClCompile Include="..\..\src\helpers\lpc.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\memfile.c" />
|
<ClCompile Include="..\..\src\helpers\memfile.c" />
|
||||||
<ClCompile Include="..\..\src\helpers\resample.c" />
|
<ClCompile Include="..\..\src\helpers\resample.c" />
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
<ClInclude Include="..\..\include\internal\dumbfile.h" />
|
<ClInclude Include="..\..\include\internal\dumbfile.h" />
|
||||||
<ClInclude Include="..\..\include\internal\fir_resampler.h" />
|
<ClInclude Include="..\..\include\internal\fir_resampler.h" />
|
||||||
<ClInclude Include="..\..\include\internal\it.h" />
|
<ClInclude Include="..\..\include\internal\it.h" />
|
||||||
<ClInclude Include="..\..\include\internal\sinc_resampler.h" />
|
<ClInclude Include="..\..\include\internal\resampler.h" />
|
||||||
<ClInclude Include="..\..\include\internal\lpc.h" />
|
<ClInclude Include="..\..\include\internal\lpc.h" />
|
||||||
<ClInclude Include="..\..\include\internal\riff.h" />
|
<ClInclude Include="..\..\include\internal\riff.h" />
|
||||||
<ClInclude Include="..\..\include\internal\stack_alloc.h" />
|
<ClInclude Include="..\..\include\internal\stack_alloc.h" />
|
||||||
|
|
|
@ -282,7 +282,7 @@
|
||||||
<ClCompile Include="..\..\src\it\readany2.c">
|
<ClCompile Include="..\..\src\it\readany2.c">
|
||||||
<Filter>src\it\readers</Filter>
|
<Filter>src\it\readers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\helpers\sinc_resampler.c">
|
<ClCompile Include="..\..\src\helpers\resampler.c">
|
||||||
<Filter>src\helpers</Filter>
|
<Filter>src\helpers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\helpers\tarray.c">
|
<ClCompile Include="..\..\src\helpers\tarray.c">
|
||||||
|
@ -320,7 +320,7 @@
|
||||||
<ClInclude Include="..\..\include\internal\blip_buf.h">
|
<ClInclude Include="..\..\include\internal\blip_buf.h">
|
||||||
<Filter>include\internal</Filter>
|
<Filter>include\internal</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\include\internal\sinc_resampler.h">
|
<ClInclude Include="..\..\include\internal\resampler.h">
|
||||||
<Filter>include\internal</Filter>
|
<Filter>include\internal</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\include\internal\tarray.h">
|
<ClInclude Include="..\..\include\internal\tarray.h">
|
||||||
|
|
|
@ -8,15 +8,17 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
835CBC8218DA95AC0087A03E /* ft2play.h in Headers */ = {isa = PBXBuildFile; fileRef = 839CAC3E18DA744700D67EA9 /* ft2play.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
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 */; };
|
839CAC4018DA746000D67EA9 /* ft2play.c in Sources */ = {isa = PBXBuildFile; fileRef = 839CAC3F18DA746000D67EA9 /* ft2play.c */; };
|
||||||
83F4D54818D82105009B2DE6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83F4D54618D82105009B2DE6 /* InfoPlist.strings */; };
|
83F4D54818D82105009B2DE6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83F4D54618D82105009B2DE6 /* InfoPlist.strings */; };
|
||||||
83F4D57718D821D2009B2DE6 /* st3play.c in Sources */ = {isa = PBXBuildFile; fileRef = 83F4D57318D821D2009B2DE6 /* st3play.c */; };
|
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, ); }; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
838A72E418DEC9A1007C8A7D /* resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = resampler.c; sourceTree = "<group>"; };
|
||||||
|
838A72E518DEC9A1007C8A7D /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = "<group>"; };
|
||||||
839CAC3E18DA744700D67EA9 /* ft2play.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ft2play.h; sourceTree = "<group>"; };
|
839CAC3E18DA744700D67EA9 /* ft2play.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ft2play.h; sourceTree = "<group>"; };
|
||||||
839CAC3F18DA746000D67EA9 /* ft2play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ft2play.c; sourceTree = "<group>"; };
|
839CAC3F18DA746000D67EA9 /* ft2play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ft2play.c; sourceTree = "<group>"; };
|
||||||
83F4D53A18D82105009B2DE6 /* modplay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = modplay.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
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 = "<group>"; };
|
83F4D54718D82105009B2DE6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
83F4D57318D821D2009B2DE6 /* st3play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = st3play.c; sourceTree = "<group>"; };
|
83F4D57318D821D2009B2DE6 /* st3play.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = st3play.c; sourceTree = "<group>"; };
|
||||||
83F4D57418D821D2009B2DE6 /* st3play.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = st3play.h; sourceTree = "<group>"; };
|
83F4D57418D821D2009B2DE6 /* st3play.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = st3play.h; sourceTree = "<group>"; };
|
||||||
83F81CB918DE4CEC0058B7C3 /* sinc_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sinc_resampler.c; sourceTree = "<group>"; };
|
|
||||||
83F81CBA18DE4CEC0058B7C3 /* sinc_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sinc_resampler.h; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -74,8 +74,8 @@
|
||||||
83F4D54318D82105009B2DE6 /* modplay */ = {
|
83F4D54318D82105009B2DE6 /* modplay */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
83F81CB918DE4CEC0058B7C3 /* sinc_resampler.c */,
|
838A72E418DEC9A1007C8A7D /* resampler.c */,
|
||||||
83F81CBA18DE4CEC0058B7C3 /* sinc_resampler.h */,
|
838A72E518DEC9A1007C8A7D /* resampler.h */,
|
||||||
83F4D57318D821D2009B2DE6 /* st3play.c */,
|
83F4D57318D821D2009B2DE6 /* st3play.c */,
|
||||||
83F4D57418D821D2009B2DE6 /* st3play.h */,
|
83F4D57418D821D2009B2DE6 /* st3play.h */,
|
||||||
839CAC3F18DA746000D67EA9 /* ft2play.c */,
|
839CAC3F18DA746000D67EA9 /* ft2play.c */,
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
isa = PBXHeadersBuildPhase;
|
isa = PBXHeadersBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
83F81CBC18DE4CEC0058B7C3 /* sinc_resampler.h in Headers */,
|
838A72E718DEC9A1007C8A7D /* resampler.h in Headers */,
|
||||||
835CBC8218DA95AC0087A03E /* ft2play.h in Headers */,
|
835CBC8218DA95AC0087A03E /* ft2play.h in Headers */,
|
||||||
83F4D57818D821D2009B2DE6 /* st3play.h in Headers */,
|
83F4D57818D821D2009B2DE6 /* st3play.h in Headers */,
|
||||||
);
|
);
|
||||||
|
@ -170,9 +170,9 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
838A72E618DEC9A1007C8A7D /* resampler.c in Sources */,
|
||||||
83F4D57718D821D2009B2DE6 /* st3play.c in Sources */,
|
83F4D57718D821D2009B2DE6 /* st3play.c in Sources */,
|
||||||
839CAC4018DA746000D67EA9 /* ft2play.c in Sources */,
|
839CAC4018DA746000D67EA9 /* ft2play.c in Sources */,
|
||||||
83F81CBB18DE4CEC0058B7C3 /* sinc_resampler.c in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "sinc_resampler.h"
|
#include "resampler.h"
|
||||||
|
|
||||||
#include "ft2play.h"
|
#include "ft2play.h"
|
||||||
|
|
||||||
|
@ -297,7 +297,6 @@ typedef struct
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int8_t interpolating;
|
int8_t interpolating;
|
||||||
int8_t oversampleCount;
|
|
||||||
|
|
||||||
float incRate;
|
float incRate;
|
||||||
float frac;
|
float frac;
|
||||||
|
@ -2000,8 +1999,8 @@ static void MainPlayer(PLAYER *p) // periodically called from mixer
|
||||||
p->voice[ch->Nr + 127] = p->voice[ch->Nr];
|
p->voice[ch->Nr + 127] = p->voice[ch->Nr];
|
||||||
voiceSetVolume(p, ch->Nr, ch->FinalVol, ch->FinalPan, 1);
|
voiceSetVolume(p, ch->Nr, ch->FinalVol, ch->FinalPan, 1);
|
||||||
voiceSetVolume(p, ch->Nr + 127, 0, 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]);
|
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 + 254], p->resampler[ch->Nr + 254]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s = ch->InstrOfs;
|
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].loopDir = 0;
|
||||||
p->voice[i].stereo = stereo;
|
p->voice[i].stereo = stereo;
|
||||||
p->voice[i].interpolating = 1;
|
p->voice[i].interpolating = 1;
|
||||||
p->voice[i].oversampleCount = 0;
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
p->voice[i].rampTerminates = 0;
|
p->voice[i].rampTerminates = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sinc_resampler_clear(p->resampler[i]);
|
resampler_clear(p->resampler[i]);
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
sinc_resampler_clear(p->resampler[i+254]);
|
resampler_clear(p->resampler[i+254]);
|
||||||
#else
|
#else
|
||||||
sinc_resampler_clear(p->resampler[i+127]);
|
resampler_clear(p->resampler[i+127]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2705,13 +2703,12 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t i, uint16_t value)
|
||||||
}
|
}
|
||||||
|
|
||||||
p->voice[i].interpolating = 1;
|
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
|
#ifdef USE_VOL_RAMP
|
||||||
sinc_resampler_clear(p->resampler[i+254]);
|
resampler_clear(p->resampler[i+254]);
|
||||||
#else
|
#else
|
||||||
sinc_resampler_clear(p->resampler[i+127]);
|
resampler_clear(p->resampler[i+127]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2764,8 +2761,6 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
int8_t loopBidi;
|
int8_t loopBidi;
|
||||||
int8_t loopDir;
|
int8_t loopDir;
|
||||||
|
|
||||||
int32_t oversampleCount;
|
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
|
|
||||||
void * resampler;
|
void * resampler;
|
||||||
|
@ -2778,30 +2773,21 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
loopBidi = p->voice[ch].loopBidi;
|
loopBidi = p->voice[ch].loopBidi;
|
||||||
loopDir = p->voice[ch].loopDir;
|
loopDir = p->voice[ch].loopDir;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
sampleData = p->voice[ch].sampleData;
|
sampleData = p->voice[ch].sampleData;
|
||||||
|
|
||||||
resampler = p->resampler[ch];
|
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)
|
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||||
{
|
{
|
||||||
p->voice[ch].busy = 1;
|
p->voice[ch].busy = 1;
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler, sampleData[samplePosition] * 256);
|
||||||
sinc_resampler_write_sample(resampler, sampleData[samplePosition] * 256);
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopDir == 1)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].loopDir = loopDir;
|
p->voice[ch].loopDir = loopDir;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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].sampleData = NULL;
|
||||||
p->voice[ch].samplePosition = 0;
|
p->voice[ch].samplePosition = 0;
|
||||||
|
@ -2860,8 +2845,8 @@ static inline void mix8b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = sinc_resampler_get_sample(resampler);
|
sample = resampler_get_sample(resampler);
|
||||||
sinc_resampler_remove_sample(resampler);
|
resampler_remove_sample(resampler);
|
||||||
|
|
||||||
sampleL = (sample * p->voice[ch].volumeL);
|
sampleL = (sample * p->voice[ch].volumeL);
|
||||||
sampleR = (sample * p->voice[ch].volumeR);
|
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 loopBidi;
|
||||||
int8_t loopDir;
|
int8_t loopDir;
|
||||||
|
|
||||||
int32_t oversampleCount;
|
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
|
|
||||||
void * resampler[2];
|
void * resampler[2];
|
||||||
|
@ -2939,9 +2922,6 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
loopBidi = p->voice[ch].loopBidi;
|
loopBidi = p->voice[ch].loopBidi;
|
||||||
loopDir = p->voice[ch].loopDir;
|
loopDir = p->voice[ch].loopDir;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
sampleData = p->voice[ch].sampleData;
|
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];
|
resampler[1] = p->resampler[ch+127];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||||
sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||||
|
|
||||||
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||||
{
|
{
|
||||||
p->voice[ch].busy = 1;
|
p->voice[ch].busy = 1;
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler[0], sampleData[samplePosition] * 256);
|
||||||
{
|
resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256);
|
||||||
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;
|
|
||||||
|
|
||||||
if (loopDir == 1)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].loopDir = loopDir;
|
p->voice[ch].loopDir = loopDir;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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].sampleData = NULL;
|
||||||
p->voice[ch].samplePosition = 0;
|
p->voice[ch].samplePosition = 0;
|
||||||
|
@ -3030,10 +3001,10 @@ static inline void mix8bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleL = sinc_resampler_get_sample(resampler[0]);
|
sampleL = resampler_get_sample(resampler[0]);
|
||||||
sampleR = sinc_resampler_get_sample(resampler[1]);
|
sampleR = resampler_get_sample(resampler[1]);
|
||||||
sinc_resampler_remove_sample(resampler[0]);
|
resampler_remove_sample(resampler[0]);
|
||||||
sinc_resampler_remove_sample(resampler[1]);
|
resampler_remove_sample(resampler[1]);
|
||||||
|
|
||||||
sampleL = (sampleL * p->voice[ch].volumeL);
|
sampleL = (sampleL * p->voice[ch].volumeL);
|
||||||
sampleR = (sampleR * p->voice[ch].volumeR);
|
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 loopBidi;
|
||||||
int8_t loopDir;
|
int8_t loopDir;
|
||||||
|
|
||||||
int32_t oversampleCount;
|
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
|
|
||||||
void * resampler;
|
void * resampler;
|
||||||
|
@ -3112,30 +3081,21 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
loopBidi = p->voice[ch].loopBidi;
|
loopBidi = p->voice[ch].loopBidi;
|
||||||
loopDir = p->voice[ch].loopDir;
|
loopDir = p->voice[ch].loopDir;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
sampleData = (const int16_t *)(p->voice[ch].sampleData);
|
sampleData = (const int16_t *)(p->voice[ch].sampleData);
|
||||||
|
|
||||||
resampler = p->resampler[ch];
|
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)
|
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||||
{
|
{
|
||||||
p->voice[ch].busy = 1;
|
p->voice[ch].busy = 1;
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler, sampleData[samplePosition]);
|
||||||
sinc_resampler_write_sample(resampler, sampleData[samplePosition]);
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopDir == 1)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].loopDir = loopDir;
|
p->voice[ch].loopDir = loopDir;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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].sampleData = NULL;
|
||||||
p->voice[ch].samplePosition = 0;
|
p->voice[ch].samplePosition = 0;
|
||||||
|
@ -3194,8 +3153,8 @@ static inline void mix16b(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = sinc_resampler_get_sample(resampler);
|
sample = resampler_get_sample(resampler);
|
||||||
sinc_resampler_remove_sample(resampler);
|
resampler_remove_sample(resampler);
|
||||||
|
|
||||||
sampleL = (sample * p->voice[ch].volumeL);
|
sampleL = (sample * p->voice[ch].volumeL);
|
||||||
sampleR = (sample * p->voice[ch].volumeR);
|
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 loopBidi;
|
||||||
int8_t loopDir;
|
int8_t loopDir;
|
||||||
|
|
||||||
int32_t oversampleCount;
|
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
|
|
||||||
void * resampler[2];
|
void * resampler[2];
|
||||||
|
@ -3273,9 +3230,6 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
loopBidi = p->voice[ch].loopBidi;
|
loopBidi = p->voice[ch].loopBidi;
|
||||||
loopDir = p->voice[ch].loopDir;
|
loopDir = p->voice[ch].loopDir;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
sampleData = (const int16_t *)(p->voice[ch].sampleData);
|
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];
|
resampler[1] = p->resampler[ch+127];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||||
sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||||
|
|
||||||
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
for (j = 0; (j < samples) && (p->voice[ch].sampleData != NULL); ++j)
|
||||||
{
|
{
|
||||||
p->voice[ch].busy = 1;
|
p->voice[ch].busy = 1;
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler[0], sampleData[samplePosition]);
|
||||||
{
|
resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition]);
|
||||||
sinc_resampler_write_sample(resampler[0], sampleData[samplePosition]);
|
|
||||||
sinc_resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopDir == 1)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].loopDir = loopDir;
|
p->voice[ch].loopDir = loopDir;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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].sampleData = NULL;
|
||||||
p->voice[ch].samplePosition = 0;
|
p->voice[ch].samplePosition = 0;
|
||||||
|
@ -3364,10 +3309,10 @@ static inline void mix16bstereo(PLAYER *p, uint32_t ch, uint32_t samples)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleL = sinc_resampler_get_sample(resampler[0]);
|
sampleL = resampler_get_sample(resampler[0]);
|
||||||
sampleR = sinc_resampler_get_sample(resampler[1]);
|
sampleR = resampler_get_sample(resampler[1]);
|
||||||
sinc_resampler_remove_sample(resampler[0]);
|
resampler_remove_sample(resampler[0]);
|
||||||
sinc_resampler_remove_sample(resampler[1]);
|
resampler_remove_sample(resampler[1]);
|
||||||
|
|
||||||
sampleL = (sampleL * p->voice[ch].volumeL);
|
sampleL = (sampleL * p->voice[ch].volumeL);
|
||||||
sampleR = (sampleR * p->voice[ch].volumeR);
|
sampleR = (sampleR * p->voice[ch].volumeR);
|
||||||
|
@ -3566,7 +3511,7 @@ void * ft2play_Alloc(uint32_t _samplingFrequency, int8_t interpolation)
|
||||||
|
|
||||||
p->samplingInterpolation = interpolation;
|
p->samplingInterpolation = interpolation;
|
||||||
|
|
||||||
sinc_init();
|
resampler_init();
|
||||||
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
for ( i = 0; i < 127 * 2 * 2; ++i )
|
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 )
|
for ( i = 0; i < 127 * 2; ++i )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
p->resampler[i] = sinc_resampler_create();
|
p->resampler[i] = resampler_create();
|
||||||
if ( !p->resampler[i] )
|
if ( !p->resampler[i] )
|
||||||
goto error;
|
goto error;
|
||||||
|
resampler_set_quality(p->resampler[i], interpolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate memory for pointers
|
// allocate memory for pointers
|
||||||
|
@ -3675,7 +3621,7 @@ void ft2play_Free(void *_p)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if ( p->resampler[i] )
|
if ( p->resampler[i] )
|
||||||
sinc_resampler_delete( p->resampler[i] );
|
resampler_delete( p->resampler[i] );
|
||||||
p->resampler[i] = NULL;
|
p->resampler[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
636
Frameworks/modplay/modplay/resampler.c
Normal file
636
Frameworks/modplay/modplay/resampler.c
Normal file
|
@ -0,0 +1,636 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
|
||||||
|
#include <xmmintrin.h>
|
||||||
|
#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 <intrin.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
52
Frameworks/modplay/modplay/resampler.h
Normal file
52
Frameworks/modplay/modplay/resampler.h
Normal file
|
@ -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
|
|
@ -1,362 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#define _USE_MATH_DEFINES
|
|
||||||
#include <math.h>
|
|
||||||
#if (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__amd64__))
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
#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 <intrin.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -63,7 +63,7 @@
|
||||||
#define inline __forceinline
|
#define inline __forceinline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "sinc_resampler.h"
|
#include "resampler.h"
|
||||||
|
|
||||||
#include "st3play.h"
|
#include "st3play.h"
|
||||||
|
|
||||||
|
@ -136,7 +136,6 @@ typedef struct
|
||||||
int8_t adpcm;
|
int8_t adpcm;
|
||||||
int8_t mixing;
|
int8_t mixing;
|
||||||
int8_t interpolating;
|
int8_t interpolating;
|
||||||
int8_t oversampleCount;
|
|
||||||
int32_t sampleLength;
|
int32_t sampleLength;
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
|
@ -485,7 +484,7 @@ void * st3play_Alloc(uint32_t outputFreq, int8_t interpolation)
|
||||||
if ( !p )
|
if ( !p )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sinc_init();
|
resampler_init();
|
||||||
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
for (i = 0; i < 64 * 2; ++i)
|
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)
|
for (i = 0; i < 64; ++i)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
p->resampler[i] = sinc_resampler_create();
|
p->resampler[i] = resampler_create();
|
||||||
if ( !p->resampler[i] )
|
if ( !p->resampler[i] )
|
||||||
{
|
{
|
||||||
st3play_Free( p );
|
st3play_Free( p );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
resampler_set_quality(p->resampler[i], interpolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
p->soundBufferSize = _soundBufferSize;
|
p->soundBufferSize = _soundBufferSize;
|
||||||
|
@ -540,7 +540,7 @@ void st3play_Free(void *_p)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if ( p->resampler[i] )
|
if ( p->resampler[i] )
|
||||||
sinc_resampler_delete( p->resampler[i] );
|
resampler_delete( p->resampler[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( p->masterBufferL )
|
if ( p->masterBufferL )
|
||||||
|
@ -928,8 +928,8 @@ static inline void doamiga(PLAYER *p, uint8_t ch)
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
p->voice[ch + 32] = p->voice[ch];
|
p->voice[ch + 32] = p->voice[ch];
|
||||||
setvol(p, ch, 2);
|
setvol(p, ch, 2);
|
||||||
sinc_resampler_dup_inplace(p->resampler[ch + 32], p->resampler[ch]);
|
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 + 64], p->resampler[ch + 64]);
|
||||||
if (p->chn[ch].vol != 255)
|
if (p->chn[ch].vol != 255)
|
||||||
{
|
{
|
||||||
if (p->chn[ch].vol <= 64)
|
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].adpcm = adpcm;
|
||||||
p->voice[voiceNumber].mixing = 1;
|
p->voice[voiceNumber].mixing = 1;
|
||||||
p->voice[voiceNumber].interpolating = 1;
|
p->voice[voiceNumber].interpolating = 1;
|
||||||
p->voice[voiceNumber].oversampleCount = 0;
|
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
p->voice[voiceNumber].rampTerminates = 0;
|
p->voice[voiceNumber].rampTerminates = 0;
|
||||||
#endif
|
#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)
|
if (p->voice[voiceNumber].samplePosition >= p->voice[voiceNumber].sampleLength)
|
||||||
p->voice[voiceNumber].samplePosition = 0;
|
p->voice[voiceNumber].samplePosition = 0;
|
||||||
|
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber] );
|
resampler_clear( p->resampler[voiceNumber] );
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber+64] );
|
resampler_clear( p->resampler[voiceNumber+64] );
|
||||||
#else
|
#else
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber+32] );
|
resampler_clear( p->resampler[voiceNumber+32] );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2641,7 +2640,6 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value)
|
||||||
p->voice[voiceNumber].samplePosition = value;
|
p->voice[voiceNumber].samplePosition = value;
|
||||||
p->voice[voiceNumber].mixing = 1;
|
p->voice[voiceNumber].mixing = 1;
|
||||||
p->voice[voiceNumber].interpolating = 1;
|
p->voice[voiceNumber].interpolating = 1;
|
||||||
p->voice[voiceNumber].oversampleCount = 0;
|
|
||||||
|
|
||||||
if (p->voice[voiceNumber].loopEnabled)
|
if (p->voice[voiceNumber].loopEnabled)
|
||||||
{
|
{
|
||||||
|
@ -2655,11 +2653,11 @@ void voiceSetSamplePosition(PLAYER *p, uint8_t voiceNumber, uint16_t value)
|
||||||
p->voice[voiceNumber].samplePosition = 0;
|
p->voice[voiceNumber].samplePosition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber] );
|
resampler_clear( p->resampler[voiceNumber] );
|
||||||
#ifdef USE_VOL_RAMP
|
#ifdef USE_VOL_RAMP
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber+64] );
|
resampler_clear( p->resampler[voiceNumber+64] );
|
||||||
#else
|
#else
|
||||||
sinc_resampler_clear( p->resampler[voiceNumber+32] );
|
resampler_clear( p->resampler[voiceNumber+32] );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2733,9 +2731,7 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
int32_t oversampleCount;
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
float volume;
|
float volume;
|
||||||
float sample;
|
float sample;
|
||||||
|
@ -2751,29 +2747,22 @@ static inline void mix8b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
panningL = p->voice[ch].panningL;
|
panningL = p->voice[ch].panningL;
|
||||||
panningR = p->voice[ch].panningR;
|
panningR = p->voice[ch].panningR;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
sampleData = p->voice[ch].sampleData;
|
sampleData = p->voice[ch].sampleData;
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
resampler = p->resampler[ch];
|
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)
|
for (j = 0; (j < samples) && sampleData; ++j)
|
||||||
{
|
{
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler, sampleData[samplePosition] * 256);
|
||||||
sinc_resampler_write_sample(resampler, sampleData[samplePosition] * 256);
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
samplePosition++;
|
samplePosition++;
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopEnabled)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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;
|
p->voice[ch].mixing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = sinc_resampler_get_sample(resampler);
|
sample = resampler_get_sample(resampler);
|
||||||
sinc_resampler_remove_sample(resampler);
|
resampler_remove_sample(resampler);
|
||||||
|
|
||||||
sample *= volume;
|
sample *= volume;
|
||||||
|
|
||||||
|
@ -2868,9 +2856,7 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
int32_t oversampleCount;
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
float volume;
|
float volume;
|
||||||
float sampleL;
|
float sampleL;
|
||||||
|
@ -2887,10 +2873,8 @@ static inline void mix8bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
panningL = p->voice[ch].panningL;
|
panningL = p->voice[ch].panningL;
|
||||||
panningR = p->voice[ch].panningR;
|
panningR = p->voice[ch].panningR;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
sampleData = p->voice[ch].sampleData;
|
sampleData = p->voice[ch].sampleData;
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
resampler[0] = p->resampler[ch];
|
resampler[0] = p->resampler[ch];
|
||||||
#ifdef USE_VOL_RAMP
|
#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];
|
resampler[1] = p->resampler[ch+32];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||||
sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||||
|
|
||||||
for (j = 0; (j < samples) && sampleData; ++j)
|
for (j = 0; (j < samples) && sampleData; ++j)
|
||||||
{
|
{
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler[0], sampleData[samplePosition] * 256);
|
||||||
{
|
resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256);
|
||||||
sinc_resampler_write_sample(resampler[0], sampleData[samplePosition] * 256);
|
|
||||||
sinc_resampler_write_sample(resampler[1], sampleData[sampleLength + samplePosition] * 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
samplePosition++;
|
samplePosition++;
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopEnabled)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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;
|
p->voice[ch].mixing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleL = sinc_resampler_get_sample(resampler[0]);
|
sampleL = resampler_get_sample(resampler[0]);
|
||||||
sampleR = sinc_resampler_get_sample(resampler[1]);
|
sampleR = resampler_get_sample(resampler[1]);
|
||||||
sinc_resampler_remove_sample(resampler[0]);
|
resampler_remove_sample(resampler[0]);
|
||||||
sinc_resampler_remove_sample(resampler[1]);
|
resampler_remove_sample(resampler[1]);
|
||||||
|
|
||||||
sampleL *= volume;
|
sampleL *= volume;
|
||||||
sampleR *= volume;
|
sampleR *= volume;
|
||||||
|
@ -3016,9 +2992,7 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
int32_t oversampleCount;
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
float volume;
|
float volume;
|
||||||
float sample;
|
float sample;
|
||||||
|
@ -3034,29 +3008,22 @@ static inline void mix16b(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
panningL = p->voice[ch].panningL;
|
panningL = p->voice[ch].panningL;
|
||||||
panningR = p->voice[ch].panningR;
|
panningR = p->voice[ch].panningR;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
sampleData = (const int16_t*)(p->voice[ch].sampleData);
|
sampleData = (const int16_t*)(p->voice[ch].sampleData);
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
resampler = p->resampler[ch];
|
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)
|
for (j = 0; (j < samples) && sampleData; ++j)
|
||||||
{
|
{
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler, get_le16(&sampleData[samplePosition]));
|
||||||
sinc_resampler_write_sample(resampler, get_le16(&sampleData[samplePosition]));
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
samplePosition++;
|
samplePosition++;
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopEnabled)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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;
|
p->voice[ch].mixing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = sinc_resampler_get_sample(resampler);
|
sample = resampler_get_sample(resampler);
|
||||||
sinc_resampler_remove_sample(resampler);
|
resampler_remove_sample(resampler);
|
||||||
|
|
||||||
sample *= volume;
|
sample *= volume;
|
||||||
|
|
||||||
|
@ -3151,9 +3117,7 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
int32_t oversampleCount;
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
float volume;
|
float volume;
|
||||||
float sampleL;
|
float sampleL;
|
||||||
|
@ -3170,10 +3134,8 @@ static inline void mix16bstereo(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
panningL = p->voice[ch].panningL;
|
panningL = p->voice[ch].panningL;
|
||||||
panningR = p->voice[ch].panningR;
|
panningR = p->voice[ch].panningR;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
|
|
||||||
sampleData = (const int16_t*)(p->voice[ch].sampleData);
|
sampleData = (const int16_t*)(p->voice[ch].sampleData);
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
resampler[0] = p->resampler[ch];
|
resampler[0] = p->resampler[ch];
|
||||||
#ifdef USE_VOL_RAMP
|
#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];
|
resampler[1] = p->resampler[ch+32];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sinc_resampler_set_rate(resampler[0], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[0], p->voice[ch].incRate );
|
||||||
sinc_resampler_set_rate(resampler[1], p->voice[ch].incRate * (float)samplingInterpolation);
|
resampler_set_rate(resampler[1], p->voice[ch].incRate );
|
||||||
|
|
||||||
for (j = 0; (j < samples) && sampleData; ++j)
|
for (j = 0; (j < samples) && sampleData; ++j)
|
||||||
{
|
{
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
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)
|
resampler_write_sample(resampler[0], get_le16(&sampleData[samplePosition]));
|
||||||
{
|
resampler_write_sample(resampler[1], get_le16(&sampleData[sampleLength + samplePosition]));
|
||||||
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;
|
|
||||||
|
|
||||||
samplePosition++;
|
samplePosition++;
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopEnabled)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
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;
|
p->voice[ch].mixing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleL = sinc_resampler_get_sample(resampler[0]);
|
sampleL = resampler_get_sample(resampler[0]);
|
||||||
sampleR = sinc_resampler_get_sample(resampler[1]);
|
sampleR = resampler_get_sample(resampler[1]);
|
||||||
sinc_resampler_remove_sample(resampler[0]);
|
resampler_remove_sample(resampler[0]);
|
||||||
sinc_resampler_remove_sample(resampler[1]);
|
resampler_remove_sample(resampler[1]);
|
||||||
|
|
||||||
sampleL *= volume;
|
sampleL *= volume;
|
||||||
sampleR *= volume;
|
sampleR *= volume;
|
||||||
|
@ -3307,10 +3261,8 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
int32_t sampleLoopEnd;
|
int32_t sampleLoopEnd;
|
||||||
int32_t sampleLoopLength;
|
int32_t sampleLoopLength;
|
||||||
int32_t samplePosition;
|
int32_t samplePosition;
|
||||||
int32_t samplingInterpolation;
|
|
||||||
int8_t lastDelta;
|
int8_t lastDelta;
|
||||||
int32_t interpolating;
|
int32_t interpolating;
|
||||||
int32_t oversampleCount;
|
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
float volume;
|
float volume;
|
||||||
float sample;
|
float sample;
|
||||||
|
@ -3326,12 +3278,10 @@ static inline void mixadpcm(PLAYER *p, uint8_t ch, uint32_t samples)
|
||||||
panningL = p->voice[ch].panningL;
|
panningL = p->voice[ch].panningL;
|
||||||
panningR = p->voice[ch].panningR;
|
panningR = p->voice[ch].panningR;
|
||||||
interpolating = p->voice[ch].interpolating;
|
interpolating = p->voice[ch].interpolating;
|
||||||
oversampleCount = p->voice[ch].oversampleCount;
|
|
||||||
lastDelta = p->voice[ch].lastDelta;
|
lastDelta = p->voice[ch].lastDelta;
|
||||||
|
|
||||||
sampleDictionary = p->voice[ch].sampleData;
|
sampleDictionary = p->voice[ch].sampleData;
|
||||||
sampleData = (uint8_t*)sampleDictionary + 16;
|
sampleData = (uint8_t*)sampleDictionary + 16;
|
||||||
samplingInterpolation = p->samplingInterpolation ? 1 : 32;
|
|
||||||
|
|
||||||
while (p->voice[ch].lastSamplePosition < p->voice[ch].samplePosition)
|
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];
|
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)
|
for (j = 0; (j < samples) && sampleData; ++j)
|
||||||
{
|
{
|
||||||
samplePosition = p->voice[ch].samplePosition;
|
samplePosition = p->voice[ch].samplePosition;
|
||||||
|
|
||||||
while (interpolating && sinc_resampler_get_free_count(resampler))
|
while (interpolating && resampler_get_free_count(resampler))
|
||||||
{
|
{
|
||||||
int8_t nextDelta = lastDelta;
|
int8_t nextDelta = lastDelta;
|
||||||
int16_t sample = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &nextDelta) * 256;
|
int16_t sample = get_adpcm_sample(sampleDictionary, sampleData, samplePosition, &nextDelta) * 256;
|
||||||
|
|
||||||
for (; oversampleCount < samplingInterpolation && sinc_resampler_get_free_count(resampler); ++oversampleCount)
|
resampler_write_sample(resampler, sample);
|
||||||
sinc_resampler_write_sample(resampler, sample);
|
|
||||||
|
|
||||||
if (oversampleCount < samplingInterpolation)
|
|
||||||
break;
|
|
||||||
|
|
||||||
lastDelta = nextDelta;
|
lastDelta = nextDelta;
|
||||||
|
|
||||||
samplePosition++;
|
samplePosition++;
|
||||||
oversampleCount = 0;
|
|
||||||
|
|
||||||
if (loopEnabled)
|
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].samplePosition = samplePosition;
|
||||||
p->voice[ch].lastSamplePosition = samplePosition;
|
p->voice[ch].lastSamplePosition = samplePosition;
|
||||||
p->voice[ch].interpolating = (int8_t)interpolating;
|
p->voice[ch].interpolating = (int8_t)interpolating;
|
||||||
p->voice[ch].oversampleCount = (int8_t)oversampleCount;
|
|
||||||
p->voice[ch].lastDelta = lastDelta;
|
p->voice[ch].lastDelta = lastDelta;
|
||||||
|
|
||||||
if ( !sinc_resampler_ready(resampler) )
|
if ( !resampler_ready(resampler) )
|
||||||
{
|
{
|
||||||
p->voice[ch].mixing = 0;
|
p->voice[ch].mixing = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample = sinc_resampler_get_sample(resampler);
|
sample = resampler_get_sample(resampler);
|
||||||
sinc_resampler_remove_sample(resampler);
|
resampler_remove_sample(resampler);
|
||||||
|
|
||||||
sample *= volume;
|
sample *= volume;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue