use a single converter for both channels (if input data is stereo), for improved efficency; renamed MemoryAudioInputStream -> LinearMemoryStream and use some template voodoo to make the baseclass of Input8bitSignedStream etc. variable; added (commented out) draf of WrappedMemoryStream

svn-id: r9209
This commit is contained in:
Max Horn 2003-07-28 01:13:31 +00:00
parent 12d872f754
commit e87bc6d89e
5 changed files with 174 additions and 88 deletions

View file

@ -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) { }
};

View file

@ -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);

View file

@ -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();
// 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();
}
/* interpolate */
out = ilast + (((icur - ilast) * rate->opos_frac + (1UL << (FRAC_BITS-1))) >> FRAC_BITS);
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);
/* output sample & increment position */
// adjust volume
out = out * vol / 256;
clampedAdd(*obuf++, out);
#if 1 // FIXME: Hack to generate stereo output
clampedAdd(*obuf++, out);
#endif
// 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);
}
// 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);
}

View file

@ -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

View file

@ -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);
}