Add support for CD Audio in Jones in the Fast Lane CD and KQ6 CD.

svn-id: r45367
This commit is contained in:
Matthew Hoops 2009-10-25 03:26:20 +00:00
parent 452ae8a576
commit 55e0efeb8f
3 changed files with 110 additions and 1 deletions

View file

@ -31,6 +31,7 @@
#include "sci/engine/kernel.h" #include "sci/engine/kernel.h"
#include "sci/engine/vm.h" // for Object #include "sci/engine/vm.h" // for Object
#include "sound/audiocd.h"
#include "sound/audiostream.h" #include "sound/audiostream.h"
#include "sound/mixer.h" #include "sound/mixer.h"
@ -112,7 +113,8 @@ enum AudioCommands {
kSciAudioPosition = 6, /* Return current position in audio stream */ kSciAudioPosition = 6, /* Return current position in audio stream */
kSciAudioRate = 7, /* Return audio rate */ kSciAudioRate = 7, /* Return audio rate */
kSciAudioVolume = 8, /* Return audio volume */ kSciAudioVolume = 8, /* Return audio volume */
kSciAudioLanguage = 9 /* Return audio language */ kSciAudioLanguage = 9, /* Return audio language */
kSciAudioCD = 10 /* Plays SCI1.1 CD audio */
}; };
enum AudioSyncCommands { enum AudioSyncCommands {
@ -1023,10 +1025,107 @@ reg_t kDoSound(EngineState *s, int argc, reg_t *argv) {
} }
} }
reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case kSciAudioWPlay:
case kSciAudioPlay: {
if (getSciVersion() == SCI_VERSION_1_1) {
// King's Quest VI CD Audio format
if (argc < 2)
return NULL_REG;
uint16 track = argv[1].toUint16() - 1;
uint32 startFrame = 0;
uint32 totalFrames = 0;
if (argc > 2)
startFrame = argv[2].toUint16() * 75;
if (argc > 3)
totalFrames = argv[3].toUint16() * 75;
AudioCD.play(track, 1, startFrame, totalFrames);
return make_reg(0, 1);
} else {
// Jones in the Fast Lane CD Audio format
if (argc != 2)
error("kDoCdAudio(%d) called with %d args", argv[0].toUint16(), argc);
AudioCD.stop();
Common::File audioMap;
if(!audioMap.open("cdaudio.map"))
error("Could not open cdaudio.map");
uint16 sample = argv[1].toUint16();
uint32 length = 0;
while (audioMap.pos() < audioMap.size()) {
uint16 res = audioMap.readUint16LE();
uint32 startFrame = audioMap.readUint16LE();
startFrame += audioMap.readByte() << 16;
audioMap.readByte(); // Unknown, always 0x20
length = audioMap.readUint16LE();
length += audioMap.readByte() << 16;
audioMap.readByte(); // Unknown, always 0x00
if (res == sample) {
AudioCD.play(1, 1, startFrame, length);
s->_audioCdStart = g_system->getMillis();
break;
}
}
audioMap.close();
return make_reg(0, length * 60 / 75); // return sample length in ticks
}
}
case kSciAudioStop:
AudioCD.stop();
if (getSciVersion() == SCI_VERSION_1_1)
return make_reg(0, 1);
break;
case kSciAudioPause:
warning("Can't pause CD Audio");
break;
case kSciAudioResume:
// This seems to be hacked up to update the CD instead of resuming
// audio like kDoAudio does.
AudioCD.updateCD();
break;
case kSciAudioPosition:
// Return -1 if the sample is done playing. Converting to frames to compare.
if (((g_system->getMillis() - s->_audioCdStart) * 75 / 1000) >= (uint32)AudioCD.getStatus().duration)
return SIGNAL_REG;
// Return the position otherwise (in ticks).
return make_reg(0, (g_system->getMillis() - s->_audioCdStart) * 60 / 1000);
case kSciAudioRate: // No need to set the audio rate
case kSciAudioVolume: // The speech setting isn't used by CD Audio
case kSciAudioLanguage: // No need to set the language
break;
case kSciAudioCD:
// Init
return make_reg(0, 1);
default:
warning("kCdDoAudio: Unhandled case %d", argv[0].toUint16());
}
return s->r_acc;
}
/** /**
* Used for speech playback and digital soundtracks in CD games * Used for speech playback and digital soundtracks in CD games
*/ */
reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) { reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// JonesCD uses different functions based on the cdaudio.map file
// to use red book tracks.
if (s->usesCdTrack())
return kDoCdAudio(s, argc, argv);
Audio::Mixer *mixer = g_system->getMixer(); Audio::Mixer *mixer = g_system->getMixer();
switch (argv[0].toUint16()) { switch (argv[0].toUint16()) {
@ -1076,6 +1175,8 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
s->resMan->setAudioLanguage(argv[1].toSint16()); s->resMan->setAudioLanguage(argv[1].toSint16());
} }
break; break;
case kSciAudioCD:
return kDoCdAudio(s, argc - 1, argv + 1);
default: default:
warning("kDoAudio: Unhandled case %d", argv[0].toUint16()); warning("kDoAudio: Unhandled case %d", argv[0].toUint16());
} }

View file

@ -114,6 +114,9 @@ EngineState::EngineState(ResourceManager *res, Kernel *kernel, Vocabulary *voc,
_lofsType = SCI_VERSION_AUTODETECT; _lofsType = SCI_VERSION_AUTODETECT;
_gfxFunctionsType = SCI_VERSION_AUTODETECT; _gfxFunctionsType = SCI_VERSION_AUTODETECT;
_moveCountType = kMoveCountUninitialized; _moveCountType = kMoveCountUninitialized;
_audioCdStart = 0;
_usesCdTrack = Common::File::exists("cdaudio.map");
} }
EngineState::~EngineState() { EngineState::~EngineState() {

View file

@ -264,6 +264,8 @@ public:
MoveCountType detectMoveCountType(); MoveCountType detectMoveCountType();
bool handleMoveCount() { return detectMoveCountType() == kIncrementMoveCount; } bool handleMoveCount() { return detectMoveCountType() == kIncrementMoveCount; }
bool usesCdTrack() { return _usesCdTrack; }
/* Debugger data: */ /* Debugger data: */
Breakpoint *bp_list; /**< List of breakpoints */ Breakpoint *bp_list; /**< List of breakpoints */
@ -283,12 +285,15 @@ public:
EngineState *successor; /**< Successor of this state: Used for restoring */ EngineState *successor; /**< Successor of this state: Used for restoring */
Common::String getLanguageString(const char *str, kLanguage lang) const; Common::String getLanguageString(const char *str, kLanguage lang) const;
uint32 _audioCdStart;
private: private:
SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType; SciVersion _doSoundType, _setCursorType, _lofsType, _gfxFunctionsType;
MoveCountType _moveCountType; MoveCountType _moveCountType;
kLanguage charToLanguage(const char c) const; kLanguage charToLanguage(const char c) const;
int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const; int methodChecksum(reg_t objAddress, Selector sel, int offset, uint size) const;
uint16 firstRetOffset(reg_t objectAddress) const; uint16 firstRetOffset(reg_t objectAddress) const;
bool _usesCdTrack;
}; };
/** /**