diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/audiostream.cpp | 64 | ||||
-rw-r--r-- | sound/audiostream.h | 10 | ||||
-rw-r--r-- | sound/rate.cpp | 86 | ||||
-rw-r--r-- | sound/rate.h | 48 | ||||
-rw-r--r-- | sound/resample.cpp | 54 |
5 files changed, 174 insertions, 88 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 7b796b8d50..1690d58fff 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -23,47 +23,79 @@ #include "mixer.h" template<int channels, int sampleSize> -class MemoryAudioInputStream : public AudioInputStream { +class LinearMemoryStream : public AudioInputStream { protected: const byte *_ptr; const byte *_end; - void advance() { _ptr += channels * sampleSize; } + void advance() { _ptr += sampleSize; } public: - MemoryAudioInputStream(const byte *ptr, uint len) : _ptr(ptr), _end(ptr+len) { } - virtual int size() { return (_end - _ptr) / (channels * sampleSize); } + LinearMemoryStream(const byte *ptr, uint len) : _ptr(ptr), _end(ptr+len) { } + virtual int size() const { return (_end - _ptr) / sampleSize; } + virtual bool isStereo() const { return channels == 2; } }; +#if 0 +TODO: Implement a wrapped memory stream, to be used by the ChannelStream class +(and possibly others?) -template<int channels> -class Input8bitSignedStream : public MemoryAudioInputStream<channels, 1> { +template<int channels, int sampleSize> +class WrappedMemoryStream : public AudioInputStream { +protected: + byte *_bufferStart; + byte *_bufferEnd; + byte *_pos; + byte *_end; + + void advance() { + _ptr += channels * sampleSize; + .. TODO: wrap + } +public: + WrappedMemoryStream(const byte *ptr, uint len) : _bufferStart(ptr), _bufferEnd(ptr+len) { } + virtual int size() const { + int size = _end - _pos; + if (size < 0) + size += _bufferEnd - _bufferStart + return size / (channels * sampleSize); + } + + void append(const byte *ptr, uint len) { + ... + } +}; +#endif + + +template<int channels, class T = class LinearMemoryStream<channels, 1> > +class Input8bitSignedStream : public T { protected: int16 readIntern() { int8 v = (int8)*_ptr; return v << 8; } public: - Input8bitSignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 1>(ptr, len) { } + Input8bitSignedStream(const byte *ptr, int len) : T(ptr, len) { } }; -template<int channels> -class Input8bitUnsignedStream : public MemoryAudioInputStream<channels, 1> { +template<int channels, class T = class LinearMemoryStream<channels, 1> > +class Input8bitUnsignedStream : public T { protected: int16 readIntern() { int8 v = (int8)(*_ptr ^ 0x80); return v << 8; } public: - Input8bitUnsignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 1>(ptr, len) { } + Input8bitUnsignedStream(const byte *ptr, int len) : T(ptr, len) { } }; -template<int channels> -class Input16bitSignedStream : public MemoryAudioInputStream<channels, 2> { +template<int channels, class T = class LinearMemoryStream<channels, 2> > +class Input16bitSignedStream : public T { protected: int16 readIntern() { return (int16)READ_BE_UINT16(_ptr); } public: - Input16bitSignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 2>(ptr, len) { } + Input16bitSignedStream(const byte *ptr, int len) : T(ptr, len) { } }; -template<int channels> -class Input16bitUnsignedStream : public MemoryAudioInputStream<channels, 2> { +template<int channels, class T = class LinearMemoryStream<channels, 2> > +class Input16bitUnsignedStream : public T { protected: int16 readIntern() { return (int16)(READ_BE_UINT16(_ptr) ^ 0x8000); } public: - Input16bitUnsignedStream(const byte *ptr, int len) : MemoryAudioInputStream<channels, 2>(ptr, len) { } + Input16bitUnsignedStream(const byte *ptr, int len) : T(ptr, len) { } }; diff --git a/sound/audiostream.h b/sound/audiostream.h index 1eca349967..cb4e986124 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -40,9 +40,10 @@ protected: virtual void advance() = 0; public: int16 read() { assert(size() > 0); int16 val = readIntern(); advance(); return val; } - int16 peek() { assert(size() > 0); return readIntern(); } - virtual int size() = 0; - bool eof() { return size() <= 0; } +// int16 peek() { assert(size() > 0); return readIntern(); } + virtual int size() const = 0; + bool eof() const { return size() <= 0; } + virtual bool isStereo() const = 0; }; class ZeroInputStream : public AudioInputStream { @@ -52,7 +53,8 @@ protected: void advance() { _len--; } public: ZeroInputStream(uint len) : _len(len) { } - virtual int size() { return _len; } + virtual int size() const { return _len; } + virtual bool isStereo() const { return false; } }; AudioInputStream *makeInputStream(byte _flags, const byte *ptr, uint32 len); diff --git a/sound/rate.cpp b/sound/rate.cpp index c056b85a9a..5d6faaeee3 100644 --- a/sound/rate.cpp +++ b/sound/rate.cpp @@ -51,7 +51,7 @@ typedef struct ratestuff unsigned long ipos; /* position in the input stream (integer) */ - st_sample_t ilast; /* last sample in the input stream */ + st_sample_t ilast[2]; /* last sample(s) in the input stream (left/right channel) */ } *rate_t; /* @@ -83,7 +83,8 @@ int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate) rate->ipos = 0; - rate->ilast = 0; + rate->ilast[0] = 0; + rate->ilast[1] = 0; return (ST_SUCCESS); } @@ -91,23 +92,29 @@ int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate) * Processed signed long samples from ibuf to obuf. * Return number of samples processed. */ +template<int channels> int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { rate_t rate = (rate_t) effp->priv; st_sample_t *ostart, *oend; - st_sample_t ilast, icur, out; + st_sample_t ilast[2], icur[2], out; unsigned long tmp; + int i; - ilast = rate->ilast; + assert(channels == 1 || channels == 2); + + for (i = 0; i < channels; i++) + ilast[i] = rate->ilast[i]; ostart = obuf; oend = obuf + *osamp; while (obuf < oend && !input.eof()) { - /* read as many input samples so that ipos > opos */ + /* read enough input samples so that ipos > opos */ while (rate->ipos <= rate->opos) { - ilast = input.read(); + for (i = 0; i < channels; i++) + ilast[i] = input.read(); rate->ipos++; /* See if we finished the input buffer yet */ @@ -115,25 +122,64 @@ int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size goto the_end; } - icur = input.peek(); - - /* interpolate */ - out = ilast + (((icur - ilast) * rate->opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS); + // read the input sample(s) + icur[0] = input.read(); + if (channels == 2) { + if (input.eof()) + goto the_end; // Shouldn't happen if data comes pair-wise + icur[1] = input.read(); + } - /* output sample & increment position */ - out = out * vol / 256; - clampedAdd(*obuf++, out); - #if 1 // FIXME: Hack to generate stereo output - clampedAdd(*obuf++, out); - #endif + while (rate->ipos > rate->opos) { + for (i = 0; i < channels; i++) { + // interpolate + out = ilast[i] + (((icur[i] - ilast[i]) * rate->opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS); + + // adjust volume + out = out * vol / 256; + + // output left channel sample + clampedAdd(*obuf++, out); + } + + // For mono input, repeat the sample to produce stereo output + if (channels == 1) + clampedAdd(*obuf++, out); + + // Increment output position + tmp = rate->opos_frac + rate->opos_inc_frac; + rate->opos = rate->opos + rate->opos_inc + (tmp >> FRAC_BITS); + rate->opos_frac = tmp & ((1UL << FRAC_BITS) - 1); + } - tmp = rate->opos_frac + rate->opos_inc_frac; - rate->opos = rate->opos + rate->opos_inc + (tmp >> FRAC_BITS); - rate->opos_frac = tmp & ((1UL << FRAC_BITS) - 1); + // Increment input position again (for the sample we read now) + rate->ipos++; + for (i = 0; i < channels; i++) + ilast[i] = icur[i]; } the_end: *osamp = obuf - ostart; - rate->ilast = ilast; + for (i = 0; i < channels; i++) + rate->ilast[i] = ilast[i]; + return (ST_SUCCESS); +} + + +#pragma mark - + + +LinearRateConverter::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) { + st_rate_start(&effp, inrate, outrate); +} + +int LinearRateConverter::flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { + if (input.isStereo()) + return st_rate_flow<2>(&effp, input, obuf, osamp, vol); + else + return st_rate_flow<1>(&effp, input, obuf, osamp, vol); +} + +int LinearRateConverter::drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { return (ST_SUCCESS); } diff --git a/sound/rate.h b/sound/rate.h index c84e33a2ad..080107c831 100644 --- a/sound/rate.h +++ b/sound/rate.h @@ -56,17 +56,6 @@ static inline void clampedAdd(int16& a, int b) { #define st_fail error -// Resample (high quality) -int st_resample_getopts(eff_t effp, int n, const char **argv); -int st_resample_start(eff_t effp, st_rate_t inrate, st_rate_t outrate); -int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); -int st_resample_drain(eff_t effp, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); -int st_resample_stop(eff_t effp); - -// Rate (linear filter, low quality) -int st_rate_start(eff_t effp, st_rate_t inrate, st_rate_t outrate); -int st_rate_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); - class RateConverter { protected: eff_struct effp; @@ -79,40 +68,17 @@ public: class LinearRateConverter : public RateConverter { public: - LinearRateConverter(st_rate_t inrate, st_rate_t outrate) { - st_rate_start(&effp, inrate, outrate); - } - virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { - return st_rate_flow(&effp, input, obuf, osamp, vol); - } - virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { - return (ST_SUCCESS); - } + LinearRateConverter(st_rate_t inrate, st_rate_t outrate); + virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); + virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); }; class ResampleRateConverter : public RateConverter { public: - ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality) { - // FIXME: quality is for now a nasty hack. - // Valid values are 0,1,2,3 (everything else is treated like 0 for now) - const char *arg = 0; - switch (quality) { - case 1: arg = "-qs"; break; - case 2: arg = "-q"; break; - case 3: arg = "-ql"; break; - } - st_resample_getopts(&effp, arg ? 1 : 0, &arg); - st_resample_start(&effp, inrate, outrate); - } - ~ResampleRateConverter() { - st_resample_stop(&effp); - } - virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { - return st_resample_flow(&effp, input, obuf, osamp, vol); - } - virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { - return st_resample_drain(&effp, obuf, osamp, vol); - } + ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality); + ~ResampleRateConverter(); + virtual int flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); + virtual int drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol); }; #endif diff --git a/sound/resample.cpp b/sound/resample.cpp index 3bbd3d18ca..a621d89213 100644 --- a/sound/resample.cpp +++ b/sound/resample.cpp @@ -274,6 +274,16 @@ int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_ const long obufSize = *osamp; #endif +TODO: adjust for the changes made to AudioInputStream; add support for stereo +initially, could just average the left/right channel -> bad for quality of course, +but easiest to implement and would get this going again. +Next step is to duplicate the X/Y buffers... a lot of computations don't care about +how many channels there are anyway, they could just be ran twice, e.g. SrcEX and SrcUD. +But better for efficiency would be to rewrite those to deal with 2 channels, too. +Because esp in SrcEX/SrcUD, only very few computations depend on the input data, +and dealing with both channels in parallel should only be a little slower than dealing +with them alone + // Constrain amount we actually process //fprintf(stderr,"Xp %d, Xread %d\n",r->Xp, r->Xread); @@ -313,7 +323,6 @@ int st_resample_flow(eff_t effp, AudioInputStream &input, st_sample_t *obuf, st_ // Finally compute the effective number of bytes to process Nproc = last - r->Xoff - r->Xp; -printf("FOO(3) Nproc %ld\n", Nproc); if (Nproc <= 0) { /* fill in starting here next time */ @@ -356,7 +365,7 @@ printf("FOO(3) Nproc %ld\n", Nproc); /* Copy back portion of input signal that must be re-used */ k = r->Xp - r->Xoff; - fprintf(stderr,"k %d, last %d\n",k,last); + //fprintf(stderr,"k %d, last %d\n",k,last); for (i = 0; i < last - k; i++) r->X[i] = r->X[i + k]; @@ -370,7 +379,8 @@ printf("osamp = %ld, Nout = %ld\n", obufSize, Nout); int sample = (int)(r->Y[i] * vol / 256); clampedAdd(*obuf++, sample); #if 1 // FIXME: Hack to generate stereo output - clampedAdd(*obuf++, sample); +// clampedAdd(*obuf++, sample); + *obuf++; #endif } @@ -514,12 +524,12 @@ static long SrcUD(resample_t r, long Nx) { Factor = r->Factor; time = r->Time; dt = 1.0 / Factor; /* Output sampling period */ - fprintf(stderr,"Factor %f, dt %f, ",Factor,dt); - fprintf(stderr,"Time %f, ",r->Time); + //fprintf(stderr,"Factor %f, dt %f, ",Factor,dt); + //fprintf(stderr,"Time %f, ",r->Time); /* (Xh * dhb)>>La is max index into Imp[] */ /*fprintf(stderr,"ct=%d\n",ct);*/ - fprintf(stderr,"ct=%.2f %d\n",(double)r->Nwing*Na/r->dhb, r->Xh); - fprintf(stderr,"ct=%ld, T=%.6f, dhb=%6f, dt=%.6f\n", r->Xh, time-floor(time),(double)r->dhb/Na,dt); + //fprintf(stderr,"ct=%.2f %d\n",(double)r->Nwing*Na/r->dhb, r->Xh); + //fprintf(stderr,"ct=%ld, T=%.6f, dhb=%6f, dt=%.6f\n", r->Xh, time-floor(time),(double)r->dhb/Na,dt); Ystart = Y = r->Y + r->Yposition; n = (int)ceil((double)Nx / dt); while (n--) { @@ -722,3 +732,33 @@ static void LpFilter(double *c, long N, double frq, double Beta, long Num) { } } } + + +#pragma mark - + + +ResampleRateConverter::ResampleRateConverter(st_rate_t inrate, st_rate_t outrate, int quality) { + // FIXME: quality is for now a nasty hack. + // Valid values are 0,1,2,3 (everything else is treated like 0 for now) + const char *arg = 0; + switch (quality) { + case 1: arg = "-qs"; break; + case 2: arg = "-q"; break; + case 3: arg = "-ql"; break; + } + st_resample_getopts(&effp, arg ? 1 : 0, &arg); + st_resample_start(&effp, inrate, outrate); +} + +ResampleRateConverter::~ResampleRateConverter() { + st_resample_stop(&effp); +} + +int ResampleRateConverter::flow(AudioInputStream &input, st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { + return st_resample_flow(&effp, input, obuf, osamp, vol); +} + +int ResampleRateConverter::drain(st_sample_t *obuf, st_size_t *osamp, st_volume_t vol) { + return st_resample_drain(&effp, obuf, osamp, vol); +} + |