scummvm/engines/icb/sound_lowlevel_pc.cpp
Paweł Kołodziejski a18e803ea6 ICB: Cleanup types
2021-03-07 09:56:34 +01:00

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