protected void FillSettings(BinaryReader binReader) { Mode = binReader.ReadEnum<Mode>(); MicrophoneMode = binReader.ReadByte(); OnDefault = binReader.ReadEnum<Mode>(); SpotMeter = binReader.ReadByte() > 0; TimeLapse = binReader.ReadEnum<TimeLapse>(); AutoPowerOff = binReader.ReadByte() > 0; FieldOfView = binReader.ReadEnum<FieldOfView>(); PhotoResolution = binReader.ReadEnum<PhotoResolution>(); VideoResolution = binReader.ReadEnum<VideoResolution>(); AudioInput = binReader.ReadByte(); PlayMode = binReader.ReadByte(); PlaybackPosition = binReader.ReadUInt32(); BeepSound = binReader.ReadEnum<BeepSound>(); LedBlink = binReader.ReadEnum<LedBlink>(); var field = binReader.ReadByte(); PreviewActive = (byte) (field & 0x1) > 0; LiveFeed = (byte) (field & 0x2) > 0; Orientation = (Orientation) (field & 0x4); OneButton = (byte) (field & 0x8) > 0; OnScreen = (byte) (field & 0x10) > 0; VideoStandard = (VideoStandard) (field & 0x20); LocateCamera = (byte) (field & 0x40) > 0; Battery = binReader.ReadByte(); UsbMode = binReader.ReadByte(); PhotosAvailableSpace = binReader.ReadUInt16BigEndian(); PhotosCount = binReader.ReadUInt16BigEndian(); VideosAvailableSpace = binReader.ReadUInt16BigEndian(); VideosCount = binReader.ReadUInt16BigEndian(); Shutter = binReader.ReadByte() > 0; field = binReader.ReadByte(); Busy = (byte) (field & 0x1) > 0; Protune = (byte) (field & 0x2) > 0; PreviewAvailable = (byte) (field & 0x4) > 0; }
public void Do(Player player, byte[] msg, ushort len) { IMuseInternal se = player._se; switch (msg[0]) { case 0: // Trigger Event // Triggers are set by doCommand(ImSetTrigger). // When a SysEx marker is encountered whose sound // ID and marker ID match what was set by ImSetTrigger, // something magical is supposed to happen.... for (var a = 0; a < se._snm_triggers.Length; ++a) { if (se._snm_triggers[a].Sound == player.Id && se._snm_triggers[a].Id == msg[1]) { se._snm_triggers[a].Sound = se._snm_triggers[a].Id = 0; se.DoCommand(8, se._snm_triggers[a].Command); break; } } break; case 1: // maybe_jump. if (player.Scanning) break; using (var br = new BinaryReader(new MemoryStream(msg))) { br.ReadByte(); player.MaybeJump(br.ReadByte(), (uint)(br.ReadByte() - 1), (uint)((br.ReadUInt16BigEndian() - 1) * 4 + br.ReadByte()), (uint)((br.ReadByte() * TicksPerBeat) >> 2) + br.ReadByte()); } break; default: scummSysEx.Do(player, msg, len); break; } }
void ReadMap() { var br = new BinaryReader(_stream); _stream.Seek(_mapOffset + 22, SeekOrigin.Begin); _resMap.resAttr = br.ReadUInt16BigEndian(); _resMap.typeOffset = br.ReadUInt16BigEndian(); _resMap.nameOffset = br.ReadUInt16BigEndian(); _resMap.numTypes = br.ReadUInt16BigEndian(); _resMap.numTypes++; _stream.Seek(_mapOffset + _resMap.typeOffset + 2, SeekOrigin.Begin); _resTypes = new ResType[_resMap.numTypes]; for (int i = 0; i < _resMap.numTypes; i++) { _resTypes[i].id = br.ReadUInt32BigEndian(); _resTypes[i].items = br.ReadUInt16BigEndian(); _resTypes[i].offset = br.ReadUInt16BigEndian(); _resTypes[i].items++; Debug.WriteLine("resType: <{0}> items: {1} offset: {2} (0x{3:X2})", _resTypes[i].id, _resTypes[i].items, _resTypes[i].offset, _resTypes[i].offset); } _resLists = new Resource[_resMap.numTypes][]; for (int i = 0; i < _resMap.numTypes; i++) { _resLists[i] = new Resource[_resTypes[i].items]; _stream.Seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset, SeekOrigin.Begin); for (int j = 0; j < _resTypes[i].items; j++) { var resPtr = _resLists[i][j] = new Resource(); resPtr.id = br.ReadUInt16BigEndian(); resPtr.nameOffset = (short)br.ReadUInt16BigEndian(); resPtr.dataOffset = br.ReadUInt32BigEndian(); br.ReadUInt32BigEndian(); resPtr.attr = (byte)(resPtr.dataOffset >> 24); resPtr.dataOffset &= 0xFFFFFF; } for (int j = 0; j < _resTypes[i].items; j++) { if (_resLists[i][j].nameOffset != -1) { _stream.Seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset, SeekOrigin.Begin); byte len = br.ReadByte(); _resLists[i][j].name = br.ReadBytes(len).GetText(); } } } }
public void Do(Player player, byte[] msg, ushort len) { IMuseInternal se = player._se; int p = 0; byte code; switch (code = msg[p++]) { case 0: { // Allocate new part. // There are 8 bytes (after decoding!) of useful information here. // Here is what we know about them so far: // BYTE 0: Channel # // BYTE 1: BIT 01(0x01): Part on?(1 = yes) // BIT 02(0x02): Reverb? (1 = yes) [bug #1088045] // BYTE 2: Priority adjustment // BYTE 3: Volume [guessing] // BYTE 4: Pan [bug #1088045] // BYTE 5: BIT 8(0x80): Percussion?(1 = yes) [guessed?] // BYTE 5: Transpose, if set to 0x80(=-1) it means no transpose // BYTE 6: Detune // BYTE 7: Pitchbend factor [bug #1088045] // BYTE 8: Program var part = player.GetPart((byte)(msg[p] & 0x0F)); var buf = DecodeSysExBytes(msg, p + 1, len - 1); if (part != null) { part.SetOnOff((buf[0] & 0x01) != 0); part.EffectLevel((byte)(((buf[0] & 0x02) != 0) ? 127 : 0)); part.Priority = (sbyte)buf[1]; part.Volume = buf[2]; part.Pan = buf[3]; part.Percussion = player.SupportsPercussion && ((buf[4] & 0x80) > 0); part.SetTranspose((sbyte)buf[4]); part.Detune = buf[5]; part.PitchBendFactor(buf[6]); if (part.Percussion) { if (part.MidiChannel != null) { part.Off(); se.ReallocateMidiChannels(player.MidiDriver); } } else { if (player.IsMIDI) { // Even in cases where a program does not seem to be specified, // i.e. bytes 15 and 16 are 0, we send a program change because // 0 is a valid program number. MI2 tests show that in such // cases, a regular program change message always seems to follow // anyway. part.Instrument.Program(buf[7], player.IsMT32); } else { // Like the original we set up the instrument data of the // specified program here too. In case the global // instrument data is not loaded already, this will take // care of setting a default instrument too. se.CopyGlobalInstrument(buf[7], part.Instrument); } part.SendAll(); } } } break; case 1: // Shut down a part. [Bug 1088045, comments] { var part = player.GetPart(msg[p]); if (part != null) part.Uninit(); } break; case 2: // Start of song. Ignore for now. break; case 16: // AdLib instrument definition(Part) { var a = (byte)(msg[p++] & 0x0F); ++p; // Skip hardware type var part = player.GetPart(a); if (part != null) { if (len == 62 || len == 48) { var buf = DecodeSysExBytes(msg, p, len - 2); part.SetInstrument(buf); } else { part.ProgramChange(254); // Must be invalid, but not 255 (which is reserved) } } } break; case 17: // AdLib instrument definition(Global) { p += 2; // Skip hardware type and... whatever came right before it var a = msg[p++]; var buf = DecodeSysExBytes(msg, p, len - 3); if (len == 63 || len == 49) se.SetGlobalInstrument(a, buf); } break; case 33: // Parameter adjust { var a = msg[p++] & 0x0F; ++p; // Skip hardware type var buf = DecodeSysExBytes(msg, p, len - 2); var part = player.GetPart((byte)a); if (part != null) { using (var br = new BinaryReader(new MemoryStream(buf))) { part.SetParam((byte)br.ReadUInt16BigEndian(), (int)br.ReadUInt16BigEndian()); } } } break; case 48: // Hook - jump { if (player.Scanning) break; var buf = DecodeSysExBytes(msg, p + 1, len - 1); using (var br = new BinaryReader(new MemoryStream(buf))) { player.MaybeJump(br.ReadByte(), br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian()); } } break; case 49: // Hook - global transpose { var buf = DecodeSysExBytes(msg, p + 1, len - 1); player.MaybeSetTranspose(buf); } break; case 50: // Hook - part on/off { var tmp = msg[p++] & 0x0F; var buf = DecodeSysExBytes(msg, p, len - 1, 1); buf[0] = (byte)tmp; player.MaybePartOnOff(buf); } break; case 51: // Hook - set volume { var tmp = msg[p++] & 0x0F; var buf = DecodeSysExBytes(msg, p, len - 1, 1); buf[0] = (byte)tmp; player.MaybeSetVolume(buf); } break; case 52: // Hook - set program { var tmp = msg[p++] & 0x0F; var buf = DecodeSysExBytes(msg, p, len - 1, 1); buf[0] = (byte)tmp; player.MaybeSetProgram(buf); } break; case 53: // Hook - set transpose { var tmp = msg[p++] & 0x0F; var buf = DecodeSysExBytes(msg, p, len - 1, 1); buf[0] = (byte)tmp; player.MaybeSetTransposePart(buf); } break; case 64: // Marker p++; len--; while (len-- != 0) { se.HandleMarker(player.Id, msg[p++]); } break; case 80: // Loop { var buf = DecodeSysExBytes(msg, p + 1, len - 1); using (var br = new BinaryReader(new MemoryStream(buf))) { player.SetLoop(br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian(), br.ReadUInt16BigEndian()); } } break; case 81: // End loop player.ClearLoop(); break; case 96: // Set instrument { var part = player.GetPart((byte)(msg[p] & 0x0F)); var a = (msg[p + 1] & 0x0F) << 12 | (msg[p + 2] & 0x0F) << 8 | (msg[p + 3] & 0x0F) << 4 | (msg[p + 4] & 0x0F); if (part != null) part.SetInstrument((uint)a); } break; default: Debug.WriteLine("Unknown SysEx command {0}", (int)code); break; } }
public override void LoadMusic(byte[] data) { input = new MemoryStream(data); UnloadMusic(); int midiType; var isGmf = false; var br = new BinaryReader(input); var sig = br.ReadBytes(4); input.Seek(0, SeekOrigin.Begin); if (AreEquals(sig, "RIFF")) { // Skip the outer RIFF header. input.Seek(8, SeekOrigin.Current); } if (AreEquals(sig, "MThd")) { // SMF with MTHd information. input.Seek(4, SeekOrigin.Current); var len = br.ReadUInt32BigEndian(); if (len != 6) { throw new InvalidOperationException(string.Format("MThd length 6 expected but found {0}", len)); } br.ReadByte(); //? midiType = br.ReadByte(); // Verify that this MIDI either is a Type 2 // or has only 1 track. We do not support // multitrack Type 1 files. NumTracks = br.ReadUInt16BigEndian(); if (midiType > 2 /*|| (midiType < 2 && _numTracks > 1)*/) { throw new InvalidOperationException(string.Format("No support for a Type {0} MIDI with {1} tracks", midiType, NumTracks)); } PulsesPerQuarterNote = br.ReadUInt16BigEndian(); } else if (AreEquals(sig, "GMF\x1")) { // Older GMD/MUS file with no header info. // Assume 1 track, 192 PPQN, and no MTrk headers. isGmf = true; midiType = 0; NumTracks = 1; PulsesPerQuarterNote = 192; // 'GMD\x1' + 3 bytes of useless (translate: unknown) information input.Seek(7, SeekOrigin.Current); } else { throw new InvalidOperationException(string.Format("Expected MThd or GMD header but found '{0}{1}{2}{3}' instead", sig[0], sig[1], sig[2], sig[3])); } // Now we identify and store the location for each track. if (NumTracks > Tracks.Length) { throw new InvalidOperationException(string.Format("Can only handle {0} tracks but was handed {1}", Tracks.Length, NumTracks)); } uint totalSize = 0; var tracksRead = 0; while (tracksRead < NumTracks) { sig = br.ReadBytes(4); if (!AreEquals(sig, "MTrk") && !isGmf) { var msg = new StringBuilder(); msg.AppendFormat("Position: {0} ('{1}')", input.Position - 4, (char)sig[0]).AppendLine(); msg.AppendFormat("Hit invalid block '{0}{1}{2}{3}' while scanning for track locations", sig[0], sig[1], sig[2], sig[3]); throw new InvalidOperationException(msg.ToString()); } // If needed, skip the MTrk and length bytes Tracks[tracksRead] = new Track{ Position = input.Position + (isGmf ? -4 : 4) }; if (!isGmf) { var len = br.ReadUInt32BigEndian(); totalSize += len; input.Seek(len, SeekOrigin.Current); } else { // TODO: vs An SMF End of Track meta event must be placed // at the end of the stream. // data[size++] = 0xFF; // data[size++] = 0x2F; // data[size++] = 0x00; // data[size++] = 0x00; throw new NotImplementedException("Gmf not implemented"); } ++tracksRead; } // If this is a Type 1 MIDI, we need to now compress // our tracks down into a single Type 0 track. //_buffer = 0; if (midiType == 1) { // FIXME: Doubled the buffer size to prevent crashes with the // Inherit the Earth MIDIs. Jamieson630 said something about a // better fix, but this will have to do in the meantime. // _buffer = (byte*)malloc(size * 2); // compressToType0(); // _numTracks = 1; // _tracks[0] = _buffer; throw new NotImplementedException("MidiType 1 not yet implemented."); } // Note that we assume the original data passed in // will persist beyond this call, i.e. we do NOT // copy the data to our own buffer. Take warning.... ResetTracking(); Tempo = 500000; ActiveTrack = 0; }
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; }
public bool LoadInstrument(Stream stream) { var br = new BinaryReader(stream); ushort soundType = br.ReadUInt16BigEndian(); if (soundType != 1) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported sound type {0}", soundType); return false; } var typeCount = br.ReadUInt16BigEndian(); if (typeCount != 1) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported data type count %d", typeCount); return false; } var dataType = br.ReadUInt16BigEndian(); if (dataType != 5) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported data type %d", dataType); return false; } br.ReadUInt32BigEndian(); // initialization option var cmdCount = br.ReadUInt16BigEndian(); if (cmdCount != 1) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported command count %d", cmdCount); return false; } var command = br.ReadUInt16BigEndian(); if (command != 0x8050 && command != 0x8051) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported command 0x%04X", command); return false; } br.ReadUInt16BigEndian(); // 0 var soundHeaderOffset = br.ReadUInt32BigEndian(); stream.Seek(soundHeaderOffset, SeekOrigin.Begin); var soundDataOffset = br.ReadUInt32BigEndian(); var size = br.ReadUInt32BigEndian(); var rate = br.ReadUInt32BigEndian() >> 16; var loopStart = br.ReadUInt32BigEndian(); var loopEnd = br.ReadUInt32BigEndian(); byte encoding = br.ReadByte(); byte baseFreq = br.ReadByte(); if (encoding != 0) { Debug.WriteLine("Player_Mac::loadInstrument: Unsupported encoding %d", encoding); return false; } stream.Seek(soundDataOffset, SeekOrigin.Current); var data = br.ReadBytes((int)size); _instrument._data = data; _instrument._size = size; _instrument._rate = rate; _instrument._loopStart = loopStart; _instrument._loopEnd = loopEnd; _instrument._baseFreq = baseFreq; return true; }
MdatResource LoadMdatFile(Stream musicData) { var br = new BinaryReader(musicData); bool hasHeader = false; var mdatSize = musicData.Length; if (mdatSize >= 0x200) { // 0x0000: 10 Bytes Header "TFMX-SONG " var buf = System.Text.Encoding.UTF8.GetString(br.ReadBytes(10)); hasHeader = buf == "TFMX-SONG "; } if (!hasHeader) { Debug.WriteLine("Tfmx: File is not a Tfmx Module"); return null; } var resource = new MdatResource(); resource.mdatAlloc = null; resource.mdatOffset = 0; resource.mdatLen = 0; // 0x000A: int16 flags resource.headerFlags = br.ReadUInt16BigEndian(); // 0x000C: int32 ? // 0x0010: 6*40 Textfield musicData.Seek(4 + 6 * 40, SeekOrigin.Current); /* 0x0100: Songstart x 32*/ for (int i = 0; i < NumSubsongs; ++i) resource.subsong[i].songstart = br.ReadUInt16BigEndian(); /* 0x0140: Songend x 32*/ for (int i = 0; i < NumSubsongs; ++i) resource.subsong[i].songend = br.ReadUInt16BigEndian(); /* 0x0180: Tempo x 32*/ for (int i = 0; i < NumSubsongs; ++i) resource.subsong[i].tempo = br.ReadUInt16BigEndian(); /* 0x01c0: unused ? */ musicData.Seek(16, SeekOrigin.Current); /* 0x01d0: trackstep, pattern data p, macro data p */ var offTrackstep = br.ReadUInt32BigEndian(); uint offPatternP, offMacroP; // This is how MI`s TFMX-Player tests for unpacked Modules. if (offTrackstep == 0) { // unpacked File resource.trackstepOffset = 0x600 + 0x200; offPatternP = 0x200 + 0x200; offMacroP = 0x400 + 0x200; } else { // packed File resource.trackstepOffset = offTrackstep; offPatternP = br.ReadUInt32BigEndian(); offMacroP = br.ReadUInt32BigEndian(); } // TODO: if a File is packed it could have for Ex only 2 Patterns/Macros // the following loops could then read beyond EOF. // To correctly handle this it would be necessary to sort the pointers and // figure out the number of Macros/Patterns // We could also analyze pointers if they are correct offsets, // so that accesses can be unchecked later // Read in pattern starting offsets musicData.Seek(offPatternP, SeekOrigin.Begin); for (int i = 0; i < MaxPatternOffsets; ++i) resource.patternOffset[i] = br.ReadUInt32BigEndian(); // use last PatternOffset (stored at 0x5FC in mdat) if unpacked File // or fixed offset 0x200 if packed resource.sfxTableOffset = offTrackstep != 0 ? 0x200 : resource.patternOffset[127]; // Read in macro starting offsets musicData.Seek(offMacroP, SeekOrigin.Begin); for (int i = 0; i < MaxMacroOffsets; ++i) resource.macroOffset[i] = br.ReadUInt32BigEndian(); // Read in mdat-file // TODO: we can skip everything thats already stored in the resource-structure. var mdatOffset = offTrackstep != 0 ? 0x200 : 0x600; // 0x200 is very conservative var allocSize = mdatSize - mdatOffset; musicData.Seek(mdatOffset, SeekOrigin.Begin); var mdatAlloc = br.ReadBytes((int)allocSize); resource.mdatAlloc = mdatAlloc; resource.mdatOffset = mdatOffset; resource.mdatLen = (int)mdatSize; return resource; }
public bool RestoreGameFromFile(byte slot) { ushort cnt; var fName = $"sword1.{slot:D3}"; using (var inf = new BinaryReader(_saveFileMan.OpenForLoading(fName))) { // TODO: //if (inf==null) //{ // // Display an error message, and do nothing // // TODO: DisplayMessage(0, "Can't open file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str()); // return false; //} uint saveHeader = inf.ReadUInt32(); if (saveHeader != SAVEGAME_HEADER) { // Display an error message, and do nothing // TODO: DisplayMessage(0, "Save game '%s' is corrupt", fName); return false; } inf.BaseStream.Seek(40, SeekOrigin.Current); // skip description byte saveVersion = inf.ReadByte(); if (saveVersion > SAVEGAME_VERSION) { // TODO: warning("Different save game version"); return false; } if (saveVersion < 2) // These older version of the savegames used a flag to signal presence of thumbnail inf.BaseStream.Seek(1, SeekOrigin.Current); SkipThumbnail(inf); inf.ReadUInt32BigEndian(); // save date inf.ReadUInt16BigEndian(); // save time if (saveVersion < 2) { // Before version 2 we didn't had play time feature // TODO: g_engine.setTotalPlayTime(0); } else { var time = inf.ReadUInt32BigEndian(); // TODO: g_engine.setTotalPlayTime(time * 1000); } _restoreBuf = new byte[ ObjectMan.TOTAL_SECTIONS * 2 + Logic.NUM_SCRIPT_VARS * 4 + (SwordObject.Size - 12000)]; var liveBuf = new UShortAccess(_restoreBuf); var scriptBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS); var playerBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS + 4 * Logic.NUM_SCRIPT_VARS); for (cnt = 0; cnt < ObjectMan.TOTAL_SECTIONS; cnt++) liveBuf[cnt] = inf.ReadUInt16(); for (cnt = 0; cnt < Logic.NUM_SCRIPT_VARS; cnt++) scriptBuf[cnt] = inf.ReadUInt32(); uint playerSize = (SwordObject.Size - 12000) / 4; for (var cnt2 = 0; cnt2 < playerSize; cnt2++) playerBuf[cnt2] = inf.ReadUInt32(); // TODO: error //if (inf.err() || inf.eos()) //{ // displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str()); // delete inf; // free(_restoreBuf); // _restoreBuf = NULL; // return false; //} } return true; }