From 6954e0facf6aabc4698ba094d9eb9ced71bafdf8 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Wed, 24 Sep 2003 22:31:34 +0000 Subject: [PATCH] Move the linear resampler to RageSoundReader_Resample_Fast. Add RageSoundReader_Resample_Good, using libresample. --- stepmania/src/RageSoundReader_Resample.cpp | 112 ++------- stepmania/src/RageSoundReader_Resample.h | 21 +- .../src/RageSoundReader_Resample_Fast.cpp | 103 ++++++++ stepmania/src/RageSoundReader_Resample_Fast.h | 41 ++++ .../src/RageSoundReader_Resample_Good.cpp | 224 ++++++++++++++++++ stepmania/src/RageSoundReader_Resample_Good.h | 52 ++++ 6 files changed, 440 insertions(+), 113 deletions(-) create mode 100644 stepmania/src/RageSoundReader_Resample_Fast.cpp create mode 100644 stepmania/src/RageSoundReader_Resample_Fast.h create mode 100644 stepmania/src/RageSoundReader_Resample_Good.cpp create mode 100644 stepmania/src/RageSoundReader_Resample_Good.h diff --git a/stepmania/src/RageSoundReader_Resample.cpp b/stepmania/src/RageSoundReader_Resample.cpp index 4732fbc79b..44e8c8cd08 100644 --- a/stepmania/src/RageSoundReader_Resample.cpp +++ b/stepmania/src/RageSoundReader_Resample.cpp @@ -1,103 +1,23 @@ #include "global.h" #include "RageSoundReader_Resample.h" +#include "RageSoundReader_Resample_Fast.h" +#include "RageSoundReader_Resample_Good.h" -RageSoundReader_Resample::RageSoundReader_Resample() +RageSoundReader_Resample *RageSoundReader_Resample::MakeResampler( ResampleQuality q ) { - source = NULL; - samplerate = -1; -} - -void RageSoundReader_Resample::Open(SoundReader *source_) -{ - source = source_; - ASSERT(source); - - samplerate = source->GetSampleRate(); - resamp.SetInputSampleRate(samplerate); -} - - -RageSoundReader_Resample::~RageSoundReader_Resample() -{ - delete source; -} - -void RageSoundReader_Resample::SetSampleRate(int hz) -{ - samplerate = hz; - resamp.SetOutputSampleRate(samplerate); -} - -int RageSoundReader_Resample::GetLength() const -{ - resamp.reset(); - return source->GetLength(); -} - -int RageSoundReader_Resample::GetLength_Fast() const -{ - resamp.reset(); - return source->GetLength_Fast(); -} - -int RageSoundReader_Resample::SetPosition_Accurate(int ms) -{ - resamp.reset(); - return source->SetPosition_Accurate(ms); -} - -int RageSoundReader_Resample::SetPosition_Fast(int ms) -{ - resamp.reset(); - return source->SetPosition_Fast(ms); -} -static const int BUFSIZE = 1024*16; - -int RageSoundReader_Resample::Read(char *buf, unsigned len) -{ - int bytes_read = 0; - while(len) + switch( q ) { - int size = resamp.read(buf, len); - - if(size == -1) - break; - - buf += size; - len -= size; - bytes_read += size; - - if(size == 0) - { - static char buf[BUFSIZE]; - - int cnt = source->Read(buf, sizeof(buf)); - - if(cnt == -1) - { - SetError(source->GetError()); - return -1; - } - if(cnt == 0) - resamp.eof(); - else - resamp.write(buf, cnt); - } + case RESAMP_FAST: + return new RageSoundReader_Resample_Fast; + case RESAMP_NORMAL: + case RESAMP_HIGHQUALITY: + { + RageSoundReader_Resample_Good *ret = new RageSoundReader_Resample_Good; + ret->SetHighQuality( q == RESAMP_HIGHQUALITY ); + return ret; + } + default: + ASSERT(0); + return NULL; } - - return bytes_read; } - -SoundReader *RageSoundReader_Resample::Copy() const -{ - SoundReader *new_source = source->Copy(); - RageSoundReader_Resample *ret = new RageSoundReader_Resample; - ret->Open(new_source); - ret->SetSampleRate(samplerate); - return ret; -} - -/* - * Copyright (c) 2003 by the person(s) listed below. All rights reserved. - * Glenn Maynard - */ diff --git a/stepmania/src/RageSoundReader_Resample.h b/stepmania/src/RageSoundReader_Resample.h index b8b7ff1140..307a73771a 100644 --- a/stepmania/src/RageSoundReader_Resample.h +++ b/stepmania/src/RageSoundReader_Resample.h @@ -7,28 +7,15 @@ /* This class changes the sampling rate of a sound. */ class RageSoundReader_Resample: public SoundReader { - int samplerate; - - SoundReader *source; - - mutable RageSoundResampler resamp; - public: /* We own source. */ - void Open(SoundReader *source); - int GetLength() const; - int GetLength_Fast() const; - int SetPosition_Accurate(int ms); - int SetPosition_Fast(int ms); - int Read(char *buf, unsigned len); - RageSoundReader_Resample(); - virtual ~RageSoundReader_Resample(); - SoundReader *Copy() const; + virtual void Open(SoundReader *source) = 0; /* Change the actual sample rate of a sound. */ - void SetSampleRate(int hz); + virtual void SetSampleRate(int hz) = 0; - int GetSampleRate() const { return samplerate; } + enum ResampleQuality { RESAMP_FAST, RESAMP_NORMAL, RESAMP_HIGHQUALITY }; + static RageSoundReader_Resample *MakeResampler( ResampleQuality q ); }; #endif diff --git a/stepmania/src/RageSoundReader_Resample_Fast.cpp b/stepmania/src/RageSoundReader_Resample_Fast.cpp new file mode 100644 index 0000000000..901abdf7a5 --- /dev/null +++ b/stepmania/src/RageSoundReader_Resample_Fast.cpp @@ -0,0 +1,103 @@ +#include "global.h" +#include "RageSoundReader_Resample_Fast.h" + +RageSoundReader_Resample_Fast::RageSoundReader_Resample_Fast() +{ + source = NULL; + samplerate = -1; +} + +void RageSoundReader_Resample_Fast::Open(SoundReader *source_) +{ + source = source_; + ASSERT(source); + + samplerate = source->GetSampleRate(); + resamp.SetInputSampleRate(samplerate); +} + + +RageSoundReader_Resample_Fast::~RageSoundReader_Resample_Fast() +{ + delete source; +} + +void RageSoundReader_Resample_Fast::SetSampleRate(int hz) +{ + samplerate = hz; + resamp.SetOutputSampleRate(samplerate); +} + +int RageSoundReader_Resample_Fast::GetLength() const +{ + resamp.reset(); + return source->GetLength(); +} + +int RageSoundReader_Resample_Fast::GetLength_Fast() const +{ + resamp.reset(); + return source->GetLength_Fast(); +} + +int RageSoundReader_Resample_Fast::SetPosition_Accurate(int ms) +{ + resamp.reset(); + return source->SetPosition_Accurate(ms); +} + +int RageSoundReader_Resample_Fast::SetPosition_Fast(int ms) +{ + resamp.reset(); + return source->SetPosition_Fast(ms); +} +static const int BUFSIZE = 1024*16; + +int RageSoundReader_Resample_Fast::Read(char *buf, unsigned len) +{ + int bytes_read = 0; + while(len) + { + int size = resamp.read(buf, len); + + if(size == -1) + break; + + buf += size; + len -= size; + bytes_read += size; + + if(size == 0) + { + static char buf[BUFSIZE]; + + int cnt = source->Read(buf, sizeof(buf)); + + if(cnt == -1) + { + SetError(source->GetError()); + return -1; + } + if(cnt == 0) + resamp.eof(); + else + resamp.write(buf, cnt); + } + } + + return bytes_read; +} + +SoundReader *RageSoundReader_Resample_Fast::Copy() const +{ + SoundReader *new_source = source->Copy(); + RageSoundReader_Resample_Fast *ret = new RageSoundReader_Resample_Fast; + ret->Open(new_source); + ret->SetSampleRate(samplerate); + return ret; +} + +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ diff --git a/stepmania/src/RageSoundReader_Resample_Fast.h b/stepmania/src/RageSoundReader_Resample_Fast.h new file mode 100644 index 0000000000..29a201cb22 --- /dev/null +++ b/stepmania/src/RageSoundReader_Resample_Fast.h @@ -0,0 +1,41 @@ +#ifndef RAGE_SOUND_READER_RESAMPLE_FAST +#define RAGE_SOUND_READER_RESAMPLE_FAST + +#include "RageSoundReader.h" +#include "RageSoundReader_Resample.h" +#include "RageSoundResampler.h" + +/* This class changes the sampling rate of a sound. */ +class RageSoundReader_Resample_Fast: public RageSoundReader_Resample +{ + int samplerate; + + bool FillBuf(); + + SoundReader *source; + + mutable RageSoundResampler resamp; + +public: + /* We own source. */ + void Open(SoundReader *source); + int GetLength() const; + int GetLength_Fast() const; + int SetPosition_Accurate(int ms); + int SetPosition_Fast(int ms); + int Read(char *buf, unsigned len); + RageSoundReader_Resample_Fast(); + virtual ~RageSoundReader_Resample_Fast(); + SoundReader *Copy() const; + + /* Change the actual sample rate of a sound. */ + void SetSampleRate(int hz); + + int GetSampleRate() const { return samplerate; } +}; + +#endif +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ diff --git a/stepmania/src/RageSoundReader_Resample_Good.cpp b/stepmania/src/RageSoundReader_Resample_Good.cpp new file mode 100644 index 0000000000..fe83286404 --- /dev/null +++ b/stepmania/src/RageSoundReader_Resample_Good.cpp @@ -0,0 +1,224 @@ +#include "global.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "RageSoundReader_Resample_Good.h" + +#include "libresample/include/resample.h" +#ifdef _WINDOWS +#pragma comment(lib, "libresample/resample.lib") +#endif + +#include "RageTimer.h" + +RageSoundReader_Resample_Good::RageSoundReader_Resample_Good() +{ + resamp[0] = resamp[1] = NULL; + source = NULL; + samplerate = -1; + BufSamples = 0; + eof = false; + HighQuality = false; +} + +/* Call this if the input position is changed or reset. */ +void RageSoundReader_Resample_Good::Reset() const +{ + BufSamples = 0; + eof = false; + FlushResampler(); +} + + +/* Call this if the input position is changed or reset. */ +void RageSoundReader_Resample_Good::FlushResampler() const +{ + for( int i = 0; i < 2; ++i ) + { + if( resamp[i] ) + resample_close( resamp[i] ); + + resamp[i] = resample_dup( empty_resamp[i] ); + } +} + +/* Call this if the sample factor changes. */ +void RageSoundReader_Resample_Good::ReopenResampler() const +{ + for( int i = 0; i < 2; ++i ) + { + if( resamp[i] ) + resample_close( resamp[i] ); + + resamp[i] = resample_open( HighQuality, GetFactor()-0.1f, GetFactor()+0.1f ); + empty_resamp[i] = resample_dup( resamp[i] ); + } +} + +void RageSoundReader_Resample_Good::Open(SoundReader *source_) +{ + source = source_; + ASSERT(source); + + samplerate = source->GetSampleRate(); +} + + +RageSoundReader_Resample_Good::~RageSoundReader_Resample_Good() +{ + for( int i = 0; i < 2; ++i ) + { + if( resamp[i] ) + resample_close( resamp[i] ); + if( empty_resamp[i] ) + resample_close( empty_resamp[i] ); + } + + delete source; +} + +float RageSoundReader_Resample_Good::GetFactor() const +{ + return float(samplerate) / source->GetSampleRate(); +} + +void RageSoundReader_Resample_Good::SetSampleRate(int hz) +{ + samplerate = hz; + ReopenResampler(); +} + +int RageSoundReader_Resample_Good::GetLength() const +{ + Reset(); + return source->GetLength(); +} + +int RageSoundReader_Resample_Good::GetLength_Fast() const +{ + Reset(); + return source->GetLength_Fast(); +} + +int RageSoundReader_Resample_Good::SetPosition_Accurate(int ms) +{ + Reset(); + return source->SetPosition_Accurate(ms); +} + +int RageSoundReader_Resample_Good::SetPosition_Fast(int ms) +{ + Reset(); + return source->SetPosition_Fast(ms); +} + +bool RageSoundReader_Resample_Good::FillBuf() +{ + int samples_free = BUFSIZE-BufSamples; + if( eof ) + return true; + if( !samples_free ) + return true; + + Sint16 tmpbuf[BUFSIZE*2]; + int cnt = source->Read((char *) tmpbuf, samples_free * sizeof(Sint16) * 2); + + if( cnt == -1 ) + { + SetError(source->GetError()); + return false; + } + + if( (unsigned) cnt < samples_free * sizeof(Sint16) * 2 ) + eof = true; + + cnt /= sizeof(Sint16); + cnt /= 2; + + for( int c = 0; c < 2; ++c ) + { + for( int s = 0; s < cnt; ++s ) + inbuf[c][s+BufSamples] = tmpbuf[s*2+c]; + } + BufSamples += cnt; + return true; +} + +int RageSoundReader_Resample_Good::Read(char *bufp, unsigned len) +{ + Sint16 *buf = (Sint16 *) bufp; + len /= 2; + const float factor = GetFactor(); + + int bytes_read = 0; + while( 1 ) + { + int samples_used = 0, samples_output = 0; + if( BufSamples ) + { + for( int c = 0; c < 2; ++c ) + { + ASSERT( resamp[c] ); + float outbuf[BUFSIZE]; + samples_output = resample_process(resamp[c], + factor, + inbuf[c], BufSamples, + eof, + &samples_used, + outbuf, len/2); + if( samples_output == -1 ) + RageException::Throw( "Unexpected resample_process return value: -1" ); + + memmove( inbuf[c], &inbuf[c][samples_used], sizeof(float) * (BufSamples-samples_used) ); + + for( int s = 0; s < samples_output; ++s ) + { + buf[s*2+c] = Sint16(clamp(outbuf[s], -32768, 32767)); + } + } + } + + BufSamples -= samples_used; + + if( !samples_output ) + { + if( !len ) + return bytes_read; /* buffer full */ + if( eof ) + return bytes_read; /* EOF and we're completely flushed */ + if( !FillBuf() ) + return -1; /* source error */ + } + + len -= samples_output*2; + buf += samples_output*2; + bytes_read += samples_output*2*sizeof(Sint16); + } +} + +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 ) + { + ASSERT( resamp[c] ); + ret->resamp[c] = resample_dup( resamp[c] ); + ret->empty_resamp[c] = resample_dup( empty_resamp[c] ); + } + ret->source = new_source; + ret->HighQuality = HighQuality; + ret->samplerate = samplerate; + memcpy( ret->inbuf, inbuf, sizeof(inbuf)); + ret->BufSamples = BufSamples; + ret->eof = eof; + +// ret->Open(new_source); +// ret->SetSampleRate(samplerate); + return ret; +} + +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */ diff --git a/stepmania/src/RageSoundReader_Resample_Good.h b/stepmania/src/RageSoundReader_Resample_Good.h new file mode 100644 index 0000000000..8eb533eff0 --- /dev/null +++ b/stepmania/src/RageSoundReader_Resample_Good.h @@ -0,0 +1,52 @@ +#ifndef RAGE_SOUND_READER_RESAMPLE_GOOD +#define RAGE_SOUND_READER_RESAMPLE_GOOD + +#include "RageSoundReader.h" +#include "RageSoundReader_Resample.h" + +/* This class changes the sampling rate of a sound. */ +class RageSoundReader_Resample_Good: public RageSoundReader_Resample +{ + enum { BUFSIZE = 4096 }; + + SoundReader *source; + bool HighQuality; + int samplerate; + + /* Mutable hell, since GetLength pretends to be const but isn't yet. */ + mutable void *resamp[2]; + mutable void *empty_resamp[2]; + float inbuf[2][BUFSIZE]; + mutable int BufSamples; + mutable bool eof; + + void Reset() const; + void FlushResampler() const; + void ReopenResampler() const; + float GetFactor() const; + bool FillBuf(); + +public: + /* We own source. */ + void Open(SoundReader *source); + int GetLength() const; + int GetLength_Fast() const; + int SetPosition_Accurate(int ms); + int SetPosition_Fast(int ms); + int Read(char *buf, unsigned len); + RageSoundReader_Resample_Good(); + virtual ~RageSoundReader_Resample_Good(); + SoundReader *Copy() const; + + /* Change the actual sample rate of a sound. */ + void SetSampleRate( int hz ); + void SetHighQuality( bool hq ) { HighQuality = hq; } + + int GetSampleRate() const { return samplerate; } +}; + +#endif +/* + * Copyright (c) 2003 by the person(s) listed below. All rights reserved. + * Glenn Maynard + */