Move the linear resampler to RageSoundReader_Resample_Fast.
Add RageSoundReader_Resample_Good, using libresample.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
Reference in New Issue
Block a user