public bool StartSpeech(ushort roomNo, ushort localNo) { if (_cowHeader == null || ServiceLocator.AudioManager == null) { // TODO: warning("Sound::startSpeech: COW file isn't open"); return false; } uint locIndex = 0xFFFFFFFF; int sampleSize = 0; uint index = 0; // if (_cowMode == CowPSX) // { // Common::File file; // uint16 i; // if (!file.open("speech.lis")) // { // warning("Could not open speech.lis"); // return false; // } // for (i = 0; !file.eos() && !file.err(); i++) // if (file.readUint16LE() == roomNo) // { // locIndex = i; // break; // } // file.close(); // if (locIndex == 0xFFFFFFFF) // { // warning("Could not find room %d in speech.lis", roomNo); // return false; // } // if (!file.open("speech.inf")) // { // warning("Could not open speech.inf"); // return false; // } // uint16 numRooms = file.readUint16LE(); // Read number of rooms referenced in this file // file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes // uint16 numLines = file.readUint16LE(); // uint16 roomOffset = file.readUint16LE(); // file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the room indexes too. // locIndex = 0xFFFFFFFF; // for (i = 0; i < numLines; i++) // if (file.readUint16LE() == localNo) // { // locIndex = i; // break; // } // if (locIndex == 0xFFFFFFFF) // { // warning("Could not find local number %d in room %d in speech.inf", roomNo, localNo); // return false; // } // file.close(); // index = _cowHeader[(roomOffset + locIndex) * 2]; // sampleSize = _cowHeader[(roomOffset + locIndex) * 2 + 1]; // } // else { locIndex = _cowHeader[roomNo] >> 2; sampleSize = (int)_cowHeader[(int)(locIndex + (localNo * 2))]; index = _cowHeader[(int)(locIndex + (localNo * 2) - 1)]; // } // debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index); IAudioStream stream = null; if (sampleSize != 0) { byte speechVol = (byte)((_speechVolR + _speechVolL) / 2); sbyte speechPan = (sbyte)((_speechVolR - _speechVolL) / 2); if ((_cowMode == CowMode.CowWave) || (_cowMode == CowMode.CowDemo)) { uint size; var data = UncompressSpeech(index + _cowHeaderSize, (uint)sampleSize, out size); if (data != null) { stream = new RawStream(SPEECH_FLAGS, 11025, true, new MemoryStream(data.Data, data.Offset, (int)size)); _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan); } } // else if (_cowMode == CowPSX && sampleSize != 0xffffffff) // { // _cowFile.seek(index * 2048); // Common::SeekableReadStream* tmp = _cowFile.readStream(sampleSize); // assert(tmp); // stream = Audio::makeXAStream(tmp, 11025); // _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream, SOUND_SPEECH_ID, speechVol, speechPan); // // with compressed audio, we can't calculate the wave volume. // // so default to talking. // for (int cnt = 0; cnt < 480; cnt++) // _waveVolume[cnt] = true; // _waveVolPos = 0; // } else if (_cowMode == CowMode.CowFLAC) { _cowFile.BaseStream.Seek(index, SeekOrigin.Begin); var tmp = _cowFile.ReadBytes(sampleSize); stream = ServiceLocator.AudioManager.MakeFlacStream(new MemoryStream(tmp)); if (stream != null) { _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } } else if (_cowMode == CowMode.CowVorbis) { _cowFile.BaseStream.Seek(index, SeekOrigin.Begin); var tmp = _cowFile.ReadBytes(sampleSize); stream = ServiceLocator.AudioManager.MakeVorbisStream(new MemoryStream(tmp)); if (stream != null) { _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } } else if (_cowMode == CowMode.CowMP3) { _cowFile.BaseStream.Seek(index, SeekOrigin.Begin); var tmp = _cowFile.ReadBytes(sampleSize); stream = ServiceLocator.AudioManager.MakeMp3Stream(new MemoryStream(tmp)); if (stream != null) { _speechHandle = _mixer.PlayStream(SoundType.Speech, stream, SOUND_SPEECH_ID, speechVol, speechPan); // with compressed audio, we can't calculate the wave volume. // so default to talking. for (int cnt = 0; cnt < 480; cnt++) _waveVolume[cnt] = true; _waveVolPos = 0; } } return true; } else return false; }
public void StartChannel(int id, byte[] data, int size, int rate, int vol, int loopStart = 0, int loopEnd = 0, int pan = 0) { int i; if (id == 0) { Debug.WriteLine("player_mod - attempted to start channel id 0"); } for (i = 0; i < MOD_MAXCHANS; i++) { if (_channels[i].id == 0) break; } if (i == MOD_MAXCHANS) { Debug.WriteLine("player_mod - too many music channels playing ({0} max)", MOD_MAXCHANS); return; } _channels[i].id = id; _channels[i].vol = (byte)vol; _channels[i].pan = (sbyte)pan; _channels[i].freq = (ushort)rate; _channels[i].ctr = 0; var stream = new RawStream(AudioFlags.None, rate, true, new MemoryStream(data)); if (loopStart != loopEnd) { _channels[i].input = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopStart, rate), new Timestamp(0, loopEnd, rate)); } else { _channels[i].input = stream; } // read the first sample var sample = new short[1]; _channels[i].input.ReadBuffer(sample,1); _channels[i].pos = sample[0]; }
public void QueueBuffer(byte[] data, int size, bool disposeAfterUse, AudioFlags flags) { var stream = new RawStream(flags, Rate, disposeAfterUse, new MemoryStream(data, 0, size)); QueueAudioStream(stream, true); }
private bool NextPart(ushort[] data, ref int i) { // return false means cancel intro var command = data[i++]; switch (command) { case SHOWSCREEN: _skyScreen.ShowScreen(data[i++]); return true; case FADEUP: _skyScreen.PaletteFadeUp(data[i++]); _relDelay += 32 * 20; // hack: the screen uses a seperate delay function for the // blocking fadeups. So add 32*20 msecs to out delay counter. return true; case FADEDOWN: _skyScreen.FnFadeDown(0); _relDelay += 32 * 20; // hack: see above. return true; case DELAY: if (!EscDelay(data[i++])) return false; return true; case DOFLIRT: _skyScreen.StartSequence(data[i++]); while (_skyScreen.SequenceRunning()) if (!EscDelay(50)) return false; return true; case SCROLLFLIRT: return FloppyScrollFlirt(); case COMMANDFLIRT: return CommandFlirt(data, ref i); case STOPFLIRT: _skyScreen.StopSequence(); return true; case STARTMUSIC: _skyMusic.StartMusic(data[i++]); return true; case WAITMUSIC: while (_skyMusic.IsPlaying) if (!EscDelay(50)) return false; return true; case BGFLIRT: _skyScreen.StartSequence(data[i++]); return true; case WAITFLIRT: while (_skyScreen.SequenceRunning()) if (!EscDelay(50)) return false; return true; case PLAYVOICE: { if (!EscDelay(200)) return false; var vData = _skyDisk.LoadFile(data[i++]); // HACK: Fill the header with silence. We should // probably use _skySound instead of calling playStream() // directly, but this will have to do for now. vData.Set(0, 127, ServiceLocator.Platform.SizeOf<DataFileHeader>()); var stream = new RawStream(AudioFlags.Unsigned, 11025, true, new MemoryStream(vData)); _voice = _mixer.PlayStream(SoundType.Speech, stream, Sound.SoundVoice); } return true; case WAITVOICE: while (_mixer.IsSoundHandleActive(_voice)) if (!EscDelay(50)) return false; return true; case LOADBG: _mixer.StopID(Sound.SoundBg); _bgBuf = _skyDisk.LoadFile(data[i++]); return true; case LOOPBG: { _mixer.StopID(Sound.SoundBg); var stream = new RawStream(AudioFlags.Unsigned, 11025, false, new MemoryStream(_bgBuf, 256, _bgBuf.Length - 768)); _bgSfx = _mixer.PlayStream(SoundType.SFX, new LoopingAudioStream(stream, 0), Sound.SoundBg); } return true; case PLAYBG: { _mixer.StopID(Sound.SoundBg); var stream = new RawStream(AudioFlags.Unsigned, 11025, false, new MemoryStream(_bgBuf, 256, _bgBuf.Length - 768)); _bgSfx = _mixer.PlayStream(SoundType.SFX, stream, Sound.SoundBg); } return true; case STOPBG: _mixer.StopID(Sound.SoundBg); return true; default: throw new NotSupportedException(string.Format("Unknown intro command {0:X2}", command)); } }
public bool StartSpeech(ushort textNum) { if (!SystemVars.Instance.SystemFlags.HasFlag(SystemFlags.AllowSpeech)) return false; var speechFileNum = (ushort)(_speechConvertTable[textNum >> 12] + (textNum & 0xFFF)); var speechData = _skyDisk.LoadFile(speechFileNum + 50000); if (speechData == null) { // TODO: debug(9, "File %d (speechFile %d from section %d) wasn't found", speechFileNum + 50000, textNum & 0xFFF, textNum >> 12); return false; } var header = ServiceLocator.Platform.ToStructure<DataFileHeader>(speechData, 0); var speechSize = header.s_tot_size - ServiceLocator.Platform.SizeOf<DataFileHeader>(); var playBuffer = new byte[speechSize]; Array.Copy(speechData, ServiceLocator.Platform.SizeOf<DataFileHeader>(), playBuffer, 0, speechSize); // Workaround for BASS bug #897775 - some voice-overs are played at // half speed in 0.0368 (the freeware CD version), in 0.0372 they sound // just fine. int rate; if (_skyDisk.DetermineGameVersion().Version.Minor == 368 && (textNum == 20905 || textNum == 20906)) rate = 22050; else rate = 11025; _mixer.StopID(SoundSpeech); var stream = new RawStream(AudioFlags.Unsigned, rate, true, new MemoryStream(playBuffer, 0, speechSize)); _ingameSpeech = _mixer.PlayStream(SoundType.Speech, stream, SoundSpeech); return true; }
public void PlaySound(ushort sound, ushort volume, byte channel) { if (channel == 0) _mixer.StopID(SoundChannel0); else _mixer.StopID(SoundChannel1); if (_soundData == null) { // TODO: warning //warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume); return; } if (sound > _soundsTotal) { // TODO: debug //debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal); return; } volume = (ushort)((volume & 0x7F) << 1); sound &= 0xFF; // Note: All those tables are big endian. Don't ask me why. *sigh* // Use the sample rate from game data, see bug #1507757. var sampleRate = _sampleRates.Data.ToUInt16BigEndian(_sampleRates.Offset + (sound << 2)); if (sampleRate > 11025) sampleRate = 11025; var dataOfs = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 0) / 2]) << 4; int dataSize = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 2) / 2]); int dataLoop = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 6) / 2]); dataOfs += _sfxBaseOfs; var stream = new RawStream(AudioFlags.Unsigned, sampleRate, false, new MemoryStream(_soundData, dataOfs, dataSize)); IAudioStream output; if (dataLoop != 0) { var loopSta = dataSize - dataLoop; var loopEnd = dataSize; output = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopSta, sampleRate), new Timestamp(0, loopEnd, sampleRate), true); } else { output = stream; } if (channel == 0) _ingameSound0 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel0, volume, 0); else _ingameSound1 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel1, volume, 0); }
public SoundHandle PlaySound(int id, byte[] sound, int size) { var flags = AudioFlags.Unsigned; var sizeOfDataFileHeader = ServiceLocator.Platform.SizeOf<DataFileHeader>(); size -= sizeOfDataFileHeader; var buffer = new byte[size]; Array.Copy(sound, sizeOfDataFileHeader, buffer, 0, size); _mixer.StopID(id); var stream = new RawStream(flags, 11025, true, new MemoryStream(buffer, 0, size)); return _mixer.PlayStream(SoundType.SFX, stream, id); }