From 42669653811f883610b84b74655c975ef1ffa7ad Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 28 Jan 2006 04:53:35 +0000 Subject: [PATCH] merge RageSoundResampler into RageSoundReader_Resample_Fast; they're just different interfaces for the same thing --- .../src/RageSoundReader_Resample_Fast.cpp | 135 +++++++++++++++--- stepmania/src/RageSoundReader_Resample_Fast.h | 18 ++- 2 files changed, 131 insertions(+), 22 deletions(-) diff --git a/stepmania/src/RageSoundReader_Resample_Fast.cpp b/stepmania/src/RageSoundReader_Resample_Fast.cpp index f10d97e456..31a56406ab 100644 --- a/stepmania/src/RageSoundReader_Resample_Fast.cpp +++ b/stepmania/src/RageSoundReader_Resample_Fast.cpp @@ -4,7 +4,18 @@ RageSoundReader_Resample_Fast::RageSoundReader_Resample_Fast() { m_pSource = NULL; - m_iOutputSampleRate = -1; + m_iInputRate = -1; + m_iOutputRate = -1; + m_iChannels = 2; + Reset(); +} + +void RageSoundReader_Resample_Fast::Reset() +{ + m_bAtEof = false; + memset( m_iPrevSample, 0, sizeof(m_iPrevSample) ); + m_iPos = 0; + m_OutBuf.clear(); } void RageSoundReader_Resample_Fast::Open( SoundReader *pSource ) @@ -12,9 +23,9 @@ void RageSoundReader_Resample_Fast::Open( SoundReader *pSource ) m_pSource = pSource; ASSERT(m_pSource); - m_iOutputSampleRate = m_pSource->GetSampleRate(); - m_Resamp.SetInputSampleRate( m_iOutputSampleRate ); - m_Resamp.SetChannels( m_pSource->GetNumChannels() ); + m_iInputRate = m_iOutputRate = m_pSource->GetSampleRate(); + ASSERT( m_pSource->GetNumChannels() < MAX_CHANNELS ); + m_iChannels = m_pSource->GetNumChannels(); } @@ -23,33 +34,30 @@ RageSoundReader_Resample_Fast::~RageSoundReader_Resample_Fast() delete m_pSource; } -void RageSoundReader_Resample_Fast::SetSampleRate( int hz ) +void RageSoundReader_Resample_Fast::SetSampleRate( int iRate ) { - m_iOutputSampleRate = hz; - m_Resamp.SetOutputSampleRate( m_iOutputSampleRate ); + m_iOutputRate = iRate; } int RageSoundReader_Resample_Fast::GetLength() const { - m_Resamp.reset(); return m_pSource->GetLength(); } int RageSoundReader_Resample_Fast::GetLength_Fast() const { - m_Resamp.reset(); return m_pSource->GetLength_Fast(); } int RageSoundReader_Resample_Fast::SetPosition_Accurate( int ms ) { - m_Resamp.reset(); + Reset(); return m_pSource->SetPosition_Accurate(ms); } int RageSoundReader_Resample_Fast::SetPosition_Fast( int ms ) { - m_Resamp.reset(); + Reset(); return m_pSource->SetPosition_Fast(ms); } static const int BUFSIZE = 1024*16; @@ -60,11 +68,17 @@ int RageSoundReader_Resample_Fast::Read( char *pBuf, unsigned iSize ) while( iSize ) { { - int iGot = m_Resamp.read( pBuf, iSize ); + ASSERT( (iSize % sizeof(int16_t)) == 0 ); - if( iGot == -1 ) + /* If no data is available, and we're m_bAtEof, stop. */ + if( m_OutBuf.size() == 0 && m_bAtEof ) break; + /* Fill as much as we have. */ + int iGot = min( m_OutBuf.size()*sizeof(int16_t), iSize ); + memcpy( pBuf, &m_OutBuf[0], iGot ); + m_OutBuf.erase( m_OutBuf.begin(), m_OutBuf.begin() + iGot/sizeof(int16_t) ); + pBuf += iGot; iSize -= iGot; iBytesRead += iGot; @@ -75,7 +89,7 @@ int RageSoundReader_Resample_Fast::Read( char *pBuf, unsigned iSize ) { static char buf[BUFSIZE]; - int iGot = m_pSource->Read(buf, sizeof(buf)); + int iGot = m_pSource->Read( buf, sizeof(buf) ); if( iGot == -1 ) { @@ -83,9 +97,29 @@ int RageSoundReader_Resample_Fast::Read( char *pBuf, unsigned iSize ) return -1; } if( iGot == 0 ) - m_Resamp.eof(); + { + ASSERT( !m_bAtEof ); + + /* 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 < m_iChannels; ++c ) + if( m_iPrevSample[c] != 0 ) + bNeedsFlush = true; + + if( bNeedsFlush ) + { + const int iSize = m_iChannels*16; + int16_t *pData = new int16_t[iSize]; + memset( pData, 0, iSize * sizeof(int16_t) ); + WriteSamples( pData, iSize * sizeof(int16_t) ); + delete[] pData; + } + + m_bAtEof = true; + } else - m_Resamp.write( buf, iGot ); + WriteSamples( buf, iGot ); } } @@ -97,12 +131,77 @@ SoundReader *RageSoundReader_Resample_Fast::Copy() const SoundReader *pNewSource = m_pSource->Copy(); RageSoundReader_Resample_Fast *pRet = new RageSoundReader_Resample_Fast; pRet->Open( pNewSource ); - pRet->SetSampleRate( m_iOutputSampleRate ); + pRet->SetSampleRate( m_iOutputRate ); return pRet; } + + +/* Write data to be converted. */ +void RageSoundReader_Resample_Fast::WriteSamples(const void *data_, int bytes) +{ + ASSERT(!m_bAtEof); + + const int16_t *data = (const int16_t *) data_; + + const unsigned samples = bytes / sizeof(int16_t); + const unsigned frames = samples / m_iChannels; + + if( m_iInputRate == m_iOutputRate ) + { + /* Optimization: */ + m_OutBuf.insert(m_OutBuf.end(), data, data+samples); + return; + } + + /* Lerp. */ + const int FIXED_SHIFT = 14; + const int FIXED_ONE = 1<> FIXED_SHIFT); + iSamplesOutput += m_iChannels; + iPos += iInputSamplesPerOutputSample; + } + + iPos -= FIXED_ONE; + + iPrevSample = pInBuf[iSamplesInput]; + iSamplesInput += m_iChannels; + } + m_iPrevSample[c] = iPrevSample; + + if( c == m_iChannels-1 ) + { + iSize = iSamplesOutput; + m_iPos = iPos; + } + } + + m_OutBuf.erase( m_OutBuf.begin()+iSize, m_OutBuf.end() ); +} + + /* - * Copyright (c) 2003-2005 Glenn Maynard + * Copyright (c) 2003-2006 Glenn Maynard * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/stepmania/src/RageSoundReader_Resample_Fast.h b/stepmania/src/RageSoundReader_Resample_Fast.h index cce3472705..3b1a6442fd 100644 --- a/stepmania/src/RageSoundReader_Resample_Fast.h +++ b/stepmania/src/RageSoundReader_Resample_Fast.h @@ -5,7 +5,6 @@ #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 @@ -25,18 +24,29 @@ public: /* Change the actual sample rate of a sound. */ void SetSampleRate( int hz ); - int GetSampleRate() const { return m_iOutputSampleRate; } + int GetSampleRate() const { return m_iOutputRate; } unsigned GetNumChannels() const { return m_pSource->GetNumChannels(); } bool IsStreamingFromDisk() const { return m_pSource->IsStreamingFromDisk(); } private: + void Reset(); bool FillBuf(); - int m_iOutputSampleRate; + /* Write data to be converted. */ + void WriteSamples( const void *data, int bytes ); SoundReader *m_pSource; - mutable RageSoundResampler m_Resamp; + int m_iInputRate; + int m_iOutputRate; + int m_iChannels; + + enum { MAX_CHANNELS = 15 }; + int16_t m_iPrevSample[MAX_CHANNELS]; + + vector m_OutBuf; + bool m_bAtEof; + int m_iPos; }; #endif