예제 #1
0
        private void UpdateFramerate()
        {
            VsyncNumerator = 1000000000;
            long refresh = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetRefresh);

            VsyncDenominator = (int)(refresh / 1000000000);
        }
예제 #2
0
        private void UpdateVideo()
        {
            BufferWidth  = LibMAME.mame_lua_get_int(MAMELuaCommand.GetWidth);
            BufferHeight = LibMAME.mame_lua_get_int(MAMELuaCommand.GetHeight);
            int    expectedSize  = BufferWidth * BufferHeight;
            int    bytesPerPixel = 4;
            IntPtr ptr           = LibMAME.mame_lua_get_string(MAMELuaCommand.GetPixels, out var lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: frame buffer pointer is null");
                return;
            }

            if (expectedSize * bytesPerPixel != lengthInBytes)
            {
                Console.WriteLine(
                    "LibMAME ERROR: frame buffer has wrong size\n" +
                    $"width:    { BufferWidth                  } pixels\n" +
                    $"height:   { BufferHeight                 } pixels\n" +
                    $"expected: { expectedSize * bytesPerPixel } bytes\n" +
                    $"received: { lengthInBytes                } bytes\n");
                return;
            }

            _frameBuffer = new int[expectedSize];
            Marshal.Copy(ptr, _frameBuffer, 0, expectedSize);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: frame buffer wasn't freed");
            }
        }
예제 #3
0
파일: MAME.cs 프로젝트: xy2iii/BizHawk
        private void GetInputFields()
        {
            int lengthInBytes;

            IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetInputFields, out lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: string buffer pointer is null");
                return;
            }

            string inputFields = Marshal.PtrToStringAnsi(ptr, lengthInBytes);

            string[] portFields = inputFields.Split(';');
            MAMEController.BoolButtons.Clear();

            foreach (string portField in portFields)
            {
                if (portField != string.Empty)
                {
                    string[] substrings = portField.Split(',');
                    string   tag        = substrings.First();
                    string   field      = substrings.Last();

                    fieldsPorts.Add(field, tag);
                    MAMEController.BoolButtons.Add(field);
                }
            }

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
            }
        }
예제 #4
0
        private void MAMESoundCallback()
        {
            int    bytesPerSample = 2;
            IntPtr ptr            = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSamples, out var lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: audio buffer pointer is null");
                return;
            }

            _numSamples = lengthInBytes / bytesPerSample;

            unsafe
            {
                short *pSample = (short *)ptr.ToPointer();
                for (int i = 0; i < _numSamples; i++)
                {
                    _audioSamples.Enqueue(*(pSample + i));
                    _dAudioSamples++;
                }
            }

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed");
            }
        }
예제 #5
0
        /*
         * FrameAdvance() and MAME
         *
         * MAME fires the periodic callback on every video and debugger update,
         * which happens every VBlank and also repeatedly at certain time
         * intervals while paused. Since MAME's luaengine runs in a separate
         * thread, it's only safe to update everything we need per frame during
         * this callback, when it's explicitly waiting for further lua commands.
         *
         * If we disable throttling and pass -update_in_pause, there will be no
         * delay between video updates. This allows to run at full speed while
         * frame-stepping.
         *
         * MAME only captures new frame data once per VBlank, while unpaused.
         * But it doesn't have an exclusive VBlank callback we could attach to.
         * It has a LUA_ON_FRAME_DONE callback, but that fires even more
         * frequently and updates all sorts of other non-video stuff, and we
         * need none of that here.
         *
         * So we filter out all the calls that happen while paused (non-VBlank
         * updates). Then, when Hawk asks us to advance a frame, we virtually
         * unpause and declare the new frame unfinished. This informs MAME that
         * it should advance one frame internally. Hawk starts waiting for the
         * MAME thread to complete the request.
         *
         * After MAME's done advancing, it fires the periodic callback again.
         * That's when we update everything and declare the new frame finished,
         * filtering out any further updates again. Then we allow Hawk to
         * complete frame-advancing.
         */
        private void MAMEPeriodicCallback()
        {
            if (_exiting)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Exit);
                _exiting = false;
            }

            if (_memAccess)
            {
                _mamePeriodicComplete.Set();
                _memoryAccessComplete.WaitOne();
                return;
            }

            //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber);

            if (!_paused)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Step);
                _frameDone = false;
                _paused    = true;
            }
            else if (!_frameDone)
            {
                Update();
                _frameDone = true;
                _mameFrameComplete.Set();
            }
        }
예제 #6
0
파일: MAME.cs 프로젝트: xy2iii/BizHawk
        private void ExecuteMAMEThread()
        {
            // dodge GC
            periodicCallback = MAMEPeriodicCallback;
            soundCallback    = MAMESoundCallback;
            bootCallback     = MAMEBootCallback;
            logCallback      = MAMELogCallback;

            LibMAME.mame_set_periodic_callback(periodicCallback);
            LibMAME.mame_set_sound_callback(soundCallback);
            LibMAME.mame_set_boot_callback(bootCallback);
            LibMAME.mame_set_log_callback(logCallback);

            // https://docs.mamedev.org/commandline/commandline-index.html
            string[] args = new string[] {
                "mame"                                                 // dummy, internally discarded by index, so has to go first
                , gameFilename                                         // no dash for rom names
                , "-noreadconfig"                                      // forbid reading any config files
                , "-norewind"                                          // forbid rewind savestates (captured upon frame advance)
                , "-skip_gameinfo"                                     // forbid this blocking screen that requires user input
                , "-nothrottle"                                        // forbid throttling to "real" speed of the device
                , "-update_in_pause"                                   // ^ including frame-advancing
                , "-rompath", gameDirectory                            // mame doesn't load roms from full paths, only from dirs to scan
                , "-volume", "-32"                                     // lowest attenuation means mame osd remains silent
                , "-output", "console"                                 // print everyting to hawk console
                , "-samplerate", sampleRate.ToString()                 // match hawk samplerate
                , "-video", "none"                                     // forbid mame window altogether
                , "-keyboardprovider", "none"
                , "-mouseprovider", "none"
                , "-lightgunprovider", "none"
                , "-joystickprovider", "none"
            };

            LibMAME.mame_launch(args.Length, args);
        }
예제 #7
0
        private void InitMemoryDomains()
        {
            var domains = new List <MemoryDomain>();

            _systemBusAddressShift = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceAddressShift);
            var dataWidth    = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceDataWidth) >> 3;          // mame returns in bits
            var size         = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetSpaceAddressMask) + dataWidth;
            var endianString = MameGetString(MAMELuaCommand.GetSpaceEndianness);
            var deviceName   = MameGetString(MAMELuaCommand.GetMainCPUName);

            //var addrSize = (size * 2).ToString();

            MemoryDomain.Endian endian = MemoryDomain.Endian.Unknown;

            if (endianString == "little")
            {
                endian = MemoryDomain.Endian.Little;
            }
            else if (endianString == "big")
            {
                endian = MemoryDomain.Endian.Big;
            }

            var mapCount = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceMapCount);

            for (int i = 1; i <= mapCount; i++)
            {
                var read  = MameGetString($"return { MAMELuaCommand.SpaceMap }[{ i }].readtype");
                var write = MameGetString($"return { MAMELuaCommand.SpaceMap }[{ i }].writetype");

                if (read == "ram" && write == "ram" || read == "rom")
                {
                    var firstOffset = LibMAME.mame_lua_get_int($"return { MAMELuaCommand.SpaceMap }[{ i }].offset");
                    var lastOffset  = LibMAME.mame_lua_get_int($"return { MAMELuaCommand.SpaceMap }[{ i }].endoff");
                    var name        = $"{ deviceName } : { read } : 0x{ firstOffset:X}-0x{ lastOffset:X}";

                    domains.Add(new MemoryDomainDelegate(name, lastOffset - firstOffset + 1, endian,
                                                         delegate(long addr)
                    {
                        return(_peek(addr, firstOffset, size));
                    },
                                                         read == "rom" ? (Action <long, byte>) null : delegate(long addr, byte val)
                    {
                        _poke(addr, val, firstOffset, size);
                    },
                                                         dataWidth));
                }
            }

            domains.Add(new MemoryDomainDelegate(deviceName + " : System Bus", size, endian,
                                                 delegate(long addr)
            {
                return(_peek(addr, 0, size));
            },
                                                 null, dataWidth));

            _memoryDomains = new MemoryDomainList(domains);
            (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(_memoryDomains);
        }
예제 #8
0
 private void MAMEBootCallback()
 {
     LibMAME.mame_lua_execute(MAMELuaCommand.Pause);
     CheckVersions();
     GetInputFields();
     Update();
     MAMEStartupComplete.Set();
 }
예제 #9
0
        private void UpdateAspect()
        {
            int x = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundX);
            int y = (int)LibMAME.mame_lua_get_double(MAMELuaCommand.GetBoundY);

            VirtualHeight = BufferWidth > BufferHeight * x / y
                                ? BufferWidth * y / x
                                : BufferHeight;
            VirtualWidth = VirtualHeight * x / y;
        }
예제 #10
0
 private void SendInput()
 {
     foreach (var fieldPort in _fieldsPorts)
     {
         LibMAME.mame_lua_execute(
             "manager:machine():ioport()" +
             $".ports  [\"{ fieldPort.Value }\"]" +
             $".fields [\"{ fieldPort.Key   }\"]" +
             $":set_value({ (_controller.IsPressed(fieldPort.Key) ? 1 : 0) })");
     }
 }
예제 #11
0
파일: MAME.cs 프로젝트: xy2iii/BizHawk
        private void UpdateGameName()
        {
            int    lengthInBytes;
            IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetGameName, out lengthInBytes);

            gameName = Marshal.PtrToStringAnsi(ptr, lengthInBytes);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
            }
        }
예제 #12
0
        public void OverrideGameSettings()
        {
            foreach (KeyValuePair <string, string> setting in _syncSettings.DriverSettings)
            {
                DriverSetting s = CurrentDriverSettings.SingleOrDefault(s => s.LookupKey == setting.Key);

                if (s != null && s.Type == SettingType.DIPSWITCH)
                {
                    LibMAME.mame_lua_execute($"{ s.LuaCode }.user_value = { setting.Value }");
                }
            }
        }
예제 #13
0
        private void MAMEBootCallback()
        {
            LibMAME.mame_lua_execute(MAMELuaCommand.Pause);

            CheckVersions();
            GetInputFields();
            Update();
            UpdateGameName();
            InitMemoryDomains();

            _mameStartupComplete.Set();
        }
예제 #14
0
        public void LoadStateBinary(BinaryReader reader)
        {
            int length = reader.ReadInt32();

            if (length != _mameSaveBuffer.Length)
            {
                throw new InvalidOperationException("Savestate buffer size mismatch!");
            }

            reader.Read(_mameSaveBuffer, 0, _mameSaveBuffer.Length);
            Frame = reader.ReadInt32();

            LibMAME.mame_lua_execute($"manager:machine():buffer_load({ _mameSaveBuffer })");
        }
예제 #15
0
파일: MAME.cs 프로젝트: gocha/BizHawk
        private void ExecuteMAMEThread()
        {
            _periodicCallback = MAMEPeriodicCallback;
            _soundCallback    = MAMESoundCallback;
            _bootCallback     = MAMEBootCallback;
            _logCallback      = MAMELogCallback;

            LibMAME.mame_set_periodic_callback(_periodicCallback);
            LibMAME.mame_set_sound_callback(_soundCallback);
            LibMAME.mame_set_boot_callback(_bootCallback);
            LibMAME.mame_set_log_callback(_logCallback);

            // https://docs.mamedev.org/commandline/commandline-index.html
            List <string> args = new List <string>
            {
                "mame"                                                  // dummy, internally discarded by index, so has to go first
                , _gameFileName                                         // no dash for rom names
                , "-noreadconfig"                                       // forbid reading ini files
                , "-nowriteconfig"                                      // forbid writing ini files
                , "-norewind"                                           // forbid rewind savestates (captured upon frame advance)
                , "-skip_gameinfo"                                      // forbid this blocking screen that requires user input
                , "-nothrottle"                                         // forbid throttling to "real" speed of the device
                , "-update_in_pause"                                    // ^ including frame-advancing
                , "-rompath", _gameDirectory                            // mame doesn't load roms from full paths, only from dirs to scan
                , "-joystick_contradictory"                             // allow L+R/U+D on digital joystick
                , "-nonvram_save"                                       // prevent dumping non-volatile ram to disk
                , "-artpath", "mame\\artwork"                           // path to load artowrk from
                , "-diff_directory", "mame\\diff"                       // hdd diffs, whenever stuff is written back to an image
                , "-cfg_directory", "?"                                 // send invalid path to prevent cfg handling
                , "-volume", "-32"                                      // lowest attenuation means mame osd remains silent
                , "-output", "console"                                  // print everything to hawk console
                , "-samplerate", _sampleRate.ToString()                 // match hawk samplerate
                , "-video", "none"                                      // forbid mame window altogether
                , "-keyboardprovider", "none"
                , "-mouseprovider", "none"
                , "-lightgunprovider", "none"
                , "-joystickprovider", "none"
                //	, "-debug"                              // launch mame debugger (because we can)
            };

            if (_syncSettings.DriverSettings.TryGetValue(
                    MAMELuaCommand.MakeLookupKey(_gameFileName.Split('.')[0], LibMAME.BIOS_LUA_CODE),
                    out string value))
            {
                args.AddRange(new[] { "-bios", value });
            }

            LibMAME.mame_launch(args.Count, args.ToArray());
        }
예제 #16
0
        /*
         * FrameAdvance() and MAME
         *
         * MAME fires the periodic callback on every video and debugger update,
         * which happens every VBlank and also repeatedly at certain time
         * intervals while paused. Since MAME's luaengine runs in a separate
         * thread, it's only safe to update everything we need per frame during
         * this callback, when it's explicitly waiting for further lua commands.
         *
         * If we disable throttling and pass -update_in_pause, there will be no
         * delay between video updates. This allows to run at full speed while
         * frame-stepping.
         *
         * MAME only captures new frame data once per VBlank, while unpaused.
         * But it doesn't have an exclusive VBlank callback we could attach to.
         * It has a LUA_ON_FRAME_DONE callback, but that fires even more
         * frequently and updates all sorts of other non-video stuff, and we
         * need none of that here.
         *
         * So we filter out all the calls that happen while paused (non-VBlank
         * updates). Then, when Hawk asks us to advance a frame, we virtually
         * unpause and declare the new frame unfinished. This informs MAME that
         * it should advance one frame internally. Hawk starts waiting for the
         * MAME thread to complete the request.
         *
         * After MAME's done advancing, it fires the periodic callback again.
         * That's when we update everything and declare the new frame finished,
         * filtering out any further updates again. Then we allow Hawk to
         * complete frame-advancing.
         */
        private void MAMEPeriodicCallback()
        {
            if (_exiting)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Exit);
                _exiting = false;
            }

            if (_memAccess)
            {
                _mamePeriodicComplete.Set();
                _memoryAccessComplete.WaitOne();
                return;
            }

            //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber);

            if (!_paused)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Step);
                _frameDone = false;
                _paused    = true;
            }
            else if (!_frameDone)
            {
                /*
                 * IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSpaceBuffer, out var lengthInBytes);
                 *
                 * if (ptr == IntPtr.Zero)
                 * {
                 *      Console.WriteLine("LibMAME ERROR: audio buffer pointer is null");
                 *      return;
                 * }
                 *
                 * //byte[] buf = new byte[lengthInBytes];
                 * //Marshal.Copy(ptr, buf, 0, lengthInBytes);
                 *
                 * if (!LibMAME.mame_lua_free_string(ptr))
                 * {
                 *      Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed");
                 * }
                 */

                Update();
                _frameDone = true;
                _mameFrameComplete.Set();
            }
        }
예제 #17
0
        private void MAMEBootCallback()
        {
            LibMAME.mame_lua_execute(MAMELuaCommand.Pause);

            CheckVersions();
            GetInputFields();
            Update();
            UpdateGameName();
            InitMemoryDomains();

            IntPtr ptr = LibMAME.mame_lua_get_string("return manager:machine():buffer_save()", out var lengthInBytes);

            _mameSaveBuffer = new byte[lengthInBytes];
            _hawkSaveBuffer = new byte[lengthInBytes + 4 + 4];

            _mameStartupComplete.Set();
        }
예제 #18
0
파일: MAME.cs 프로젝트: xy2iii/BizHawk
        private void CheckVersions()
        {
            int    lengthInBytes;
            IntPtr ptr         = LibMAME.mame_lua_get_string(MAMELuaCommand.GetVersion, out lengthInBytes);
            string MAMEVersion = Marshal.PtrToStringAnsi(ptr, lengthInBytes);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
            }

            string version = this.Attributes().PortedVersion;

            Debug.Assert(version == MAMEVersion,
                         "MAME versions desync!\n\n" +
                         $"MAME is { MAMEVersion }\n" +
                         $"MAMEHawk is { version }");
        }
예제 #19
0
        private static string MameGetString(string command)
        {
            IntPtr ptr = LibMAME.mame_lua_get_string(command, out var lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: string buffer pointer is null");
                return("");
            }

            var ret = Marshal.PtrToStringAnsi(ptr, lengthInBytes);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: string buffer wasn't freed");
            }

            return(ret);
        }
예제 #20
0
        private void _poke(long addr, byte val, int firstOffset, long size)
        {
            if (addr < 0 || addr >= size)
            {
                throw new ArgumentOutOfRangeException();
            }

            if (!_memAccess)
            {
                _memAccess = true;
                _mamePeriodicComplete.WaitOne();
            }

            addr += firstOffset;

            LibMAME.mame_lua_execute($"{ MAMELuaCommand.GetSpace }:write_u8({ addr << _systemBusAddressShift }, { val })");

            _memoryAccessComplete.Set();
        }
예제 #21
0
        private void MAMEBootCallback()
        {
            LibMAME.mame_lua_execute(MAMELuaCommand.Pause);

            CheckVersions();
            GetInputFields();
            UpdateVideo();
            UpdateAspect();
            UpdateFramerate();
            UpdateGameName();
            InitMemoryDomains();

            int length = LibMAME.mame_lua_get_int("return string.len(manager:machine():buffer_save())");

            _mameSaveBuffer = new byte[length];
            _hawkSaveBuffer = new byte[length + 4 + 4 + 4 + 1];

            _mameStartupComplete.Set();
        }
예제 #22
0
        private void ExecuteMAMEThread()
        {
            // dodge GC
            _periodicCallback = MAMEPeriodicCallback;
            _soundCallback    = MAMESoundCallback;
            _bootCallback     = MAMEBootCallback;
            _logCallback      = MAMELogCallback;

            LibMAME.mame_set_periodic_callback(_periodicCallback);
            LibMAME.mame_set_sound_callback(_soundCallback);
            LibMAME.mame_set_boot_callback(_bootCallback);
            LibMAME.mame_set_log_callback(_logCallback);

            // https://docs.mamedev.org/commandline/commandline-index.html
            string[] args =
            {
                "mame"                                                  // dummy, internally discarded by index, so has to go first
                , _gameFilename                                         // no dash for rom names
                , "-noreadconfig"                                       // forbid reading ini files
                , "-nowriteconfig"                                      // forbid writing ini files
                , "-norewind"                                           // forbid rewind savestates (captured upon frame advance)
                , "-skip_gameinfo"                                      // forbid this blocking screen that requires user input
                , "-nothrottle"                                         // forbid throttling to "real" speed of the device
                , "-update_in_pause"                                    // ^ including frame-advancing
                , "-rompath", _gameDirectory                            // mame doesn't load roms from full paths, only from dirs to scan
                , "-joystick_contradictory"                             // L+R/U+D on digital joystick
                , "-nonvram_save"                                       // prevent dumping non-volatile ram to disk
                , "-artpath", "mame\\artwork"                           // path to load artowrk from
                , "-diff_directory", "mame\\diff"                       // hdd diffs, whenever stuff is written back to an image
                , "-cfg_directory", ":"                                 // send invalid path to prevent cfg handling
                , "-volume", "-32"                                      // lowest attenuation means mame osd remains silent
                , "-output", "console"                                  // print everything to hawk console
                , "-samplerate", _sampleRate.ToString()                 // match hawk samplerate
                , "-video", "none"                                      // forbid mame window altogether
                , "-keyboardprovider", "none"
                , "-mouseprovider", "none"
                , "-lightgunprovider", "none"
                , "-joystickprovider", "none"
            };

            LibMAME.mame_launch(args.Length, args);
        }
예제 #23
0
        private byte _peek(long addr, int firstOffset, long size)
        {
            if (addr < 0 || addr >= size)
            {
                throw new ArgumentOutOfRangeException();
            }

            if (!_memAccess)
            {
                _memAccess = true;
                _mamePeriodicComplete.WaitOne();
            }

            addr += firstOffset;

            var val = (byte)LibMAME.mame_lua_get_int($"{ MAMELuaCommand.GetSpace }:read_u8({ addr << _systemBusAddressShift })");

            _memoryAccessComplete.Set();

            return(val);
        }
예제 #24
0
        private byte _peek(long addr, int firstOffset, long size)
        {
            if (addr < 0 || addr >= size)
            {
                throw new ArgumentOutOfRangeException();
            }

            if (!_memAccess)
            {
                _memAccess = true;
                _mamePeriodicComplete.WaitOne();
            }

            addr += firstOffset;

            var val = (byte)LibMAME.mame_read_byte((uint)addr << _systemBusAddressShift);

            _memoryAccessComplete.Set();

            return(val);
        }
예제 #25
0
        public void LoadStateBinary(BinaryReader reader)
        {
            int length = reader.ReadInt32();

            if (length != _mameSaveBuffer.Length)
            {
                throw new InvalidOperationException("Savestate buffer size mismatch!");
            }

            reader.Read(_mameSaveBuffer, 0, _mameSaveBuffer.Length);
            LibMAME.SaveError err = LibMAME.mame_load_buffer(_mameSaveBuffer, _mameSaveBuffer.Length);

            if (err != LibMAME.SaveError.NONE)
            {
                throw new InvalidOperationException("MAME SAVESTATE ERROR: " + err.ToString());
            }

            Frame      = reader.ReadInt32();
            LagCount   = reader.ReadInt32();
            IsLagFrame = reader.ReadBoolean();
        }
예제 #26
0
        public void SaveStateBinary(BinaryWriter writer)
        {
            writer.Write(_mameSaveBuffer.Length);

            LibMAME.SaveError err = LibMAME.mame_save_buffer(_mameSaveBuffer, out int length);

            if (length != _mameSaveBuffer.Length)
            {
                throw new InvalidOperationException("Savestate buffer size mismatch!");
            }

            if (err != LibMAME.SaveError.NONE)
            {
                throw new InvalidOperationException("MAME LOADSTATE ERROR: " + err.ToString());
            }

            writer.Write(_mameSaveBuffer);
            writer.Write(Frame);
            writer.Write(LagCount);
            writer.Write(IsLagFrame);
        }
예제 #27
0
        public void SaveStateBinary(BinaryWriter writer)
        {
            IntPtr ptr = LibMAME.mame_lua_get_string("return manager:machine():buffer_save()", out var lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: audio buffer pointer is null");
                return;
            }

            Marshal.Copy(ptr, _mameSaveBuffer, 0, lengthInBytes);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed");
            }

            writer.Write(_mameSaveBuffer.Length);
            writer.Write(_mameSaveBuffer);
            writer.Write(Frame);
        }
예제 #28
0
파일: MAME.cs 프로젝트: xy2iii/BizHawk
        /*
         * FrameAdvance() and MAME
         *
         * MAME fires the periodic callback on every video and debugger update,
         * which happens every VBlank and also repeatedly at certain time
         * intervals while paused. Since MAME's luaengine runs in a separate
         * thread, it's only safe to update everything we need per frame during
         * this callback, when it's explicitly waiting for further lua commands.
         *
         * If we disable throttling and pass -update_in_pause, there will be no
         * delay between video updates. This allows to run at full speed while
         * frame-stepping.
         *
         * MAME only captures new frame data once per VBlank, while unpaused.
         * But it doesn't have an exclusive VBlank callback we could attach to.
         * It has a LUA_ON_FRAME_DONE callback, but that fires even more
         * frequently and updates all sorts of other non-video stuff, and we
         * need none of that here.
         *
         * So we filter out all the calls that happen while paused (non-VBlank
         * updates). Then, when Hawk asks us to advance a frame, we virtually
         * unpause and declare the new frame unfinished. This informs MAME that
         * it should advance one frame internally. Hawk starts waiting for the
         * MAME thread to complete the request.
         *
         * After MAME's done advancing, it fires the periodic callback again.
         * That's when we update everything and declare the new frame finished,
         * filtering out any further updates again. Then we allow Hawk to
         * complete frame-advancing.
         */
        private void MAMEPeriodicCallback()
        {
            if (exiting)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Exit);
                exiting = false;
            }

            int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber);

            if (!paused)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Step);
                frameDone = false;
                paused    = true;
            }
            else if (!frameDone)
            {
                Update();
                frameDone = true;
                MAMEFrameComplete.Set();
            }
        }
예제 #29
0
        private void MAMEPeriodicCallback()
        {
            if (_exiting)
            {
                LibMAME.mame_lua_execute(MAMELuaCommand.Exit);
                _exiting = false;
            }

            for (; _memAccess;)
            {
                _mamePeriodicComplete.Set();
                _memoryAccessComplete.WaitOne();

                if (!_frameDone && !_paused || _exiting)                 // FrameAdvance() has been requested
                {
                    _memAccess = false;
                    return;
                }
            }

            //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber);

            if (!_paused)
            {
                SendInput();
                LibMAME.mame_lua_execute(MAMELuaCommand.Step);
                _frameDone = false;
                _paused    = true;
            }
            else if (!_frameDone)
            {
                UpdateVideo();
                _frameDone = true;
                _mameFrameComplete.Set();
            }
        }
예제 #30
0
        public void FetchDefaultGameSettings()
        {
            string DIPSwitchTags = MameGetString(MAMELuaCommand.GetDIPSwitchTags);

            string[] tags = DIPSwitchTags.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string tag in tags)
            {
                string   DIPSwitchFields = MameGetString(MAMELuaCommand.GetDIPSwitchFields(tag));
                string[] fieldNames      = DIPSwitchFields.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string fieldName in fieldNames)
                {
                    DriverSetting setting = new DriverSetting()
                    {
                        Name         = fieldName,
                        GameName     = _gameShortName,
                        LuaCode      = MAMELuaCommand.InputField(tag, fieldName),
                        Type         = SettingType.DIPSWITCH,
                        DefaultValue = LibMAME.mame_lua_get_int(
                            $"return { MAMELuaCommand.InputField(tag, fieldName) }.defvalue").ToString()
                    };

                    string   DIPSwitchOptions = MameGetString(MAMELuaCommand.GetDIPSwitchOptions(tag, fieldName));
                    string[] options          = DIPSwitchOptions.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (string option in options)
                    {
                        string[] opt = option.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries);
                        setting.Options.Add(opt[0], opt[1]);
                    }

                    CurrentDriverSettings.Add(setting);
                }
            }
        }