Cleaned up the sound code enough to add cutscene voice-overs. I haven't had

the time to do much testing yet, but it seems to work for me.

svn-id: r10361
This commit is contained in:
Torbjörn Andersson 2003-09-22 06:36:38 +00:00
parent 18961542f9
commit 8e28b0c6b4
5 changed files with 65 additions and 188 deletions

View File

@ -479,7 +479,8 @@ typedef struct {
uint16 startFrame;
uint16 endFrame;
mem *text_mem;
mem *speech_mem;
uint32 speechBufferSize;
uint16 *speech_mem;
} _sequenceTextInfo;
// keeps count of number of text lines to disaply during the sequence
@ -513,10 +514,9 @@ void CreateSequenceSpeech(_movieTextObject *sequenceText[]) { // (James23may97)
uint32 local_text;
uint32 text_res;
uint8 *text;
int16 wavId; // ie. offical text number (actor text number)
uint32 wavId; // ie. offical text number (actor text number)
uint8 speechRunning;
char speechFile[256];
int32 wavSize;
// for each sequence text line that's been logged
for (line = 0; line < sequenceTextLines; line++) {
@ -568,45 +568,10 @@ void CreateSequenceSpeech(_movieTextObject *sequenceText[]) { // (James23may97)
else
strcpy(speechFile, "speech.clu");
wavSize = g_sound->GetCompSpeechSize(speechFile, wavId);
if (wavSize) {
// if we've got the wav
// allocate memory for speech buffer
// last param is an optional id for type of
// mem block
sequence_text_list[line].speech_mem = Twalloc(wavSize, MEM_locked, UID_temp);
// if mem allocated ok (should be fine, but
// worth checking)
if (sequence_text_list[line].speech_mem) {
// Load speech & decompress to our
// buffer
if (g_sound->PreFetchCompSpeech(speechFile, wavId, sequence_text_list[line].speech_mem->ad) == RD_OK) {
// ok, we've got speech!
// now float this buffer so we
// can make space for the next
// text sprites and/or speech
// samples
Float_mem(sequence_text_list[line].speech_mem);
speechRunning = 1;
} else {
// whoops, sample didn't load
// & decompress for some
// reason...
// may as well free up speech
// buffer now, rather than in
// ClearSequenceSpeech();
Free_mem(sequence_text_list[line].speech_mem);
sequence_text_list[line].speech_mem = NULL;
}
}
sequence_text_list[line].speechBufferSize = g_sound->PreFetchCompSpeech((char *) speechFile, wavId, &sequence_text_list[line].speech_mem);
if (sequence_text_list[line].speechBufferSize) {
// ok, we've got speech!
speechRunning = 1;
}
}
@ -664,12 +629,11 @@ void CreateSequenceSpeech(_movieTextObject *sequenceText[]) { // (James23may97)
// if we've loaded a speech sample for this line...
if (sequence_text_list[line].speech_mem) {
Lock_mem(sequence_text_list[line].speech_mem);
// for drivers: set up pointer to decompressed wav in
// memory
sequenceText[line]->speech = (_wavHeader *) sequence_text_list[line].speech_mem->ad;
sequenceText[line]->speechBufferSize = sequence_text_list[line].speechBufferSize;
sequenceText[line]->speech = sequence_text_list[line].speech_mem;
}
}
}
@ -689,7 +653,7 @@ void ClearSequenceSpeech(_movieTextObject *textSprites[]) { // (James27may97)
// free up the mem block containing this speech sample
if (sequence_text_list[line].speech_mem)
Free_mem(sequence_text_list[line].speech_mem);
free(sequence_text_list[line].speech_mem);
}
// IMPORTANT! Reset the line count ready for the next sequence!

View File

@ -23,6 +23,8 @@
#include "bs2/header.h" // HACK: For cutscenes instruction message
#include "bs2/memory.h" // HACK: For cutscenes instruction message
#include "bs2/maketext.h" // HACK: For cutscenes instruction message
#include "bs2/sword2.h"
#include "sound/mixer.h"
#include "rdwin.h"
#include "_mouse.h"
#include "d_draw.h"
@ -542,8 +544,6 @@ int32 PlaySmacker(char *filename, _movieTextObject *text[], uint8 *musicOut) {
// WORKAROUND: For now, we just do the voice-over parts of the
// movies, since they're separate from the actual smacker files.
// TODO: Play the voice-over sounds.
// Do we really need to pre-cache the text sprites and speech data
// like this? It'd be simpler to just store the text id and construct
// the data as we go along.
@ -600,6 +600,8 @@ int32 PlaySmacker(char *filename, _movieTextObject *text[], uint8 *musicOut) {
BS2_SetPalette(0, 256, tmpPal, RDPAL_INSTANT);
while (1) {
PlayingSoundHandle handle;
if (!text[textCounter])
break;
@ -607,8 +609,9 @@ int32 PlaySmacker(char *filename, _movieTextObject *text[], uint8 *musicOut) {
EraseBackBuffer();
OpenTextObject(text[textCounter]);
DrawTextObject(text[textCounter]);
if (text[textCounter]->speech)
debug(0, "FIXME: Play subtitle speech");
if (text[textCounter]->speech) {
g_sword2->_mixer->playRaw(&handle, text[textCounter]->speech, text[textCounter]->speechBufferSize, 22050, SoundMixer::FLAG_16BITS);
}
}
if (frameCounter == text[textCounter]->endFrame) {
@ -624,7 +627,7 @@ int32 PlaySmacker(char *filename, _movieTextObject *text[], uint8 *musicOut) {
char key;
if (ReadKey(&key) == RD_OK && key == 27) {
// StopWavSpeech()
g_sword2->_mixer->stopHandle(handle);
break;
}

View File

@ -330,53 +330,25 @@ int32 Sword2Sound::AmISpeaking() {
return RDSE_QUIET;
}
int32 Sword2Sound::GetCompSpeechSize(const char *filename, uint32 speechid) {
uint32 speechIndex[2];
File fp;
// Open the speech cluster and find the data offset & size
fp.open(filename);
if (fp.isOpen() == false)
return 0;
fp.seek((++speechid) * 8, SEEK_SET);
if (fp.read(speechIndex, sizeof(uint32) * 2) != (sizeof(uint32) * 2)) {
fp.close();
return 0;
}
fp.close();
#ifdef SCUMM_BIG_ENDIAN
speechIndex[0] = SWAP_BYTES_32(speechIndex[0]);
speechIndex[1] = SWAP_BYTES_32(speechIndex[1]);
#endif
if (!speechIndex[0] || !speechIndex[1])
return 0;
return (speechIndex[1] - 1) * 2 + sizeof(_wavHeader) + 8;
}
int32 Sword2Sound::PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *waveMem) {
uint32 Sword2Sound::PreFetchCompSpeech(const char *filename, uint32 speechid, uint16 **buf) {
uint32 i;
uint16 *data16;
uint8 *data8;
uint32 speechIndex[2];
_wavHeader *pwf = (_wavHeader *) waveMem;
File fp;
uint32 bufferSize;
*buf = NULL;
// Open the speech cluster and find the data offset & size
fp.open(filename);
if (fp.isOpen() == false)
return RDERR_INVALIDFILENAME;
if (!fp.isOpen())
return 0;
fp.seek((++speechid) * 8, SEEK_SET);
fp.seek((speechid + 1) * 8, SEEK_SET);
if (fp.read(speechIndex, sizeof(uint32) * 2) != (sizeof(uint32) * 2)) {
fp.close();
return RDERR_READERROR;
return 0;
}
#ifdef SCUMM_BIG_ENDIAN
@ -386,128 +358,72 @@ int32 Sword2Sound::PreFetchCompSpeech(const char *filename, uint32 speechid, uin
if (!speechIndex[0] || !speechIndex[1]) {
fp.close();
return RDERR_INVALIDID;
return 0;
}
data16 = (uint16 *) (waveMem + sizeof(_wavHeader));
// Create a temporary buffer for compressed speech
if ((data8 = (uint8 *) malloc(speechIndex[1])) == NULL) {
fp.close();
return 0;
}
memset(pwf, 0, sizeof(_wavHeader));
pwf->riff = MKID('RIFF');
pwf->wavID = MKID('WAVE');
pwf->format = MKID('fmt ');
pwf->formatLen = TO_LE_32(0x00000010);
pwf->formatTag = TO_LE_16(0x0001);
pwf->channels = TO_LE_16(0x0001);
pwf->samplesPerSec = TO_LE_16(0x5622);
pwf->avgBytesPerSec = TO_LE_16(0x0000);
pwf->blockAlign = TO_LE_16(0xAC44);
pwf->unknown1 = TO_LE_16(0x0000);
pwf->unknown2 = TO_LE_16(0x0002);
pwf->bitsPerSample = TO_LE_16(0x0010);
*((uint32 *) data16) = MKID('data');
data16 += 2;
*((uint32 *) data16) = TO_LE_32((speechIndex[1] - 1) * 2);
data16 += 2;
pwf->fileLength = (speechIndex[1] - 1) * 2 + sizeof(_wavHeader) + 8;
// Calculate position in buffer to load compressed sound into
data8 = (uint8 *) data16 + (speechIndex[1] - 1);
fp.seek(speechIndex[0], SEEK_SET);
if (fp.read(data8, speechIndex[1]) != speechIndex[1]) {
fp.close();
return RDERR_INVALIDID;
free(data8);
return 0;
}
fp.close();
// Decompress data into speech buffer.
bufferSize = (speechIndex[1] - 1) * 2;
*buf = (uint16 *) malloc(bufferSize);
if (!*buf) {
free(data8);
return 0;
}
uint16 *data16 = *buf;
// Starting Value
data16[0] = READ_LE_UINT16(data8);
for (i = 1; i < (speechIndex[1] - 1); i++) {
for (i = 1; i < speechIndex[1] - 1; i++) {
if (GetCompressedSign(data8[i + 1]))
data16[i] = data16[i - 1] - (GetCompressedAmplitude(data8[i + 1]) << GetCompressedShift(data8[i + 1]));
else
data16[i] = data16[i - 1] + (GetCompressedAmplitude(data8[i + 1]) << GetCompressedShift(data8[i + 1]));
}
return RD_OK;
free(data8);
#ifndef SCUMM_BIG_ENDIAN
// Until the mixer supports LE samples natively, we need to convert
// our LE ones to BE
for (uint j = 0; j < bufferSize / 2; j++)
data16[j] = SWAP_BYTES_16(data16[j]);
#endif
return bufferSize;
}
int32 Sword2Sound::PlayCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan) {
uint32 i;
uint16 *data16;
uint8 *data8;
uint32 speechIndex[2];
File fp;
uint32 bufferSize;
if (!speechMuted) {
if (GetSpeechStatus() == RDERR_SPEECHPLAYING)
return RDERR_SPEECHPLAYING;
// Open the speech cluster and find the data offset & size
fp.open(filename);
if (fp.isOpen() == false)
return RDERR_INVALIDFILENAME;
fp.seek((++speechid) * 8, SEEK_SET);
bufferSize = PreFetchCompSpeech(filename, speechid, &data16);
if (fp.read(speechIndex, sizeof(uint32) * 2) != (sizeof(uint32) * 2)) {
fp.close();
return RDERR_READERROR;
}
#ifdef SCUMM_BIG_ENDIAN
speechIndex[0] = SWAP_BYTES_32(speechIndex[0]);
speechIndex[1] = SWAP_BYTES_32(speechIndex[1]);
#endif
if (speechIndex[0] == 0 || speechIndex[1] == 0) {
fp.close();
return RDERR_INVALIDID;
}
bufferSize = (speechIndex[1] - 1) * 2;
// Create tempory buffer for compressed speech
if ((data8 = (uint8 *) malloc(speechIndex[1])) == NULL) {
fp.close();
return(RDERR_OUTOFMEMORY);
}
fp.seek(speechIndex[0], SEEK_SET);
if (fp.read(data8, speechIndex[1]) != speechIndex[1]) {
fp.close();
free(data8);
return RDERR_INVALIDID;
}
fp.close();
// Decompress data into speech buffer.
data16 = (uint16 *) malloc(bufferSize);
// Starting Value
data16[0] = READ_LE_UINT16(data8);
for (i = 1; i < bufferSize / 2; i++) {
if (GetCompressedSign(data8[i + 1]))
data16[i] = data16[i - 1] - (GetCompressedAmplitude(data8[i + 1]) << GetCompressedShift(data8[i + 1]));
else
data16[i] = data16[i - 1] + (GetCompressedAmplitude(data8[i + 1]) << GetCompressedShift(data8[i + 1]));
}
free(data8);
// We don't know exactly what went wrong here.
if (bufferSize == 0)
return RDERR_OUTOFMEMORY;
// Modify the volume according to the master volume
@ -520,13 +436,6 @@ int32 Sword2Sound::PlayCompSpeech(const char *filename, uint32 speechid, uint8 v
uint32 flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE;
#ifndef SCUMM_BIG_ENDIAN
// Until the mixer supports LE samples natively, we need to
// convert our LE ones to BE
for (uint j = 0; j < (bufferSize / 2); j++)
data16[j] = SWAP_BYTES_16(data16[j]);
#endif
_mixer->playRaw(&soundHandleSpeech, data16, bufferSize, 22050, flags, -1, volume, p);
speechStatus = 1;
@ -667,6 +576,7 @@ int32 Sword2Sound::OpenFx(int32 id, uint8 *data) {
i++;
data++;
}
if (!data32)
return RDERR_INVALIDWAV;

View File

@ -74,8 +74,7 @@ class Sword2Sound {
void FxServer(void);
int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan);
int32 PlayCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan);
int32 PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *waveMem);
int32 GetCompSpeechSize(const char *filename, uint32 speechid);
uint32 PreFetchCompSpeech(const char *filename, uint32 speechid, uint16 **buf);
int32 AmISpeaking();
int32 StopSpeechSword2(void);
int32 GetSpeechStatus(void);

View File

@ -1293,7 +1293,8 @@ typedef struct
uint16 startFrame;
uint16 endFrame;
_spriteInfo *textSprite;
_wavHeader *speech;
uint32 speechBufferSize;
uint16 *speech;
} _movieTextObject;