aboutsummaryrefslogtreecommitdiff
path: root/sword1/music.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sword1/music.cpp')
-rw-r--r--sword1/music.cpp201
1 files changed, 160 insertions, 41 deletions
diff --git a/sword1/music.cpp b/sword1/music.cpp
index b8b6d010fe..f49704a50d 100644
--- a/sword1/music.cpp
+++ b/sword1/music.cpp
@@ -24,15 +24,122 @@
#include "sound/mixer.h"
#include "common/util.h"
#include "common/file.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
namespace Sword1 {
+WaveAudioStream *makeWaveStream(File *source, uint32 size) {
+ return new WaveAudioStream(source, size);
+}
+
+WaveAudioStream::WaveAudioStream(File *source, uint32 pSize) {
+ uint32 size;
+ uint8 wavHeader[WAVEHEADERSIZE];
+
+ _sourceFile = source;
+ _sourceFile->incRef();
+ if (_sourceFile->isOpen()) {
+ _sourceFile->read(wavHeader, WAVEHEADERSIZE);
+ _isStereo = (READ_LE_UINT16(wavHeader + 0x16) == 2);
+ _rate = READ_LE_UINT16(wavHeader + 0x18);
+ size = ((pSize) ? pSize : READ_LE_UINT32(wavHeader + 0x28));
+ assert(size <= (source->size() - source->pos()));
+ _bitsPerSample = READ_LE_UINT16(wavHeader + 0x22);
+ _samplesLeft = (size * 8) / _bitsPerSample;
+ if ((_bitsPerSample != 16) && (_bitsPerSample != 8))
+ error("WaveAudioStream: unknown wave type");
+ } else {
+ _samplesLeft = 0;
+ _isStereo = false;
+ _bitsPerSample = 16;
+ _rate = 22050;
+ }
+}
+
+WaveAudioStream::~WaveAudioStream(void) {
+ _sourceFile->decRef();
+}
+
+int WaveAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples = ((int)_samplesLeft < numSamples) ? (int)_samplesLeft : numSamples;
+ if (_bitsPerSample == 16)
+ for (int cnt = 0; cnt < samples; cnt++)
+ *buffer++ = (int16)_sourceFile->readUint16LE();
+ else
+ for (int cnt = 0; cnt < samples; cnt++)
+ *buffer++ = (int16)_sourceFile->readByte() << 8;
+ _samplesLeft -= samples;
+ return samples;
+}
+
+bool WaveAudioStream::endOfData(void) const {
+ if (_samplesLeft == 0)
+ return true;
+ else
+ return false;
+}
+
// This means fading takes 3 seconds.
#define FADE_LENGTH 3
// These functions are only called from Music, so I'm just going to
// assume that if locking is needed it has already been taken care of.
+AudioStream *MusicHandle::createAudioSource(void) {
+ _file.seek(0);
+ switch (_musicMode) {
+#ifdef USE_MAD
+ case MusicMp3:
+ printf("creating mp3 stream\n");
+ return makeMP3Stream(&_file, _file.size());
+#endif
+#ifdef USE_VORBIS
+ case MusicVorbis:
+ return makeVorbisStream(&_file, _file.size());
+#endif
+ case MusicWave:
+ return makeWaveStream(&_file, 0);
+ case MusicNone: // shouldn't happen
+ warning("createAudioSource ran into null create\n");
+ return NULL;
+ default:
+ error("MusicHandle::createAudioSource: called with illegal MusicMode");
+ }
+ return NULL; // never reached
+}
+
+bool MusicHandle::play(const char *fileBase, bool loop) {
+ char fileName[30];
+ stop();
+ _musicMode = MusicNone;
+#ifdef USE_MAD
+ sprintf(fileName, "%s.mp3", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicMp3;
+#endif
+#ifdef USE_VORBIS
+ if (!_file.isOpen()) { // mp3 doesn't exist (or not compiled with MAD support)
+ sprintf(fileName, "%s.ogg", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicVorbis;
+ }
+#endif
+ if (!_file.isOpen()) {
+ sprintf(fileName, "%s.wav", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicWave;
+ else {
+ warning("Music file %s could not be opened", fileName);
+ return false;
+ }
+ }
+ _audioSource = createAudioSource();
+ _looping = loop;
+ fadeUp();
+ return true;
+}
+
void MusicHandle::fadeDown() {
if (streaming()) {
if (_fading < 0)
@@ -57,53 +164,67 @@ bool MusicHandle::endOfData() const {
return !streaming();
}
+// is we don't have an audiosource, return some dummy values.
+// shouldn't happen anyways.
+bool MusicHandle::streaming(void) const {
+ return (_audioSource) ? (!_audioSource->endOfStream()) : false;
+}
+
+bool MusicHandle::isStereo(void) const {
+ return (_audioSource) ? _audioSource->isStereo() : false;
+}
+
+int MusicHandle::getRate(void) const {
+ return (_audioSource) ? _audioSource->getRate() : 11025;
+}
+
int MusicHandle::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- for (samples = 0; samples < numSamples && !endOfData(); samples++) {
- int16 sample = _file.readUint16LE();
- if (_file.ioFailed()) {
- if (!_looping) {
- stop();
- sample = 0;
- } else {
- _file.clearIOFailed();
- _file.seek(WAVEHEADERSIZE);
- sample = _file.readUint16LE();
+ int totalSamples = 0;
+ int16 *bufStart = buffer;
+ if (!_audioSource)
+ return 0;
+ int expectedSamples = numSamples;
+ while ((expectedSamples > 0) && _audioSource) { // _audioSource becomes NULL if we reach EOF and aren't looping
+ int samplesReturned = _audioSource->readBuffer(buffer, expectedSamples);
+ buffer += samplesReturned;
+ totalSamples += samplesReturned;
+ expectedSamples -= samplesReturned;
+ if ((expectedSamples > 0) && _audioSource->endOfData()) {
+ debug(2, "Music reached EOF");
+ _audioSource->endOfData();
+ if (_looping) {
+ delete _audioSource; // recreate same source.
+ _audioSource = createAudioSource();
}
+ if ((!_looping) || (!_audioSource))
+ stop();
}
- if (_fading > 0) {
- if (--_fading == 0) {
- _looping = false;
- _file.close();
- }
- sample = (sample * _fading) / _fadeSamples;
- } else if (_fading < 0) {
- _fading--;
- sample = -(sample * _fading) / _fadeSamples;
- if (_fading <= -_fadeSamples)
- _fading = 0;
+ }
+ // buffer was filled, now do the fading (if necessary)
+ int samplePos = 0;
+ while ((_fading > 0) && (samplePos < totalSamples)) { // fade down
+ bufStart[samplePos] = (bufStart[samplePos] * --_fading) / _fadeSamples;
+ samplePos++;
+ if (_fading == 0) {
+ stop();
+ // clear the rest of the buffer
+ memset(bufStart + samplePos, 0, (totalSamples - samplePos) * 2);
+ return samplePos;
}
- *buffer++ = sample;
}
- return samples;
-}
-
-bool MusicHandle::play(const char *filename, bool loop) {
- uint8 wavHeader[WAVEHEADERSIZE];
- stop();
- if (!_file.open(filename)) {
- warning("Music file %s could not be opened", filename);
- return false;
+ while ((_fading < 0) && (samplePos < totalSamples)) { // fade up
+ bufStart[samplePos] = -(bufStart[samplePos] * --_fading) / _fadeSamples;
+ if (_fading <= -_fadeSamples)
+ _fading = 0;
}
- _file.read(wavHeader, WAVEHEADERSIZE);
- _stereo = (READ_LE_UINT16(wavHeader + 0x16) == 2);
- _rate = READ_LE_UINT16(wavHeader + 0x18);
- _looping = loop;
- fadeUp();
- return true;
+ return totalSamples;
}
void MusicHandle::stop() {
+ if (_audioSource) {
+ delete _audioSource;
+ _audioSource = NULL;
+ }
if (_file.isOpen())
_file.close();
_fading = 0;
@@ -183,9 +304,7 @@ void Music::startMusic(int32 tuneId, int32 loopFlag) {
_handles[1].fadeDown();
newStream = 0;
}
- char fName[20];
- sprintf(fName, "%s.wav", _tuneList[tuneId]);
- if (_handles[newStream].play(fName, loopFlag != 0)) {
+ if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
delete _converter[newStream];
_converter[newStream] = makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
}