Пример #1
0
uint32 Sound::preFetchCompSpeech(uint32 speechId, uint16 **buf) {
    int cd = _vm->_resman->getCD();
    uint32 numSamples;

    SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1];

    Audio::AudioStream *input = getAudioStream(fh, "speech", cd, speechId, &numSamples);

    if (!input)
        return 0;

    *buf = NULL;

    // Decompress data into speech buffer.

    uint32 bufferSize = 2 * numSamples;

    *buf = (uint16 *)malloc(bufferSize);
    if (!*buf) {
        delete input;
        fh->file.close();
        return 0;
    }

    uint32 readSamples = input->readBuffer((int16 *)*buf, numSamples);

    fh->file.close();
    delete input;

    return 2 * readSamples;
}
Пример #2
0
void Sound::playSoundData(Audio::SoundHandle *handle, byte *soundData, uint sound, int pan, int vol, bool loop) {
	byte *buffer, flags;
	uint16 compType;
	int blockAlign, rate;

	int size = READ_LE_UINT32(soundData + 4);
	Common::MemoryReadStream stream(soundData, size);
	if (!Audio::loadWAVFromStream(stream, size, rate, flags, &compType, &blockAlign)) {
		error("playSoundData: Not a valid WAV data");
	}

	// The Feeble Files originally used DirectSound, which specifies volume
	// and panning differently than ScummVM does, using a logarithmic scale
	// rather than a linear one.
	//
	// Volume is a value between -10,000 and 0.
	// Panning is a value between -10,000 and 10,000.
	//
	// In both cases, the -10,000 represents -100 dB. When panning, only
	// one speaker's volume is affected - just like in ScummVM - with
	// negative values affecting the left speaker, and positive values
	// affecting the right speaker. Thus -10,000 means the left speaker is
	// silent.

	int v, p;

	vol = CLIP(vol, -10000, 0);
	pan = CLIP(pan, -10000, 10000);

	if (vol) {
		v = (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, (double)vol / 2000.0) + 0.5);
	} else {
		v = Audio::Mixer::kMaxChannelVolume;
	}

	if (pan < 0) {
		p = (int)(255.0 * pow(10.0, (double)pan / 2000.0) + 127.5);
	} else if (pan > 0) {
		p = (int)(255.0 * pow(10.0, (double)pan / -2000.0) - 127.5);
	} else {
		p = 0;
	}

	if (loop == true)
		flags |= Audio::Mixer::FLAG_LOOP;
	
	if (compType == 2) {
		Audio::AudioStream *sndStream = Audio::makeADPCMStream(&stream, size, Audio::kADPCMMS, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign);
		buffer = (byte *)malloc(size * 4);
		size = sndStream->readBuffer((int16*)buffer, size * 2);
		size *= 2; // 16bits.
		delete sndStream;
	} else {
		buffer = (byte *)malloc(size);
		memcpy(buffer, soundData + stream.pos(), size);
	}

	_mixer->playRaw(handle, buffer, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE, -1, v, p);
}
Пример #3
0
bool Console::cmdRawToWav(int argc, const char **argv) {
	if (argc != 3) {
		debugPrintf("Use %s <rawFilePath> <wavFileName> to dump a .RAW file to .WAV\n", argv[0]);
		return true;
	}

	Common::File file;
	if (!_engine->getSearchManager()->openFile(file, argv[1])) {
		warning("File not found: %s", argv[1]);
		return true;
	}

	Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine);

	Common::DumpFile output;
	output.open(argv[2]);

	output.writeUint32BE(MKTAG('R', 'I', 'F', 'F'));
	output.writeUint32LE(file.size() * 2 + 36);
	output.writeUint32BE(MKTAG('W', 'A', 'V', 'E'));
	output.writeUint32BE(MKTAG('f', 'm', 't', ' '));
	output.writeUint32LE(16);
	output.writeUint16LE(1);
	uint16 numChannels;
	if (audioStream->isStereo()) {
		numChannels = 2;
		output.writeUint16LE(2);
	} else {
		numChannels = 1;
		output.writeUint16LE(1);
	}
	output.writeUint32LE(audioStream->getRate());
	output.writeUint32LE(audioStream->getRate() * numChannels * 2);
	output.writeUint16LE(numChannels * 2);
	output.writeUint16LE(16);
	output.writeUint32BE(MKTAG('d', 'a', 't', 'a'));
	output.writeUint32LE(file.size() * 2);
	int16 *buffer = new int16[file.size()];
	audioStream->readBuffer(buffer, file.size());
#ifndef SCUMM_LITTLE_ENDIAN
	for (int i = 0; i < file.size(); ++i)
		buffer[i] = TO_LE_16(buffer[i]);
#endif
	output.write(buffer, file.size() * 2);

	delete[] buffer;


	return true;
}
Пример #4
0
bool LoopingAudioStream::endOfData() const {
	if (!_stream)
		return true;
	if (_loop)
		return false;
	return _stream->endOfData();
}
Пример #5
0
extern "C" int SimpleRate_readFudge(Audio::AudioStream &input, int16 *a, int b)
{
#ifdef DEBUG_RATECONV
	debug("Reading ptr=%x n%d", a, b);
#endif
	return input.readBuffer(a, b);
}
Пример #6
0
void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) {
	Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec);
	int skipFrames = timeDiff.totalNumberOfFrames();

	if (skipFrames <= 0)
		return;

	Audio::AudioStream *audioStream = getAudioStream();
	if (!audioStream)
		return;

	if (audioStream->isStereo())
		skipFrames *= 2;

	int16 *tempBuffer = new int16[skipFrames];
	audioStream->readBuffer(tempBuffer, skipFrames);
	delete[] tempBuffer;
}
Пример #7
0
extern "C" int SimpleRate_readFudge(Audio::AudioStream &input,
                                    int16 *a, int b)
{
#ifdef DEBUG_RATECONV
    fprintf(stderr, "Reading ptr=%x n%d\n", a, b);
    fflush(stderr);
#endif
    return input.readBuffer(a, b);
}
Пример #8
0
void AppendableSnd::queueBuffer(Common::SeekableReadStream *bufferIn) {
	assert (_as);

	// Setup the ADPCM decoder
	uint32 sizeIn = bufferIn->size();
	Audio::AudioStream *adpcm = makeDecoder(bufferIn, sizeIn);

	// Setup the output buffer
	uint32 sizeOut = sizeIn * 2;
	byte *bufferOut = new byte[sizeOut * 2];

	// Decode to raw samples
	sizeOut = adpcm->readBuffer((int16 *)bufferOut, sizeOut);
	assert (adpcm->endOfData());
	delete adpcm;

	// Queue the decoded samples
	_as->queueBuffer(bufferOut, sizeOut * 2);
}
Пример #9
0
int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
	if (!_loop) {
		return _stream->readBuffer(buffer, numSamples);
	}

	int16 *buf = buffer;
	int samplesLeft = numSamples;

	while (samplesLeft > 0) {
		int len = _stream->readBuffer(buf, samplesLeft);
		if (len < samplesLeft) {
			delete _stream;
			_stream = _parent->makeAudioStream(_loopSound);
		}
		samplesLeft -= len;
		buf += len;
	}

	return numSamples;
}
Пример #10
0
void convertRawToWav(const Common::String &inputFile, ZVision *engine, const Common::String &outputFile) {
	Common::File file;
	if (!file.open(inputFile))
		return;

	Audio::AudioStream *audioStream = makeRawZorkStream(inputFile, engine);

	Common::DumpFile output;
	output.open(outputFile);

	output.writeUint32BE(MKTAG('R', 'I', 'F', 'F'));
	output.writeUint32LE(file.size() * 2 + 36);
	output.writeUint32BE(MKTAG('W', 'A', 'V', 'E'));
	output.writeUint32BE(MKTAG('f', 'm', 't', ' '));
	output.writeUint32LE(16);
	output.writeUint16LE(1);
	uint16 numChannels;
	if (audioStream->isStereo()) {
		numChannels = 2;
		output.writeUint16LE(2);
	} else {
		numChannels = 1;
		output.writeUint16LE(1);
	}
	output.writeUint32LE(audioStream->getRate());
	output.writeUint32LE(audioStream->getRate() * numChannels * 2);
	output.writeUint16LE(numChannels * 2);
	output.writeUint16LE(16);
	output.writeUint32BE(MKTAG('d', 'a', 't', 'a'));
	output.writeUint32LE(file.size() * 2);
	int16 *buffer = new int16[file.size()];
	audioStream->readBuffer(buffer, file.size());
	output.write(buffer, file.size() * 2);

	delete[] buffer;
}
Пример #11
0
	AudioStreamWrapper(Audio::AudioStream *stream) {
		_stream = stream;

		int rate = _stream->getRate();

		// A file where the sample rate claims to be 11025 Hz is
		// probably compressed with the old tool. We force the real
		// sample rate, which is 11840 Hz.
		//
		// However, a file compressed with the newer tool is not
		// guaranteed to have a sample rate of 11840 Hz. LAME will
		// automatically resample it to 12000 Hz. So in all other
		// cases, we use the rate from the file.

		if (rate == 11025)
			_rate = 11840;
		else
			_rate = rate;
	}
Пример #12
0
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;
}
Пример #13
0
bool VideoDecoder::AudioTrack::endOfTrack() const {
	Audio::AudioStream *stream = getAudioStream();
	return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData();
}
Пример #14
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);
		}
	}
}
Пример #15
0
	uint getChannels() const { return _stream->getChannels(); }
Пример #16
0
	bool isStereo() const { return _stream ? _stream->isStereo() : 0; }
Пример #17
0
	int getRate() const { return _stream ? _stream->getRate() : 22050; }
Пример #18
0
	bool endOfStream() const {
		return _stream->endOfStream();
	}
Пример #19
0
	bool endOfData() const {
		return _stream->endOfData();
	}
Пример #20
0
	bool isStereo() const {
		return _stream->isStereo();
	}
Пример #21
0
	int readBuffer(int16 *buffer, const int numSamples) {
		return _stream->readBuffer(buffer, numSamples);
	}
Пример #22
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);
		}
	}
}