mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-22 04:01:23 +00:00
DIRECTOR: Fix audio lifetime, implement b_puppetSound
This commit is contained in:
parent
3382e3e965
commit
59d6c5e5fd
@ -461,6 +461,7 @@ bool RIFXArchive::openStream(Common::SeekableReadStream *stream, uint32 startOff
|
||||
tag == MKTAG('R', 'T', 'E', '0') ||
|
||||
tag == MKTAG('R', 'T', 'E', '1') ||
|
||||
tag == MKTAG('R', 'T', 'E', '2') ||
|
||||
tag == MKTAG('s', 'n', 'd', ' ') ||
|
||||
tag == MKTAG('L', 'c', 't', 'x') ||
|
||||
tag == MKTAG('L', 'n', 'a', 'm') ||
|
||||
tag == MKTAG('L', 's', 'c', 'r'))
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "director/cachedmactext.h"
|
||||
#include "director/cast.h"
|
||||
#include "director/score.h"
|
||||
#include "director/sound.h"
|
||||
#include "director/stxt.h"
|
||||
|
||||
namespace Director {
|
||||
|
@ -30,10 +30,6 @@ namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Audio {
|
||||
struct SeekableAudioStream;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class ReadStreamEndian;
|
||||
@ -43,6 +39,7 @@ namespace Director {
|
||||
|
||||
class Stxt;
|
||||
class CachedMacText;
|
||||
class SNDDecoder;
|
||||
|
||||
class Cast {
|
||||
public:
|
||||
@ -80,7 +77,7 @@ public:
|
||||
SoundCast(Common::ReadStreamEndian &stream, uint16 version);
|
||||
|
||||
bool _looping;
|
||||
Audio::SeekableAudioStream *_audio;
|
||||
SNDDecoder *_audio;
|
||||
};
|
||||
|
||||
class ShapeCast : public Cast {
|
||||
|
@ -23,11 +23,13 @@
|
||||
#include "common/system.h"
|
||||
|
||||
#include "director/director.h"
|
||||
#include "director/cast.h"
|
||||
#include "director/lingo/lingo.h"
|
||||
#include "director/lingo/lingo-builtins.h"
|
||||
#include "director/lingo/lingo-code.h"
|
||||
#include "director/frame.h"
|
||||
#include "director/score.h"
|
||||
#include "director/sound.h"
|
||||
#include "director/sprite.h"
|
||||
#include "director/stxt.h"
|
||||
|
||||
@ -1394,11 +1396,33 @@ void LB::b_puppetPalette(int nargs) {
|
||||
}
|
||||
|
||||
void LB::b_puppetSound(int nargs) {
|
||||
g_lingo->convertVOIDtoString(0, nargs);
|
||||
if (nargs != 1) {
|
||||
error("b_puppetSound: expected 1 argument, got %d", nargs);
|
||||
g_lingo->dropStack(nargs);
|
||||
return;
|
||||
}
|
||||
Score *score = g_director->getCurrentScore();
|
||||
|
||||
g_lingo->printSTUBWithArglist("b_puppetSound", nargs);
|
||||
DirectorSound *sound = g_director->getSoundManager();
|
||||
Datum castMember = g_lingo->pop();
|
||||
int castId = g_lingo->castIdFetch(castMember);
|
||||
|
||||
if (castId == 0) {
|
||||
sound->stopSound(1);
|
||||
} else {
|
||||
Cast *cast = score->_loadedCast->getVal(castId);
|
||||
if (cast->_type != kCastSound) {
|
||||
error("b_puppetSound: attempted to play a non-SoundCast cast member");
|
||||
return;
|
||||
}
|
||||
SNDDecoder *sd = ((SoundCast *)cast)->_audio;
|
||||
if (!sd) {
|
||||
warning("b_puppetSound: no audio data attached to cast");
|
||||
return;
|
||||
}
|
||||
sound->playStream(*sd->getAudioStream(), 1);
|
||||
}
|
||||
|
||||
g_lingo->dropStack(nargs);
|
||||
}
|
||||
|
||||
void LB::b_puppetSprite(int nargs) {
|
||||
@ -1802,29 +1826,7 @@ void LB::b_cast(int nargs) {
|
||||
void LB::b_field(int nargs) {
|
||||
Datum d = g_lingo->pop();
|
||||
|
||||
int id;
|
||||
|
||||
if (!g_director->getCurrentScore()) {
|
||||
warning("b_field: Assigning to a field in an empty score");
|
||||
d.u.i = 0;
|
||||
d.type = INT;
|
||||
g_lingo->push(d);
|
||||
return;
|
||||
}
|
||||
|
||||
if (d.type == STRING) {
|
||||
if (g_director->getCurrentScore()->_castsNames.contains(*d.u.s))
|
||||
id = g_director->getCurrentScore()->_castsNames[*d.u.s];
|
||||
else
|
||||
error("b_field: Reference to non-existent field: %s", d.u.s->c_str());
|
||||
} else if (d.type == INT || d.type == FLOAT) {
|
||||
d.toInt();
|
||||
id = d.u.i;
|
||||
} else {
|
||||
error("b_field: Incorrect reference type: %s", d.type2str());
|
||||
}
|
||||
|
||||
d.u.i = id;
|
||||
d.u.i = g_lingo->castIdFetch(d);
|
||||
|
||||
d.type = REFERENCE;
|
||||
|
||||
|
@ -488,7 +488,7 @@ void Lingo::processIf(int startlabel, int endlabel, int finalElse) {
|
||||
int Lingo::castIdFetch(Datum &var) {
|
||||
Score *score = _vm->getCurrentScore();
|
||||
if (!score) {
|
||||
warning("castFetch: Score is empty");
|
||||
warning("castIdFetch: Score is empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -497,15 +497,15 @@ int Lingo::castIdFetch(Datum &var) {
|
||||
if (score->_castsNames.contains(*var.u.s))
|
||||
id = score->_castsNames[*var.u.s];
|
||||
else
|
||||
warning("castFetch: reference to non-existent cast member: %s", var.u.s->c_str());
|
||||
warning("castIdFetch: reference to non-existent cast member: %s", var.u.s->c_str());
|
||||
} else if (var.type == INT || var.type == FLOAT) {
|
||||
var.toInt();
|
||||
if (!score->_loadedCast->contains(var.u.i))
|
||||
warning("castFetch: reference to non-existent cast ID: %d", var.u.i);
|
||||
warning("castIdFetch: reference to non-existent cast ID: %d", var.u.i);
|
||||
else
|
||||
id = var.u.i;
|
||||
} else {
|
||||
error("castFetch: was expecting STRING or INT, got %s", var.type2str());
|
||||
error("castIdFetch: was expecting STRING or INT, got %s", var.type2str());
|
||||
}
|
||||
|
||||
return id;
|
||||
|
@ -698,27 +698,9 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
|
||||
|
||||
Datum Lingo::getTheCast(Datum &id1, int field) {
|
||||
Datum d;
|
||||
int id = 0;
|
||||
int id = g_lingo->castIdFetch(id1);
|
||||
|
||||
Score *score = _vm->getCurrentScore();
|
||||
|
||||
if (!score) {
|
||||
warning("Lingo::getTheCast(): The cast %d field \"%s\" setting over non-active score", id, field2str(field));
|
||||
return d;
|
||||
}
|
||||
|
||||
if (id1.type == INT) {
|
||||
id = id1.u.i;
|
||||
} else if (id1.type == STRING) {
|
||||
if (score->_castsNames.contains(*id1.u.s)) {
|
||||
id = score->_castsNames[*id1.u.s];
|
||||
} else {
|
||||
warning("Lingo::getTheCast(): Unknown the cast \"%s\"", id1.u.s->c_str());
|
||||
}
|
||||
} else {
|
||||
warning("Lingo::getTheCast(): Unknown the cast id type: %s", id1.type2str());
|
||||
return d;
|
||||
}
|
||||
|
||||
// Setting default type
|
||||
d.type = INT;
|
||||
|
||||
|
@ -403,7 +403,8 @@ void Score::loadSpriteSounds(bool isSharedCast) {
|
||||
}
|
||||
|
||||
if (sndData != NULL && soundCast != NULL) {
|
||||
Audio::SeekableAudioStream *audio = makeSNDStream(sndData);
|
||||
SNDDecoder *audio = new SNDDecoder();
|
||||
audio->loadStream(*sndData);
|
||||
soundCast->_audio = audio;
|
||||
}
|
||||
}
|
||||
|
@ -97,10 +97,14 @@ void DirectorSound::playMCI(Audio::AudioStream &stream, uint32 from, uint32 to)
|
||||
|
||||
void DirectorSound::playStream(Audio::AudioStream &stream, uint8 soundChannel) {
|
||||
Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(&stream);
|
||||
playStream(*seekStream, soundChannel);
|
||||
}
|
||||
|
||||
void DirectorSound::playStream(Audio::SeekableAudioStream &stream, uint8 soundChannel) {
|
||||
if (soundChannel == 1)
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound1, seekStream);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound1, &stream);
|
||||
else
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound2, seekStream);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _sound2, &stream);
|
||||
}
|
||||
|
||||
bool DirectorSound::isChannelActive(uint8 channelID) {
|
||||
@ -115,6 +119,15 @@ bool DirectorSound::isChannelActive(uint8 channelID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void DirectorSound::stopSound(uint8 channelID) {
|
||||
if (channelID == 1) {
|
||||
_mixer->stopHandle(*_sound1);
|
||||
} else if (channelID == 2) {
|
||||
_mixer->stopHandle(*_sound2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void DirectorSound::stopSound() {
|
||||
_mixer->stopHandle(*_sound1);
|
||||
_mixer->stopHandle(*_sound2);
|
||||
@ -125,55 +138,78 @@ void DirectorSound::systemBeep() {
|
||||
_speaker->play(Audio::PCSpeaker::kWaveFormSquare, 500, 150);
|
||||
}
|
||||
|
||||
SNDDecoder::SNDDecoder() {
|
||||
_data = nullptr;
|
||||
_channels = 0;
|
||||
_size = 0;
|
||||
_rate = 0;
|
||||
_flags = 0;
|
||||
}
|
||||
|
||||
SNDDecoder::~SNDDecoder() {
|
||||
if (_data) {
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SNDDecoder::loadStream(Common::SeekableSubReadStreamEndian &stream) {
|
||||
if (_data) {
|
||||
free(_data);
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *makeSNDStream(Common::SeekableSubReadStreamEndian *stream) {
|
||||
if (debugChannelSet(5, kDebugLoading)) {
|
||||
debugC(5, kDebugLoading, "snd header:");
|
||||
stream->hexdump(0x4e);
|
||||
stream.hexdump(0x4e);
|
||||
}
|
||||
|
||||
// unk1
|
||||
for (uint32 i = 0; i < 0x14; i++) {
|
||||
stream->readByte();
|
||||
stream.readByte();
|
||||
}
|
||||
uint16 channels = stream->readUint16();
|
||||
if (channels != 1 || channels != 2) {
|
||||
_channels = stream.readUint16();
|
||||
if (!(_channels == 1 || _channels == 2)) {
|
||||
warning("STUB: loadSpriteSounds: no support for old sound format");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
uint16 rate = stream->readUint16();
|
||||
_rate = stream.readUint16();
|
||||
|
||||
// unk2
|
||||
for (uint32 i = 0; i < 0x06; i++) {
|
||||
stream->readByte();
|
||||
stream.readByte();
|
||||
}
|
||||
uint32 length = stream->readUint32();
|
||||
/*uint16 unk3 =*/stream->readUint16();
|
||||
/*uint32 length_copy =*/stream->readUint32();
|
||||
/*uint8 unk4 =*/stream->readByte();
|
||||
/*uint8 unk5 =*/stream->readByte();
|
||||
/*uint16 unk6 =*/stream->readUint16();
|
||||
uint32 length = stream.readUint32();
|
||||
/*uint16 unk3 =*/stream.readUint16();
|
||||
/*uint32 length_copy =*/stream.readUint32();
|
||||
/*uint8 unk4 =*/stream.readByte();
|
||||
/*uint8 unk5 =*/stream.readByte();
|
||||
/*uint16 unk6 =*/stream.readUint16();
|
||||
// unk7
|
||||
for (uint32 i = 0; i < 0x12; i++) {
|
||||
stream->readByte();
|
||||
stream.readByte();
|
||||
}
|
||||
uint16 bits = stream->readUint16();
|
||||
uint16 bits = stream.readUint16();
|
||||
// unk8
|
||||
for (uint32 i = 0; i < 0x0c; i++) {
|
||||
stream->readByte();
|
||||
stream.readByte();
|
||||
}
|
||||
|
||||
byte flags = 0;
|
||||
flags |= channels == 2 ? Audio::FLAG_STEREO : 0;
|
||||
flags |= bits == 16 ? Audio::FLAG_16BITS : 0;
|
||||
flags |= bits == 8 ? Audio::FLAG_UNSIGNED : 0;
|
||||
uint32 size = length * channels * (bits == 16 ? 2 : 1);
|
||||
_flags = 0;
|
||||
_flags |= _channels == 2 ? Audio::FLAG_STEREO : 0;
|
||||
_flags |= bits == 16 ? Audio::FLAG_16BITS : 0;
|
||||
_flags |= bits == 8 ? Audio::FLAG_UNSIGNED : 0;
|
||||
_size = length * _channels * (bits == 16 ? 2 : 1);
|
||||
|
||||
byte *data = (byte *)malloc(size);
|
||||
assert(data);
|
||||
stream->read(data, size);
|
||||
_data = (byte *)malloc(_size);
|
||||
assert(_data);
|
||||
stream.read(_data, _size);
|
||||
|
||||
return Audio::makeRawStream(data, size, rate, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *SNDDecoder::getAudioStream() {
|
||||
return Audio::makeRawStream(_data, _size, _rate, _flags, DisposeAfterUse::NO);
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,12 +50,29 @@ public:
|
||||
void playAIFF(Common::String filename, uint8 channelID);
|
||||
void playMCI(Audio::AudioStream &stream, uint32 from, uint32 to);
|
||||
void playStream(Audio::AudioStream &stream, uint8 soundChannel);
|
||||
void playStream(Audio::SeekableAudioStream &stream, uint8 soundChannel);
|
||||
void systemBeep();
|
||||
bool isChannelActive(uint8 channelID);
|
||||
void stopSound(uint8 channelID);
|
||||
void stopSound();
|
||||
};
|
||||
|
||||
Audio::SeekableAudioStream *makeSNDStream(Common::SeekableSubReadStreamEndian *stream);
|
||||
|
||||
class SNDDecoder {
|
||||
public:
|
||||
SNDDecoder();
|
||||
~SNDDecoder();
|
||||
|
||||
bool loadStream(Common::SeekableSubReadStreamEndian &stream);
|
||||
Audio::SeekableAudioStream *getAudioStream();
|
||||
|
||||
private:
|
||||
byte *_data;
|
||||
uint16 _channels;
|
||||
uint32 _size;
|
||||
uint16 _rate;
|
||||
byte _flags;
|
||||
};
|
||||
|
||||
} // End of namespace Director
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user