Beispiel #1
0
uint Sound::playSoundBuffer(Audio::SoundHandle *handle, const SoundSample &buffer, int volume,
				sndHandleType handleType, bool loop) {
	if (!buffer._stream && !buffer._data) {
		warning("Empty stream");
		return 0;
	}
	// Create a new SeekableReadStream which will be automatically disposed
	// after the sample stops playing.  Do not dispose the original
	// data/stream though.
	// Beware that if the sample comes from an archive (i.e., is stored in
	// buffer._stream), then you must NOT play it more than once at the
	// same time, because streams are not thread-safe.  Playing it
	// repeatedly is OK.  Currently this is ensured by that archives are
	// only used for dubbing, which is only played from one place in
	// script.cpp, which blocks until the dubbed sentence has finished
	// playing.
	Common::SeekableReadStream *stream;
	const int skip = buffer._format == RAW80 ? 80 : 0;
	if (buffer._stream) {
		stream = new Common::SeekableSubReadStream(
			buffer._stream, skip, buffer._stream->size() /* end */, DisposeAfterUse::NO);
	} else {
		stream = new Common::MemoryReadStream(
			buffer._data + skip, buffer._length - skip /* length */, DisposeAfterUse::NO);
	}

	Audio::SeekableAudioStream *reader = NULL;
	switch (buffer._format) {
	case RAW:
	case RAW80:
		reader = Audio::makeRawStream(stream, buffer._frequency, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
		break;
#ifdef USE_MAD
	case MP3:
		reader = Audio::makeMP3Stream(stream, DisposeAfterUse::YES);
		break;
#endif
#ifdef USE_VORBIS
	case OGG:
		reader = Audio::makeVorbisStream(stream, DisposeAfterUse::YES);
		break;
#endif
#ifdef USE_FLAC
	case FLAC:
		reader = Audio::makeFLACStream(stream, DisposeAfterUse::YES);
		break;
#endif
	default:
		error("Unsupported compression format %d", static_cast<int> (buffer._format));
		delete stream;
		return 0;
	}

	const uint length = reader->getLength().msecs();
	const Audio::Mixer::SoundType soundType = (handleType == kVoiceHandle) ?
				Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType;
	Audio::AudioStream *audio_stream = Audio::makeLoopingAudioStream(reader, loop ? 0 : 1);
	_mixer->playStream(soundType, handle, audio_stream, -1, volume);
	return length;
}
Beispiel #2
0
int32 Sound::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) {
	Audio::SeekableAudioStream *audioStream = getVoiceStream(file);

	if (!audioStream) {
		return 0;
	}

	int playTime = audioStream->getLength().msecs();
	playVoiceStream(audioStream, handle, volume, isSfx);
	return playTime;
}
Beispiel #3
0
bool Win32AudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate,
		Audio::Mixer::SoundType soundType) {
	// Prefer emulation
	if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate, soundType))
		return true;

	// If we're set to only emulate, or have no CD drive, return here
	if (onlyEmulate || _driveHandle == INVALID_HANDLE_VALUE)
		return false;

	// HACK: For now, just assume that track number is right
	// That only works because ScummVM uses the wrong track number anyway

	if (track >= (int)_tocEntries.size() - 1) {
		warning("No such track %d", track);
		return false;
	}

	// Bail if the track isn't an audio track
	if ((_tocEntries[track].Control & 0x04) != 0) {
		warning("Track %d is not audio", track);
		return false;
	}

	// Create the AudioStream and play it
	debug(1, "Playing CD track %d", track);

	Audio::SeekableAudioStream *audioStream = new Win32AudioCDStream(_driveHandle, _tocEntries[track], _tocEntries[track + 1]);

	Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
	Audio::Timestamp end = (duration == 0) ? audioStream->getLength() : Audio::Timestamp(0, startFrame + duration, 75);

	// Fake emulation since we're really playing an AudioStream
	_emulating = true;

	_mixer->playStream(
	    soundType,
	    &_handle,
	    Audio::makeLoopingAudioStream(audioStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops),
	    -1,
	    _cd.volume,
	    _cd.balance,
	    DisposeAfterUse::YES,
	    true);
	return true;
}
Beispiel #4
0
Audio::Timestamp VideoDecoder::SeekableAudioTrack::getDuration() const {
	Audio::SeekableAudioStream *stream = getSeekableAudioStream();
	assert(stream);
	return stream->getLength();
}
Beispiel #5
0
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;
}
void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool only_emulate) {
	if (numLoops != 0 || startFrame != 0) {
		_cd.track = track;
		_cd.numLoops = numLoops;
		_cd.start = startFrame;
		_cd.duration = duration;

		// Try to load the track from a compressed data file, and if found, use
		// that. If not found, attempt to start regular Audio CD playback of
		// the requested track.
		char trackName[2][16];
		sprintf(trackName[0], "track%d", track);
		sprintf(trackName[1], "track%02d", track);
		Audio::SeekableAudioStream *stream = 0;

		for (int i = 0; !stream && i < 2; ++i)
			stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]);

		// Stop any currently playing emulated track
		_mixer->stopHandle(_handle);

		if (stream != 0) {
			Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
			Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : stream->getLength();

			/*
			FIXME: Seems numLoops == 0 and numLoops == 1 both indicate a single repetition,
			while all other positive numbers indicate precisely the number of desired
			repetitions. Finally, -1 means infinitely many
			*/
			_emulating = true;
			_mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
			                        Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
		} else {
			_emulating = false;
			if (!only_emulate)
				playCD(track, numLoops, startFrame, duration);
		}
	}
}