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; }
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; }
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; }
Audio::Timestamp VideoDecoder::SeekableAudioTrack::getDuration() const { Audio::SeekableAudioStream *stream = getSeekableAudioStream(); assert(stream); return stream->getLength(); }
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); } } }