コード例 #1
0
        public void Dispose()
        {
            if (!Links.Contains(this))
            {
                return;
            }

            Links.Remove(this);
            if (Links.Count > 0)
            {
                return;
            }

            // Last link - dispose.
            h_GBSIOInit.Undo();
            h_GBSIOInit.Free();
            h_GBSIOInit = null;

            h_GBSIODeinit.Undo();
            h_GBSIODeinit.Free();
            h_GBSIODeinit = null;

            h_mTimingInit.Undo();
            h_mTimingInit.Free();
            h_mTimingInit = null;

            h_mCoreConfigLoadDefaults.Undo();
            h_mCoreConfigLoadDefaults.Free();
            h_mCoreConfigLoadDefaults = null;

            h_mSDLAttachPlayer.Undo();
            h_mSDLAttachPlayer.Free();
            h_mSDLAttachPlayer = null;

            Timing = (mTiming *)IntPtr.Zero;
            SIO    = (GBSIO *)IntPtr.Zero;

            Marshal.FreeHGlobal((IntPtr)Driver);
            Driver = (GBSIODriver *)IntPtr.Zero;

            Marshal.FreeHGlobal((IntPtr)QueueCheckEvent->name);
            Marshal.FreeHGlobal((IntPtr)QueueCheckEvent);
            QueueCheckEvent = (mTimingEvent *)IntPtr.Zero;
        }
コード例 #2
0
        private static byte DriverWriteSC(GBSIODriver *driver, byte value)
        {
            // 0x80: Transfer enabled
            // 0x01: Shift Clock, must be "external" (0)
            if ((value & 0x80) == 0x80 && (value & 0x01) != 0x01)
            {
                // Game waiting for transfer from outside - dequeue or kick off QueueCheck loop.
                if (!Dequeue())
                {
                    // We haven't dequeued anything - schedule QueueCheck.
                    mTimingSchedule(Timing, QueueCheckEvent, SyncWait);
                }
            }
            else
            {
                // Unexpected SC
                Console.WriteLine($"DRIVR SC 0x{value.ToString("X2")}");
            }

            // Note: Value currently unused by GBSIOWriteSC, but python binding returns input.
            return(value);
        }
コード例 #3
0
        public MGBALink()
        {
            if (Links.Count == 0)
            {
                // First link - setup.

                IntPtr libmgba    = DynamicDll.OpenLibrary("libmgba.dll");
                IntPtr libmgbasdl = DynamicDll.OpenLibrary("libmgba-sdl.dll");

                // Hook GBSIOInit to grab a reference to GBSIO.
                h_GBSIOInit = new NativeDetour(
                    libmgba.GetFunction("GBSIOInit"),
                    typeof(MGBALink).GetMethod("GBSIOInit", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_GBSIOInit = h_GBSIOInit.GenerateTrampoline <d_GBSIOInit>();

                // Hook GBSIODeinit to properly dispose everything.
                h_GBSIODeinit = new NativeDetour(
                    libmgba.GetFunction("GBSIODeinit"),
                    typeof(MGBALink).GetMethod("GBSIODeinit", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_GBSIODeinit = h_GBSIODeinit.GenerateTrampoline <d_GBSIODeinit>();

                // Hook mTimingInit (called via non-exported GBInit) to set up any timing-related stuff and the driver.
                h_mTimingInit = new NativeDetour(
                    libmgba.GetFunction("mTimingInit"),
                    typeof(MGBALink).GetMethod("mTimingInit", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_mTimingInit = h_mTimingInit.GenerateTrampoline <d_mTimingInit>();

                // Hook mCoreConfigLoadDefaults to change the configs before loading them.
                h_mCoreConfigLoadDefaults = new NativeDetour(
                    libmgba.GetFunction("mCoreConfigLoadDefaults"),
                    typeof(MGBALink).GetMethod("mCoreConfigLoadDefaults", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_mCoreConfigLoadDefaults = h_mCoreConfigLoadDefaults.GenerateTrampoline <d_mCoreConfigLoadDefaults>();

                // Hook mSDLAttachPlayer to hook the renderer's runloop.
                // This is required to fix any managed runtime <-> unmanaged state bugs.
                h_mSDLAttachPlayer = new NativeDetour(
                    libmgbasdl.GetFunction("mSDLAttachPlayer"),
                    typeof(MGBALink).GetMethod("mSDLAttachPlayer", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_mSDLAttachPlayer = h_mSDLAttachPlayer.GenerateTrampoline <d_mSDLAttachPlayer>();

                // Hook mSDLInitAudio to force our own sample rate.
                h_mSDLInitAudio = new NativeDetour(
                    libmgbasdl.GetFunction("mSDLInitAudio"),
                    typeof(MGBALink).GetMethod("mSDLInitAudio", BindingFlags.NonPublic | BindingFlags.Static)
                    );
                orig_mSDLInitAudio = h_mSDLInitAudio.GenerateTrampoline <d_mSDLInitAudio>();

                // Setup the custom GBSIODriver, responsible for syncing dequeues.
                Driver = (GBSIODriver *)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(GBSIODriver)));
                // Slow but functional zeroing.
                for (int i = 0; i < sizeof(mTimingEvent); i++)
                {
                    Driver->p = (GBSIO *)IntPtr.Zero;
                }
                Driver->init    = PinnedPtr <GBSIODriver.d_init>(DriverInit);
                Driver->deinit  = PinnedPtr <GBSIODriver.d_deinit>(DriverDeinit);
                Driver->writeSB = PinnedPtr <GBSIODriver.d_writeSB>(DriverWriteSB);
                Driver->writeSC = PinnedPtr <GBSIODriver.d_writeSC>(DriverWriteSC);

                // Setup the queue check event.
                QueueCheckEvent = (mTimingEvent *)Marshal.AllocHGlobal(sizeof(mTimingEvent));
                // Slow but functional zeroing.
                for (int i = 0; i < sizeof(mTimingEvent); i++)
                {
                    *((byte *)((IntPtr)QueueCheckEvent + i)) = 0x00;
                }
                QueueCheckEvent->context  = (void *)IntPtr.Zero;
                QueueCheckEvent->name     = (byte *)Marshal.StringToHGlobalAnsi("MidiToGBG Queue Check");
                QueueCheckEvent->callback = PinnedPtr <mTimingEvent.d_callback>(QueueCheck);
                QueueCheckEvent->priority = 0x30;
            }

            Links.Add(this);
        }
コード例 #4
0
 private static void DriverWriteSB(GBSIODriver *driver, byte value)
 {
     Console.WriteLine($"DRIVR SB 0x{value.ToString("X2")}");
 }
コード例 #5
0
 private static void DriverDeinit(GBSIODriver *driver)
 {
     Console.WriteLine("DRIVR -");
 }
コード例 #6
0
 private static bool DriverInit(GBSIODriver *driver)
 {
     Console.WriteLine("DRIVR +");
     return(true);
 }
コード例 #7
0
 public static void GBSIOSetDriver(GBSIO *sio, GBSIODriver *driver) => INTERNAL_GBSIOSetDriver((IntPtr)sio, (IntPtr)driver);