aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/audiostream.cpp15
-rw-r--r--sound/audiostream.h14
-rw-r--r--sound/flac.cpp26
-rw-r--r--sound/fmopl.h4
-rw-r--r--sound/midiplugin.h2
-rw-r--r--sound/mp3.cpp70
-rw-r--r--sound/softsynth/mt32/mt32emu.h2
-rw-r--r--sound/vorbis.cpp13
8 files changed, 138 insertions, 8 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
index 0fba6affdb..4454a09fe6 100644
--- a/sound/audiostream.cpp
+++ b/sound/audiostream.cpp
@@ -102,6 +102,11 @@ AudioStream* AudioStream::openStreamFile(const Common::String &basename, uint32
#pragma mark --- LinearMemoryStream ---
#pragma mark -
+inline int32 calculatePlayTime(int rate, int samples) {
+ int32 seconds = samples / rate;
+ int32 milliseconds = (1000 * (samples % rate)) / rate;
+ return seconds * 1000 + milliseconds;
+}
/**
* A simple raw audio stream, purely memory based. It operates on a single
@@ -122,10 +127,11 @@ protected:
const byte *_loopEnd;
const int _rate;
const byte *_origPtr;
+ const int32 _playtime;
public:
LinearMemoryStream(int rate, const byte *ptr, uint len, uint loopOffset, uint loopLen, bool autoFreeMemory)
- : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate) {
+ : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate), _playtime(calculatePlayTime(rate, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1))) {
// Verify the buffer sizes are sane
if (is16Bit && stereo)
@@ -147,10 +153,11 @@ public:
}
int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const { return stereo; }
- bool endOfData() const { return _ptr >= _end; }
+ bool isStereo() const { return stereo; }
+ bool endOfData() const { return _ptr >= _end; }
- int getRate() const { return _rate; }
+ int getRate() const { return _rate; }
+ int32 getTotalPlayTime() const { return _playtime; }
};
template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
diff --git a/sound/audiostream.h b/sound/audiostream.h
index ed6b37e51c..04133936ee 100644
--- a/sound/audiostream.h
+++ b/sound/audiostream.h
@@ -93,6 +93,20 @@ public:
* NULL in case of an error (e.g. invalid/nonexisting file)
*/
static AudioStream* openStreamFile(const Common::String &basename, uint32 startTime = 0, uint32 duration = 0, uint numLoops = 1);
+
+ enum {
+ kUnknownPlayTime = -1
+ };
+
+ /**
+ * Returns total playtime of the AudioStream object.
+ * Note that this does not require to return an playtime, if the
+ * playtime of the AudioStream is unknown it returns 'kUnknownPlayTime'.
+ * @see kUnknownPlayTime
+ *
+ * @return playtime in milliseconds
+ */
+ virtual int32 getTotalPlayTime() const { return kUnknownPlayTime; }
};
/**
diff --git a/sound/flac.cpp b/sound/flac.cpp
index 8dc3586142..f058d2dc6f 100644
--- a/sound/flac.cpp
+++ b/sound/flac.cpp
@@ -102,6 +102,9 @@ protected:
/** index + 1(!) of the last sample to be played - 0 is end of stream */
FLAC__uint64 _lastSample;
+ /** total play time */
+ int32 _totalPlayTime;
+
/** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */
bool _lastSampleWritten;
@@ -141,6 +144,8 @@ public:
return _streaminfo.channels == 0 || (_lastSampleWritten && _sampleCache.bufFill == 0);
}
+ int32 getTotalPlayTime() const { return _totalPlayTime; }
+
bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; }
protected:
@@ -235,7 +240,28 @@ FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool disp
// avoid overflows).
_firstSample = (FLAC__uint64)(startTime * (_streaminfo.sample_rate / 1000.0));
_lastSample = (FLAC__uint64)(endTime * (_streaminfo.sample_rate / 1000.0));
+
if (_firstSample == 0 || seekAbsolute(_firstSample)) {
+ int32 samples = kUnknownPlayTime;
+
+ if (!_lastSample) {
+ if (_streaminfo.total_samples)
+ samples = _streaminfo.total_samples - _firstSample;
+ } else {
+ samples = _lastSample - _firstSample - 1;
+ }
+
+ if (samples != kUnknownPlayTime && samples >= 0 && numLoops) {
+ const int32 rate = _streaminfo.sample_rate;
+
+ int32 seconds = samples / rate;
+ int32 milliseconds = (1000 * (samples % rate)) / rate;
+
+ _totalPlayTime = (seconds * 1000 + milliseconds) * numLoops;
+ } else {
+ _totalPlayTime = kUnknownPlayTime;
+ }
+
return; // no error occured
}
}
diff --git a/sound/fmopl.h b/sound/fmopl.h
index cc2f967f25..890a2d1a56 100644
--- a/sound/fmopl.h
+++ b/sound/fmopl.h
@@ -167,7 +167,7 @@ int OPLTimerOver(FM_OPL *OPL, int c);
void OPLWriteReg(FM_OPL *OPL, int r, int v);
void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
-#endif
-
// Factory method
FM_OPL *makeAdlibOPL(int rate);
+
+#endif
diff --git a/sound/midiplugin.h b/sound/midiplugin.h
index c3b407a142..0247e160e1 100644
--- a/sound/midiplugin.h
+++ b/sound/midiplugin.h
@@ -84,7 +84,7 @@ private:
friend class Common::Singleton<SingletonBaseType>;
public:
- const MidiPlugin::list &getPlugins() const;
+ const MidiPlugin::List &getPlugins() const;
};
/** Convenience shortcut for accessing the MIDI manager. */
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
index 72ed361926..eea725ce3a 100644
--- a/sound/mp3.cpp
+++ b/sound/mp3.cpp
@@ -63,6 +63,8 @@ protected:
const mad_timer_t _endTime;
mad_timer_t _totalTime;
+ int32 _totalPlayTime;
+
mad_stream _stream;
mad_frame _frame;
mad_synth _synth;
@@ -87,6 +89,7 @@ public:
bool endOfData() const { return _state == MP3_STATE_EOS; }
bool isStereo() const { return MAD_NCHANNELS(&_frame.header) == 2; }
int getRate() const { return _frame.header.samplerate; }
+ int32 getTotalPlayTime() const { return _totalPlayTime; }
protected:
void decodeMP3Data();
@@ -111,6 +114,73 @@ MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispos
// may read a few bytes beyond the end of the input buffer).
memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
+ // Calculate play time
+ mad_timer_t length;
+
+ mad_timer_set(&length, 0, 0, 1000);
+ mad_timer_add(&length, start);
+ mad_timer_negate(&length);
+
+ if (mad_timer_sign(end) == 0) {
+ mad_timer_add(&length, end);
+ } else {
+ mad_stream_init(&_stream);
+ mad_frame_init(&_frame);
+
+ // Reset the stream data
+ _inStream->seek(0, SEEK_SET);
+
+ // Update state
+ _state = MP3_STATE_READY;
+
+ // Read the first few sample bytes
+ readMP3Data();
+
+ do {
+ // If necessary, load more data into the stream decoder
+ if (_stream.error == MAD_ERROR_BUFLEN)
+ readMP3Data();
+
+ while (_state == MP3_STATE_READY) {
+ _stream.error = MAD_ERROR_NONE;
+
+ // Decode the next header. Note: mad_frame_decode would do this for us, too.
+ // However, for seeking we don't want to decode the full frame (else it would
+ // be far too slow).
+ if (mad_header_decode(&_frame.header, &_stream) == -1) {
+ if (_stream.error == MAD_ERROR_BUFLEN) {
+ break; // Read more data
+ } else if (MAD_RECOVERABLE(_stream.error)) {
+ debug(6, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
+ continue;
+ } else {
+ warning("MP3InputStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
+ break;
+ }
+ }
+
+ // Sum up the total playback time so far
+ mad_timer_add(&length, _frame.header.duration);
+ }
+ } while (_state != MP3_STATE_EOS);
+
+ mad_synth_finish(&_synth);
+ mad_frame_finish(&_frame);
+
+ // Reinit stream
+ _state = MP3_STATE_INIT;
+
+ // Reset the stream data
+ _inStream->seek(0, SEEK_SET);
+ }
+
+ _totalPlayTime = mad_timer_count(length, MAD_UNITS_MILLISECONDS);
+
+ if (numLoops && mad_timer_sign(length) >= 0)
+ _totalPlayTime *= numLoops;
+ else
+ _totalPlayTime = kUnknownPlayTime;
+
// Decode the first chunk of data. This is necessary so that _frame
// is setup and isStereo() and getRate() return correct results.
decodeMP3Data();
diff --git a/sound/softsynth/mt32/mt32emu.h b/sound/softsynth/mt32/mt32emu.h
index 0aa4df7488..6eedf04bc0 100644
--- a/sound/softsynth/mt32/mt32emu.h
+++ b/sound/softsynth/mt32/mt32emu.h
@@ -29,7 +29,7 @@
#define MT32EMU_MONITOR_PARTIALS 0
// Determines how the waveform cache file is handled (must be regenerated after sampling rate change)
#define MT32EMU_WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache
-//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generage but don't save cache
+//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generate but don't save cache
//#define MT32EMU_WAVECACHEMODE 2 // Ignore existing cache, generate and save cache
//#define MT32EMU_WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp
index a4b0f854e9..64f67d2a13 100644
--- a/sound/vorbis.cpp
+++ b/sound/vorbis.cpp
@@ -92,6 +92,7 @@ protected:
bool _isStereo;
int _rate;
uint _numLoops;
+ const uint _totalNumLoops;
#ifdef USE_TREMOR
ogg_int64_t _startTime;
@@ -118,6 +119,17 @@ public:
bool isStereo() const { return _isStereo; }
int getRate() const { return _rate; }
+ int32 getTotalPlayTime() const {
+ if (!_totalNumLoops)
+ return AudioStream::kUnknownPlayTime;
+
+#ifdef USE_TREMOR
+ return (_endTime - _startTime) * _totalNumLoops;
+#else
+ return (int32)((_endTime - _startTime) * 1000.0) * _totalNumLoops;
+#endif
+ }
+
protected:
void refill();
};
@@ -126,6 +138,7 @@ VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool
_inStream(inStream),
_disposeAfterUse(dispose),
_numLoops(numLoops),
+ _totalNumLoops(numLoops),
_bufferEnd(_buffer + ARRAYSIZE(_buffer)) {
bool err = (ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap) < 0);