mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
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:
parent
18961542f9
commit
8e28b0c6b4
@ -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!
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -1293,7 +1293,8 @@ typedef struct
|
||||
uint16 startFrame;
|
||||
uint16 endFrame;
|
||||
_spriteInfo *textSprite;
|
||||
_wavHeader *speech;
|
||||
uint32 speechBufferSize;
|
||||
uint16 *speech;
|
||||
} _movieTextObject;
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user