SoundHandle StartTalkSound(int offset, int b, int mode) { Stream file; SoundHandle handle = new SoundHandle(); var id = -1; if (vm.Game.GameId == GameId.CurseOfMonkeyIsland) { sfxMode |= mode; return(handle); } else if (vm.Game.GameId == GameId.Dig) { sfxMode |= mode; if (!(vm.Game.Features.HasFlag(GameFeatures.Demo))) { return(handle); } throw new NotImplementedException(); } else { if (_sfxFilename == null) { // Console.Error.WriteLine("StartTalkSound: SFX file not found"); return(handle); } // Some games frequently assume that starting one sound effect will // automatically stop any other that may be playing at that time. So // that is what we do here, but we make an exception for speech. if (mode == 1 && (vm.Game.GameId == GameId.Tentacle || vm.Game.GameId == GameId.SamNMax)) { id = 777777 + _talkSoundChannel; _mixer.StopID(id); } int num = 0; if (b > 8) { num = (b - 8) >> 1; } offset += 8; _mouthSyncTimes = new ushort[num + 1]; file = ServiceLocator.FileStorage.OpenFileRead(_sfxFilename); var br = new BinaryReader(file); file.Seek(offset, SeekOrigin.Begin); for (int i = 0; i < num; i++) { _mouthSyncTimes[i] = br.ReadUInt16BigEndian(); } // Adjust offset to account for the mouth sync times. It is noteworthy // that we do not adjust the size here for compressed streams, since // they only set size to the size of the compressed sound data. offset += num * 2; // TODO: In case we ever set up the size for VOC streams, we should // really check whether the size contains the _mouthSyncTimes. // if (SoundMode == SoundMode.VOCMode) // size -= num * 2; _mouthSyncTimes[num] = 0xFFFF; sfxMode |= mode; _curSoundPos = 0; _mouthSyncMode = true; } var input = new VocStream(file, true); var iMuseDigital = vm.MusicEngine as IMuseDigital; if (iMuseDigital != null) { iMuseDigital.StartVoice(TalkSoundID, input); } else { if (mode == 1) { handle = _mixer.PlayStream(SoundType.SFX, input, id); } else { handle = _mixer.PlayStream(SoundType.Speech, input, id); } } return(handle); }
void PrepareSound(byte[] ptr, SoundDesc sound) { if (ptr.ToText() == "Crea") { bool quit = false; int len; int offset = ptr.ToInt16(20); int code = ptr.ToInt16(24); sound.NumRegions = 0; sound.Region = new Region[70]; sound.NumJumps = 0; sound.Jump = new Jump[1]; sound.NumSyncs = 0; sound.ResPtr = ptr; sound.Bits = 8; sound.Channels = 1; while (!quit) { len = ptr.ToInt32(offset); code = len & 0xFF; if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) { // try again with 2 bytes forward (workaround for some FT sounds (ex.362, 363) offset += 2; len = ptr.ToInt32(offset); code = len & 0xFF; if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) { throw new NotSupportedException(string.Format("Invalid code in VOC file : {0}", code)); } } offset += 4; len >>= 8; switch (code) { case 0: quit = true; break; case 1: { int time_constant = ptr[offset]; offset += 2; len -= 2; sound.Freq = (ushort)VocStream.GetSampleRateFromVOCRate(time_constant); sound.Region[sound.NumRegions].Offset = offset; sound.Region[sound.NumRegions].Length = len; sound.NumRegions++; } break; case 6: // begin of loop sound.Jump[0].Dest = offset + 8; sound.Jump[0].HookId = 0; sound.Jump[0].FadeDelay = 0; break; case 7: // end of loop sound.Jump[0].Offset = offset - 4; sound.NumJumps++; sound.Region[sound.NumRegions].Offset = offset - 4; sound.Region[sound.NumRegions].Length = 0; sound.NumRegions++; break; default: throw new InvalidOperationException(string.Format("Invalid code in VOC file : {0}", code)); // quit = true; // break; } offset += len; } } else if (ptr.ToText() == "iMUS") { string tag; int size = 0; int posPtr = 16; int curIndexRegion = 0; int curIndexJump = 0; int curIndexSync = 0; int curIndexMarker = 0; sound.NumRegions = 0; sound.NumJumps = 0; sound.NumSyncs = 0; sound.NumMarkers = 0; CountElements(ptr, posPtr, ref sound.NumRegions, ref sound.NumJumps, ref sound.NumSyncs, ref sound.NumMarkers); sound.Region = new Region[sound.NumRegions]; sound.Jump = new Jump[sound.NumJumps]; sound.Sync = new Sync[sound.NumSyncs]; sound.Marker = new Marker[sound.NumMarkers]; do { tag = ptr.ToText(posPtr); posPtr += 4; switch (tag) { case "FRMT": posPtr += 12; sound.Bits = (byte)ptr.ToUInt32BigEndian(posPtr); posPtr += 4; sound.Freq = (ushort)ptr.ToUInt32BigEndian(posPtr); posPtr += 4; sound.Channels = (byte)ptr.ToUInt32BigEndian(posPtr); posPtr += 4; break; case "TEXT": if (string.Equals(ptr.ToText(posPtr + 8), "exit")) { sound.Marker[curIndexMarker].Pos = ptr.ToInt32BigEndian(posPtr + 4); sound.Marker[curIndexMarker].Ptr = ptr.GetText(posPtr + 8); curIndexMarker++; } size = ptr.ToInt32BigEndian(posPtr); posPtr += size + 4; break; case "STOP": size = ptr.ToInt32BigEndian(posPtr); posPtr += size + 4; break; case "REGN": posPtr += 4; sound.Region[curIndexRegion].Offset = ptr.ToInt32BigEndian(posPtr); posPtr += 4; sound.Region[curIndexRegion].Length = ptr.ToInt32BigEndian(posPtr); posPtr += 4; curIndexRegion++; break; case "JUMP": posPtr += 4; sound.Jump[curIndexJump].Offset = ptr.ToInt32BigEndian(posPtr); posPtr += 4; sound.Jump[curIndexJump].Dest = ptr.ToInt32BigEndian(posPtr); posPtr += 4; sound.Jump[curIndexJump].HookId = (byte)ptr.ToInt32BigEndian(posPtr); posPtr += 4; sound.Jump[curIndexJump].FadeDelay = (short)ptr.ToInt32BigEndian(posPtr); posPtr += 4; curIndexJump++; break; case "SYNC": size = ptr.ToInt32BigEndian(posPtr); posPtr += 4; sound.Sync[curIndexSync].Ptr = new byte[size]; Array.Copy(ptr, posPtr, sound.Sync[curIndexSync].Ptr, 0, size); curIndexSync++; posPtr += size; break; case "DATA": posPtr += 4; break; default: throw new InvalidOperationException( string.Format("ImuseDigiSndMgr::prepareSound({0}/{1}) Unknown sfx header '{2}'", sound.SoundId, sound.Name, tag)); } } while (tag != "DATA"); sound.OffsetData = posPtr; } else { throw new InvalidOperationException("ImuseDigiSndMgr::prepareSound(): Unknown sound format"); } }