Move the linear resampler to RageSoundReader_Resample_Fast.

Add RageSoundReader_Resample_Good, using libresample.
This commit is contained in:
Glenn Maynard
2003-09-24 22:31:34 +00:00
parent 83c58f3b3a
commit 6954e0facf
6 changed files with 440 additions and 113 deletions
+16 -96
View File
@@ -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
*/
+4 -17
View File
@@ -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
@@ -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
*/
@@ -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
*/
@@ -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
*/
@@ -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
*/