mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 13:50:13 +00:00
289 lines
8.6 KiB
C++
289 lines
8.6 KiB
C++
/* ResidualVM - A 3D game interpreter
|
|
*
|
|
* ResidualVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
* file distributed with this source distribution.
|
|
*
|
|
* Additional copyright for this file:
|
|
* Copyright (C) 1999-2000 Revolution Software Ltd.
|
|
* This code is based on source code created by Revolution Software,
|
|
* used with permission.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "engines/icb/p4.h"
|
|
#include "engines/icb/common/px_common.h"
|
|
#include "engines/icb/common/px_sfx_description.h"
|
|
#include "engines/icb/common/px_linkeddatafile.h"
|
|
#include "engines/icb/debug.h"
|
|
#include "engines/icb/sound/music_manager.h"
|
|
#include "engines/icb/sound/speech_manager.h"
|
|
#include "engines/icb/sound/fx_manager.h"
|
|
#include "engines/icb/sound.h"
|
|
#include "engines/icb/res_man_pc.h"
|
|
#include "engines/icb/global_objects.h"
|
|
#include "engines/icb/mission.h"
|
|
|
|
namespace ICB {
|
|
|
|
bool8 DoesClusterContainFile(pxString clustername, uint32 hash_to_find, uint32 &fileoffset, uint32 &filesize) {
|
|
// Manually open the cluster file
|
|
Common::SeekableReadStream *stream = openDiskFileForBinaryStreamRead(clustername.c_str());
|
|
|
|
if (stream == NULL)
|
|
Fatal_error(pxVString("Failed to open cluster: %s", clustername.c_str()));
|
|
|
|
// Read in first 16 bytes so we can get the header size
|
|
uint32 data[4];
|
|
stream->read(data, sizeof(uint32) * 4);
|
|
|
|
// Get the size in bytes of the cluster header
|
|
uint32 clustersize = data[2];
|
|
|
|
// Seek to beginning of file
|
|
stream->seek(0, SEEK_SET);
|
|
|
|
// Get storage
|
|
uint8 *memory = new uint8[clustersize];
|
|
if (!memory)
|
|
Fatal_error("DoesClusterContainFile() was refused memory allocation.");
|
|
|
|
// Read the header into memory
|
|
stream->read(memory, sizeof(uint8) * clustersize);
|
|
// Close the file
|
|
delete stream;
|
|
|
|
// Cast memory to header structure
|
|
Cluster_API *clu = (Cluster_API *)memory;
|
|
|
|
// Look for the file in the cluster
|
|
int32 nFiles = (int32)clu->ho.noFiles;
|
|
|
|
int32 i;
|
|
for (i = 0; i < nFiles; i++) {
|
|
// Have we found it
|
|
if (hash_to_find == clu->hn[i].hash)
|
|
break;
|
|
}
|
|
|
|
// Check i < nFiles
|
|
if (i >= nFiles) {
|
|
// Couldn't find the file
|
|
fileoffset = 0;
|
|
filesize = 0;
|
|
return FALSE8;
|
|
}
|
|
|
|
// Get the figures we need for streaming
|
|
filesize = clu->hn[i].size;
|
|
fileoffset = clu->hn[i].offset;
|
|
|
|
// Tidy up
|
|
delete[] memory;
|
|
|
|
return TRUE8;
|
|
}
|
|
|
|
void SetupSndEngine() {}
|
|
|
|
void LoadSessionSounds(const char *cluster) { Tdebug("sounds.txt", "Setting up session sfx data cluster \"%s\"", cluster); }
|
|
|
|
void LoadMissionSounds(const char *cluster) { Tdebug("sounds.txt", "Setting up mission sfx data cluster \"%s\"", cluster); }
|
|
|
|
// in Hz
|
|
int32 GetSamplePitch(const char *sampleName, bool8 isInSession) {
|
|
if (g_theFxManager) {
|
|
Tdebug("sounds.txt", "Getting sample rate for %s (isInSession=%d) = %d", sampleName, isInSession,
|
|
g_theFxManager->GetDefaultRate(pxVString("samples\\pc\\%s.wav", sampleName)));
|
|
|
|
int32 rate = 0;
|
|
pxString smp;
|
|
smp.Format("%s.wav", sampleName);
|
|
|
|
uint32 b_offset, sz;
|
|
|
|
if (!DoesClusterContainFile(pxVString("g\\samples.clu"), HashString(smp), b_offset, sz))
|
|
Fatal_error(pxVString("Couldn't find %s in global sample cluster", (const char *)smp));
|
|
|
|
// Pass sample name only if we're running from clusters
|
|
rate = (g_theFxManager->GetDefaultRate(smp, b_offset));
|
|
|
|
// Return sample rate of a wav file
|
|
return rate;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void StartSample(int32 ch, const char *sampleName, bool8 isInSession, int32 looping) {
|
|
int32 result;
|
|
|
|
if (g_theFxManager) {
|
|
// Unload sample if channel has one
|
|
g_theFxManager->Unregister(ch);
|
|
|
|
// Load the sample into memory
|
|
pxString smp;
|
|
smp.Format("%s.wav", sampleName);
|
|
|
|
uint32 b_offset, sz;
|
|
|
|
if (!DoesClusterContainFile(pxVString("g\\samples.clu"), HashString(smp), b_offset, sz))
|
|
Fatal_error(pxVString("Couldn't find %s in global sample cluster", (const char *)smp));
|
|
|
|
// Pass sample name only if we're running from clusters
|
|
result = g_theFxManager->Register(ch, pxVString("%s.wav", sampleName), 0, b_offset);
|
|
|
|
// Set channel looping status
|
|
g_theFxManager->SetLooping(ch, looping);
|
|
// Begin palyback
|
|
g_theFxManager->Play(ch);
|
|
|
|
Tdebug("sounds.txt", "playing sample: %s in channel %d (is in session=%d result=%d looping=%d)", sampleName, ch, isInSession, result, looping);
|
|
}
|
|
}
|
|
|
|
// stop channel ch
|
|
void StopSample(int32 ch) {
|
|
// Halt playback for this channel
|
|
if (g_theFxManager)
|
|
g_theFxManager->Stop(ch);
|
|
}
|
|
|
|
// set volume 0=none, 127=full... and pan -128 - 128 (l-r)
|
|
void SetChannelVolumeAndPan(int32 ch, int32 volume, int32 pan) {
|
|
if (g_theFxManager) {
|
|
// Set channel volume and pan (cumulative effect)
|
|
g_theFxManager->SetVolume(ch, volume);
|
|
g_theFxManager->SetPan(ch, pan);
|
|
}
|
|
|
|
Tdebug("sounds.txt", "Setting channel %d vol=%d pan=%d", ch, volume, pan);
|
|
}
|
|
|
|
// set pitch in hz
|
|
void SetChannelPitch(int32 ch, int32 pitch) {
|
|
if (g_theFxManager) {
|
|
// Set channel playback frequency
|
|
g_theFxManager->SetPitch(ch, pitch);
|
|
}
|
|
|
|
Tdebug("sounds.txt", "Setting channel %d pitch=%d", ch, pitch);
|
|
}
|
|
|
|
// Speech support routines
|
|
|
|
// just return 1, no preloading so always continue
|
|
int32 PreloadSpeech(uint32) { return 1; }
|
|
|
|
// do the line of text
|
|
int32 SayLineOfSpeech(uint32 speechHash) {
|
|
if ((g_theSpeechManager) && (GetSpeechVolume() > 0)) {
|
|
|
|
// If we are testing the translations wavs then we need to look elsewhere for the wav files
|
|
if (tt) {
|
|
// Righto, where do we find them?
|
|
char hashfile[20];
|
|
EngineHashToFile(speechHash, hashfile);
|
|
|
|
pxString wavFileName = pxVString("%s\\speech\\%s.wav", tt_text, hashfile);
|
|
|
|
if (checkFileExists(wavFileName)) {
|
|
// The wav has been found. Speak it
|
|
|
|
// OK, go for it...
|
|
g_theSpeechManager->StartSpeech(wavFileName, 0, (uint8)GetSpeechVolume());
|
|
|
|
return g_theSpeechManager->GetLength();
|
|
} else {
|
|
Message_box(pxVString("Wav %s not found", (const char *)wavFileName));
|
|
return (2 * 12);
|
|
}
|
|
}
|
|
|
|
// Need to look in the session music cluster first off
|
|
|
|
pxString clustername;
|
|
|
|
/* const char* cluster_root = "thegame\\english\\pc\\everything\\cd1" ;*/
|
|
|
|
// Construct full pathname to the session speech cluster
|
|
char h_mission_name[8];
|
|
pxString missionname = g_mission->Fetch_tiny_mission_name();
|
|
// Make the mission name lowercase!
|
|
missionname.ToLower();
|
|
HashFile(missionname, h_mission_name);
|
|
|
|
// Convert to lower-case for FS operations
|
|
pxString missionHash(h_mission_name);
|
|
missionHash.ToLower();
|
|
pxString sessionHash(g_mission->session->Fetch_session_h_name());
|
|
sessionHash.ToLower();
|
|
|
|
clustername.Format("m\\%s\\%s\\speech.clu", missionHash.c_str(), sessionHash.c_str());
|
|
|
|
uint32 file_offset, file_size;
|
|
if (!DoesClusterContainFile(clustername, speechHash, file_offset, file_size)) {
|
|
|
|
clustername.Format("g\\speech.clu");
|
|
|
|
// Take a look
|
|
if (!DoesClusterContainFile(clustername, speechHash, file_offset, file_size)) {
|
|
// OK - rather than blowing up, use the default wav
|
|
if (!DoesClusterContainFile(clustername, HashString("unavail"), file_offset, file_size)) {
|
|
Fatal_error("Speech cluster doesn't contain unavail.wav? Is it even there?");
|
|
}
|
|
}
|
|
}
|
|
|
|
// OK, go for it...
|
|
g_theSpeechManager->StartSpeech(clustername, file_offset, (uint8)GetSpeechVolume());
|
|
|
|
return g_theSpeechManager->GetLength();
|
|
}
|
|
|
|
// Sound device is unavailable for some reason so return a hardcoded
|
|
// delay of 3 seconds (which the user can click through anyhow)
|
|
return (3 * 12);
|
|
}
|
|
|
|
// This is the same as StopSpeechPlayback for the PC but different for the PSX !
|
|
void CancelSpeechPlayback() {
|
|
if (g_theSpeechManager) {
|
|
g_theSpeechManager->StopSpeech();
|
|
}
|
|
}
|
|
|
|
// Should this really just stop the speech or should it continue until the sample has finished ?
|
|
// The PSX version waits until the speech has finished
|
|
void StopSpeechPlayback() {
|
|
if (g_theSpeechManager) {
|
|
g_theSpeechManager->StopSpeech();
|
|
}
|
|
}
|
|
|
|
// Don't know if there's any call for this but what the heck...
|
|
bool8 IsSpeechPlaying() {
|
|
if (g_theSpeechManager) {
|
|
return g_theSpeechManager->IsPlaying();
|
|
}
|
|
|
|
return FALSE8;
|
|
}
|
|
|
|
} // End of namespace ICB
|