Example #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;
        }
Example #2
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);
        }
Example #3
0
 public static void mTimingDeschedule(mTiming *timing, mTimingEvent * @event) => INTERNAL_mTimingDeschedule((IntPtr)timing, (IntPtr)@event);
Example #4
0
 public static bool mTimingIsScheduled(mTiming *timing, mTimingEvent * @event) => INTERNAL_mTimingIsScheduled((IntPtr)timing, (IntPtr)@event);
Example #5
0
 public static void mTimingSchedule(mTiming *timing, mTimingEvent * @event, int when) => INTERNAL_mTimingSchedule((IntPtr)timing, (IntPtr)@event, when);