scummvm/engines/sky/sound.cpp
Torbjörn Andersson 117dee5e4a Fixed bug #1995033 ("BASS: BG Sound stopped on opening item list"). Apparently
the sound is supposed to be paused and then unpaused, but the pause function is
called many more times than the unpause function. In the original, this
presumably didn't matter. In ScummVM's mixer, it does.

svn-id: r33570
2008-08-03 10:16:17 +00:00

1275 lines
21 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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.
*
* $URL$
* $Id$
*
*/
#include "common/endian.h"
#include "sky/disk.h"
#include "sky/logic.h"
#include "sky/sky.h"
#include "sky/skydefs.h"
#include "sky/sound.h"
#include "sky/struc.h"
namespace Sky {
#define SOUND_FILE_BASE 60203
#define MAX_FX_NUMBER 393
#define SFXF_START_DELAY 0x80
#define SFXF_SAVE 0x20
#include "common/pack-start.h" // START STRUCT PACKING
struct RoomList {
uint8 room;
uint8 adlibVolume;
uint8 rolandVolume;
} PACKED_STRUCT;
struct Sfx {
uint8 soundNo;
uint8 flags;
RoomList roomList[10];
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
uint16 Sound::_speechConvertTable[8] = {
0, //;Text numbers to file numbers
600, //; 553 lines in section 0
600+500, //; 488 lines in section 1
600+500+1330, //;1303 lines in section 2
600+500+1330+950, //; 922 lines in section 3
600+500+1330+950+1150, //;1140 lines in section 4
600+500+1330+950+1150+550, //; 531 lines in section 5
600+500+1330+950+1150+550+150, //; 150 lines in section 6
};
static const Sfx fx_null = {
0,
0,
{
{ 200,127,127 },
{ 255,0,0 }
}
};
static const Sfx fx_level_3_ping = {
1,
0,
{
{ 28,63,63 },
{ 29,63,63 },
{ 31,63,63 },
{ 255,0,0 },
}
};
static const Sfx fx_factory_sound = {
1,
SFXF_SAVE,
{
{ 255,30,30 },
}
};
static const Sfx fx_crowbar_plaster = {
1,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_masonry_fall = {
1,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_prise_brick = {
2,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_rope_creak = {
2,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_ping = {
3,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_force_fire_door = {
3,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_brick_hit_foster = {
3,
10+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_brick_hit_plank = {
3,
8+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_rm3_lift_moving = {
4,
SFXF_SAVE,
{
{ 3,127,127 },
{ 2,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_weld = {
4,
0,
{
{ 15,127,127 },
{ 7,127,127 },
{ 6,60,60 },
{ 12,60,60 },
{ 13,60,60 },
{ 255,0,0 },
}
};
static const Sfx fx_weld12 = {
4,
0,
{
{ 12,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_spray_on_skin = {
4,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_plank_vibrating = {
4,
6+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_press_bang = {
5,
0,
{
{ 0,50,100 },
{ 255,0,0 },
}
};
static const Sfx fx_spanner_clunk = {
5,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_break_crystals = {
5,
0,
{
{ 96,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_press_hiss = {
6,
0,
{
{ 0,40,40 },
{ 255,0,0 },
}
};
static const Sfx fx_open_door = {
6,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_open_lamb_door = {
6,
0,
{
{ 20,127,127 },
{ 21,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_splash = {
6,
22+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_disintegrate = {
7,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_buzzer = {
7,
4+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_lathe = {
7,
SFXF_SAVE,
{
{ 4,60,60 },
{ 2,20,20 },
{ 255,0,0 },
}
};
static const Sfx fx_hit_crowbar_brick = {
7,
9+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_hello_helga = {
8,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_statue_on_armour = {
8,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_lift_alarm = {
8,
SFXF_SAVE,
{
{ 2,63,63 },
{ 255,0,0 },
}
};
static const Sfx fx_drop_crowbar = {
8,
5+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_byee_helga = {
9,
3+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_shed_door_creak = {
10,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_explosion = {
10,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_fire_crackle_in_pit = {
9,
SFXF_SAVE,
{
{ 255,127,127 },
}
};
static const Sfx fx_remove_bar_grill = {
10,
7+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_grill_creak = {
10,
43+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_steam1 = {
11,
SFXF_SAVE,
{
{ 18,20,20 },
{ 255,0,0 },
}
};
static const Sfx fx_steam2 = {
11,
SFXF_SAVE,
{
{ 18,63,63 },
{ 255,0,0 },
}
};
static const Sfx fx_steam3 = {
11,
SFXF_SAVE,
{
{ 18,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_crowbar_wooden = {
11,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_helmet_down_3 = {
11,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_guard_fall = {
11,
4,
{
{ 255,127,127 },
}
};
#if 0
static const Sfx fx_furnace = {
11,
0,
{
{ 3,90,90 },
{ 255,0,0 },
}
};
#endif
static const Sfx fx_fall_thru_box = {
12,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_lazer = {
12,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_scanner = {
12,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_helmet_up_3 = {
12,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_liquid_bubble = {
12,
SFXF_SAVE,
{
{ 80,127,127 },
{ 72,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_liquid_drip = {
13,
6+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_goo_drip = {
13,
5+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_comp_bleeps = {
13,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_use_crowbar_grill = {
13,
34+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_helmet_grind = {
14,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_lift_moving = {
14,
SFXF_SAVE,
{
{ 7,127,127 },
{ 29,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_use_secateurs = {
14,
18+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_hit_joey1 = {
14,
7+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_hit_joey2 = {
14,
13+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_dani_phone_ring = {
15,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_sc74_pod_down = {
15,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_phone = {
15,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_25_weld = {
15,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_lift_open_7 = {
15,
0,
{
{ 7,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_lift_close_7 = {
16,
0,
{
{ 7,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_s2_helmet = {
16,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_hiss_in_nitrogen = {
16,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_dog_yap_indoors = {
16,
0,
{
{ 38,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_dog_yap_outdoors = {
16,
0,
{
{ 31,127,127 },
{ 30,40,40 },
{ 32,40,40 },
{ 33,40,40 },
{ 255,0,0 },
}
};
static const Sfx fx_locker_creak_open = {
17,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_big_tent_gurgle = {
17,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_wind_howl = {
17,
SFXF_SAVE,
{
{ 1,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_lift_open_29 = {
17,
0,
{
{ 29,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_lift_arrive_7 = {
17,
0,
{
{ 7,63,63 },
{ 255,0,0 },
}
};
static const Sfx fx_lift_close_29 = {
18,
0,
{
{ 29,127,127 },
{ 28,127,127 },
{ 255,0,0 },
}
};
static const Sfx fx_shaft_industrial_noise = {
18,
SFXF_SAVE,
{
{ 255,127,127 },
}
};
static const Sfx fx_gall_drop = {
18,
29+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_door_slam_under = {
19,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_reichs_fish = {
19,
SFXF_SAVE,
{
{ 255,60,60 },
}
};
static const Sfx fx_judges_gavel1 = {
19,
13+SFXF_START_DELAY,
{
{ 255,60,60 },
}
};
static const Sfx fx_judges_gavel2 = {
19,
16+SFXF_START_DELAY,
{
{ 255,90,90 },
}
};
static const Sfx fx_judges_gavel3 = {
19,
19+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_wind_3 = {
20,
SFXF_SAVE,
{
{ 255,60,60 },
}
};
static const Sfx fx_fact_sensor = {
20,
SFXF_SAVE,
{
{ 255,60,60 },
}
};
static const Sfx fx_medi_stab_gall = {
20,
17+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_computer_3 = {
21,
SFXF_SAVE,
{
{ 255,127,127 },
}
};
static const Sfx fx_timber_cracking = {
21,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_anchor_fall = {
22,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_elevator_4 = {
22,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_star_trek_2 = {
22,
SFXF_SAVE,
{
{ 255,127,127 },
}
};
static const Sfx fx_lift_closing = {
23,
0,
{
{ 255,127,127 },
}
};
static const Sfx fx_heartbeat = {
23,
11+SFXF_START_DELAY,
{
{ 67,60,60 },
{ 68,60,60 },
{ 69,60,60 },
{ 77,20,20 },
{ 78,50,50 },
{ 79,70,70 },
{ 80,127,127 },
{ 81,60,60 },
{ 255,0,0 },
}
};
static const Sfx fx_pos_key = {
25,
2+SFXF_START_DELAY,
{
{ 255,127,127 },
}
};
static const Sfx fx_neg_key = {
26,
2+SFXF_START_DELAY,
{
{ 255,100,100 },
}
};
static const Sfx fx_orifice_swallow_drip = {
28,
0,
{
{ 255,127,127 },
}
};
static const Sfx *musicList[] = {
&fx_press_bang, // 256 banging of the press
&fx_press_hiss, // 257 hissing press
&fx_wind_howl, // 258 howling wind
&fx_spanner_clunk, // 259 spanner in works
&fx_reichs_fish, // 260 Reichs fish
&fx_explosion, // 261 panel blows open
&fx_wind_3, // 262 single steam
&fx_open_door, // 263 general open door
&fx_open_lamb_door, // 264 lamb door opens
&fx_comp_bleeps, // 265 scanner bleeps
&fx_helmet_down_3, // 266
&fx_helmet_up_3, // 267
&fx_helmet_grind, // 268
&fx_lift_close_29, // 269 rm 29 lift closes
&fx_lift_open_29, // 270 rm 29 lift opens
&fx_computer_3, // 271 rm 29 lift arrives
&fx_level_3_ping, // 272 background noise in room 4
&fx_lift_alarm, // 273 loader alarm
&fx_null, // 274 furnace room background noise
&fx_rm3_lift_moving, // 275 lift moving in room 3
&fx_lathe, // 276 jobsworth lathe
&fx_factory_sound, // 277 factory background sound
&fx_weld, // 278 do some welding
&fx_lift_close_7, // 279 rm 7 lift closes
&fx_lift_open_7, // 280 rm 7 lift opens
&fx_lift_arrive_7, // 281 rm 7 lift arrives
&fx_lift_moving, // 282 lift moving
&fx_scanner, // 283 scanner operating
&fx_force_fire_door, // 284 Force fire door open
&fx_null, // 285 General door creak
&fx_phone, // 286 telephone
&fx_lazer, // 287 lazer
&fx_lazer, // 288 lazer
&fx_anchor_fall, // 289 electric ;not used on amiga
&fx_weld12, // 290 welding in room 12 (not joey)
&fx_hello_helga, // 291 helga appears
&fx_byee_helga, // 292 helga disapears
&fx_null, // 293 smash through window ;doesn't exist
&fx_pos_key, // 294
&fx_neg_key, // 295
&fx_s2_helmet, // 296 ;helmet down section 2
&fx_s2_helmet, // 297 ; " up " "
&fx_lift_arrive_7, // 298 ;security door room 7
&fx_null, // 299
&fx_rope_creak, // 300
&fx_crowbar_wooden, // 301
&fx_fall_thru_box, // 302
&fx_use_crowbar_grill, // 303
&fx_use_secateurs, // 304
&fx_grill_creak, // 305
&fx_timber_cracking, // 306
&fx_masonry_fall, // 307
&fx_masonry_fall, // 308
&fx_crowbar_plaster, // 309
&fx_prise_brick, // 310
&fx_brick_hit_foster, // 311
&fx_spray_on_skin, // 312
&fx_hit_crowbar_brick, // 313
&fx_drop_crowbar, // 314
&fx_fire_crackle_in_pit, // 315
&fx_remove_bar_grill, // 316
&fx_liquid_bubble, // 317
&fx_liquid_drip, // 318
&fx_guard_fall, // 319
&fx_sc74_pod_down, // 320
&fx_hiss_in_nitrogen, // 321
&fx_null, // 322
&fx_hit_joey1, // 323
&fx_hit_joey2, // 324
&fx_medi_stab_gall, // 325
&fx_gall_drop, // 326
&fx_null, // 327
&fx_null, // 328
&fx_null, // 329
&fx_big_tent_gurgle, // 330
&fx_null, // 331
&fx_orifice_swallow_drip, // 332
&fx_brick_hit_plank, // 333
&fx_goo_drip, // 334
&fx_plank_vibrating, // 335
&fx_splash, // 336
&fx_buzzer, // 337
&fx_shed_door_creak, // 338
&fx_dog_yap_outdoors, // 339
&fx_dani_phone_ring, // 340
&fx_locker_creak_open, // 341
&fx_judges_gavel1, // 342
&fx_dog_yap_indoors, // 343
&fx_brick_hit_plank, // 344
&fx_brick_hit_plank, // 345
&fx_shaft_industrial_noise, // 346
&fx_judges_gavel2, // 347
&fx_judges_gavel3, // 348
&fx_elevator_4, // 349
&fx_lift_closing, // 350
&fx_null, // 351
&fx_null, // 352
&fx_sc74_pod_down, // 353
&fx_null, // 354
&fx_null, // 355
&fx_heartbeat, // 356
&fx_star_trek_2, // 357
&fx_null, // 358
&fx_null, // 359
&fx_null, // 350
&fx_null, // 361
&fx_null, // 362
&fx_null, // 363
&fx_null, // 364
&fx_null, // 365
&fx_break_crystals, // 366
&fx_disintegrate, // 367
&fx_statue_on_armour, // 368
&fx_null, // 369
&fx_null, // 360
&fx_ping, // 371
&fx_null, // 372
&fx_door_slam_under, // 373
&fx_null, // 374
&fx_null, // 375
&fx_null, // 376
&fx_null, // 377
&fx_null, // 378
&fx_null, // 379
&fx_steam1, // 380
&fx_steam2, // 381
&fx_steam2, // 382
&fx_steam3, // 383
&fx_null, // 384
&fx_null, // 385
&fx_fact_sensor, // 386 Sensor in Potts' room
&fx_null, // 387
&fx_null, // 388
&fx_null, // 389
&fx_null, // 390
&fx_null, // 391
&fx_null, // 392
&fx_null, // 393
&fx_25_weld // 394 my anchor weld bodge
};
SfxQueue Sound::_sfxQueue[MAX_QUEUED_FX] = {
{ 0, 0, 0, 0},
{ 0, 0, 0, 0},
{ 0, 0, 0, 0},
{ 0, 0, 0, 0}
};
Sound::Sound(Audio::Mixer *mixer, Disk *pDisk, uint8 pVolume) {
_skyDisk = pDisk;
_soundData = NULL;
_mixer = mixer;
_saveSounds[0] = _saveSounds[1] = 0xFFFF;
_mainSfxVolume = pVolume;
_isPaused = false;
}
Sound::~Sound(void) {
_mixer->stopAll();
if (_soundData)
free(_soundData);
}
void Sound::playSound(uint32 id, byte *sound, uint32 size, Audio::SoundHandle *handle) {
byte flags = 0;
flags |= Audio::Mixer::FLAG_UNSIGNED|Audio::Mixer::FLAG_AUTOFREE;
size -= sizeof(struct dataFileHeader);
byte *buffer = (byte *)malloc(size);
memcpy(buffer, sound+sizeof(struct dataFileHeader), size);
_mixer->stopID(id);
_mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer, size, 11025, flags, id);
}
void Sound::loadSection(uint8 pSection) {
fnStopFx();
_mixer->stopAll();
if (_soundData)
free(_soundData);
_soundData = _skyDisk->loadFile(pSection * 4 + SOUND_FILE_BASE);
uint16 asmOfs;
if (SkyEngine::_systemVars.gameVersion == 109) {
if (pSection == 0)
asmOfs = 0x78;
else
asmOfs = 0x7C;
} else
asmOfs = 0x7E;
if ((_soundData[asmOfs] != 0x3C) || (_soundData[asmOfs + 0x27] != 0x8D) ||
(_soundData[asmOfs + 0x28] != 0x1E) || (_soundData[asmOfs + 0x2F] != 0x8D) ||
(_soundData[asmOfs + 0x30] != 0x36))
error("Unknown sounddriver version!");
_soundsTotal = _soundData[asmOfs + 1];
uint16 sRateTabOfs = READ_LE_UINT16(_soundData + asmOfs + 0x29);
_sfxBaseOfs = READ_LE_UINT16(_soundData + asmOfs + 0x31);
_sampleRates = _soundData + sRateTabOfs;
_sfxInfo = _soundData + _sfxBaseOfs;
// if we just restored a savegame, the sfxqueue holds the sound we need to restart
if (!(SkyEngine::_systemVars.systemFlags & SF_GAME_RESTORED))
for (uint8 cnt = 0; cnt < 4; cnt++)
_sfxQueue[cnt].count = 0;
}
void Sound::playSound(uint16 sound, uint16 volume, uint8 channel) {
if (channel == 0)
_mixer->stopID(SOUND_CH0);
else
_mixer->stopID(SOUND_CH1);
if (!_soundData) {
warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume);
return;
}
if (sound > _soundsTotal) {
debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal);
return;
}
volume = (volume & 0x7F) << 1;
sound &= 0xFF;
// Note: All those tables are big endian. Don't ask me why. *sigh*
// Use the sample rate from game data, see bug #1507757.
uint16 sampleRate = READ_BE_UINT16(_sampleRates + (sound << 2));
if (sampleRate > 11025)
sampleRate = 11025;
uint32 dataOfs = READ_BE_UINT16(_sfxInfo + (sound << 3) + 0) << 4;
uint32 dataSize = READ_BE_UINT16(_sfxInfo + (sound << 3) + 2);
uint32 dataLoop = READ_BE_UINT16(_sfxInfo + (sound << 3) + 6);
dataOfs += _sfxBaseOfs;
byte flags = Audio::Mixer::FLAG_UNSIGNED;
uint32 loopSta = 0, loopEnd = 0;
if (dataLoop) {
loopSta = dataSize - dataLoop;
loopEnd = dataSize;
flags |= Audio::Mixer::FLAG_LOOP;
}
if (channel == 0)
_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_ingameSound0, _soundData + dataOfs, dataSize, sampleRate, flags, SOUND_CH0, volume, 0, loopSta, loopEnd);
else
_mixer->playRaw(Audio::Mixer::kSFXSoundType, &_ingameSound1, _soundData + dataOfs, dataSize, sampleRate, flags, SOUND_CH1, volume, 0, loopSta, loopEnd);
}
void Sound::fnStartFx(uint32 sound, uint8 channel) {
_saveSounds[channel] = 0xFFFF;
if (sound < 256 || sound > MAX_FX_NUMBER || (SkyEngine::_systemVars.systemFlags & SF_FX_OFF))
return;
uint8 screen = (uint8)(Logic::_scriptVariables[SCREEN] & 0xff);
if (sound == 278 && screen == 25) // is this weld in room 25
sound= 394;
sound &= ~(1 << 8);
const Sfx *sfx = musicList[sound];
const RoomList *roomList = sfx->roomList;
int i = 0;
if (roomList[i].room != 0xff) // if room list empty then do all rooms
while (roomList[i].room != screen) { // check rooms
i++;
if (roomList[i].room == 0xff)
return;
}
// get fx volume
uint8 volume = _mainSfxVolume; // start with standard vol
if (SkyEngine::_systemVars.systemFlags & SF_SBLASTER)
volume = roomList[i].adlibVolume;
else if (SkyEngine::_systemVars.systemFlags & SF_ROLAND)
volume = roomList[i].rolandVolume;
volume = (volume * _mainSfxVolume) >> 8;
// Check the flags, the sound may come on after a delay.
if (sfx->flags & SFXF_START_DELAY) {
for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
if (_sfxQueue[cnt].count == 0) {
_sfxQueue[cnt].chan = channel;
_sfxQueue[cnt].fxNo = sfx->soundNo;
_sfxQueue[cnt].vol = volume;
_sfxQueue[cnt].count = sfx->flags & 0x7F;
return;
}
}
return; // ignore sound if it can't be queued
}
if (sfx->flags & SFXF_SAVE)
_saveSounds[channel] = sfx->soundNo | (volume << 8);
playSound(sfx->soundNo, volume, channel);
}
void Sound::checkFxQueue(void) {
for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
if (_sfxQueue[cnt].count) {
_sfxQueue[cnt].count--;
if (_sfxQueue[cnt].count == 0)
playSound(_sfxQueue[cnt].fxNo, _sfxQueue[cnt].vol, _sfxQueue[cnt].chan);
}
}
}
void Sound::restoreSfx(void) {
// queue sfx, so they will be started when the player exits the control panel
memset(_sfxQueue, 0, sizeof(_sfxQueue));
uint8 queueSlot = 0;
if (_saveSounds[0] != 0xFFFF) {
_sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[0];
_sfxQueue[queueSlot].vol = (uint8)(_saveSounds[0] >> 8);
_sfxQueue[queueSlot].chan = 0;
_sfxQueue[queueSlot].count = 1;
queueSlot++;
}
if (_saveSounds[1] != 0xFFFF) {
_sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[1];
_sfxQueue[queueSlot].vol = (uint8)(_saveSounds[1] >> 8);
_sfxQueue[queueSlot].chan = 1;
_sfxQueue[queueSlot].count = 1;
}
}
void Sound::fnStopFx(void) {
_mixer->stopID(SOUND_CH0);
_mixer->stopID(SOUND_CH1);
_saveSounds[0] = _saveSounds[1] = 0xFFFF;
}
void Sound::stopSpeech(void) {
_mixer->stopID(SOUND_SPEECH);
}
bool Sound::startSpeech(uint16 textNum) {
if (!(SkyEngine::_systemVars.systemFlags & SF_ALLOW_SPEECH))
return false;
uint16 speechFileNum = _speechConvertTable[textNum >> 12] + (textNum & 0xFFF);
uint8 *speechData = _skyDisk->loadFile(speechFileNum + 50000);
if (!speechData) {
debug(9,"File %d (speechFile %d from section %d) wasn't found", speechFileNum + 50000, textNum & 0xFFF, textNum >> 12);
return false;
}
uint32 speechSize = ((dataFileHeader *)speechData)->s_tot_size - sizeof(dataFileHeader);
uint8 *playBuffer = (uint8 *)malloc(speechSize);
memcpy(playBuffer, speechData + sizeof(dataFileHeader), speechSize);
free(speechData);
// Workaround for BASS bug #897775 - some voice-overs are played at
// half speed in 0.0368 (the freeware CD version), in 0.0372 they sound
// just fine.
uint rate;
if (_skyDisk->determineGameVersion() == 368 && (textNum == 20905 || textNum == 20906))
rate = 22050;
else
rate = 11025;
_mixer->stopID(SOUND_SPEECH);
_mixer->playRaw(Audio::Mixer::kSpeechSoundType, &_ingameSpeech, playBuffer, speechSize, rate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE, SOUND_SPEECH);
return true;
}
void Sound::fnPauseFx(void) {
if (!_isPaused) {
_isPaused = true;
_mixer->pauseID(SOUND_CH0, true);
_mixer->pauseID(SOUND_CH1, true);
}
}
void Sound::fnUnPauseFx(void) {
if (_isPaused) {
_isPaused = false;
_mixer->pauseID(SOUND_CH0, false);
_mixer->pauseID(SOUND_CH1, false);
}
}
} // End of namespace Sky