From 27243e074c3329185ea887bb3a857e340b3388a4 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 24 Jul 2004 01:22:10 +0000 Subject: [PATCH] working on variable channel count support (to allow preloading mono samples in half memory, and to avoid redundant resampling in mono files) --- stepmania/src/RageSoundReader.h | 1 + stepmania/src/RageSoundReader_Preload.cpp | 6 +- stepmania/src/RageSoundReader_Preload.h | 5 +- .../src/RageSoundReader_Resample_Fast.cpp | 1 + stepmania/src/RageSoundReader_Resample_Fast.h | 1 + .../src/RageSoundReader_Resample_Good.cpp | 92 +++++++++++-------- stepmania/src/RageSoundReader_Resample_Good.h | 12 ++- stepmania/src/RageSoundResampler.cpp | 17 ++-- stepmania/src/RageSoundResampler.h | 6 +- 9 files changed, 83 insertions(+), 58 deletions(-) diff --git a/stepmania/src/RageSoundReader.h b/stepmania/src/RageSoundReader.h index f0581ec054..0562698f69 100644 --- a/stepmania/src/RageSoundReader.h +++ b/stepmania/src/RageSoundReader.h @@ -21,6 +21,7 @@ public: virtual ~SoundReader() { } virtual SoundReader *Copy() const = 0; virtual int GetSampleRate() const = 0; + virtual unsigned GetNumChannels() const { return 2; } /* 1 or 2 */ bool Error() const { return !error.empty(); } string GetError() const { return error; } diff --git a/stepmania/src/RageSoundReader_Preload.cpp b/stepmania/src/RageSoundReader_Preload.cpp index 5c8638aee6..dc7975b321 100644 --- a/stepmania/src/RageSoundReader_Preload.cpp +++ b/stepmania/src/RageSoundReader_Preload.cpp @@ -5,8 +5,7 @@ #include "RageSoundReader_Preload.h" #include "PrefsManager.h" -const int channels = 2; -const int samplesize = 2 * channels; /* 16-bit */ +#define samplesize (2 * channels) /* 16-bit */ /* If a sound is smaller than this, we'll load it entirely into memory. */ const unsigned max_prebuf_size = 1024*256; @@ -20,7 +19,8 @@ bool SoundReader_Preload::Open(SoundReader *source) { ASSERT(source); samplerate = source->GetSampleRate(); - + channels = source->GetNumChannels(); + /* Check the length, and see if we think it'll fit in the buffer. */ int len = source->GetLength_Fast(); if(len != -1) diff --git a/stepmania/src/RageSoundReader_Preload.h b/stepmania/src/RageSoundReader_Preload.h index fd0301e844..1e69b60607 100644 --- a/stepmania/src/RageSoundReader_Preload.h +++ b/stepmania/src/RageSoundReader_Preload.h @@ -22,7 +22,8 @@ public: const string &get() const; }; -class SoundReader_Preload: public SoundReader { +class SoundReader_Preload: public SoundReader +{ rc_string buf; /* Bytes: */ @@ -31,6 +32,7 @@ class SoundReader_Preload: public SoundReader { int total_samples() const; int samplerate; + unsigned channels; float OffsetFix; public: @@ -43,6 +45,7 @@ public: int SetPosition_Fast(int ms); int Read(char *buf, unsigned len); int GetSampleRate() const { return samplerate; } + unsigned GetNumChannels() const { return channels; } SoundReader *Copy() const; ~SoundReader_Preload() { } diff --git a/stepmania/src/RageSoundReader_Resample_Fast.cpp b/stepmania/src/RageSoundReader_Resample_Fast.cpp index bcd11c23df..24292ff6f4 100644 --- a/stepmania/src/RageSoundReader_Resample_Fast.cpp +++ b/stepmania/src/RageSoundReader_Resample_Fast.cpp @@ -14,6 +14,7 @@ void RageSoundReader_Resample_Fast::Open(SoundReader *source_) samplerate = source->GetSampleRate(); resamp.SetInputSampleRate(samplerate); + resamp.SetChannels( source->GetNumChannels() ); } diff --git a/stepmania/src/RageSoundReader_Resample_Fast.h b/stepmania/src/RageSoundReader_Resample_Fast.h index 8f3f98a5f7..a92a24aa97 100644 --- a/stepmania/src/RageSoundReader_Resample_Fast.h +++ b/stepmania/src/RageSoundReader_Resample_Fast.h @@ -32,6 +32,7 @@ public: void SetSampleRate(int hz); int GetSampleRate() const { return samplerate; } + unsigned GetNumChannels() const { return source->GetNumChannels(); } }; #endif diff --git a/stepmania/src/RageSoundReader_Resample_Good.cpp b/stepmania/src/RageSoundReader_Resample_Good.cpp index d014a2c35c..914a14b3e6 100644 --- a/stepmania/src/RageSoundReader_Resample_Good.cpp +++ b/stepmania/src/RageSoundReader_Resample_Good.cpp @@ -20,10 +20,12 @@ #include "RageTimer.h" +#define channels source->GetNumChannels() + RageSoundReader_Resample_Good::RageSoundReader_Resample_Good() { - resamp[0] = resamp[1] = NULL; source = NULL; + empty_resamp = NULL; samplerate = -1; BufSamples = 0; eof = false; @@ -37,12 +39,13 @@ void RageSoundReader_Resample_Good::Reset() eof = false; /* Flush the resampler. */ - for( int i = 0; i < 2; ++i ) + for( unsigned i = 0; i < resamplers.size(); ++i ) { - if( resamp[i] ) - resample_close( resamp[i] ); + resample_channel &r = resamplers[i]; + if( r.resamp ) + resample_close( r.resamp ); - resamp[i] = resample_dup( empty_resamp[i] ); + r.resamp = resample_dup( empty_resamp ); } } @@ -50,13 +53,16 @@ void RageSoundReader_Resample_Good::Reset() /* Call this if the sample factor changes. */ void RageSoundReader_Resample_Good::ReopenResampler() { - for( int i = 0; i < 2; ++i ) - { - if( resamp[i] ) - resample_close( resamp[i] ); + if( empty_resamp ) + resample_close( empty_resamp ); + empty_resamp = resample_open( HighQuality, GetFactor()-0.1f, GetFactor()+0.1f ); - resamp[i] = resample_open( HighQuality, GetFactor()-0.1f, GetFactor()+0.1f ); - empty_resamp[i] = resample_dup( resamp[i] ); + for( unsigned i = 0; i < resamplers.size(); ++i ) + { + resample_channel &r = resamplers[i]; + if( r.resamp ) + resample_close( r.resamp ); + r.resamp = resample_dup( empty_resamp ); } } @@ -66,19 +72,23 @@ void RageSoundReader_Resample_Good::Open(SoundReader *source_) ASSERT(source); samplerate = source->GetSampleRate(); + + for( unsigned i = 0; i < source->GetNumChannels(); ++i ) + resamplers.push_back( resample_channel() ); } RageSoundReader_Resample_Good::~RageSoundReader_Resample_Good() { - for( int i = 0; i < 2; ++i ) + for( unsigned i = 0; i < resamplers.size(); ++i ) { - if( resamp[i] ) - resample_close( resamp[i] ); - if( empty_resamp[i] ) - resample_close( empty_resamp[i] ); + if( resamplers[i].resamp ) + resample_close( resamplers[i].resamp ); } + if( empty_resamp ) + resample_close( empty_resamp ); + delete source; } @@ -123,8 +133,9 @@ bool RageSoundReader_Resample_Good::FillBuf() if( !samples_free ) return true; - int16_t tmpbuf[BUFSIZE*2]; - int cnt = source->Read((char *) tmpbuf, samples_free * sizeof(int16_t) * 2); + const int bytes_per_frame = sizeof(int16_t)*channels; + int16_t *tmpbuf = (int16_t *) alloca( BUFSIZE*bytes_per_frame ); + int cnt = source->Read( (char *) tmpbuf, samples_free * bytes_per_frame ); if( cnt == -1 ) { @@ -132,16 +143,16 @@ bool RageSoundReader_Resample_Good::FillBuf() return false; } - if( (unsigned) cnt < samples_free * sizeof(int16_t) * 2 ) + if( cnt < samples_free * bytes_per_frame ) eof = true; - cnt /= sizeof(int16_t); - cnt /= 2; + cnt /= bytes_per_frame; - for( int c = 0; c < 2; ++c ) + for( unsigned i = 0; i < channels; ++i ) { + resample_channel &r = resamplers[i]; for( int s = 0; s < cnt; ++s ) - inbuf[c][s+BufSamples] = tmpbuf[s*2+c]; + r.inbuf[s+BufSamples] = tmpbuf[s*resamplers.size()+i]; } BufSamples += cnt; return true; @@ -150,7 +161,7 @@ bool RageSoundReader_Resample_Good::FillBuf() int RageSoundReader_Resample_Good::Read(char *bufp, unsigned len) { int16_t *buf = (int16_t *) bufp; - len /= 2; + len /= sizeof(int16_t); /* bytes -> samples */ const float factor = GetFactor(); int bytes_read = 0; @@ -159,24 +170,25 @@ int RageSoundReader_Resample_Good::Read(char *bufp, unsigned len) int samples_used = 0, samples_output = 0; if( BufSamples ) { - for( int c = 0; c < 2; ++c ) + for( unsigned i = 0; i < channels; ++i ) { - ASSERT( resamp[c] ); + resample_channel &r = resamplers[i]; + ASSERT( r.resamp ); float outbuf[BUFSIZE]; - samples_output = resample_process(resamp[c], + samples_output = resample_process( r.resamp, factor, - inbuf[c], BufSamples, + r.inbuf, BufSamples, eof, &samples_used, - outbuf, len/2); + outbuf, len/channels); if( samples_output == -1 ) RageException::Throw( "Unexpected resample_process return value: -1" ); - memmove( inbuf[c], &inbuf[c][samples_used], sizeof(float) * (BufSamples-samples_used) ); + memmove( r.inbuf, &r.inbuf[samples_used], sizeof(float) * (BufSamples-samples_used) ); for( int s = 0; s < samples_output; ++s ) { - buf[s*2+c] = int16_t(clamp(outbuf[s], -32768, 32767)); + buf[s*channels+i] = int16_t(clamp(outbuf[s], -32768, 32767)); } } } @@ -193,9 +205,9 @@ int RageSoundReader_Resample_Good::Read(char *bufp, unsigned len) return -1; /* source error */ } - len -= samples_output*2; - buf += samples_output*2; - bytes_read += samples_output*2*sizeof(int16_t); + len -= samples_output*channels; + buf += samples_output*channels; + bytes_read += samples_output*channels*sizeof(int16_t); } } @@ -204,16 +216,18 @@ SoundReader *RageSoundReader_Resample_Good::Copy() const SoundReader *new_source = source->Copy(); RageSoundReader_Resample_Good *ret = new RageSoundReader_Resample_Good; - for( int c = 0; c < 2; ++c ) + for( unsigned i = 0; i < channels; ++i ) { - ASSERT( resamp[c] ); - ret->resamp[c] = resample_dup( resamp[c] ); - ret->empty_resamp[c] = resample_dup( empty_resamp[c] ); + const resample_channel &r = resamplers[i]; + ASSERT( r.resamp ); + ret->resamplers.push_back( resample_channel() ); + ret->resamplers[i].resamp = resample_dup( r.resamp ); + memcpy( ret->resamplers[i].inbuf, r.inbuf, sizeof(r.inbuf)); } + ret->empty_resamp = resample_dup( empty_resamp ); ret->source = new_source; ret->HighQuality = HighQuality; ret->samplerate = samplerate; - memcpy( ret->inbuf, inbuf, sizeof(inbuf)); ret->BufSamples = BufSamples; ret->eof = eof; diff --git a/stepmania/src/RageSoundReader_Resample_Good.h b/stepmania/src/RageSoundReader_Resample_Good.h index 8c3e135ee0..110e0df965 100644 --- a/stepmania/src/RageSoundReader_Resample_Good.h +++ b/stepmania/src/RageSoundReader_Resample_Good.h @@ -13,9 +13,14 @@ class RageSoundReader_Resample_Good: public RageSoundReader_Resample bool HighQuality; int samplerate; - void *resamp[2]; - void *empty_resamp[2]; - float inbuf[2][BUFSIZE]; + void *empty_resamp; + struct resample_channel + { + resample_channel(): resamp(NULL) { } + void *resamp; + float inbuf[BUFSIZE]; + }; + vector resamplers; /* one per channel */ int BufSamples; bool eof; @@ -41,6 +46,7 @@ public: void SetHighQuality( bool hq ) { HighQuality = hq; } int GetSampleRate() const { return samplerate; } + unsigned GetNumChannels() const { return source->GetNumChannels(); } }; #endif diff --git a/stepmania/src/RageSoundResampler.cpp b/stepmania/src/RageSoundResampler.cpp index 65df022e09..772ab7bac1 100644 --- a/stepmania/src/RageSoundResampler.cpp +++ b/stepmania/src/RageSoundResampler.cpp @@ -10,8 +10,6 @@ * one. I'll optimize it if it becomes an issue. */ -const int channels = 2; - RageSoundResampler::RageSoundResampler() { reset(); @@ -24,6 +22,7 @@ void RageSoundResampler::reset() memset(t, 0, sizeof(t)); outbuf.clear(); ipos = 0; + Channels = 2; } @@ -35,7 +34,7 @@ void RageSoundResampler::write(const void *data_, int bytes) const int16_t *data = (const int16_t *) data_; const unsigned samples = bytes / sizeof(int16_t); - const unsigned frames = samples / channels; + const unsigned frames = samples / Channels; if(InputRate == OutputRate) { @@ -55,7 +54,7 @@ void RageSoundResampler::write(const void *data_, int bytes) int ipos_begin = (int) roundf(ipos / div); int ipos_end = (int) roundf((ipos+1) / div); - for(int c = 0; c < channels; ++c) + for(int c = 0; c < Channels; ++c) { const float f = 0.5f; prev[c] = int16_t(prev[c] * (f) + data[c] * (1-f)); @@ -64,14 +63,14 @@ void RageSoundResampler::write(const void *data_, int bytes) } ipos++; } - data += channels; + data += Channels; } #else /* Lerp. */ const float div = float(InputRate) / OutputRate; for(unsigned f = 0; f < frames; ++f) { - for(int c = 0; c < channels; ++c) + for(int c = 0; c < Channels; ++c) { while(t[c] < 1.0f) { @@ -85,7 +84,7 @@ void RageSoundResampler::write(const void *data_, int bytes) } ipos++; - data += channels; + data += Channels; } #endif } @@ -98,13 +97,13 @@ void RageSoundResampler::eof() /* Write some silence to flush out the real data. If we don't have any sound, * don't do this, so seeking past end of file doesn't write silence. */ bool bNeedsFlush = false; - for( int c = 0; c < channels; ++c ) + for( int c = 0; c < Channels; ++c ) if( prev[c] != 0 ) bNeedsFlush = true; if( bNeedsFlush ) { - const int size = channels*16; + const int size = Channels*16; int16_t *data = new int16_t[size]; memset(data, 0, size * sizeof(int16_t)); write(data, size * sizeof(int16_t)); diff --git a/stepmania/src/RageSoundResampler.h b/stepmania/src/RageSoundResampler.h index cab20a0f7c..3ee9dd46c7 100644 --- a/stepmania/src/RageSoundResampler.h +++ b/stepmania/src/RageSoundResampler.h @@ -1,12 +1,11 @@ #ifndef RAGE_SOUND_RESAMPLER_H #define RAGE_SOUND_RESAMPLER_H -enum { MAX_CHANNELS = 15 }; - class RageSoundResampler { - int InputRate, OutputRate; + int InputRate, OutputRate, Channels; + enum { MAX_CHANNELS = 15 }; int16_t prev[MAX_CHANNELS]; vector outbuf; @@ -19,6 +18,7 @@ public: RageSoundResampler(); /* Configuration: */ + void SetChannels( int c ) { ASSERT( c < MAX_CHANNELS ); Channels = c; } void SetInputSampleRate(int hz) { InputRate = hz; } void SetOutputSampleRate(int hz) { OutputRate = hz; }