aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/audiostream.cpp64
-rw-r--r--sound/audiostream.h10
-rw-r--r--sound/rate.cpp86
-rw-r--r--sound/rate.h48
-rw-r--r--sound/resample.cpp54
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);
+}
+