renamed eof -> eos (end of stream); hid MP3/Vorbis stream classes completly (by providing factory methods); new readBuffer method for AudioInputStream for improved speed of the mixer; new MusicStream class (subclassed for MP3/Vorbis sound) which offers a getRate method; some other tweaks
svn-id: r9467
This commit is contained in:
parent
679e818b0b
commit
d280258e09
4 changed files with 214 additions and 103 deletions
|
@ -47,6 +47,17 @@ protected:
|
||||||
const byte *_loopPtr;
|
const byte *_loopPtr;
|
||||||
const byte *_loopEnd;
|
const byte *_loopEnd;
|
||||||
|
|
||||||
|
inline int16 readIntern() {
|
||||||
|
//assert(_ptr < _end);
|
||||||
|
int16 val = readSample<is16Bit, isUnsigned>(_ptr);
|
||||||
|
_ptr += (is16Bit ? 2 : 1);
|
||||||
|
if (_loopPtr && _ptr == _end) {
|
||||||
|
_ptr = _loopPtr;
|
||||||
|
_end = _loopEnd;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
inline bool eosIntern() const { return _ptr >= _end; };
|
||||||
public:
|
public:
|
||||||
LinearMemoryStream(const byte *ptr, uint len, uint loopOffset, uint loopLen)
|
LinearMemoryStream(const byte *ptr, uint len, uint loopOffset, uint loopLen)
|
||||||
: _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0) {
|
: _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0) {
|
||||||
|
@ -57,22 +68,25 @@ public:
|
||||||
if (stereo) // Stereo requires even sized data
|
if (stereo) // Stereo requires even sized data
|
||||||
assert(len % 2 == 0);
|
assert(len % 2 == 0);
|
||||||
}
|
}
|
||||||
int16 read() {
|
int readBuffer(int16 *buffer, int numSamples) {
|
||||||
//assert(_ptr < _end);
|
int samples = 0;
|
||||||
int16 val = readSample<is16Bit, isUnsigned>(_ptr);
|
do {
|
||||||
_ptr += (is16Bit ? 2 : 1);
|
const int len = MIN(numSamples, (_end - _ptr) / (is16Bit ? 2 : 1));
|
||||||
if (_loopPtr && _ptr == _end) {
|
for (; samples < len; samples++) {
|
||||||
_ptr = _loopPtr;
|
*buffer++ = readSample<is16Bit, isUnsigned>(_ptr);
|
||||||
_end = _loopEnd;
|
_ptr += (is16Bit ? 2 : 1);
|
||||||
}
|
}
|
||||||
return val;
|
if (_loopPtr && _ptr == _end) {
|
||||||
}
|
_ptr = _loopPtr;
|
||||||
bool eof() const {
|
_end = _loopEnd;
|
||||||
return _ptr >= _end;
|
}
|
||||||
}
|
} while (samples < numSamples && !eosIntern());
|
||||||
bool isStereo() const {
|
return samples;
|
||||||
return stereo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16 read() { return readIntern(); }
|
||||||
|
bool eos() const { return eosIntern(); }
|
||||||
|
bool isStereo() const { return stereo; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,14 +104,16 @@ protected:
|
||||||
byte *_pos;
|
byte *_pos;
|
||||||
byte *_end;
|
byte *_end;
|
||||||
|
|
||||||
|
inline int16 readIntern();
|
||||||
|
inline bool eosIntern() const { return _end == _pos; };
|
||||||
public:
|
public:
|
||||||
WrappedMemoryStream(uint bufferSize);
|
WrappedMemoryStream(uint bufferSize);
|
||||||
~WrappedMemoryStream() { free(_bufferStart); }
|
~WrappedMemoryStream() { free(_bufferStart); }
|
||||||
int16 read();
|
int readBuffer(int16 *buffer, int numSamples);
|
||||||
bool eof() const;
|
|
||||||
bool isStereo() const {
|
int16 read() { return readIntern(); }
|
||||||
return stereo;
|
bool eos() const { return eosIntern(); }
|
||||||
}
|
bool isStereo() const { return stereo; }
|
||||||
|
|
||||||
void append(const byte *data, uint32 len);
|
void append(const byte *data, uint32 len);
|
||||||
};
|
};
|
||||||
|
@ -113,7 +129,7 @@ WrappedMemoryStream<stereo, is16Bit, isUnsigned>::WrappedMemoryStream(uint buffe
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool stereo, bool is16Bit, bool isUnsigned>
|
template<bool stereo, bool is16Bit, bool isUnsigned>
|
||||||
int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::read() {
|
inline int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readIntern() {
|
||||||
//assert(_pos != _end);
|
//assert(_pos != _end);
|
||||||
int16 val = readSample<is16Bit, isUnsigned>(_pos);
|
int16 val = readSample<is16Bit, isUnsigned>(_pos);
|
||||||
_pos += (is16Bit ? 2 : 1);
|
_pos += (is16Bit ? 2 : 1);
|
||||||
|
@ -126,8 +142,12 @@ int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::read() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool stereo, bool is16Bit, bool isUnsigned>
|
template<bool stereo, bool is16Bit, bool isUnsigned>
|
||||||
bool WrappedMemoryStream<stereo, is16Bit, isUnsigned>::eof() const {
|
int WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readBuffer(int16 *buffer, int numSamples) {
|
||||||
return _end == _pos;
|
int samples;
|
||||||
|
for (samples = 0; samples < numSamples && !eosIntern(); samples++) {
|
||||||
|
*buffer++ = readIntern();
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool stereo, bool is16Bit, bool isUnsigned>
|
template<bool stereo, bool is16Bit, bool isUnsigned>
|
||||||
|
@ -160,6 +180,37 @@ void WrappedMemoryStream<stereo, is16Bit, isUnsigned>::append(const byte *data,
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_MAD
|
#ifdef USE_MAD
|
||||||
|
class MP3InputStream : public MusicStream {
|
||||||
|
struct mad_stream _stream;
|
||||||
|
struct mad_frame _frame;
|
||||||
|
struct mad_synth _synth;
|
||||||
|
mad_timer_t _duration;
|
||||||
|
uint32 _posInFrame;
|
||||||
|
uint32 _bufferSize;
|
||||||
|
int _size;
|
||||||
|
bool _isStereo;
|
||||||
|
int _curChannel;
|
||||||
|
File *_file;
|
||||||
|
byte *_ptr;
|
||||||
|
int _rate;
|
||||||
|
bool _initialized;
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
void refill();
|
||||||
|
inline int16 readIntern();
|
||||||
|
inline bool eosIntern() const;
|
||||||
|
public:
|
||||||
|
MP3InputStream(File *file, mad_timer_t duration, uint size = 0);
|
||||||
|
~MP3InputStream();
|
||||||
|
int readBuffer(int16 *buffer, int numSamples);
|
||||||
|
|
||||||
|
int16 read() { return readIntern(); }
|
||||||
|
bool eos() const { return eosIntern(); }
|
||||||
|
bool isStereo() const { return _isStereo; }
|
||||||
|
|
||||||
|
int getRate() const { return _rate; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playback the MP3 data in the given file for the specified duration.
|
* Playback the MP3 data in the given file for the specified duration.
|
||||||
|
@ -299,7 +350,7 @@ void MP3InputStream::refill() {
|
||||||
_posInFrame = 0;
|
_posInFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3InputStream::eof() const {
|
inline bool MP3InputStream::eosIntern() const {
|
||||||
return (_size < 0 || _posInFrame >= _synth.pcm.length);
|
return (_size < 0 || _posInFrame >= _synth.pcm.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +368,7 @@ static inline int scale_sample(mad_fixed_t sample) {
|
||||||
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
return sample >> (MAD_F_FRACBITS + 1 - 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 MP3InputStream::read() {
|
inline int16 MP3InputStream::readIntern() {
|
||||||
if (_size < 0 || _posInFrame >= _synth.pcm.length) { // EOF
|
if (_size < 0 || _posInFrame >= _synth.pcm.length) { // EOF
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -343,6 +394,18 @@ int16 MP3InputStream::read() {
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MP3InputStream::readBuffer(int16 *buffer, int numSamples) {
|
||||||
|
int samples;
|
||||||
|
for (samples = 0; samples < numSamples && !eosIntern(); samples++) {
|
||||||
|
*buffer++ = readIntern();
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
MusicStream *makeMP3Stream(File *file, mad_timer_t duration, uint size) {
|
||||||
|
return new MP3InputStream(file, duration, size);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,6 +416,29 @@ int16 MP3InputStream::read() {
|
||||||
|
|
||||||
#ifdef USE_VORBIS
|
#ifdef USE_VORBIS
|
||||||
|
|
||||||
|
class VorbisInputStream : public MusicStream {
|
||||||
|
OggVorbis_File *_ov_file;
|
||||||
|
int _end_pos;
|
||||||
|
bool _eofFlag;
|
||||||
|
int _numChannels;
|
||||||
|
int16 _buffer[4096];
|
||||||
|
int16 *_pos;
|
||||||
|
|
||||||
|
void refill();
|
||||||
|
inline int16 readIntern();
|
||||||
|
inline bool eosIntern() const;
|
||||||
|
public:
|
||||||
|
VorbisInputStream(OggVorbis_File *file, int duration);
|
||||||
|
int readBuffer(int16 *buffer, int numSamples);
|
||||||
|
|
||||||
|
int16 read() { return readIntern(); }
|
||||||
|
bool eos() const { return eosIntern(); }
|
||||||
|
bool isStereo() const { return _numChannels >= 2; }
|
||||||
|
|
||||||
|
int getRate() const { return ov_info(_ov_file, -1)->rate; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef CHUNKSIZE
|
#ifdef CHUNKSIZE
|
||||||
#define VORBIS_TREMOR
|
#define VORBIS_TREMOR
|
||||||
#endif
|
#endif
|
||||||
|
@ -371,14 +457,14 @@ VorbisInputStream::VorbisInputStream(OggVorbis_File *file, int duration)
|
||||||
_eofFlag = false;
|
_eofFlag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 VorbisInputStream::read() {
|
inline int16 VorbisInputStream::readIntern() {
|
||||||
if (_pos >= _buffer + ARRAYSIZE(_buffer)) {
|
if (_pos >= _buffer + ARRAYSIZE(_buffer)) {
|
||||||
refill();
|
refill();
|
||||||
}
|
}
|
||||||
return *_pos++;
|
return *_pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VorbisInputStream::eof() const {
|
inline bool VorbisInputStream::eosIntern() const {
|
||||||
if (_eofFlag)
|
if (_eofFlag)
|
||||||
return true;
|
return true;
|
||||||
if (_pos < _buffer + ARRAYSIZE(_buffer))
|
if (_pos < _buffer + ARRAYSIZE(_buffer))
|
||||||
|
@ -386,6 +472,14 @@ bool VorbisInputStream::eof() const {
|
||||||
return (_end_pos <= ov_pcm_tell(_ov_file));
|
return (_end_pos <= ov_pcm_tell(_ov_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VorbisInputStream::readBuffer(int16 *buffer, int numSamples) {
|
||||||
|
int samples;
|
||||||
|
for (samples = 0; samples < numSamples && !eosIntern(); samples++) {
|
||||||
|
*buffer++ = readIntern();
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
void VorbisInputStream::refill() {
|
void VorbisInputStream::refill() {
|
||||||
// Read the samples
|
// Read the samples
|
||||||
uint len_left = sizeof(_buffer);
|
uint len_left = sizeof(_buffer);
|
||||||
|
@ -426,6 +520,10 @@ void VorbisInputStream::refill() {
|
||||||
_pos = _buffer;
|
_pos = _buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MusicStream *makeVorbisStream(OggVorbis_File *file, int duration) {
|
||||||
|
return new VorbisInputStream(file, duration);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
|
#include "common/util.h"
|
||||||
#ifdef USE_MAD
|
#ifdef USE_MAD
|
||||||
#include <mad.h>
|
#include <mad.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -47,10 +48,34 @@ class AudioInputStream {
|
||||||
public:
|
public:
|
||||||
virtual ~AudioInputStream() {}
|
virtual ~AudioInputStream() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the given buffer with up to numSamples samples.
|
||||||
|
* Returns the actual number of samples read, or -1 if
|
||||||
|
* a critical error occured (note: you *must* check if
|
||||||
|
* this value is less than what you requested, this can
|
||||||
|
* happend when the stream is fully used up).
|
||||||
|
* For stereo stream, buffer will be filled with interleaved
|
||||||
|
* left and right channel samples.
|
||||||
|
*
|
||||||
|
* For maximum efficency, subclasses should always override
|
||||||
|
* the default implementation!
|
||||||
|
*/
|
||||||
|
virtual int readBuffer(int16 *buffer, int numSamples) {
|
||||||
|
int samples;
|
||||||
|
for (samples = 0; samples < numSamples && !eos(); samples++) {
|
||||||
|
*buffer++ = read();
|
||||||
|
}
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a singel (16 bit signed) sample from the stream. */
|
||||||
virtual int16 read() = 0;
|
virtual int16 read() = 0;
|
||||||
//virtual int size() const = 0;
|
|
||||||
|
/** Is this a stereo stream? */
|
||||||
virtual bool isStereo() const = 0;
|
virtual bool isStereo() const = 0;
|
||||||
virtual bool eof() const = 0;
|
|
||||||
|
/* End of stream reached? */
|
||||||
|
virtual bool eos() const = 0;
|
||||||
|
|
||||||
virtual int getRate() const { return -1; }
|
virtual int getRate() const { return -1; }
|
||||||
};
|
};
|
||||||
|
@ -65,64 +90,34 @@ protected:
|
||||||
int _len;
|
int _len;
|
||||||
public:
|
public:
|
||||||
ZeroInputStream(uint len) : _len(len) { }
|
ZeroInputStream(uint len) : _len(len) { }
|
||||||
|
int readBuffer(int16 *buffer, int numSamples) {
|
||||||
|
int samples = MIN(_len, numSamples);
|
||||||
|
memset(buffer, 0, samples * 2);
|
||||||
|
_len -= samples;
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
int16 read() { assert(_len > 0); _len--; return 0; }
|
int16 read() { assert(_len > 0); _len--; return 0; }
|
||||||
int size() const { return _len; }
|
int size() const { return _len; }
|
||||||
bool isStereo() const { return false; }
|
bool isStereo() const { return false; }
|
||||||
bool eof() const { return _len <= 0; }
|
bool eos() const { return _len <= 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_MAD
|
class MusicStream : public AudioInputStream {
|
||||||
class MP3InputStream : public AudioInputStream {
|
|
||||||
struct mad_stream _stream;
|
|
||||||
struct mad_frame _frame;
|
|
||||||
struct mad_synth _synth;
|
|
||||||
mad_timer_t _duration;
|
|
||||||
uint32 _posInFrame;
|
|
||||||
uint32 _bufferSize;
|
|
||||||
int _size;
|
|
||||||
bool _isStereo;
|
|
||||||
int _curChannel;
|
|
||||||
File *_file;
|
|
||||||
byte *_ptr;
|
|
||||||
int _rate;
|
|
||||||
bool _initialized;
|
|
||||||
|
|
||||||
bool init();
|
|
||||||
void refill();
|
|
||||||
public:
|
public:
|
||||||
MP3InputStream(File *file, mad_timer_t duration, uint size = 0);
|
virtual int getRate() const = 0;
|
||||||
~MP3InputStream();
|
|
||||||
int16 read();
|
|
||||||
bool eof() const;
|
|
||||||
bool isStereo() const { return _isStereo; }
|
|
||||||
|
|
||||||
int getRate() const { return _rate; }
|
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_VORBIS
|
|
||||||
class VorbisInputStream : public AudioInputStream {
|
|
||||||
OggVorbis_File *_ov_file;
|
|
||||||
int _end_pos;
|
|
||||||
bool _eofFlag;
|
|
||||||
int _numChannels;
|
|
||||||
int16 _buffer[4096];
|
|
||||||
int16 *_pos;
|
|
||||||
|
|
||||||
void refill();
|
|
||||||
public:
|
|
||||||
VorbisInputStream(OggVorbis_File *file, int duration);
|
|
||||||
int16 read();
|
|
||||||
bool eof() const;
|
|
||||||
bool isStereo() const { return _numChannels >= 2; }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
|
AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen);
|
||||||
WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len);
|
WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len);
|
||||||
|
|
||||||
|
#ifdef USE_MAD
|
||||||
|
MusicStream *makeMP3Stream(File *file, mad_timer_t duration, uint size = 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_VORBIS
|
||||||
|
MusicStream *makeVorbisStream(OggVorbis_File *file, int duration);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -709,7 +709,7 @@ void ChannelRaw::mix(int16 *data, uint len) {
|
||||||
assert(_input);
|
assert(_input);
|
||||||
assert(_converter);
|
assert(_converter);
|
||||||
|
|
||||||
if (_input->eof()) {
|
if (_input->eos()) {
|
||||||
// TODO: call drain method
|
// TODO: call drain method
|
||||||
destroy();
|
destroy();
|
||||||
return;
|
return;
|
||||||
|
@ -820,7 +820,7 @@ void ChannelStream::mix(int16 *data, uint len) {
|
||||||
assert(_input);
|
assert(_input);
|
||||||
assert(_converter);
|
assert(_converter);
|
||||||
|
|
||||||
if (_input->eof()) {
|
if (_input->eos()) {
|
||||||
// TODO: call drain method
|
// TODO: call drain method
|
||||||
|
|
||||||
// Normally, the stream stays around even if all its data is used up.
|
// Normally, the stream stays around even if all its data is used up.
|
||||||
|
@ -929,7 +929,7 @@ static inline int scale_sample(mad_fixed_t sample) {
|
||||||
ChannelMP3::ChannelMP3(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, uint size)
|
ChannelMP3::ChannelMP3(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, uint size)
|
||||||
: Channel(mixer, handle) {
|
: Channel(mixer, handle) {
|
||||||
// Create the input stream
|
// Create the input stream
|
||||||
_input = new MP3InputStream(file, mad_timer_zero, size);
|
_input = makeMP3Stream(file, mad_timer_zero, size);
|
||||||
|
|
||||||
// Get a rate converter instance
|
// Get a rate converter instance
|
||||||
//printf("ChannelMP3: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo());
|
//printf("ChannelMP3: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo());
|
||||||
|
@ -951,7 +951,7 @@ void ChannelMP3::mix(int16 *data, uint len) {
|
||||||
assert(_input);
|
assert(_input);
|
||||||
assert(_converter);
|
assert(_converter);
|
||||||
|
|
||||||
if (_input->eof()) {
|
if (_input->eos()) {
|
||||||
// TODO: call drain method
|
// TODO: call drain method
|
||||||
destroy();
|
destroy();
|
||||||
return;
|
return;
|
||||||
|
@ -1013,7 +1013,7 @@ void ChannelMP3::mix(int16 *data, uint len) {
|
||||||
ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, mad_timer_t duration)
|
ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, mad_timer_t duration)
|
||||||
: Channel(mixer, handle) {
|
: Channel(mixer, handle) {
|
||||||
// Create the input stream
|
// Create the input stream
|
||||||
_input = new MP3InputStream(file, duration, 0);
|
_input = makeMP3Stream(file, duration, 0);
|
||||||
|
|
||||||
// Get a rate converter instance
|
// Get a rate converter instance
|
||||||
//printf("ChannelMP3CDMusic: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo());
|
//printf("ChannelMP3CDMusic: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo());
|
||||||
|
@ -1034,7 +1034,7 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) {
|
||||||
assert(_input);
|
assert(_input);
|
||||||
assert(_converter);
|
assert(_converter);
|
||||||
|
|
||||||
if (_input->eof()) {
|
if (_input->eos()) {
|
||||||
// TODO: call drain method
|
// TODO: call drain method
|
||||||
destroy();
|
destroy();
|
||||||
return;
|
return;
|
||||||
|
@ -1158,15 +1158,11 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) {
|
||||||
ChannelVorbis::ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track)
|
ChannelVorbis::ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track)
|
||||||
: Channel(mixer, handle) {
|
: Channel(mixer, handle) {
|
||||||
#ifdef SOX_HACK
|
#ifdef SOX_HACK
|
||||||
vorbis_info *vi;
|
|
||||||
|
|
||||||
// Create the input stream
|
// Create the input stream
|
||||||
_input = new VorbisInputStream(ov_file, duration);
|
_input = makeVorbisStream(ov_file, duration);
|
||||||
|
|
||||||
// Get a rate converter instance
|
// Get a rate converter instance
|
||||||
vi = ov_info(ov_file, -1);
|
_converter = makeRateConverter(_input->getRate(), mixer->getOutputRate(), _input->isStereo());
|
||||||
assert(vi->channels == 1 || vi->channels == 2);
|
|
||||||
_converter = makeRateConverter(vi->rate, mixer->getOutputRate(), _input->isStereo());
|
|
||||||
#else
|
#else
|
||||||
_ov_file = ov_file;
|
_ov_file = ov_file;
|
||||||
|
|
||||||
|
@ -1187,7 +1183,7 @@ void ChannelVorbis::mix(int16 *data, uint len) {
|
||||||
assert(_input);
|
assert(_input);
|
||||||
assert(_converter);
|
assert(_converter);
|
||||||
|
|
||||||
if (_input->eof()) {
|
if (_input->eos()) {
|
||||||
// TODO: call drain method
|
// TODO: call drain method
|
||||||
destroy();
|
destroy();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -30,9 +30,20 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "sound/rate.h"
|
#include "sound/rate.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The precision of the fractional computations used by the rate converter.
|
||||||
|
* Normally you should never have to modify this value.
|
||||||
|
*/
|
||||||
#define FRAC_BITS 16
|
#define FRAC_BITS 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the intermediate input cache. Bigger values may increase
|
||||||
|
* performance, but only until some point (depends largely on cache size,
|
||||||
|
* target processor and various other factors), at which it will decrease
|
||||||
|
* again.
|
||||||
|
*/
|
||||||
|
#define INTERMEDIATE_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Audio rate converter based on simple linear Interpolation.
|
* Audio rate converter based on simple linear Interpolation.
|
||||||
|
@ -48,7 +59,9 @@
|
||||||
template<bool stereo, bool reverseStereo>
|
template<bool stereo, bool reverseStereo>
|
||||||
class LinearRateConverter : public RateConverter {
|
class LinearRateConverter : public RateConverter {
|
||||||
protected:
|
protected:
|
||||||
bool _reverseStereo;
|
st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
|
||||||
|
const st_sample_t *inPtr;
|
||||||
|
int inLen;
|
||||||
|
|
||||||
/** fractional position of the output stream in input stream unit */
|
/** fractional position of the output stream in input stream unit */
|
||||||
unsigned long opos, opos_frac;
|
unsigned long opos, opos_frac;
|
||||||
|
@ -101,6 +114,8 @@ LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate
|
||||||
|
|
||||||
ilast[0] = ilast[1] = 0;
|
ilast[0] = ilast[1] = 0;
|
||||||
icur[0] = icur[1] = 0;
|
icur[0] = icur[1] = 0;
|
||||||
|
|
||||||
|
inLen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -112,6 +127,9 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioInputStream &input, st
|
||||||
{
|
{
|
||||||
st_sample_t *ostart, *oend;
|
st_sample_t *ostart, *oend;
|
||||||
st_sample_t out[2], tmpOut;
|
st_sample_t out[2], tmpOut;
|
||||||
|
|
||||||
|
const int numChannels = stereo ? 2 : 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
ostart = obuf;
|
ostart = obuf;
|
||||||
oend = obuf + osamp * 2;
|
oend = obuf + osamp * 2;
|
||||||
|
@ -120,16 +138,17 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioInputStream &input, st
|
||||||
|
|
||||||
// read enough input samples so that ipos > opos
|
// read enough input samples so that ipos > opos
|
||||||
while (ipos <= opos) {
|
while (ipos <= opos) {
|
||||||
|
// Check if we have to refill the buffer
|
||||||
// Abort if we reached the end of the input buffer
|
if (inLen == 0) {
|
||||||
if (input.eof())
|
inPtr = inBuf;
|
||||||
goto the_end;
|
inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
|
||||||
|
if (inLen <= 0)
|
||||||
ilast[0] = icur[0];
|
goto the_end;
|
||||||
icur[0] = input.read();
|
}
|
||||||
if (stereo) {
|
for (i = 0; i < numChannels; i++) {
|
||||||
ilast[1] = icur[1];
|
ilast[i] = icur[i];
|
||||||
icur[1] = input.read();
|
icur[i] = *inPtr++;
|
||||||
|
inLen--;
|
||||||
}
|
}
|
||||||
ipos++;
|
ipos++;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +204,10 @@ public:
|
||||||
int16 tmp[2];
|
int16 tmp[2];
|
||||||
st_size_t len = osamp;
|
st_size_t len = osamp;
|
||||||
assert(input.isStereo() == stereo);
|
assert(input.isStereo() == stereo);
|
||||||
while (!input.eof() && len--) {
|
|
||||||
|
// TODO: use readBuffer
|
||||||
|
|
||||||
|
while (!input.eos() && len--) {
|
||||||
tmp[0] = tmp[1] = (input.read() * vol) >> 8;
|
tmp[0] = tmp[1] = (input.read() * vol) >> 8;
|
||||||
if (stereo)
|
if (stereo)
|
||||||
tmp[reverseStereo ? 0 : 1] = (input.read() * vol) >> 8;
|
tmp[reverseStereo ? 0 : 1] = (input.read() * vol) >> 8;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue