mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
Objectified the AudioResource code (used for speech and digitized music in CD talkie games)
svn-id: r40880
This commit is contained in:
parent
5ef58bdfbe
commit
d59796fb54
engines/sci
@ -86,11 +86,6 @@ namespace Sci {
|
||||
#define _K_SCI1_SOUND_REVERB 19 /* Get/Set */
|
||||
#define _K_SCI1_SOUND_UPDATE_VOL_PRI 20
|
||||
|
||||
Audio::SoundHandle _audioHandle;
|
||||
uint16 _audioRate;
|
||||
int16 _lang;
|
||||
byte *_audioMap;
|
||||
|
||||
enum AudioCommands {
|
||||
// TODO: find the difference between kSci1AudioWPlay and kSci1AudioPlay
|
||||
kSci1AudioWPlay = 1, /* Plays an audio stream */
|
||||
@ -999,33 +994,6 @@ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) {
|
||||
return kDoSound_SCI0(s, funct_nr, argc, argv);
|
||||
}
|
||||
|
||||
bool findAudEntry(uint16 audioNumber, byte& volume, uint32& offset, uint32& size) {
|
||||
// AUDIO00X.MAP contains 10-byte entries:
|
||||
// w nEntry
|
||||
// dw offset+volume (as in resource.map)
|
||||
// dw size
|
||||
// ending with 10 0xFFs
|
||||
uint16 n;
|
||||
uint32 off;
|
||||
|
||||
if (_audioMap == 0)
|
||||
return false;
|
||||
|
||||
byte *ptr = _audioMap;
|
||||
while ((n = READ_UINT16(ptr)) != 0xFFFF) {
|
||||
if (n == audioNumber) {
|
||||
off = READ_LE_UINT32(ptr + 2);
|
||||
size = READ_LE_UINT32(ptr + 6);
|
||||
volume = off >> 28;
|
||||
offset = off & 0x0FFFFFFF;
|
||||
return true;
|
||||
}
|
||||
ptr += 10;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used for speech playback in CD games
|
||||
reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) {
|
||||
Audio::Mixer *mixer = g_system->getMixer();
|
||||
@ -1034,94 +1002,50 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) {
|
||||
switch (UKPV(0)) {
|
||||
case kSci1AudioWPlay:
|
||||
case kSci1AudioPlay: {
|
||||
mixer->stopHandle(_audioHandle);
|
||||
s->sound.audioResource->stop();
|
||||
|
||||
Audio::AudioStream *audioStream = 0;
|
||||
|
||||
// Try to load from an external patch file first
|
||||
Sci::Resource* audioRes = s->resmgr->findResource(kResourceTypeAudio, UKPV(1), 1);
|
||||
Audio::AudioStream *audioStream = 0;
|
||||
|
||||
if (audioRes) {
|
||||
audioStream = Audio::makeLinearInputStream(audioRes->data, audioRes->size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0);
|
||||
sampleLen = audioRes->size * 60 / _audioRate;
|
||||
audioStream = s->sound.audioResource->getAudioStream(audioRes, &sampleLen);
|
||||
} else {
|
||||
// No patch file found, read it from the audio volume
|
||||
byte volume;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
|
||||
if (findAudEntry(UKPV(1), volume, offset, size)) {
|
||||
uint32 start = offset * 1000 / _audioRate;
|
||||
uint32 duration = size * 1000 / _audioRate;
|
||||
|
||||
char filename[40];
|
||||
sprintf(filename, "AUDIO%03d.%03d", _lang, volume);
|
||||
|
||||
// Try to load compressed
|
||||
audioStream = Audio::AudioStream::openStreamFile(filename, start, duration);
|
||||
if (!audioStream) {
|
||||
// Compressed file load failed, try to load original raw data
|
||||
byte *soundbuff = (byte *)malloc(size);
|
||||
Common::File* audioFile = new Common::File();
|
||||
if (audioFile->open(filename)) {
|
||||
audioFile->seek(offset);
|
||||
audioFile->read(soundbuff, size);
|
||||
audioFile->close();
|
||||
delete audioFile;
|
||||
|
||||
audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate,
|
||||
Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sampleLen = size * 60 / _audioRate;
|
||||
}
|
||||
audioStream = s->sound.audioResource->getAudioStream(UKPV(1), &sampleLen);
|
||||
}
|
||||
|
||||
if (audioStream)
|
||||
mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream);
|
||||
}
|
||||
mixer->playInputStream(Audio::Mixer::kSpeechSoundType, s->sound.audioResource->getAudioHandle(), audioStream);
|
||||
|
||||
}
|
||||
return make_reg(0, sampleLen); // return sample length in ticks
|
||||
case kSci1AudioStop:
|
||||
mixer->stopHandle(_audioHandle);
|
||||
s->sound.audioResource->stop();
|
||||
break;
|
||||
case kSci1AudioPause:
|
||||
mixer->pauseHandle(_audioHandle, true);
|
||||
s->sound.audioResource->pause();
|
||||
break;
|
||||
case kSci1AudioResume:
|
||||
mixer->pauseHandle(_audioHandle, false);
|
||||
s->sound.audioResource->resume();
|
||||
break;
|
||||
case kSci1AudioPosition:
|
||||
if (mixer->isSoundHandleActive(_audioHandle)) {
|
||||
return make_reg(0, mixer->getSoundElapsedTime(_audioHandle) * 6 / 100); // return elapsed time in ticks
|
||||
} else {
|
||||
return make_reg(0, -1); // Sound finished
|
||||
}
|
||||
return make_reg(0, s->sound.audioResource->getAudioPosition());
|
||||
case kSci1AudioRate:
|
||||
_audioRate = UKPV(1);
|
||||
s->sound.audioResource->setAudioRate(UKPV(1));
|
||||
break;
|
||||
case kSci1AudioVolume:
|
||||
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, UKPV(1));
|
||||
break;
|
||||
case kSci1AudioLanguage:
|
||||
// TODO: CD Audio (used for example in the end credits of KQ6CD)
|
||||
if (SKPV(1) != -1) {
|
||||
_lang = UKPV(1);
|
||||
if (s->sound.audioResource)
|
||||
delete s->sound.audioResource;
|
||||
|
||||
char filename[40];
|
||||
sprintf(filename, "AUDIO%03d.MAP", _lang);
|
||||
// The audio resource is freed when freeing all resources
|
||||
s->sound.audioResource = new AudioResource();
|
||||
s->sound.audioResource->setAudioLang(SKPV(1));
|
||||
|
||||
Common::File* audioMapFile = new Common::File();
|
||||
if (audioMapFile->open(filename)) {
|
||||
// TODO: This needs to be freed, right now we got a memory leak here!
|
||||
_audioMap = new byte[audioMapFile->size()];
|
||||
audioMapFile->read(_audioMap, audioMapFile->size());
|
||||
audioMapFile->close();
|
||||
delete audioMapFile;
|
||||
} else {
|
||||
_audioMap = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warning("kDoAudio: Unhandled case %d", UKPV(0));
|
||||
|
@ -1159,4 +1159,113 @@ void ResourceSync::stopSync() {
|
||||
//syncStarted = false; // not used
|
||||
}
|
||||
|
||||
|
||||
AudioResource::AudioResource() {
|
||||
_audioRate = 0;
|
||||
_lang = 0;
|
||||
_audioMap = 0;
|
||||
}
|
||||
|
||||
AudioResource::~AudioResource() {
|
||||
delete _audioMap;
|
||||
_audioMap = 0;
|
||||
}
|
||||
|
||||
void AudioResource::setAudioLang(int16 lang) {
|
||||
// TODO: CD Audio (used for example in the end credits of KQ6CD)
|
||||
if (lang != -1) {
|
||||
_lang = lang;
|
||||
|
||||
char filename[40];
|
||||
sprintf(filename, "AUDIO%03d.MAP", _lang);
|
||||
|
||||
Common::File* audioMapFile = new Common::File();
|
||||
if (audioMapFile->open(filename)) {
|
||||
// The audio map is freed in the destructor
|
||||
_audioMap = new byte[audioMapFile->size()];
|
||||
audioMapFile->read(_audioMap, audioMapFile->size());
|
||||
audioMapFile->close();
|
||||
delete audioMapFile;
|
||||
} else {
|
||||
_audioMap = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AudioResource::getAudioPosition() {
|
||||
if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) {
|
||||
return g_system->getMixer()->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks
|
||||
} else {
|
||||
return -1; // Sound finished
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioResource::findAudEntry(uint16 audioNumber, byte& volume, uint32& offset, uint32& size) {
|
||||
// AUDIO00X.MAP contains 10-byte entries:
|
||||
// w nEntry
|
||||
// dw offset+volume (as in resource.map)
|
||||
// dw size
|
||||
// ending with 10 0xFFs
|
||||
uint16 n;
|
||||
uint32 off;
|
||||
|
||||
if (_audioMap == 0)
|
||||
return false;
|
||||
|
||||
byte *ptr = _audioMap;
|
||||
while ((n = READ_UINT16(ptr)) != 0xFFFF) {
|
||||
if (n == audioNumber) {
|
||||
off = READ_LE_UINT32(ptr + 2);
|
||||
size = READ_LE_UINT32(ptr + 6);
|
||||
volume = off >> 28;
|
||||
offset = off & 0x0FFFFFFF;
|
||||
return true;
|
||||
}
|
||||
ptr += 10;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Audio::AudioStream* AudioResource::getAudioStream(uint16 audioNumber, int* sampleLen) {
|
||||
Audio::AudioStream *audioStream = 0;
|
||||
byte volume;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
|
||||
if (findAudEntry(audioNumber, volume, offset, size)) {
|
||||
uint32 start = offset * 1000 / _audioRate;
|
||||
uint32 duration = size * 1000 / _audioRate;
|
||||
|
||||
char filename[40];
|
||||
sprintf(filename, "AUDIO%03d.%03d", _lang, volume);
|
||||
|
||||
// Try to load compressed
|
||||
audioStream = Audio::AudioStream::openStreamFile(filename, start, duration);
|
||||
if (!audioStream) {
|
||||
// Compressed file load failed, try to load original raw data
|
||||
byte *soundbuff = (byte *)malloc(size);
|
||||
Common::File* audioFile = new Common::File();
|
||||
if (audioFile->open(filename)) {
|
||||
audioFile->seek(offset);
|
||||
audioFile->read(soundbuff, size);
|
||||
audioFile->close();
|
||||
delete audioFile;
|
||||
|
||||
audioStream = Audio::makeLinearInputStream(soundbuff, size, _audioRate,
|
||||
Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
*sampleLen = size * 60 / _audioRate;
|
||||
}
|
||||
|
||||
return audioStream;
|
||||
}
|
||||
|
||||
Audio::AudioStream* AudioResource::getAudioStream(Resource* audioRes, int* sampleLen) {
|
||||
*sampleLen = audioRes->size * 60 / _audioRate;
|
||||
return Audio::makeLinearInputStream(audioRes->data, audioRes->size, _audioRate, Audio::Mixer::FLAG_UNSIGNED, 0, 0);
|
||||
}
|
||||
|
||||
} // End of namespace Sci
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include "common/file.h"
|
||||
#include "common/archive.h"
|
||||
|
||||
#include "sound/audiostream.h"
|
||||
#include "sound/mixer.h" // for SoundHandle
|
||||
|
||||
#include "sci/engine/vm.h" // for Object
|
||||
#include "sci/decompressor.h"
|
||||
|
||||
@ -299,6 +302,32 @@ protected:
|
||||
//bool _syncStarted; // not used
|
||||
};
|
||||
|
||||
class AudioResource {
|
||||
public:
|
||||
AudioResource();
|
||||
~AudioResource();
|
||||
|
||||
void setAudioRate(uint16 audioRate) { _audioRate = audioRate; }
|
||||
void setAudioLang(int16 lang);
|
||||
|
||||
Audio::SoundHandle* getAudioHandle() { return &_audioHandle; }
|
||||
int getAudioPosition();
|
||||
Audio::AudioStream* getAudioStream(uint16 audioNumber, int* sampleLen);
|
||||
Audio::AudioStream* getAudioStream(Resource* audioRes, int* sampleLen);
|
||||
|
||||
void stop() { g_system->getMixer()->stopHandle(_audioHandle); }
|
||||
void pause() { g_system->getMixer()->pauseHandle(_audioHandle, true); }
|
||||
void resume() { g_system->getMixer()->pauseHandle(_audioHandle, false); }
|
||||
|
||||
private:
|
||||
Audio::SoundHandle _audioHandle;
|
||||
uint16 _audioRate;
|
||||
int16 _lang;
|
||||
byte *_audioMap;
|
||||
|
||||
bool findAudEntry(uint16 audioNumber, byte& volume, uint32& offset, uint32& size);
|
||||
};
|
||||
|
||||
} // End of namespace Sci
|
||||
|
||||
#endif // SCI_SCICORE_RESOURCE_H
|
||||
|
@ -367,6 +367,7 @@ void sfx_init(sfx_state_t *self, ResourceManager *resmgr, int flags) {
|
||||
self->flags = flags;
|
||||
self->debug = 0; /* Disable all debugging by default */
|
||||
self->soundSync = NULL;
|
||||
self->audioResource = NULL;
|
||||
|
||||
if (flags & SFX_STATE_FLAG_NOSOUND) {
|
||||
player = NULL;
|
||||
@ -443,6 +444,12 @@ void sfx_exit(sfx_state_t *self) {
|
||||
|
||||
if (strcmp(player->name, "new") == 0)
|
||||
g_system->getMixer()->stopAll();
|
||||
|
||||
// Delete audio resources for CD talkie games
|
||||
if (self->audioResource) {
|
||||
delete self->audioResource;
|
||||
self->audioResource = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sfx_suspend(sfx_state_t *self, int suspend) {
|
||||
|
@ -55,7 +55,8 @@ struct sfx_state_t {
|
||||
song_t *song; /* Active song, or start of active song chain */
|
||||
int suspended; /* Whether we are suspended */
|
||||
unsigned int debug; /* Debug flags */
|
||||
ResourceSync *soundSync; /* Used by kDoSync for speech syncing in talkie games */
|
||||
ResourceSync *soundSync; /* Used by kDoSync for speech syncing in CD talkie games */
|
||||
AudioResource *audioResource; /* Used for audio resources in CD talkie games */
|
||||
};
|
||||
|
||||
/***********/
|
||||
|
Loading…
Reference in New Issue
Block a user