示例#1
0
void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) {
	Audio::RewindableAudioStream *stream = 0;
	byte *ptr, *spoolPtr;
	int size = -1;
	int priority, rate;
	byte flags = Audio::FLAG_UNSIGNED;

	Audio::Mixer::SoundType type = Audio::Mixer::kSFXSoundType;
	if (soundID > _vm->_numSounds)
		type = Audio::Mixer::kMusicSoundType;
	else if (soundID == 1)
		type = Audio::Mixer::kSpeechSoundType;


	if (heChannel == -1)
		heChannel = (_vm->VAR_RESERVED_SOUND_CHANNELS != 0xFF) ? findFreeSoundChannel() : 1;

	debug(5,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags);

	if (soundID >= 10000) {
		// Special codes, used in pjgames
		return;
	}

	if (soundID > _vm->_numSounds) {
		int music_offs;
		Common::File musicFile;
		Common::String buf(_vm->generateFilename(-4));

		if (musicFile.open(buf) == false) {
			warning("playHESound: Can't open music file %s", buf.c_str());
			return;
		}
		if (!getHEMusicDetails(soundID, music_offs, size)) {
			debug(0, "playHESound: musicID %d not found", soundID);
			return;
		}

		musicFile.seek(music_offs, SEEK_SET);

		_mixer->stopHandle(_heSoundChannels[heChannel]);
		spoolPtr = _vm->_res->createResource(rtSpoolBuffer, heChannel, size);
		assert(spoolPtr);
		musicFile.read(spoolPtr, size);
		musicFile.close();

		if (_vm->_game.heversion == 70) {
			stream = Audio::makeRawStream(spoolPtr, size, 11025, flags, DisposeAfterUse::NO);
			_mixer->playStream(type, &_heSoundChannels[heChannel], stream, soundID);
			return;
		}
	}

	if (soundID > _vm->_numSounds) {
		ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel);
	} else {
		ptr = _vm->getResourceAddress(rtSound, soundID);
	}

	if (!ptr) {
		return;
	}

	// Support for sound in later HE games
	if (READ_BE_UINT32(ptr) == MKTAG('R','I','F','F') || READ_BE_UINT32(ptr) == MKTAG('W','S','O','U')) {
		uint16 compType;
		int blockAlign;
		int codeOffs = -1;

		priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);

		byte *sbngPtr = findSoundTag(MKTAG('S','B','N','G'), ptr);
		if (sbngPtr != NULL) {
			codeOffs = sbngPtr - ptr + 8;
		}

		if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
			int curSnd = _heChannel[heChannel].sound;
			if (curSnd == 1 && soundID != 1)
				return;
			if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
				return;
		}

		if (READ_BE_UINT32(ptr) == MKTAG('W','S','O','U'))
			ptr += 8;

		size = READ_LE_UINT32(ptr + 4);
		Common::MemoryReadStream memStream(ptr, size);

		if (!Audio::loadWAVFromStream(memStream, size, rate, flags, &compType, &blockAlign)) {
			error("playHESound: Not a valid WAV file (%d)", soundID);
		}

		assert(heOffset >= 0 && heOffset < size);

		// FIXME: Disabled sound offsets, due to asserts been triggered
		heOffset = 0;

		_vm->setHETimer(heChannel + 4);
		_heChannel[heChannel].sound = soundID;
		_heChannel[heChannel].priority = priority;
		_heChannel[heChannel].rate = rate;
		_heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
		_heChannel[heChannel].codeOffs = codeOffs;
		memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));

		// TODO: Extra sound flags
		if (heFlags & 1) {
			_heChannel[heChannel].timer = 0;
		} else {
			_heChannel[heChannel].timer = size * 1000 / rate;
		}

		_mixer->stopHandle(_heSoundChannels[heChannel]);
		if (compType == 17) {
			Audio::AudioStream *voxStream = Audio::makeADPCMStream(&memStream, DisposeAfterUse::NO, size, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign);

			// FIXME: Get rid of this crude hack to turn a ADPCM stream into a raw stream.
			// It seems it is only there to allow looping -- if that is true, we certainly
			// can do without it, using a LoopingAudioStream.

			byte *sound = (byte *)malloc(size * 4);
			/* On systems where it matters, malloc will return
			 * even addresses, so the use of (void *) in the
			 * following cast shuts the compiler from warning
			 * unnecessarily. */
			size = voxStream->readBuffer((int16*)(void *)sound, size * 2);
			size *= 2; // 16bits.
			delete voxStream;

			_heChannel[heChannel].rate = rate;
			if (_heChannel[heChannel].timer)
				_heChannel[heChannel].timer = size * 1000 / rate;

			// makeADPCMStream returns a stream in native endianness, but RawMemoryStream
			// defaults to big endian. If we're on a little endian system, set the LE flag.
#ifdef SCUMM_LITTLE_ENDIAN
			flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
			stream = Audio::makeRawStream(sound + heOffset, size - heOffset, rate, flags);
		} else {
			stream = Audio::makeRawStream(ptr + memStream.pos() + heOffset, size - heOffset, rate, flags, DisposeAfterUse::NO);
		}
		_mixer->playStream(type, &_heSoundChannels[heChannel],
						Audio::makeLoopingAudioStream(stream, (heFlags & 1) ? 0 : 1), soundID);
	}
	// Support for sound in Humongous Entertainment games
	else if (READ_BE_UINT32(ptr) == MKTAG('D','I','G','I') || READ_BE_UINT32(ptr) == MKTAG('T','A','L','K')) {
		byte *sndPtr = ptr;
		int codeOffs = -1;

		priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);
		rate = READ_LE_UINT16(ptr + 22);

		// Skip DIGI/TALK (8) and HSHD (24) blocks
		ptr += 32;

		if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
			int curSnd = _heChannel[heChannel].sound;
			if (curSnd == 1 && soundID != 1)
				return;
			if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
				return;
		}

		if (READ_BE_UINT32(ptr) == MKTAG('S','B','N','G')) {
			codeOffs = ptr - sndPtr + 8;
			ptr += READ_BE_UINT32(ptr + 4);
		}

		assert(READ_BE_UINT32(ptr) == MKTAG('S','D','A','T'));
		size = READ_BE_UINT32(ptr + 4) - 8;
		if (heOffset < 0 || heOffset > size) {
			// Occurs when making fireworks in puttmoon
			heOffset = 0;
		}
		size -= heOffset;

		if (_overrideFreq) {
			// Used by the piano in Fatty Bear's Birthday Surprise
			rate = _overrideFreq;
			_overrideFreq = 0;
		}

		_vm->setHETimer(heChannel + 4);
		_heChannel[heChannel].sound = soundID;
		_heChannel[heChannel].priority = priority;
		_heChannel[heChannel].rate = rate;
		_heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
		_heChannel[heChannel].codeOffs = codeOffs;
		memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));

		// TODO: Extra sound flags
		if (heFlags & 1) {
			_heChannel[heChannel].timer = 0;
		} else {
			_heChannel[heChannel].timer = size * 1000 / rate;
		}

		_mixer->stopHandle(_heSoundChannels[heChannel]);

		stream = Audio::makeRawStream(ptr + heOffset + 8, size, rate, flags, DisposeAfterUse::NO);
		_mixer->playStream(type, &_heSoundChannels[heChannel],
						Audio::makeLoopingAudioStream(stream, (heFlags & 1) ? 0 : 1), soundID);
	}
	// Support for PCM music in 3DO versions of Humongous Entertainment games
	else if (READ_BE_UINT32(ptr) == MKTAG('M','R','A','W')) {
		priority = *(ptr + 18);
		rate = READ_LE_UINT16(ptr + 22);

		// Skip DIGI (8) and HSHD (24) blocks
		ptr += 32;

		assert(READ_BE_UINT32(ptr) == MKTAG('S','D','A','T'));
		size = READ_BE_UINT32(ptr + 4) - 8;

		byte *sound = (byte *)malloc(size);
		memcpy(sound, ptr + 8, size);

		_mixer->stopID(_currentMusic);
		_currentMusic = soundID;

		stream = Audio::makeRawStream(sound, size, rate, 0);
		_mixer->playStream(Audio::Mixer::kMusicSoundType, NULL, stream, soundID);
	}
	else if (READ_BE_UINT32(ptr) == MKTAG('M','I','D','I')) {
		if (_vm->_imuse) {
			// This is used in the DOS version of Fatty Bear's
			// Birthday Surprise to change the note on the piano
			// when not using a digitized instrument.
			_vm->_imuse->stopSound(_currentMusic);
			_currentMusic = soundID;
			_vm->_imuse->startSoundWithNoteOffset(soundID, heOffset);
		}
	}
}
示例#2
0
void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) {
	byte *ptr, *spoolPtr;
	int size = -1;
	int priority, rate;
	byte flags = Audio::Mixer::FLAG_UNSIGNED;

	Audio::Mixer::SoundType type = Audio::Mixer::kSFXSoundType;
	if (soundID > _vm->_numSounds)
		type = Audio::Mixer::kMusicSoundType;
	else if (soundID == 1)
		type = Audio::Mixer::kSpeechSoundType;


	if (heChannel == -1)
		heChannel = (_vm->VAR_RESERVED_SOUND_CHANNELS != 0xFF) ? findFreeSoundChannel() : 1;

	debug(5,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags);

	if (soundID >= 10000) {
		// Special codes, used in pjgames
		return;
	}

	if (soundID > _vm->_numSounds) {
		int music_offs;
		Common::File musicFile;
		Common::String buf(_vm->generateFilename(-4));

		if (musicFile.open(buf) == false) {
			warning("playHESound: Can't open music file %s", buf.c_str());
			return;
		}
		if (!getHEMusicDetails(soundID, music_offs, size)) {
			debug(0, "playHESound: musicID %d not found", soundID);
			return;
		}

		musicFile.seek(music_offs, SEEK_SET);

		_mixer->stopHandle(_heSoundChannels[heChannel]);
		spoolPtr = _vm->_res->createResource(rtSpoolBuffer, heChannel, size);
		assert(spoolPtr);
		musicFile.read(spoolPtr, size);
		musicFile.close();

		if (_vm->_game.heversion == 70) {
			_mixer->playRaw(type, &_heSoundChannels[heChannel], spoolPtr, size, 11025, flags, soundID);
			return;
		}
	}

	if (soundID > _vm->_numSounds) {
		ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel);
	} else {
		ptr = _vm->getResourceAddress(rtSound, soundID);
	}

	if (!ptr) {
		return;
	}

	// Support for sound in later HE games
	if (READ_BE_UINT32(ptr) == MKID_BE('RIFF') || READ_BE_UINT32(ptr) == MKID_BE('WSOU')) {
		uint16 compType;
		int blockAlign;
		char *sound;
		int codeOffs = -1;

		priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);

		byte *sbngPtr = findSoundTag(MKID_BE('SBNG'), ptr);
		if (sbngPtr != NULL) {
			codeOffs = sbngPtr - ptr + 8;
		}

		if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
			int curSnd = _heChannel[heChannel].sound;
			if (curSnd == 1 && soundID != 1)
				return;
			if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
				return;
		}

		if (READ_BE_UINT32(ptr) == MKID_BE('WSOU'))
			ptr += 8;

		size = READ_LE_UINT32(ptr + 4);
		Common::MemoryReadStream stream(ptr, size);

		if (!Audio::loadWAVFromStream(stream, size, rate, flags, &compType, &blockAlign)) {
			error("playHESound: Not a valid WAV file (%d)", soundID);
		}

		assert(heOffset >= 0 && heOffset < size);

		// FIXME: Disabled sound offsets, due to asserts been triggered
		heOffset = 0;

		_vm->setHETimer(heChannel + 4);
		_heChannel[heChannel].sound = soundID;
		_heChannel[heChannel].priority = priority;
		_heChannel[heChannel].rate = rate;
		_heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
		_heChannel[heChannel].codeOffs = codeOffs;
		memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));

		// TODO: Extra sound flags
		if (heFlags & 1) {
			flags |= Audio::Mixer::FLAG_LOOP;
			_heChannel[heChannel].timer = 0;
		} else {
			_heChannel[heChannel].timer = size * 1000 / rate;
		}

		_mixer->stopHandle(_heSoundChannels[heChannel]);
		if (compType == 17) {
			Audio::AudioStream *voxStream = Audio::makeADPCMStream(&stream, false, size, Audio::kADPCMMSIma, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign);

			sound = (char *)malloc(size * 4);
			size = voxStream->readBuffer((int16*)sound, size * 2);
			size *= 2; // 16bits.
			delete voxStream;

			_heChannel[heChannel].rate = rate;
			if (_heChannel[heChannel].timer)
				_heChannel[heChannel].timer = size * 1000 / rate;

			flags |= Audio::Mixer::FLAG_AUTOFREE;
			_mixer->playRaw(type, &_heSoundChannels[heChannel], sound + heOffset, size - heOffset, rate, flags, soundID);
		} else {
			_mixer->playRaw(type, &_heSoundChannels[heChannel], ptr + stream.pos() + heOffset, size - heOffset, rate, flags, soundID);
		}
	}
	// Support for sound in Humongous Entertainment games
	else if (READ_BE_UINT32(ptr) == MKID_BE('DIGI') || READ_BE_UINT32(ptr) == MKID_BE('TALK')) {
		byte *sndPtr = ptr;
		int codeOffs = -1;

		priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);
		rate = READ_LE_UINT16(ptr + 22);

		// Skip DIGI/TALK (8) and HSHD (24) blocks
		ptr += 32;

		if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
			int curSnd = _heChannel[heChannel].sound;
			if (curSnd == 1 && soundID != 1)
				return;
			if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
				return;
		}

		if (READ_BE_UINT32(ptr) == MKID_BE('SBNG')) {
			codeOffs = ptr - sndPtr + 8;
			ptr += READ_BE_UINT32(ptr + 4);
		}

		assert(READ_BE_UINT32(ptr) == MKID_BE('SDAT'));
		size = READ_BE_UINT32(ptr + 4) - 8;
		if (heOffset < 0 || heOffset > size) {
			// Occurs when making fireworks in puttmoon
			heOffset = 0;
		}
		size -= heOffset;

		if (_overrideFreq) {
			// Used by the piano in Fatty Bear's Birthday Surprise
			rate = _overrideFreq;
			_overrideFreq = 0;
		}

		_vm->setHETimer(heChannel + 4);
		_heChannel[heChannel].sound = soundID;
		_heChannel[heChannel].priority = priority;
		_heChannel[heChannel].rate = rate;
		_heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
		_heChannel[heChannel].codeOffs = codeOffs;
		memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));

		// TODO: Extra sound flags
		if (heFlags & 1) {
			flags |= Audio::Mixer::FLAG_LOOP;
			_heChannel[heChannel].timer = 0;
		} else {
			_heChannel[heChannel].timer = size * 1000 / rate;
		}

		_mixer->stopHandle(_heSoundChannels[heChannel]);
		_mixer->playRaw(type, &_heSoundChannels[heChannel], ptr + heOffset + 8, size, rate, flags, soundID);
	}
	// Support for PCM music in 3DO versions of Humongous Entertainment games
	else if (READ_BE_UINT32(ptr) == MKID_BE('MRAW')) {
		priority = *(ptr + 18);
		rate = READ_LE_UINT16(ptr + 22);

		// Skip DIGI (8) and HSHD (24) blocks
		ptr += 32;

		assert(READ_BE_UINT32(ptr) == MKID_BE('SDAT'));
		size = READ_BE_UINT32(ptr + 4) - 8;

		flags = Audio::Mixer::FLAG_AUTOFREE;
		byte *sound = (byte *)malloc(size);
		memcpy(sound, ptr + 8, size);

		_mixer->stopID(_currentMusic);
		_currentMusic = soundID;
		_mixer->playRaw(Audio::Mixer::kMusicSoundType, NULL, sound, size, rate, flags, soundID);
	}
	else if (READ_BE_UINT32(ptr) == MKID_BE('MIDI')) {
		if (_vm->_imuse) {
			_vm->_imuse->stopSound(_currentMusic);
			_currentMusic = soundID;
			_vm->_imuse->startSound(soundID);
		}
	}
}