2010-05-27 08:09:32 +00:00
/* 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 .
2014-02-18 02:34:24 +01:00
*
2010-05-27 08:09:32 +00:00
* 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 .
2014-02-18 02:34:24 +01:00
*
2010-05-27 08:09:32 +00:00
* 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 .
*
*/
// Resource library
2010-06-15 12:20:03 +00:00
# include "common/archive.h"
2010-05-27 08:09:32 +00:00
# include "common/file.h"
2011-04-24 11:34:27 +03:00
# include "common/textconsole.h"
2016-03-18 22:55:56 -05:00
# include "common/memstream.h"
2010-05-27 08:09:32 +00:00
# include "sci/resource.h"
2010-06-15 12:08:40 +00:00
# include "sci/resource_intern.h"
2010-05-27 08:09:32 +00:00
# include "sci/util.h"
namespace Sci {
2010-06-16 00:24:16 +00:00
AudioVolumeResourceSource : : AudioVolumeResourceSource ( ResourceManager * resMan , const Common : : String & name , ResourceSource * map , int volNum )
2010-06-15 12:14:39 +00:00
: VolumeResourceSource ( name , map , volNum , kSourceAudioVolume ) {
2010-06-15 12:17:47 +00:00
_audioCompressionType = 0 ;
2010-06-15 12:16:42 +00:00
/*
* Check if this audio volume got compressed by our tool . If that is the
* case , set _audioCompressionType and read in the offset translation
* table for later usage .
*/
2017-05-13 22:07:53 -05:00
Common : : SeekableReadStream * fileStream = getVolumeFile ( resMan , nullptr ) ;
2010-06-15 12:17:25 +00:00
if ( ! fileStream )
2010-05-27 08:09:32 +00:00
return ;
2010-06-05 14:09:52 +00:00
fileStream - > seek ( 0 , SEEK_SET ) ;
2017-05-10 00:33:43 -05:00
const uint32 compressionType = fileStream - > readUint32BE ( ) ;
2010-05-27 08:09:32 +00:00
switch ( compressionType ) {
2011-04-12 16:53:15 +02:00
case MKTAG ( ' M ' , ' P ' , ' 3 ' , ' ' ) :
case MKTAG ( ' O ' , ' G ' , ' G ' , ' ' ) :
case MKTAG ( ' F ' , ' L ' , ' A ' , ' C ' ) :
2010-06-15 12:16:42 +00:00
_audioCompressionType = compressionType ;
2017-05-10 00:33:43 -05:00
const uint32 numEntries = fileStream - > readUint32LE ( ) ;
if ( ! numEntries ) {
error ( " Compressed audio volume %s has no relocation table entries " , name . c_str ( ) ) ;
2010-05-27 08:09:32 +00:00
}
2017-05-10 00:33:43 -05:00
CompressedTableEntry * lastEntry = nullptr ;
for ( uint i = 0 ; i < numEntries ; + + i ) {
CompressedTableEntry nextEntry ;
const uint32 sourceOffset = fileStream - > readUint32LE ( ) ;
nextEntry . offset = fileStream - > readUint32LE ( ) ;
if ( lastEntry ! = nullptr ) {
lastEntry - > size = nextEntry . offset - lastEntry - > offset ;
}
_compressedOffsets . setVal ( sourceOffset , nextEntry ) ;
lastEntry = & _compressedOffsets . getVal ( sourceOffset ) ;
}
lastEntry - > size = fileStream - > size ( ) - lastEntry - > offset ;
2010-05-27 08:09:32 +00:00
}
2010-06-05 14:09:52 +00:00
2017-05-13 22:07:53 -05:00
resMan - > disposeVolumeFileStream ( fileStream , this ) ;
2010-05-27 08:09:32 +00:00
}
2010-06-15 12:18:57 +00:00
bool Resource : : loadFromWaveFile ( Common : : SeekableReadStream * file ) {
2016-12-31 20:39:57 -06:00
byte * ptr = new byte [ _size ] ;
_data = ptr ;
2010-06-15 12:18:57 +00:00
2016-12-31 20:39:57 -06:00
uint32 bytesRead = file - > read ( ptr , _size ) ;
if ( bytesRead ! = _size )
2017-03-30 14:02:27 -05:00
error ( " Read %d bytes from %s but expected %u " , bytesRead , _id . toString ( ) . c_str ( ) , _size ) ;
2010-05-27 08:09:32 +00:00
2010-06-15 12:19:14 +00:00
_status = kResStatusAllocated ;
2010-05-27 08:09:32 +00:00
return true ;
}
2010-06-15 12:18:57 +00:00
bool Resource : : loadFromAudioVolumeSCI11 ( Common : : SeekableReadStream * file ) {
2010-05-27 08:09:32 +00:00
// Check for WAVE files here
2010-06-02 13:17:36 +00:00
uint32 riffTag = file - > readUint32BE ( ) ;
2011-04-12 16:53:15 +02:00
if ( riffTag = = MKTAG ( ' R ' , ' I ' , ' F ' , ' F ' ) ) {
2016-12-31 20:39:57 -06:00
_size = file - > readUint32LE ( ) + 8 ;
2010-06-02 13:17:36 +00:00
file - > seek ( - 8 , SEEK_CUR ) ;
2010-06-15 12:18:57 +00:00
return loadFromWaveFile ( file ) ;
2010-05-27 08:09:32 +00:00
}
2010-06-02 13:17:36 +00:00
file - > seek ( - 4 , SEEK_CUR ) ;
2010-05-27 08:09:32 +00:00
2013-12-11 08:25:23 +01:00
// Rave-resources (King's Quest 6) don't have any header at all
if ( getType ( ) ! = kResourceTypeRave ) {
ResourceType type = _resMan - > convertResType ( file - > readByte ( ) ) ;
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
2013-12-11 08:25:23 +01:00
if ( ( ( getType ( ) = = kResourceTypeAudio | | getType ( ) = = kResourceTypeAudio36 ) & & ( type ! = kResourceTypeAudio ) )
| | ( ( getType ( ) = = kResourceTypeSync | | getType ( ) = = kResourceTypeSync36 ) & & ( type ! = kResourceTypeSync ) ) ) {
warning ( " Resource type mismatch loading %s " , _id . toString ( ) . c_str ( ) ) ;
2010-06-15 12:19:14 +00:00
unalloc ( ) ;
2010-05-27 08:09:32 +00:00
return false ;
}
2014-10-28 16:17:06 +02:00
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
const uint8 headerSize = file - > readByte ( ) ;
2013-12-11 08:25:23 +01:00
if ( type = = kResourceTypeAudio ) {
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
if ( headerSize ! = 7 & & headerSize ! = 11 & & headerSize ! = 12 ) {
2017-05-07 14:09:58 -05:00
warning ( " Unsupported audio header size %d in %s " , headerSize , _id . toString ( ) . c_str ( ) ) ;
2013-12-11 08:25:23 +01:00
unalloc ( ) ;
return false ;
}
2010-05-27 08:09:32 +00:00
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
if ( headerSize ! = 7 ) { // Size is defined already from the map
2013-12-11 08:25:23 +01:00
// Load sample size
file - > seek ( 7 , SEEK_CUR ) ;
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
_size = file - > readUint32LE ( ) + headerSize + kResourceHeaderSize ;
2017-05-07 14:09:58 -05:00
if ( file - > err ( ) | | file - > eos ( ) ) {
warning ( " Error while reading size of %s " , _id . toString ( ) . c_str ( ) ) ;
unalloc ( ) ;
return false ;
}
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
// Adjust offset to point at the beginning of the audio file
// again
2013-12-11 08:25:23 +01:00
file - > seek ( - 11 , SEEK_CUR ) ;
}
SCI32: Fix audio, wave, VMD, Duck, CLUT, TGA, ZZZ, Etc patches
Specifically, audio patches are used in at least PQ:SWAT
(40103.AUD), Lighthouse (9103.AUD), and the GK2 demo (300.AUD).
2017-01-08 22:59:30 -06:00
// SOL audio files are designed to require the resource header
file - > seek ( - 2 , SEEK_CUR ) ;
2010-06-22 15:18:55 +00:00
}
2010-05-27 08:09:32 +00:00
}
2010-06-15 12:18:57 +00:00
return loadPatch ( file ) ;
2010-05-27 08:09:32 +00:00
}
2010-06-15 12:18:57 +00:00
bool Resource : : loadFromAudioVolumeSCI1 ( Common : : SeekableReadStream * file ) {
2016-12-31 20:39:57 -06:00
byte * ptr = new byte [ size ( ) ] ;
_data = ptr ;
2010-05-27 08:09:32 +00:00
2016-12-31 20:39:57 -06:00
if ( ! ptr ) {
2017-03-30 14:02:27 -05:00
error ( " Can't allocate %u bytes needed for loading %s " , _size , _id . toString ( ) . c_str ( ) ) ;
2010-05-27 08:09:32 +00:00
}
2016-12-31 20:39:57 -06:00
uint32 bytesRead = file - > read ( ptr , size ( ) ) ;
if ( bytesRead ! = size ( ) )
2017-03-30 14:02:27 -05:00
warning ( " Read %d bytes from %s but expected %u " , bytesRead , _id . toString ( ) . c_str ( ) , _size ) ;
2010-05-27 08:09:32 +00:00
2010-06-15 12:19:14 +00:00
_status = kResStatusAllocated ;
2010-05-27 08:09:32 +00:00
return true ;
}
2010-06-25 16:16:29 +00:00
void ResourceManager : : addNewGMPatch ( SciGameId gameId ) {
2010-05-27 08:09:32 +00:00
Common : : String gmPatchFile ;
2010-06-25 16:16:29 +00:00
switch ( gameId ) {
case GID_ECOQUEST :
2010-05-27 08:09:32 +00:00
gmPatchFile = " ECO1GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_HOYLE3 :
2010-05-27 08:09:32 +00:00
gmPatchFile = " HOY3GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_LSL1 :
2010-05-27 08:09:32 +00:00
gmPatchFile = " LL1_GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_LSL5 :
2010-05-27 08:09:32 +00:00
gmPatchFile = " LL5_GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_LONGBOW :
2010-05-27 08:09:32 +00:00
gmPatchFile = " ROBNGM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_SQ1 :
2010-05-27 08:09:32 +00:00
gmPatchFile = " SQ1_GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_SQ4 :
2010-05-27 08:09:32 +00:00
gmPatchFile = " SQ4_GM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
case GID_FAIRYTALES :
2010-05-27 08:09:32 +00:00
gmPatchFile = " TALEGM.PAT " ;
2010-06-25 16:16:29 +00:00
break ;
default :
break ;
}
2010-05-27 08:09:32 +00:00
if ( ! gmPatchFile . empty ( ) & & Common : : File : : exists ( gmPatchFile ) ) {
2010-06-15 12:10:41 +00:00
ResourceSource * psrcPatch = new PatchResourceSource ( gmPatchFile ) ;
2010-05-27 08:09:32 +00:00
processPatch ( psrcPatch , kResourceTypePatch , 4 ) ;
}
}
2017-05-08 00:04:40 -05:00
void ResourceManager : : processWavePatch ( ResourceId resourceId , const Common : : String & name ) {
2010-06-15 12:10:41 +00:00
ResourceSource * resSrc = new WaveResourceSource ( name ) ;
2010-06-15 12:18:31 +00:00
Common : : File file ;
file . open ( name ) ;
2010-06-10 15:06:25 +00:00
2017-06-07 23:24:09 -05:00
updateResource ( resourceId , resSrc , 0 , file . size ( ) , name ) ;
2012-01-15 19:02:19 +02:00
_sources . push_back ( resSrc ) ;
2010-06-10 15:06:25 +00:00
debugC ( 1 , kDebugLevelResMan , " Patching %s - OK " , name . c_str ( ) ) ;
}
2010-05-27 08:09:32 +00:00
void ResourceManager : : readWaveAudioPatches ( ) {
// Here we do check for SCI1.1+ so we can patch wav files in as audio resources
Common : : ArchiveMemberList files ;
SearchMan . listMatchingMembers ( files , " *.wav " ) ;
for ( Common : : ArchiveMemberList : : const_iterator x = files . begin ( ) ; x ! = files . end ( ) ; + + x ) {
Common : : String name = ( * x ) - > getName ( ) ;
2012-02-20 16:03:39 +01:00
if ( Common : : isDigit ( name [ 0 ] ) )
2010-06-10 15:06:25 +00:00
processWavePatch ( ResourceId ( kResourceTypeAudio , atoi ( name . c_str ( ) ) ) , name ) ;
2010-05-27 08:09:32 +00:00
}
}
void ResourceManager : : removeAudioResource ( ResourceId resId ) {
// Remove resource, unless it was loaded from a patch
if ( _resMap . contains ( resId ) ) {
Resource * res = _resMap . getVal ( resId ) ;
2010-06-15 12:09:30 +00:00
if ( res - > _source - > getSourceType ( ) = = kSourceAudioVolume ) {
2010-05-27 08:09:32 +00:00
if ( res - > _status = = kResStatusLocked ) {
warning ( " Failed to remove resource %s (still in use) " , resId . toString ( ) . c_str ( ) ) ;
} else {
if ( res - > _status = = kResStatusEnqueued )
removeFromLRU ( res ) ;
_resMap . erase ( resId ) ;
delete res ;
}
}
}
}
// Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD):
// =========
// 6-byte entries:
// w nEntry
// dw offset
// Late SCI1.1 65535.MAP structure (uses RESOURCE.SFX):
// =========
// 5-byte entries:
// w nEntry
// tb offset (cumulative)
2010-08-02 18:30:37 +00:00
// QFG3 Demo 0.MAP structure:
// =========
// 10-byte entries:
// w nEntry
// dw offset
// dw size
// LB2 Floppy/Mother Goose SCI1.1 0.MAP structure:
// =========
// 8-byte entries:
// w nEntry
// w 0xffff
// dw offset
2010-05-27 08:09:32 +00:00
// Early SCI1.1 MAP structure:
// ===============
// 10-byte entries:
// b noun
// b verb
// b cond
// b seq
// dw offset
// w syncSize + syncAscSize
// Late SCI1.1 MAP structure:
// ===============
// Header:
// dw baseOffset
// Followed by 7 or 11-byte entries:
// b noun
// b verb
// b cond
// b seq
// tb cOffset (cumulative offset)
// w syncSize (iff seq has bit 7 set)
// w syncAscSize (iff seq has bit 6 set)
2016-08-19 10:05:05 -05:00
int ResourceManager : : readAudioMapSCI11 ( IntMapResourceSource * map ) {
2010-09-18 09:47:18 +00:00
# ifndef ENABLE_SCI32
// SCI32 support is not built in. Check if this is a SCI32 game
// and if it is abort here.
2010-11-09 16:06:33 +00:00
if ( _volVersion > = kResVersionSci2 )
2010-09-18 09:47:18 +00:00
return SCI_ERROR_RESMAP_NOT_FOUND ;
# endif
2010-05-27 08:09:32 +00:00
uint32 offset = 0 ;
2017-05-07 14:09:58 -05:00
const ResourceId mapResId ( kResourceTypeMap , map - > _mapNumber ) ;
Resource * mapRes = findResource ( mapResId , false ) ;
2010-05-27 08:09:32 +00:00
if ( ! mapRes ) {
2017-05-07 14:09:58 -05:00
warning ( " Failed to open %s " , mapResId . toString ( ) . c_str ( ) ) ;
2010-05-27 08:09:32 +00:00
return SCI_ERROR_RESMAP_NOT_FOUND ;
}
2016-08-19 10:05:05 -05:00
ResourceSource * src = findVolume ( map , map - > _volumeNumber ) ;
2010-05-27 08:09:32 +00:00
2016-08-19 10:05:05 -05:00
if ( ! src ) {
2017-05-07 14:09:58 -05:00
warning ( " Failed to find volume for %s " , mapResId . toString ( ) . c_str ( ) ) ;
return SCI_ERROR_NO_RESOURCE_FILES_FOUND ;
}
Common : : SeekableReadStream * fileStream = getVolumeFile ( src ) ;
if ( ! fileStream ) {
2017-05-10 00:33:43 -05:00
warning ( " Failed to open file stream for %s " , src - > getLocationName ( ) . c_str ( ) ) ;
2010-05-27 08:09:32 +00:00
return SCI_ERROR_NO_RESOURCE_FILES_FOUND ;
2016-08-19 10:05:05 -05:00
}
2010-05-27 08:09:32 +00:00
2017-05-07 14:09:58 -05:00
const uint32 srcSize = fileStream - > size ( ) ;
2017-05-13 22:07:53 -05:00
disposeVolumeFileStream ( fileStream , src ) ;
2016-12-31 20:39:57 -06:00
SciSpan < const byte > : : const_iterator ptr = mapRes - > cbegin ( ) ;
2010-05-27 08:09:32 +00:00
2010-06-22 15:18:55 +00:00
// Heuristic to detect entry size
uint32 entrySize = 0 ;
2016-12-31 20:39:57 -06:00
for ( int i = mapRes - > size ( ) - 1 ; i > = 0 ; - - i ) {
2010-06-22 15:18:55 +00:00
if ( ptr [ i ] = = 0xff )
entrySize + + ;
else
break ;
}
2010-05-27 08:09:32 +00:00
2016-08-19 10:05:05 -05:00
if ( map - > _mapNumber = = 65535 ) {
2016-12-31 20:39:57 -06:00
while ( ptr ! = mapRes - > cend ( ) ) {
uint16 n = ptr . getUint16LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 2 ;
if ( n = = 0xffff )
break ;
2010-06-22 15:18:55 +00:00
if ( entrySize = = 6 ) {
2016-12-31 20:39:57 -06:00
offset = ptr . getUint32LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 4 ;
} else {
2016-12-31 20:39:57 -06:00
offset + = ptr . getUint24LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 3 ;
}
2017-05-07 14:09:58 -05:00
addResource ( ResourceId ( kResourceTypeAudio , n ) , src , offset , 0 , map - > getLocationName ( ) ) ;
2010-05-27 08:09:32 +00:00
}
2016-08-19 10:05:05 -05:00
} else if ( map - > _mapNumber = = 0 & & entrySize = = 10 & & ptr [ 3 ] = = 0 ) {
2010-06-22 15:18:55 +00:00
// QFG3 demo format
// ptr[3] would be 'seq' in the normal format and cannot possibly be 0
2016-12-31 20:39:57 -06:00
while ( ptr ! = mapRes - > cend ( ) ) {
uint16 n = ptr . getUint16BE ( ) ;
2010-06-22 15:18:55 +00:00
ptr + = 2 ;
if ( n = = 0xffff )
break ;
2016-12-31 20:39:57 -06:00
offset = ptr . getUint32LE ( ) ;
2010-06-22 15:18:55 +00:00
ptr + = 4 ;
2016-12-31 20:39:57 -06:00
uint32 size = ptr . getUint32LE ( ) ;
2010-06-22 15:18:55 +00:00
ptr + = 4 ;
2017-05-07 14:09:58 -05:00
addResource ( ResourceId ( kResourceTypeAudio , n ) , src , offset , size , map - > getLocationName ( ) ) ;
2010-08-02 18:30:37 +00:00
}
2016-12-31 20:39:57 -06:00
} else if ( map - > _mapNumber = = 0 & & entrySize = = 8 & & ( ptr + 2 ) . getUint16LE ( ) = = 0xffff ) {
2010-08-02 18:30:37 +00:00
// LB2 Floppy/Mother Goose SCI1.1 format
Common : : SeekableReadStream * stream = getVolumeFile ( src ) ;
2016-12-31 20:39:57 -06:00
while ( ptr ! = mapRes - > cend ( ) ) {
uint16 n = ptr . getUint16LE ( ) ;
2010-08-02 18:30:37 +00:00
ptr + = 4 ;
if ( n = = 0xffff )
break ;
2017-05-07 14:09:58 -05:00
const ResourceId audioResId ( kResourceTypeAudio , n ) ;
2016-12-31 20:39:57 -06:00
offset = ptr . getUint32LE ( ) ;
2010-08-02 18:30:37 +00:00
ptr + = 4 ;
2017-05-10 00:33:43 -05:00
uint32 size ;
if ( src - > getAudioCompressionType ( ) = = 0 ) {
// The size is not stored in the map and the entries have no order.
// We need to dig into the audio resource in the volume to get the size.
stream - > seek ( offset + 1 ) ;
byte headerSize = stream - > readByte ( ) ;
if ( headerSize ! = 11 & & headerSize ! = 12 ) {
error ( " Unexpected header size in %s: should be 11 or 12, got %d " , audioResId . toString ( ) . c_str ( ) , headerSize ) ;
}
2010-08-02 18:30:37 +00:00
2017-05-10 00:33:43 -05:00
stream - > skip ( 7 ) ;
size = stream - > readUint32LE ( ) + headerSize + 2 ;
} else {
size = 0 ;
}
2017-05-07 14:09:58 -05:00
addResource ( audioResId , src , offset , size , map - > getLocationName ( ) ) ;
2010-06-22 15:18:55 +00:00
}
2017-05-13 22:07:53 -05:00
disposeVolumeFileStream ( stream , src ) ;
2010-05-27 08:09:32 +00:00
} else {
2011-06-20 00:59:48 +02:00
bool isEarly = ( entrySize ! = 11 ) ;
2010-05-27 08:09:32 +00:00
if ( ! isEarly ) {
2016-12-31 20:39:57 -06:00
offset = ptr . getUint32LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 4 ;
}
2016-12-31 20:39:57 -06:00
while ( ptr ! = mapRes - > cend ( ) ) {
uint32 n = ptr . getUint32BE ( ) ;
2017-05-10 00:33:43 -05:00
uint32 syncSize = 0 ;
2010-05-27 08:09:32 +00:00
ptr + = 4 ;
if ( n = = 0xffffffff )
break ;
if ( isEarly ) {
2016-12-31 20:39:57 -06:00
offset = ptr . getUint32LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 4 ;
} else {
2016-12-31 20:39:57 -06:00
offset + = ptr . getUint24LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 3 ;
}
if ( isEarly | | ( n & 0x80 ) ) {
2016-12-31 20:39:57 -06:00
syncSize = ptr . getUint16LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 2 ;
2013-12-10 01:40:46 +02:00
// FIXME: The sync36 resource seems to be two bytes too big in KQ6CD
// (bytes taken from the RAVE resource right after it)
2016-12-31 20:39:57 -06:00
if ( syncSize > 0 ) {
2017-05-07 14:09:58 -05:00
addResource ( ResourceId ( kResourceTypeSync36 , map - > _mapNumber , n & 0xffffff3f ) , src , offset , syncSize , map - > getLocationName ( ) ) ;
2016-12-31 20:39:57 -06:00
}
2010-05-27 08:09:32 +00:00
}
2016-12-02 15:16:32 -06:00
// Checking for this 0x40 flag breaks at least Laura Bow 2 CD 1.1
// map 448
if ( g_sci - > getGameId ( ) = = GID_KQ6 & & ( n & 0x40 ) ) {
2010-06-15 12:19:39 +00:00
// This seems to define the size of raw lipsync data (at least
2013-12-10 01:40:46 +02:00
// in KQ6 CD Windows).
2017-05-10 00:33:43 -05:00
uint32 kq6HiresSyncSize = ptr . getUint16LE ( ) ;
2010-05-27 08:09:32 +00:00
ptr + = 2 ;
2013-12-10 01:40:46 +02:00
if ( kq6HiresSyncSize > 0 ) {
2017-05-10 15:29:10 -05:00
// Rave resources do not have separate entries in the audio
// map (their data was just appended to sync resources), so
// we have to use the sync resource offset first and then
// adjust the offset & size later, otherwise offset
// validation will fail for compressed volumes (since the
// relocation table in a compressed volume only contains
// offsets that existed in the original audio map)
Resource * res = addResource ( ResourceId ( kResourceTypeRave , map - > _mapNumber , n & 0xffffff3f ) , src , offset , syncSize + kq6HiresSyncSize , map - > getLocationName ( ) ) ;
res - > _fileOffset + = syncSize ;
res - > _size - = syncSize ;
2013-12-10 01:40:46 +02:00
syncSize + = kq6HiresSyncSize ;
}
2010-05-27 08:09:32 +00:00
}
2017-05-07 14:09:58 -05:00
const ResourceId id ( kResourceTypeAudio36 , map - > _mapNumber , n & 0xffffff3f ) ;
2016-12-14 11:27:49 -06:00
2017-01-10 19:59:32 -06:00
// Map 405 on CD 1 of the US release of PQ:SWAT 1.000 is broken
// and points to garbage in the RESOURCE.AUD. The affected audio36
// assets seem to be able to load successfully from one of the later
// CDs, so just ignore the map on this disc
if ( g_sci - > getGameId ( ) = = GID_PQSWAT & & map - > _volumeNumber = = 1 & & map - > _mapNumber = = 405 ) {
continue ;
}
2016-12-14 11:27:49 -06:00
// At least version 1.00 of GK2 has multiple invalid audio36 map
// entries on CD 6
if ( g_sci - > getGameId ( ) = = GID_GK2 & &
map - > _volumeNumber = = 6 & &
offset + syncSize > = srcSize ) {
debugC ( kDebugLevelResMan , " Invalid offset %u for %s in map %d for disc %d " , offset + syncSize , id . toPatchNameBase36 ( ) . c_str ( ) , map - > _mapNumber , map - > _volumeNumber ) ;
continue ;
}
2017-05-07 14:09:58 -05:00
addResource ( id , src , offset + syncSize , 0 , map - > getLocationName ( ) ) ;
2010-05-27 08:09:32 +00:00
}
}
return 0 ;
}
// AUDIOnnn.MAP contains 10-byte entries:
// Early format:
// w 5 bits resource type and 11 bits resource number
// dw 7 bits volume number and 25 bits offset
// dw size
// Later format:
// w nEntry
// dw offset+volume (as in resource.map)
// dw size
// ending with 10 0xFFs
int ResourceManager : : readAudioMapSCI1 ( ResourceSource * map , bool unload ) {
Common : : File file ;
2010-06-15 12:09:51 +00:00
if ( ! file . open ( map - > getLocationName ( ) ) )
2010-05-27 08:09:32 +00:00
return SCI_ERROR_RESMAP_NOT_FOUND ;
bool oldFormat = ( file . readUint16LE ( ) > > 11 ) = = kResourceTypeAudio ;
file . seek ( 0 ) ;
2016-12-31 20:39:57 -06:00
for ( ; ; ) {
2010-05-27 08:09:32 +00:00
uint16 n = file . readUint16LE ( ) ;
uint32 offset = file . readUint32LE ( ) ;
uint32 size = file . readUint32LE ( ) ;
if ( file . eos ( ) | | file . err ( ) ) {
2010-06-15 12:09:51 +00:00
warning ( " Error while reading %s " , map - > getLocationName ( ) . c_str ( ) ) ;
2010-05-27 08:09:32 +00:00
return SCI_ERROR_RESMAP_NOT_FOUND ;
}
if ( n = = 0xffff )
break ;
byte volume_nr ;
if ( oldFormat ) {
n & = 0x07ff ; // Mask out resource type
volume_nr = offset > > 25 ; // most significant 7 bits
offset & = 0x01ffffff ; // least significant 25 bits
} else {
volume_nr = offset > > 28 ; // most significant 4 bits
offset & = 0x0fffffff ; // least significant 28 bits
}
2010-06-15 12:11:56 +00:00
ResourceSource * src = findVolume ( map , volume_nr ) ;
2010-05-27 08:09:32 +00:00
if ( src ) {
2017-05-07 14:09:58 -05:00
const ResourceId resId ( kResourceTypeAudio , n ) ;
2016-12-31 20:39:57 -06:00
2010-05-27 08:09:32 +00:00
if ( unload )
2017-05-07 14:09:58 -05:00
removeAudioResource ( resId ) ;
else
addResource ( resId , src , offset , size , map - > getLocationName ( ) ) ;
2010-05-27 08:09:32 +00:00
} else {
warning ( " Failed to find audio volume %i " , volume_nr ) ;
2017-05-07 14:09:58 -05:00
return SCI_ERROR_NO_RESOURCE_FILES_FOUND ;
2010-05-27 08:09:32 +00:00
}
}
return 0 ;
}
void ResourceManager : : setAudioLanguage ( int language ) {
if ( _audioMapSCI1 ) {
2010-06-15 12:15:05 +00:00
if ( _audioMapSCI1 - > _volumeNumber = = language ) {
2010-05-27 08:09:32 +00:00
// This language is already loaded
return ;
}
// We already have a map loaded, so we unload it first
2017-05-07 14:09:58 -05:00
if ( readAudioMapSCI1 ( _audioMapSCI1 , true ) ! = SCI_ERROR_NONE ) {
_hasBadResources = true ;
}
2010-05-27 08:09:32 +00:00
// Remove all volumes that use this map from the source list
Common : : List < ResourceSource * > : : iterator it = _sources . begin ( ) ;
while ( it ! = _sources . end ( ) ) {
ResourceSource * src = * it ;
2010-06-15 12:18:07 +00:00
if ( src - > findVolume ( _audioMapSCI1 , src - > _volumeNumber ) ) {
2010-05-27 08:09:32 +00:00
it = _sources . erase ( it ) ;
delete src ;
} else {
+ + it ;
}
}
// Remove the map itself from the source list
_sources . remove ( _audioMapSCI1 ) ;
delete _audioMapSCI1 ;
_audioMapSCI1 = NULL ;
}
2016-11-22 13:24:29 -06:00
Common : : String filename = Common : : String : : format ( " AUDIO%03d " , language ) ;
Common : : String fullname = filename + " .MAP " ;
2010-05-27 08:09:32 +00:00
if ( ! Common : : File : : exists ( fullname ) ) {
warning ( " No audio map found for language %i " , language ) ;
return ;
}
2010-06-15 12:14:39 +00:00
_audioMapSCI1 = addSource ( new ExtAudioMapResourceSource ( fullname , language ) ) ;
2010-05-27 08:09:32 +00:00
// Search for audio volumes for this language and add them to the source list
Common : : ArchiveMemberList files ;
2016-11-22 13:24:29 -06:00
SearchMan . listMatchingMembers ( files , filename + " .0?? " ) ;
2010-05-27 08:09:32 +00:00
for ( Common : : ArchiveMemberList : : const_iterator x = files . begin ( ) ; x ! = files . end ( ) ; + + x ) {
const Common : : String name = ( * x ) - > getName ( ) ;
const char * dot = strrchr ( name . c_str ( ) , ' . ' ) ;
int number = atoi ( dot + 1 ) ;
2010-06-16 00:24:16 +00:00
addSource ( new AudioVolumeResourceSource ( this , name , _audioMapSCI1 , number ) ) ;
2010-05-27 08:09:32 +00:00
}
scanNewSources ( ) ;
}
int ResourceManager : : getAudioLanguage ( ) const {
2010-06-15 12:15:05 +00:00
return ( _audioMapSCI1 ? _audioMapSCI1 - > _volumeNumber : 0 ) ;
2010-05-27 08:09:32 +00:00
}
2010-08-19 13:52:21 +00:00
bool ResourceManager : : isGMTrackIncluded ( ) {
// This check only makes sense for SCI1 and newer games
if ( getSciVersion ( ) < SCI_VERSION_1_EARLY )
return false ;
// SCI2 and newer games always have GM tracks
if ( getSciVersion ( ) > = SCI_VERSION_2 )
return true ;
// For the leftover games, we can safely use SCI_VERSION_1_EARLY for the soundVersion
const SciVersion soundVersion = SCI_VERSION_1_EARLY ;
2010-08-20 09:35:20 +00:00
// Read the first song and check if it has a GM track
2010-08-19 13:52:21 +00:00
bool result = false ;
2012-01-15 18:25:00 +01:00
Common : : List < ResourceId > resources = listResources ( kResourceTypeSound , - 1 ) ;
Common : : sort ( resources . begin ( ) , resources . end ( ) ) ;
Common : : List < ResourceId > : : iterator itr = resources . begin ( ) ;
2010-08-20 09:35:20 +00:00
int firstSongId = itr - > getNumber ( ) ;
SoundResource * song1 = new SoundResource ( firstSongId , this , soundVersion ) ;
2010-08-19 13:52:21 +00:00
if ( ! song1 ) {
warning ( " ResourceManager::isGMTrackIncluded: track 1 not found " ) ;
return false ;
}
SoundResource : : Track * gmTrack = song1 - > getTrackByType ( 0x07 ) ;
if ( gmTrack )
result = true ;
delete song1 ;
return result ;
}
2010-06-26 19:55:49 +00:00
SoundResource : : SoundResource ( uint32 resourceNr , ResourceManager * resMan , SciVersion soundVersion ) : _resMan ( resMan ) , _soundVersion ( soundVersion ) {
Resource * resource = _resMan - > findResource ( ResourceId ( kResourceTypeSound , resourceNr ) , true ) ;
2010-05-27 08:09:32 +00:00
int trackNr , channelNr ;
if ( ! resource )
return ;
_innerResource = resource ;
2015-02-14 15:20:23 +01:00
_soundPriority = 0xFF ;
2010-05-27 08:09:32 +00:00
Channel * channel , * sampleChannel ;
switch ( _soundVersion ) {
case SCI_VERSION_0_EARLY :
case SCI_VERSION_0_LATE :
// SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
_trackCount = 1 ;
_tracks = new Track [ _trackCount ] ;
_tracks - > digitalChannelNr = - 1 ;
_tracks - > type = 0 ; // Not used for SCI0
_tracks - > channelCount = 1 ;
// Digital sample data included? -> Add an additional channel
2016-12-31 20:39:57 -06:00
if ( resource - > getUint8At ( 0 ) = = 2 )
2010-05-27 08:09:32 +00:00
_tracks - > channelCount + + ;
_tracks - > channels = new Channel [ _tracks - > channelCount ] ;
channel = & _tracks - > channels [ 0 ] ;
2013-04-14 01:32:37 +02:00
channel - > flags | = 2 ; // don't remap (SCI0 doesn't have remapping)
2010-05-27 08:09:32 +00:00
if ( _soundVersion = = SCI_VERSION_0_EARLY ) {
2016-12-31 20:39:57 -06:00
channel - > data = resource - > subspan ( 0x11 ) ;
2010-05-27 08:09:32 +00:00
} else {
2016-12-31 20:39:57 -06:00
channel - > data = resource - > subspan ( 0x21 ) ;
2010-05-27 08:09:32 +00:00
}
if ( _tracks - > channelCount = = 2 ) {
// Digital sample data included
_tracks - > digitalChannelNr = 1 ;
sampleChannel = & _tracks - > channels [ 1 ] ;
// we need to find 0xFC (channel terminator) within the data
2016-12-31 20:39:57 -06:00
SciSpan < const byte > : : const_iterator it = channel - > data . cbegin ( ) ;
while ( it ! = channel - > data . cend ( ) & & * it ! = 0xfc )
it + + ;
2010-05-27 08:09:32 +00:00
// Skip any following 0xFCs as well
2016-12-31 20:39:57 -06:00
while ( it ! = channel - > data . cend ( ) & & * it = = 0xfc )
it + + ;
2010-05-27 08:09:32 +00:00
// Now adjust channels accordingly
2016-12-31 20:39:57 -06:00
sampleChannel - > data = channel - > data . subspan ( it - channel - > data . cbegin ( ) ) ;
channel - > data = channel - > data . subspan ( 0 , it - channel - > data . cbegin ( ) ) ;
2010-05-27 08:09:32 +00:00
// Read sample header information
//Offset 14 in the header contains the frequency as a short integer. Offset 32 contains the sample length, also as a short integer.
2016-12-31 20:39:57 -06:00
_tracks - > digitalSampleRate = sampleChannel - > data . getUint16LEAt ( 14 ) ;
_tracks - > digitalSampleSize = sampleChannel - > data . getUint16LEAt ( 32 ) ;
2010-05-27 08:09:32 +00:00
_tracks - > digitalSampleStart = 0 ;
_tracks - > digitalSampleEnd = 0 ;
sampleChannel - > data + = 44 ; // Skip over header
}
break ;
case SCI_VERSION_1_EARLY :
case SCI_VERSION_1_LATE :
2016-12-31 20:39:57 -06:00
case SCI_VERSION_2_1_EARLY : {
SciSpan < const byte > data = * resource ;
2010-05-27 08:09:32 +00:00
// Count # of tracks
_trackCount = 0 ;
while ( ( * data + + ) ! = 0xFF ) {
_trackCount + + ;
while ( * data ! = 0xFF )
data + = 6 ;
2016-12-31 20:39:57 -06:00
+ + data ;
2010-05-27 08:09:32 +00:00
}
_tracks = new Track [ _trackCount ] ;
2016-12-31 20:39:57 -06:00
data = * resource ;
2010-06-26 19:55:49 +00:00
byte channelCount ;
2010-05-27 08:09:32 +00:00
for ( trackNr = 0 ; trackNr < _trackCount ; trackNr + + ) {
// Track info starts with track type:BYTE
// Then the channel information gets appended Unknown:WORD, ChannelOffset:WORD, ChannelSize:WORD
// 0xFF:BYTE as terminator to end that track and begin with another track type
// Track type 0xFF is the marker signifying the end of the tracks
_tracks [ trackNr ] . type = * data + + ;
// Counting # of channels used
2016-12-31 20:39:57 -06:00
SciSpan < const byte > data2 = data ;
2010-06-26 19:55:49 +00:00
channelCount = 0 ;
2010-05-27 08:09:32 +00:00
while ( * data2 ! = 0xFF ) {
data2 + = 6 ;
2010-06-26 19:55:49 +00:00
channelCount + + ;
2010-05-27 08:09:32 +00:00
_tracks [ trackNr ] . channelCount + + ;
}
2010-06-26 19:55:49 +00:00
_tracks [ trackNr ] . channels = new Channel [ channelCount ] ;
_tracks [ trackNr ] . channelCount = 0 ;
2010-05-27 08:09:32 +00:00
_tracks [ trackNr ] . digitalChannelNr = - 1 ; // No digital sound associated
_tracks [ trackNr ] . digitalSampleRate = 0 ;
_tracks [ trackNr ] . digitalSampleSize = 0 ;
_tracks [ trackNr ] . digitalSampleStart = 0 ;
_tracks [ trackNr ] . digitalSampleEnd = 0 ;
if ( _tracks [ trackNr ] . type ! = 0xF0 ) { // Digital track marker - not supported currently
2010-06-26 19:55:49 +00:00
channelNr = 0 ;
while ( channelCount - - ) {
2010-05-27 08:09:32 +00:00
channel = & _tracks [ trackNr ] . channels [ channelNr ] ;
2016-12-31 20:39:57 -06:00
const uint16 dataOffset = data . getUint16LEAt ( 2 ) ;
2013-12-31 13:42:58 +01:00
2016-12-31 20:39:57 -06:00
if ( dataOffset > = resource - > size ( ) ) {
2010-06-26 19:55:49 +00:00
warning ( " Invalid offset inside sound resource %d: track %d, channel %d " , resourceNr , trackNr , channelNr ) ;
2013-12-31 13:42:58 +01:00
data + = 6 ;
continue ;
}
2016-12-31 20:39:57 -06:00
uint16 size = data . getUint16LEAt ( 4 ) ;
2016-03-08 03:36:02 +01:00
2016-12-31 20:39:57 -06:00
if ( dataOffset + size > resource - > size ( ) ) {
2016-03-08 03:36:02 +01:00
warning ( " Invalid size inside sound resource %d: track %d, channel %d " , resourceNr , trackNr , channelNr ) ;
2016-12-31 20:39:57 -06:00
size = resource - > size ( ) - dataOffset ;
2016-03-08 03:36:02 +01:00
}
2016-12-31 20:39:57 -06:00
channel - > data = resource - > subspan ( dataOffset , size ) ;
2013-12-31 13:42:58 +01:00
channel - > curPos = 0 ;
2016-12-31 20:39:57 -06:00
channel - > number = channel - > data [ 0 ] ;
2013-04-14 01:32:37 +02:00
2016-12-31 20:39:57 -06:00
channel - > poly = channel - > data [ 1 ] & 0x0F ;
channel - > prio = channel - > data [ 1 ] > > 4 ;
2013-12-31 13:42:58 +01:00
channel - > time = channel - > prev = 0 ;
channel - > data + = 2 ; // skip over header
if ( channel - > number = = 0xFE ) { // Digital channel
_tracks [ trackNr ] . digitalChannelNr = channelNr ;
2016-12-31 20:39:57 -06:00
_tracks [ trackNr ] . digitalSampleRate = channel - > data . getUint16LEAt ( 0 ) ;
_tracks [ trackNr ] . digitalSampleSize = channel - > data . getUint16LEAt ( 2 ) ;
_tracks [ trackNr ] . digitalSampleStart = channel - > data . getUint16LEAt ( 4 ) ;
_tracks [ trackNr ] . digitalSampleEnd = channel - > data . getUint16LEAt ( 6 ) ;
2013-12-31 13:42:58 +01:00
channel - > data + = 8 ; // Skip over header
2013-04-14 01:32:37 +02:00
channel - > flags = 0 ;
} else {
channel - > flags = channel - > number > > 4 ;
channel - > number = channel - > number & 0x0F ;
// 0x20 is set on rhythm channels to prevent remapping
// CHECKME: Which SCI versions need that set manually?
if ( channel - > number = = 9 )
channel - > flags | = 2 ;
// Note: flag 1: channel start offset is 0 instead of 10
// (currently: everything 0)
// also: don't map the channel to device
// flag 2: don't remap
// flag 4: start muted
// QfG2 lacks flags 2 and 4, and uses (flags >= 1) as
// the condition for starting offset 0, without the "don't map"
2010-05-27 08:09:32 +00:00
}
2013-12-31 13:42:58 +01:00
_tracks [ trackNr ] . channelCount + + ;
channelNr + + ;
2010-05-27 08:09:32 +00:00
data + = 6 ;
}
} else {
2015-02-14 15:20:23 +01:00
// The first byte of the 0xF0 track's channel list is priority
_soundPriority = * data ;
2010-05-27 08:09:32 +00:00
// Skip over digital track
data + = 6 ;
}
2016-12-31 20:39:57 -06:00
+ + data ; // Skipping 0xFF that closes channels list
2010-05-27 08:09:32 +00:00
}
break ;
2016-12-31 20:39:57 -06:00
}
2010-05-27 08:09:32 +00:00
default :
error ( " SoundResource: SCI version %d is unsupported " , _soundVersion ) ;
}
}
SoundResource : : ~ SoundResource ( ) {
for ( int trackNr = 0 ; trackNr < _trackCount ; trackNr + + )
delete [ ] _tracks [ trackNr ] . channels ;
delete [ ] _tracks ;
_resMan - > unlockResource ( _innerResource ) ;
}
#if 0
SoundResource : : Track * SoundResource : : getTrackByNumber ( uint16 number ) {
if ( _soundVersion < = SCI_VERSION_0_LATE )
return & _tracks [ 0 ] ;
if ( /*number >= 0 &&*/ number < _trackCount )
return & _tracks [ number ] ;
return NULL ;
}
# endif
SoundResource : : Track * SoundResource : : getTrackByType ( byte type ) {
if ( _soundVersion < = SCI_VERSION_0_LATE )
return & _tracks [ 0 ] ;
for ( int trackNr = 0 ; trackNr < _trackCount ; trackNr + + ) {
if ( _tracks [ trackNr ] . type = = type )
return & _tracks [ trackNr ] ;
}
return NULL ;
}
SoundResource : : Track * SoundResource : : getDigitalTrack ( ) {
for ( int trackNr = 0 ; trackNr < _trackCount ; trackNr + + ) {
if ( _tracks [ trackNr ] . digitalChannelNr ! = - 1 )
return & _tracks [ trackNr ] ;
}
return NULL ;
}
// Gets the filter mask for SCI0 sound resources
int SoundResource : : getChannelFilterMask ( int hardwareMask , bool wantsRhythm ) {
2016-12-31 20:39:57 -06:00
SciSpan < const byte > data = * _innerResource ;
2010-05-27 08:09:32 +00:00
int channelMask = 0 ;
if ( _soundVersion > SCI_VERSION_0_LATE )
return 0 ;
2016-12-31 20:39:57 -06:00
+ + data ; // Skip over digital sample flag
2010-05-27 08:09:32 +00:00
for ( int channelNr = 0 ; channelNr < 16 ; channelNr + + ) {
channelMask = channelMask > > 1 ;
byte flags ;
if ( _soundVersion = = SCI_VERSION_0_EARLY ) {
// Each channel is specified by a single byte
// Upper 4 bits of the byte is a voices count
// Lower 4 bits -> bit 0 set: use for AdLib
// bit 1 set: use for PCjr
// bit 2 set: use for PC speaker
// bit 3 set and bit 0 clear: control channel (15)
// bit 3 set and bit 0 set: rhythm channel (9)
// Note: control channel is dynamically assigned inside the drivers,
// but seems to be fixed at 15 in the song data.
flags = * data + + ;
// Get device bits
flags & = 0x7 ;
} else {
// Each channel is specified by 2 bytes
// 1st byte is voices count
// 2nd byte is play mask, which specifies if the channel is supposed to be played
// by the corresponding hardware
// Skip voice count
2016-12-31 20:39:57 -06:00
+ + data ;
2010-05-27 08:09:32 +00:00
flags = * data + + ;
}
bool play ;
switch ( channelNr ) {
case 15 :
// Always play control channel
play = true ;
break ;
case 9 :
// Play rhythm channel when requested
play = wantsRhythm ;
break ;
default :
// Otherwise check for flag
play = flags & hardwareMask ;
}
if ( play ) {
// This Channel is supposed to be played by the hardware
channelMask | = 0x8000 ;
}
}
return channelMask ;
}
byte SoundResource : : getInitialVoiceCount ( byte channel ) {
if ( _soundVersion > SCI_VERSION_0_LATE )
return 0 ; // TODO
2016-12-31 20:39:57 -06:00
// Skip over digital sample flag
SciSpan < const byte > data = _innerResource - > subspan ( 1 ) ;
2010-05-27 08:09:32 +00:00
if ( _soundVersion = = SCI_VERSION_0_EARLY )
return data [ channel ] > > 4 ;
else
return data [ channel * 2 ] ;
}
2011-02-10 12:40:48 +00:00
void WaveResourceSource : : loadResource ( ResourceManager * resMan , Resource * res ) {
Common : : SeekableReadStream * fileStream = getVolumeFile ( resMan , res ) ;
if ( ! fileStream )
return ;
fileStream - > seek ( res - > _fileOffset , SEEK_SET ) ;
res - > loadFromWaveFile ( fileStream ) ;
2017-05-13 22:07:53 -05:00
resMan - > disposeVolumeFileStream ( fileStream , this ) ;
2011-02-10 12:40:48 +00:00
}
void AudioVolumeResourceSource : : loadResource ( ResourceManager * resMan , Resource * res ) {
Common : : SeekableReadStream * fileStream = getVolumeFile ( resMan , res ) ;
if ( ! fileStream )
return ;
2017-05-10 00:33:43 -05:00
fileStream - > seek ( res - > _fileOffset , SEEK_SET ) ;
// For compressed audio, using loadFromAudioVolumeSCI1 is a hack to bypass
// the resource type checking in loadFromAudioVolumeSCI11 (since
// loadFromAudioVolumeSCI1 does nothing more than read raw data)
if ( _audioCompressionType ! = 0 & &
( res - > getType ( ) = = kResourceTypeAudio | |
res - > getType ( ) = = kResourceTypeAudio36 ) ) {
res - > loadFromAudioVolumeSCI1 ( fileStream ) ;
} else if ( getSciVersion ( ) < SCI_VERSION_1_1 )
2011-02-10 12:40:48 +00:00
res - > loadFromAudioVolumeSCI1 ( fileStream ) ;
else
res - > loadFromAudioVolumeSCI11 ( fileStream ) ;
2017-05-13 22:07:53 -05:00
resMan - > disposeVolumeFileStream ( fileStream , this ) ;
2011-02-10 12:40:48 +00:00
}
2011-02-10 16:48:29 +00:00
bool ResourceManager : : addAudioSources ( ) {
2016-08-19 10:05:05 -05:00
# ifdef ENABLE_SCI32
// Multi-disc audio is added during addAppropriateSources for those titles
// that require it
if ( _multiDiscAudio ) {
return true ;
}
# endif
2012-01-15 18:25:00 +01:00
Common : : List < ResourceId > resources = listResources ( kResourceTypeMap ) ;
Common : : List < ResourceId > : : iterator itr ;
2011-02-10 16:48:29 +00:00
2012-01-15 18:25:00 +01:00
for ( itr = resources . begin ( ) ; itr ! = resources . end ( ) ; + + itr ) {
2017-05-07 14:09:58 -05:00
const Resource * mapResource = _resMap . getVal ( * itr ) ;
ResourceSource * src = addSource ( new IntMapResourceSource ( mapResource - > getResourceLocation ( ) , 0 , itr - > getNumber ( ) ) ) ;
2011-02-10 16:48:29 +00:00
2016-08-19 10:05:05 -05:00
if ( itr - > getNumber ( ) = = 65535 & & Common : : File : : exists ( " RESOURCE.SFX " ) )
2011-02-10 16:48:29 +00:00
addSource ( new AudioVolumeResourceSource ( this , " RESOURCE.SFX " , src , 0 ) ) ;
else if ( Common : : File : : exists ( " RESOURCE.AUD " ) )
addSource ( new AudioVolumeResourceSource ( this , " RESOURCE.AUD " , src , 0 ) ) ;
else
return false ;
}
return true ;
}
2017-01-09 17:23:29 -06:00
void ResourceManager : : changeAudioDirectory ( const Common : : String & path ) {
// Resources must be cleared before ResourceSources because the destructor
// of a Resource accesses its own ResourceSource
ResourceMap : : iterator resIt = _resMap . begin ( ) ;
while ( resIt ! = _resMap . end ( ) ) {
Resource * resource = resIt - > _value ;
ResourceType type = resource - > getType ( ) ;
if ( type = = kResourceTypeMap | |
type = = kResourceTypeAudio36 | |
type = = kResourceTypeSync36 ) {
if ( type = = kResourceTypeMap & & resource - > getNumber ( ) = = 65535 ) {
+ + resIt ;
2011-02-10 16:48:29 +00:00
continue ;
2011-11-02 00:23:18 +02:00
}
2011-02-10 16:48:29 +00:00
2017-01-09 17:23:29 -06:00
if ( resource - > _status = = kResStatusLocked ) {
resource - > _lockers = 1 ;
unlockResource ( resource ) ;
}
if ( resource - > _status = = kResStatusEnqueued ) {
removeFromLRU ( resource ) ;
}
delete resource ;
_resMap . erase ( resIt ) ;
}
+ + resIt ;
}
Common : : List < ResourceSource * > : : iterator sourceIt = _sources . begin ( ) ;
while ( sourceIt ! = _sources . end ( ) ) {
ResourceSource * source = * sourceIt ;
ResSourceType sourceType = source - > getSourceType ( ) ;
if ( ( sourceType = = kSourceIntMap & & source - > _volumeNumber ! = 65535 ) | |
( sourceType = = kSourceAudioVolume & & source - > getLocationName ( ) ! = " RESOURCE.SFX " ) ) {
sourceIt = _sources . erase ( sourceIt ) ;
2011-02-10 16:48:29 +00:00
delete source ;
2011-11-02 00:17:13 +02:00
} else {
2017-01-09 17:23:29 -06:00
+ + sourceIt ;
2011-02-10 16:48:29 +00:00
}
}
2017-05-07 14:09:58 -05:00
const Common : : String audioResourceName = ( path . empty ( ) ? " " : path + " / " ) + " RESOURCE.AUD " ;
2011-02-10 16:48:29 +00:00
2012-01-15 18:25:00 +01:00
Common : : List < ResourceId > resources = listResources ( kResourceTypeMap ) ;
Common : : List < ResourceId > : : iterator it ;
for ( it = resources . begin ( ) ; it ! = resources . end ( ) ; + + it ) {
2011-02-10 16:48:29 +00:00
// Don't readd 65535.map or resource.sfx
2017-01-09 17:23:29 -06:00
if ( it - > getNumber ( ) = = 65535 )
2011-02-10 16:48:29 +00:00
continue ;
2017-05-07 14:09:58 -05:00
const Resource * mapResource = _resMap . getVal ( * it ) ;
ResourceSource * src = addSource ( new IntMapResourceSource ( mapResource - > getResourceLocation ( ) , 0 , it - > getNumber ( ) ) ) ;
2011-02-10 16:48:29 +00:00
addSource ( new AudioVolumeResourceSource ( this , audioResourceName , src , 0 ) ) ;
}
scanNewSources ( ) ;
}
2010-05-27 08:09:32 +00:00
} // End of namespace Sci