working on variable channel count support (to allow preloading mono samples

in half memory, and to avoid redundant resampling in mono files)
This commit is contained in:
Glenn Maynard
2004-07-24 01:22:10 +00:00
parent 694a4d3e70
commit 27243e074c
9 changed files with 83 additions and 58 deletions
+1
View File
@@ -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; }
+3 -3
View File
@@ -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)
+4 -1
View File
@@ -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() { }
@@ -14,6 +14,7 @@ void RageSoundReader_Resample_Fast::Open(SoundReader *source_)
samplerate = source->GetSampleRate();
resamp.SetInputSampleRate(samplerate);
resamp.SetChannels( source->GetNumChannels() );
}
@@ -32,6 +32,7 @@ public:
void SetSampleRate(int hz);
int GetSampleRate() const { return samplerate; }
unsigned GetNumChannels() const { return source->GetNumChannels(); }
};
#endif
+53 -39
View File
@@ -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;
@@ -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<resample_channel> 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
+8 -9
View File
@@ -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));
+3 -3
View File
@@ -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<int16_t> 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; }