aboutsummaryrefslogtreecommitdiff
path: root/engines/tsage/sound.cpp
diff options
context:
space:
mode:
authorPaul Gilbert2013-10-14 22:58:29 -0400
committerPaul Gilbert2013-10-14 22:58:29 -0400
commitacc7cd58a203fb0c1991c3b8b35c2f296b739f06 (patch)
tree5a1d7b1ffe37b0c77977b015ff4b650d8f9a66dc /engines/tsage/sound.cpp
parentc9aa875c8de12a9851a66433654f00c60a14ca14 (diff)
downloadscummvm-rg350-acc7cd58a203fb0c1991c3b8b35c2f296b739f06.tar.gz
scummvm-rg350-acc7cd58a203fb0c1991c3b8b35c2f296b739f06.tar.bz2
scummvm-rg350-acc7cd58a203fb0c1991c3b8b35c2f296b739f06.zip
TSAGE: Beginnings of R2R voice streaming
Diffstat (limited to 'engines/tsage/sound.cpp')
-rw-r--r--engines/tsage/sound.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp
index b9567cece2..a5480fe6b4 100644
--- a/engines/tsage/sound.cpp
+++ b/engines/tsage/sound.cpp
@@ -1540,6 +1540,23 @@ void Sound::play(int soundNum) {
_soundManager->addToPlayList(this);
}
+bool Sound::playBuffers(const byte *soundData) {
+ prime(-2);
+ _soundManager->addToPlayList(this);
+
+ debug(1, "TODO: Sound::checkCannels");
+ if (/* _soundManager.checkChannels() */ true) {
+ uint32 size = READ_UINT32(soundData + 4);
+ if (size == 0 || size > 0xffff)
+ error("Sound::playBuffers() called with illegal buffer length");
+
+ warning("TODO: Implement Sound::primeSoundData for voice playback");
+ } else {
+ stop();
+ return false;
+ }
+}
+
void Sound::stop() {
g_globals->_soundManager.removeFromPlayList(this);
_unPrime();
@@ -2505,6 +2522,192 @@ void ASoundExt::changeSound(int soundNum) {
/*--------------------------------------------------------------------------*/
+void PlayStream::ResFileData::load(Common::SeekableReadStream &stream) {
+ // Validate that it's the correct data file
+ char header[4];
+ stream.read(&header[0], 4);
+ if (strncmp(header, "SPAM", 4))
+ error("Invalid voice resource data");
+
+ _fileChunkSize = stream.readUint32LE();
+ _field8 = stream.readUint16LE();
+ _indexSize = stream.readUint16LE();
+ _chunkSize = stream.readUint16LE();
+
+ stream.skip(20);
+}
+
+PlayStream::PlayStream(): EventHandler() {
+ _index = NULL;
+ _chunks[0] = _chunks[1] = NULL;
+ _voiceNum = 0;
+ _currentChunkIndex = 0;
+ _nextChunkIndex = 0;
+ _endAction = NULL;
+ _field2F0 = _field2FA = 0;
+}
+
+PlayStream::~PlayStream() {
+ remove();
+}
+
+bool PlayStream::setFile(const Common::String &filename) {
+ remove();
+
+ // Open the resource file for access
+ if (!_file.open(filename))
+ return false;
+
+ // Load header
+ _resData.load(_file);
+
+ // Load the index
+ _index = new uint16[_resData._indexSize / 2];
+ for (uint i = 0; i < (_resData._indexSize / 2); ++i)
+ _index[i] = _file.readUint16LE();
+
+ // Allocate space for loading voice chunks into
+ _chunks[0] = new byte[_resData._chunkSize];
+ _chunks[1] = new byte[_resData._chunkSize];
+
+ // Initialise variables
+ _voiceNum = 0;
+ _currentChunkIndex = _nextChunkIndex = 0;
+
+ return true;
+}
+
+bool PlayStream::play(int voiceNum, EventHandler *endAction) {
+ uint32 offset = getFileOffset(_index, _resData._fileChunkSize, voiceNum);
+ if (offset) {
+ _voiceNum = 0;
+ _currentChunkIndex = _nextChunkIndex = 0;
+ if (_sound.isPlaying())
+ _sound.stop();
+
+ _file.seek(offset);
+ _file.read(_chunks[0], _resData._chunkSize);
+ _file.read(_chunks[1], _resData._chunkSize);
+
+ _currentChunkIndex = 0;
+ _nextChunkIndex = 1;
+ _voiceNum = voiceNum;
+ _endAction = endAction;
+
+ if (!strncmp((const char *)_chunks[_currentChunkIndex], "FEED", 4)) {
+ // Valid sound data found
+ const byte *data = _chunks[_currentChunkIndex];
+
+ _field2F0 = _field2FA = READ_UINT16(data + 10);
+
+ //_fnP = proc2;
+ _field300 = this;
+ _soundData = data + 16;
+ _streamSize = READ_LE_UINT16(data + 4) - 16;
+
+ // Start playing the sound data
+ if (!_sound.playBuffers(_soundData)) {
+ _voiceNum = 0;
+ _currentChunkIndex = _nextChunkIndex = 0;
+ }
+
+ return true;
+ }
+ }
+
+ // If it reaches this point, no valid voice data found
+ return false;
+}
+
+void PlayStream::stop() {
+ _voiceNum = 0;
+ _currentChunkIndex = _nextChunkIndex = 0;
+ _endAction = NULL;
+
+ if (_sound.isPlaying())
+ _sound.stop();
+}
+
+bool PlayStream::isPlaying() const {
+ return _voiceNum != 0;
+}
+
+void PlayStream::remove() {
+ stop();
+ _file.close();
+
+ // Free data buffers
+ delete[] _index;
+ delete[] _chunks[0];
+ delete[] _chunks[1];
+ _index = NULL;
+ _chunks[0] = _chunks[1] = NULL;
+
+ _endAction = NULL;
+ _voiceNum = 0;
+ _currentChunkIndex = 0;
+ _nextChunkIndex = 0;
+}
+
+void PlayStream::dispatch() {
+ if ((_voiceNum != 0) && (_currentChunkIndex == _nextChunkIndex)) {
+ if (READ_LE_UINT16(_chunks[_currentChunkIndex] + 6) != 0) {
+ uint32 bytesRead = _file.read(_chunks[_nextChunkIndex ^ 1], _resData._chunkSize);
+
+ if (bytesRead != _resData._chunkSize) {
+ byte *data = _chunks[_currentChunkIndex];
+ Common::fill(data, data + 128, 0);
+
+ _voiceNum = 0;
+ }
+
+ _nextChunkIndex ^= 1;
+ } else if (!isPlaying()) {
+ // If voice has finished playing, reset fields
+ EventHandler *endAction = _endAction;
+ _endAction = NULL;
+ _voiceNum = 0;
+ _currentChunkIndex = 0;
+ _nextChunkIndex = 0;
+
+ if (endAction)
+ // Signal given end action
+ endAction->signal();
+ }
+ }
+}
+
+uint32 PlayStream::getFileOffset(const uint16 *data, int count, int voiceNum) {
+ assert(data);
+ int bitsIndex = voiceNum & 7;
+ int byteIndex = voiceNum >> 3;
+ int shiftAmount = bitsIndex * 2;
+ int bitMask = 3 << shiftAmount;
+ int v = (data[byteIndex] & bitMask) >> shiftAmount;
+ uint32 offset = 0;
+
+ if (!v)
+ return 0;
+
+ // Loop to figure out offsets from indexes skipped over
+ for (int i = 0; i < (voiceNum >> 3); ++i) {
+ for (int bit = 0; bit < 16; bit += 2)
+ offset += ((data[i] >> bit) & 3) * count;
+ }
+
+ // Bit index loop
+ for (int i = 0; i < bitsIndex; --i)
+ offset += ((data[byteIndex] >> (i * 2)) & 3) * count;
+
+ return offset;
+}
+
+void PlayStream::stream() {
+ // TODO
+}
+
+/*--------------------------------------------------------------------------*/
+
SoundDriver::SoundDriver() {
_driverResID = 0;
_minVersion = _maxVersion = 0;