bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) { size_t soundResourceLength; bool result = false; GameSoundType resourceType = kSoundPCM; int rate = 0, size = 0; Common::File *file; if (resourceId == (uint32)-1) { return false; } #ifdef ENABLE_IHNM //TODO: move to resource_res so we can use normal "getResourceData" and "getFile" methods if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { char soundFileName[40]; int dirIndex = resourceId / 64; if ((context->fileType() & GAME_VOICEFILE) != 0) { if (_voiceSerial == 0) { sprintf(soundFileName, "Voices/VoicesS/Voices%d/VoicesS%03x", dirIndex, resourceId); } else { sprintf(soundFileName, "Voices/Voices%d/Voices%d/Voices%d%03x", _voiceSerial, dirIndex, _voiceSerial, resourceId); } } else { sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId); } file = new Common::File(); file->open(soundFileName); soundResourceLength = file->size(); } else #endif { ResourceData* resourceData = context->getResourceData(resourceId); file = context->getFile(resourceData); file->seek(resourceData->offset); soundResourceLength = resourceData->size; } Common::SeekableReadStream &readS = *file; bool uncompressedSound = false; if (soundResourceLength >= 8) { byte header[8]; readS.read(&header, 8); readS.seek(readS.pos() - 8); if (!memcmp(header, "Creative", 8)) { resourceType = kSoundVOC; } else if (!memcmp(header, "RIFF", 4) != 0) { resourceType = kSoundWAV; } else if (!memcmp(header, "FORM", 4) != 0) { resourceType = kSoundAIFF; } else if (!memcmp(header, "ajkg", 4) != 0) { resourceType = kSoundShorten; } // If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed // Patch data for this resource is in file p2_a.iaf or p2_a.voc if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->getResourceData(resourceId)->patchData != NULL) uncompressedSound = true; // FIXME: Currently, the SFX.RES file in IHNM cannot be compressed if (_vm->getGameId() == GID_IHNM && (context->fileType() & GAME_SOUNDFILE)) uncompressedSound = true; if (context->isCompressed() && !uncompressedSound) { if (header[0] == char(0)) { resourceType = kSoundMP3; } else if (header[0] == char(1)) { resourceType = kSoundOGG; } else if (header[0] == char(2)) { resourceType = kSoundFLAC; } } } // Default sound type is 16-bit signed PCM, used in ITE byte rawFlags = Audio::FLAG_16BITS; if (_vm->getGameId() == GID_ITE) { if (context->fileType() & GAME_MACBINARY) { // ITE Mac has sound in the Mac snd format resourceType = kSoundMacSND; } else if (_vm->getFeatures() & GF_8BIT_UNSIGNED_PCM) { // older ITE demos rawFlags |= Audio::FLAG_UNSIGNED; rawFlags &= ~Audio::FLAG_16BITS; } else if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) { // Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded. resourceType = kSoundVOX; } } buffer.stream = 0; // Check for LE sounds if (!context->isBigEndian()) rawFlags |= Audio::FLAG_LITTLE_ENDIAN; switch (resourceType) { case kSoundPCM: { // In ITE CD German, some voices are absent and contain just 5 zero bytes. // Round down to an even number when the audio is 16-bit so makeRawStream // will accept the data (needs to be an even size for 16-bit data). // See bug #1256701 if ((soundResourceLength & 1) && (rawFlags & Audio::FLAG_16BITS)) soundResourceLength &= ~1; Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(soundResourceLength), 22050, rawFlags); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundVOX: buffer.stream = Audio::makeADPCMStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES, soundResourceLength, Audio::kADPCMOki, 22050, 1); buffer.streamLength = Audio::Timestamp(0, soundResourceLength * 2, buffer.stream->getRate()); result = true; break; case kSoundMacSND: { Audio::SeekableAudioStream *audStream = Audio::makeMacSndStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundAIFF: { Audio::SeekableAudioStream *audStream = Audio::makeAIFFStream(READ_STREAM(soundResourceLength), DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundVOC: { Audio::SeekableAudioStream *audStream = Audio::makeVOCStream(READ_STREAM(soundResourceLength), Audio::FLAG_UNSIGNED, DisposeAfterUse::YES); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } break; case kSoundWAV: case kSoundShorten: if (resourceType == kSoundWAV) { result = Audio::loadWAVFromStream(readS, size, rate, rawFlags); #ifdef ENABLE_SAGA2 } else if (resourceType == kSoundShorten) { result = loadShortenFromStream(readS, size, rate, rawFlags); #endif } if (result) { Audio::SeekableAudioStream *audStream = Audio::makeRawStream(READ_STREAM(size), rate, rawFlags); buffer.stream = audStream; buffer.streamLength = audStream->getLength(); } break; case kSoundMP3: case kSoundOGG: case kSoundFLAC: { readS.skip(9); // skip sfx header Audio::SeekableAudioStream *audStream = 0; Common::SeekableReadStream *memStream = READ_STREAM(soundResourceLength - 9); if (resourceType == kSoundMP3) { #ifdef USE_MAD audStream = Audio::makeMP3Stream(memStream, DisposeAfterUse::YES); #endif } else if (resourceType == kSoundOGG) { #ifdef USE_VORBIS audStream = Audio::makeVorbisStream(memStream, DisposeAfterUse::YES); #endif } else /* if (resourceType == kSoundFLAC) */ { #ifdef USE_FLAC audStream = Audio::makeFLACStream(memStream, DisposeAfterUse::YES); #endif } if (audStream) { buffer.stream = audStream; buffer.streamLength = audStream->getLength(); result = true; } else { delete memStream; } } break; default: error("SndRes::load Unknown sound type"); } if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { delete file; } if (onlyHeader) { delete buffer.stream; buffer.stream = 0; } return result; }
bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buffer, bool onlyHeader) { Audio::AudioStream *voxStream; size_t soundResourceLength; bool result = false; GameSoundTypes resourceType = kSoundPCM; byte *data = 0; int rate = 0, size = 0; Common::File* file; if (resourceId == (uint32)-1) { return false; } #ifdef ENABLE_IHNM //TODO: move to resource_res so we can use normal "getResourceData" and "getFile" methods if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { char soundFileName[40]; int dirIndex = resourceId / 64; if ((context->fileType() & GAME_VOICEFILE) != 0) { if (_voiceSerial == 0) { sprintf(soundFileName, "Voices/VoicesS/Voices%d/VoicesS%03x", dirIndex, resourceId); } else { sprintf(soundFileName, "Voices/Voices%d/Voices%d/Voices%d%03x", _voiceSerial, dirIndex, _voiceSerial, resourceId); } } else { sprintf(soundFileName, "SFX/SFX%d/SFX%03x", dirIndex, resourceId); } file = new Common::File(); file->open(soundFileName); soundResourceLength = file->size(); } else #endif { ResourceData* resourceData = context->getResourceData(resourceId); file = context->getFile(resourceData); file->seek(resourceData->offset); soundResourceLength = resourceData->size; } Common::SeekableReadStream& readS = *file; bool uncompressedSound = false; if (soundResourceLength >= 8) { byte header[8]; readS.read(&header, 8); readS.seek(readS.pos() - 8); if (!memcmp(header, "Creative", 8)) { resourceType = kSoundVOC; } else if (!memcmp(header, "RIFF", 4) != 0) { resourceType = kSoundWAV; } else if (!memcmp(header, "FORM", 4) != 0) { resourceType = kSoundAIFF; } else if (!memcmp(header, "ajkg", 4) != 0) { resourceType = kSoundShorten; } // If patch data exists for sound resource 4 (used in ITE intro), don't treat this sound as compressed // Patch data for this resource is in file p2_a.iaf or p2_a.voc if (_vm->getGameId() == GID_ITE && resourceId == 4 && context->getResourceData(resourceId)->patchData != NULL) uncompressedSound = true; // FIXME: Currently, the SFX.RES file in IHNM cannot be compressed if (_vm->getGameId() == GID_IHNM && (context->fileType() & GAME_SOUNDFILE)) uncompressedSound = true; if (context->isCompressed() && !uncompressedSound) { if (header[0] == char(0)) { resourceType = kSoundMP3; } else if (header[0] == char(1)) { resourceType = kSoundOGG; } else if (header[0] == char(2)) { resourceType = kSoundFLAC; } } } // Default sound type is 16-bit signed PCM, used in ITE by PCM and VOX files buffer.isCompressed = context->isCompressed(); buffer.soundType = resourceType; buffer.originalSize = 0; // Set default flags and frequency for PCM, VOC and VOX files, which got no header buffer.flags = Audio::FLAG_16BITS; buffer.frequency = 22050; if (_vm->getGameId() == GID_ITE) { if (_vm->getFeatures() & GF_8BIT_UNSIGNED_PCM) { // older ITE demos buffer.flags |= Audio::FLAG_UNSIGNED; buffer.flags &= ~Audio::FLAG_16BITS; } else { // Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded if (!uncompressedSound && !scumm_stricmp(context->fileName(), "voicesd.rsc")) resourceType = kSoundVOX; } } buffer.buffer = NULL; // Check for LE sounds if (!context->isBigEndian()) buffer.flags |= Audio::FLAG_LITTLE_ENDIAN; if ((context->fileType() & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES)) buffer.flags |= Audio::FLAG_LITTLE_ENDIAN; // Older Mac versions of ITE were Macbinary packed int soundOffset = (context->fileType() & GAME_MACBINARY) ? 36 : 0; switch (resourceType) { case kSoundPCM: buffer.size = soundResourceLength - soundOffset; if (!onlyHeader) { buffer.buffer = (byte *) malloc(buffer.size); if (soundOffset > 0) readS.skip(soundOffset); readS.read(buffer.buffer, buffer.size); } result = true; break; case kSoundVOX: buffer.size = soundResourceLength * 4; if (!onlyHeader) { voxStream = Audio::makeADPCMStream(&readS, DisposeAfterUse::NO, soundResourceLength, Audio::kADPCMOki); buffer.buffer = (byte *)malloc(buffer.size); voxStream->readBuffer((int16*)buffer.buffer, soundResourceLength * 2); delete voxStream; } result = true; break; case kSoundWAV: case kSoundAIFF: case kSoundShorten: case kSoundVOC: if (resourceType == kSoundWAV) { result = Audio::loadWAVFromStream(readS, size, rate, buffer.flags); } else if (resourceType == kSoundAIFF) { result = Audio::loadAIFFFromStream(readS, size, rate, buffer.flags); #ifdef ENABLE_SAGA2 } else if (resourceType == kSoundShorten) { result = loadShortenFromStream(readS, size, rate, buffer.flags); #endif } else if (resourceType == kSoundVOC) { data = Audio::loadVOCFromStream(readS, size, rate); result = (data != NULL); if (onlyHeader) free(data); buffer.flags |= Audio::FLAG_UNSIGNED; buffer.flags &= ~Audio::FLAG_16BITS; buffer.flags &= ~Audio::FLAG_STEREO; } if (result) { buffer.frequency = rate; buffer.size = size; if (!onlyHeader) { if (resourceType == kSoundVOC) { buffer.buffer = data; } else { buffer.buffer = (byte *)malloc(size); readS.read(buffer.buffer, size); } } } break; case kSoundMP3: case kSoundOGG: case kSoundFLAC: ResourceData *resourceData; resourceData = context->getResourceData(resourceId); // Read compressed sfx header readS.readByte(); // Skip compression identifier byte buffer.frequency = readS.readUint16LE(); buffer.originalSize = readS.readUint32LE(); if (readS.readByte() == 8) // read sample bits buffer.flags &= ~Audio::FLAG_16BITS; if (readS.readByte() != 0) // read stereo flag buffer.flags |= Audio::FLAG_STEREO; buffer.size = soundResourceLength; buffer.soundType = resourceType; buffer.fileOffset = resourceData->offset + 9; // skip compressed sfx header: byte + uint16 + uint32 + byte + byte if (!onlyHeader) { buffer.buffer = (byte *)malloc(buffer.size); readS.read(buffer.buffer, buffer.size); } result = true; break; default: error("SndRes::load Unknown sound type"); } if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) { delete file; } // In ITE CD De some voices are absent and contain just 5 bytes header // Round it to even number so soundmanager will not crash. // See bug #1256701 buffer.size &= ~(0x1); return result; }