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:
parent
12d872f754
commit
e87bc6d89e
5 changed files with 174 additions and 88 deletions
|
@ -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) { }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
48
sound/rate.h
48
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue