]> granicus.if.org Git - handbrake/commitdiff
WinGui: Some in-progress code that I'll pickup later on.
authorsr55 <sr55.hb@outlook.com>
Sun, 7 Jul 2013 15:45:18 +0000 (15:45 +0000)
committersr55 <sr55.hb@outlook.com>
Sun, 7 Jul 2013 15:45:18 +0000 (15:45 +0000)
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5638 b64f7644-9d1e-0410-96f1-a4d463321fa5

win/CS/HandBrakeWPF/Helpers/Macros.cs [new file with mode: 0644]
win/CS/HandBrakeWPF/Helpers/PictureSize.cs [new file with mode: 0644]

diff --git a/win/CS/HandBrakeWPF/Helpers/Macros.cs b/win/CS/HandBrakeWPF/Helpers/Macros.cs
new file mode 100644 (file)
index 0000000..8ea8d11
--- /dev/null
@@ -0,0 +1,101 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="Macros.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   The macros.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Helpers\r
+{\r
+    /// <summary>\r
+    /// The macros.\r
+    /// </summary>\r
+    public class Macros\r
+    {\r
+        /// <summary>\r
+        /// The even.\r
+        /// #define EVEN( a )        ( (a) + ( (a) & 1 ) )\r
+        /// </summary>\r
+        /// <param name="a">\r
+        /// The a.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="bool"/>.\r
+        /// </returns>\r
+        public static bool Even(int a)\r
+        {\r
+            return (a) + ((a) & 1) == 1;\r
+        }\r
+        \r
+        /// <summary>\r
+        /// The multipl e_ mo d_ down.\r
+        /// #define MULTIPLE_MOD_DOWN( a, b ) ((b==1)?a:( b * ( (a) / b ) ))\r
+        /// </summary>\r
+        /// <param name="a">\r
+        /// The a.\r
+        /// </param>\r
+        /// <param name="b">\r
+        /// The b.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="double"/>.\r
+        /// </returns>\r
+        public static int MultipleModDown(int a, int b)\r
+        {\r
+            return (b == 1) ? a : (b * ((a) / b));\r
+        }\r
+\r
+        /// <summary>\r
+        /// The multiple mod up.\r
+        /// #define MULTIPLE_MOD_UP( a, b ) ((b==1)?a:( b * ( ( (a) + (b) - 1) / b ) ))\r
+        /// </summary>\r
+        /// <param name="a">\r
+        /// The a.\r
+        /// </param>\r
+        /// <param name="b">\r
+        /// The b.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="double"/>.\r
+        /// </returns>\r
+        public static int MultipleModUp(int a, int b)\r
+        {\r
+            return (b == 1) ? a : (b * (((a) + (b) - 1) / b));\r
+        }\r
+\r
+        /// <summary>\r
+        /// The multiple of mod x\r
+        /// #define MULTIPLE_MOD( a, b ) ((b==1)?a:( b * ( ( (a) + (b / 2) - 1) / b ) ))\r
+        /// </summary>\r
+        /// <param name="a">\r
+        /// The a.\r
+        /// </param>\r
+        /// <param name="b">\r
+        /// The b.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="double"/>.\r
+        /// </returns>\r
+        public static int MultipleMod(int a, int b)\r
+        {\r
+            return (b == 1) ? a : (b * (((a) + (b / 2) - 1) / b));\r
+        }\r
+\r
+        /// <summary>\r
+        /// The multiple of 16.\r
+        /// #define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) )\r
+        /// </summary>\r
+        /// <param name="a">\r
+        /// The a.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="bool"/>.\r
+        /// </returns>\r
+        public static bool Multiple16(int a)\r
+        {\r
+            return 16 * (((a) + 8) / 16) == 1;\r
+        }\r
+    }\r
+}\r
diff --git a/win/CS/HandBrakeWPF/Helpers/PictureSize.cs b/win/CS/HandBrakeWPF/Helpers/PictureSize.cs
new file mode 100644 (file)
index 0000000..d4cbd2e
--- /dev/null
@@ -0,0 +1,582 @@
+// --------------------------------------------------------------------------------------------------------------------\r
+// <copyright file="PictureSize.cs" company="HandBrake Project (http://handbrake.fr)">\r
+//   This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.\r
+// </copyright>\r
+// <summary>\r
+//   Defines the PictureSize type.\r
+// </summary>\r
+// --------------------------------------------------------------------------------------------------------------------\r
+\r
+namespace HandBrakeWPF.Helpers\r
+{\r
+    using System;\r
+    using System.Runtime.InteropServices;\r
+\r
+    using HandBrake.Interop.HbLib;\r
+    using HandBrake.Interop.Model;\r
+    using HandBrake.Interop.Model.Encoding;\r
+\r
+    /// <summary>\r
+    /// The picture size Helpers\r
+    /// </summary>\r
+    public class PictureSize\r
+    {\r
+        /// <summary>\r
+        /// The picture settings job.\r
+        /// </summary>\r
+        public class PictureSettingsJob\r
+        {\r
+            /// <summary>\r
+            /// Gets or sets the crop.\r
+            /// </summary>\r
+            public Cropping Crop { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the modulus.\r
+            /// </summary>\r
+            public int? Modulus { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the par w.\r
+            /// </summary>\r
+            public int ParW { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the par h.\r
+            /// </summary>\r
+            public int ParH { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets a value indicating whether itu par.\r
+            /// </summary>\r
+            public bool ItuPar { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the width.\r
+            /// </summary>\r
+            public int Width { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the height.\r
+            /// </summary>\r
+            public int Height { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the anamorphic mode.\r
+            /// </summary>\r
+            public Anamorphic AnamorphicMode { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the max width.\r
+            /// </summary>\r
+            public int MaxWidth { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the max height.\r
+            /// </summary>\r
+            public int MaxHeight { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets a value indicating whether keep display aspect.\r
+            /// </summary>\r
+            public bool KeepDisplayAspect { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the dar width.\r
+            /// </summary>\r
+            public int DarWidth { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the dar height.\r
+            /// </summary>\r
+            public int DarHeight { get; set; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// The picture settings title.\r
+        /// </summary>\r
+        public class PictureSettingsTitle\r
+        {\r
+            /// <summary>\r
+            /// Gets or sets the width.\r
+            /// </summary>\r
+            public int Width { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the height.\r
+            /// </summary>\r
+            public int Height { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the par w.\r
+            /// </summary>\r
+            public int ParW { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the par h.\r
+            /// </summary>\r
+            public int ParH { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the aspect.\r
+            /// </summary>\r
+            public double Aspect { get; set; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// The anamorphic result.\r
+        /// </summary>\r
+        public class AnamorphicResult\r
+        {\r
+            /// <summary>\r
+            /// Gets or sets the output width.\r
+            /// </summary>\r
+            public int OutputWidth { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the output height.\r
+            /// </summary>\r
+            public double OutputHeight { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the output par width.\r
+            /// </summary>\r
+            public double OutputParWidth { get; set; }\r
+\r
+            /// <summary>\r
+            /// Gets or sets the output par height.\r
+            /// </summary>\r
+            public double OutputParHeight { get; set; }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Calculates job width and height for anamorphic content,\r
+        /// * @param output_width Pointer to returned storage width\r
+        /// * @param output_height Pointer to returned storage height\r
+        /// * @param output_par_width Pointer to returned pixel width\r
+        /// * @param output_par_height Pointer to returned pixel height\r
+        /// </summary>\r
+        /// <param name="job">\r
+        /// The job.\r
+        /// </param>\r
+        /// <param name="title">\r
+        /// The title.\r
+        /// </param>\r
+        /// <param name="output_width">\r
+        /// The output_width.\r
+        /// </param>\r
+        /// <param name="output_height">\r
+        /// The output_height.\r
+        /// </param>\r
+        /// <param name="output_par_width">\r
+        /// The output_par_width.\r
+        /// </param>\r
+        /// <param name="output_par_height">\r
+        /// The output_par_height.\r
+        /// </param>\r
+        public static void hb_set_anamorphic_size(PictureSettingsJob job, PictureSettingsTitle title,\r
+                 out int output_width, out int output_height,\r
+                 out int output_par_width, out int output_par_height)\r
+        {\r
+            /* Initialise the Output Width / Height */\r
+            output_width = 0;\r
+            output_height = 0;\r
+\r
+            /* Set up some variables to make the math easier to follow. */\r
+            int cropped_width = title.Width - job.Crop.Left - job.Crop.Right;\r
+            int cropped_height = title.Height - job.Crop.Top - job.Crop.Bottom;\r
+            double storage_aspect = cropped_width / (double)cropped_height;\r
+            int mod = job.Modulus.HasValue ? job.Modulus.Value : 16;\r
+            double aspect = title.Aspect;\r
+\r
+            long pixel_aspect_width = job.ParW;\r
+            long pixel_aspect_height = job.ParH;\r
+\r
+            /* If a source was really NTSC or PAL and the user specified ITU PAR
+               values, replace the standard PAR values with the ITU broadcast ones. */\r
+            if (title.Width == 720 && job.ItuPar)\r
+            {\r
+                // convert aspect to a scaled integer so we can test for 16:9 & 4:3\r
+                // aspect ratios ignoring insignificant differences in the LSBs of\r
+                // the floating point representation.\r
+                int iaspect = (int)Math.Round(aspect * 9.0, 0);  // int iaspect = aspect * 9.; TODO CHECK THIS\r
+\r
+                /* Handle ITU PARs */\r
+                if (title.Height == 480)\r
+                {\r
+                    /* It's NTSC */\r
+                    if (iaspect == 16)\r
+                    {\r
+                        /* It's widescreen */\r
+                        pixel_aspect_width = 40;\r
+                        pixel_aspect_height = 33;\r
+                    }\r
+                    else if (iaspect == 12)\r
+                    {\r
+                        /* It's 4:3 */\r
+                        pixel_aspect_width = 10;\r
+                        pixel_aspect_height = 11;\r
+                    }\r
+                }\r
+                else if (title.Height == 576)\r
+                {\r
+                    /* It's PAL */\r
+                    if (iaspect == 16)\r
+                    {\r
+                        /* It's widescreen */\r
+                        pixel_aspect_width = 16;\r
+                        pixel_aspect_height = 11;\r
+                    }\r
+                    else if (iaspect == 12)\r
+                    {\r
+                        /* It's 4:3 */\r
+                        pixel_aspect_width = 12;\r
+                        pixel_aspect_height = 11;\r
+                    }\r
+                }\r
+            }\r
+\r
+            /* Figure out what width the source would display at. */\r
+            int source_display_width = (int)(cropped_width * (double)pixel_aspect_width / (double)pixel_aspect_height);    // TODO Check casting\r
+\r
+            /*
+               3 different ways of deciding output dimensions:
+                - 1: Strict anamorphic, preserve source dimensions
+                - 2: Loose anamorphic, round to mod16 and preserve storage aspect ratio
+                - 3: Power user anamorphic, specify everything
+            */\r
+            int width, height;\r
+            int maxWidth, maxHeight;\r
+\r
+            maxWidth = Macros.MultipleModDown(job.MaxWidth, mod);\r
+            maxHeight = Macros.MultipleModDown(job.MaxHeight, mod);\r
+\r
+            switch (job.AnamorphicMode)\r
+            {\r
+                case Anamorphic.Strict:\r
+                    /* Strict anamorphic */\r
+                    output_width = Macros.MultipleMod(cropped_width, 2);\r
+                    output_height = Macros.MultipleMod(cropped_height, 2);\r
+                    // adjust the source PAR for new width/height\r
+                    // new PAR = source PAR * ( old width / new_width ) * ( new_height / old_height )\r
+                    pixel_aspect_width = (long)title.ParW * cropped_width * (output_height);\r
+                    pixel_aspect_height = (long)title.ParH * (output_width) * cropped_height;\r
+                    break;\r
+\r
+                case Anamorphic.Loose:\r
+                    /* "Loose" anamorphic.
+                        - Uses mod16-compliant dimensions,
+                        - Allows users to set the width
+                    */\r
+                    width = job.Width;\r
+                    // height: Gets set later, ignore user job->height value\r
+\r
+                    /* Gotta handle bounding dimensions.
+                       If the width is too big, just reset it with no rescaling.
+                       Instead of using the aspect-scaled job height,
+                       we need to see if the job width divided by the storage aspect
+                       is bigger than the max. If so, set it to the max (this is sloppy).
+                       If not, set job height to job width divided by storage aspect.
+                    */\r
+\r
+                    /* Time to get picture width that divide cleanly.*/\r
+                    width = Macros.MultipleMod(width, mod);\r
+\r
+                    if (maxWidth != 0 && (maxWidth < job.Width))\r
+                        width = maxWidth;\r
+\r
+                    /* Verify these new dimensions don't violate max height and width settings */\r
+                    height = (int)Math.Round(((double)width / storage_aspect) + 0.5, 0);  // TODO Check Casting and rounding\r
+\r
+                    /* Time to get picture height that divide cleanly.*/\r
+                    height = Macros.MultipleMod(height, mod);\r
+\r
+                    if (maxHeight != 0 && (maxHeight < height))\r
+                    {\r
+                        height = maxHeight;\r
+                        width = (int)Math.Round(((double)height * storage_aspect) + 0.5, 0); // TODO Check asting and arounding.\r
+                        width = Macros.MultipleMod(width, mod);\r
+                    }\r
+\r
+                    /* The film AR is the source's display width / cropped source height.
+                       The output display width is the output height * film AR.
+                       The output PAR is the output display width / output storage width. */\r
+                    pixel_aspect_width = (long)height * cropped_width * pixel_aspect_width;\r
+                    pixel_aspect_height = (long)width * cropped_height * pixel_aspect_height;\r
+\r
+                    /* Pass the results back to the caller */\r
+                    output_width = width;\r
+                    output_height = height;\r
+                    break;\r
+\r
+                case Anamorphic.Custom:\r
+                    /* Anamorphic 3: Power User Jamboree
+                       - Set everything based on specified values */\r
+\r
+                    /* Use specified storage dimensions */\r
+                    storage_aspect = job.Width / (double)job.Height;\r
+                    width = job.Width;\r
+                    height = job.Height;\r
+\r
+                    /* Time to get picture dimensions that divide cleanly.*/\r
+                    width = Macros.MultipleMod(width, mod);\r
+                    height = Macros.MultipleMod(height, mod);\r
+\r
+                    /* Bind to max dimensions */\r
+                    if (maxWidth != 0 && width > maxWidth)\r
+                    {\r
+                        width = maxWidth;\r
+                        // If we are keeping the display aspect, then we are going\r
+                        // to be modifying the PAR anyway.  So it's preferred\r
+                        // to let the width/height stray some from the original\r
+                        // requested storage aspect.\r
+                        //\r
+                        // But otherwise, PAR and DAR will change the least\r
+                        // if we stay as close as possible to the requested\r
+                        // storage aspect.\r
+                        if (!job.KeepDisplayAspect)\r
+                        {\r
+                            height = (int)Math.Round(((double)width / storage_aspect) + 0.5, 0); // TODO Check rounding and casting\r
+                            height = Macros.MultipleMod(height, mod);\r
+                        }\r
+                    }\r
+                    if (maxHeight != 0 && height > maxHeight)\r
+                    {\r
+                        height = maxHeight;\r
+                        // Ditto, see comment above\r
+                        if (!job.KeepDisplayAspect)\r
+                        {\r
+                            width = (int)Math.Round(((double)height * storage_aspect) + 0.5, 0); // TODO check Rounding and casting\r
+                            width = Macros.MultipleMod(width, mod);\r
+                        }\r
+                    }\r
+\r
+                    /* That finishes the storage dimensions. On to display. */\r
+                    if (job.DarWidth != 0 && job.DarHeight != 0)\r
+                    {\r
+                        /* We need to adjust the PAR to produce this aspect. */\r
+                        pixel_aspect_width = (long)height * job.DarWidth / job.DarHeight;\r
+                        pixel_aspect_height = width;\r
+                    }\r
+                    else\r
+                    {\r
+                        /* If we're doing ana 3 and not specifying a DAR, care needs to be taken.
+                           This indicates a PAR is potentially being set by the interface. But
+                           this is an output PAR, to correct a source, and it should not be assumed
+                           that it properly creates a display aspect ratio when applied to the source,
+                           which could easily be stored in a different resolution. */\r
+                        if (job.KeepDisplayAspect)\r
+                        {\r
+                            /* We can ignore the possibility of a PAR change */\r
+                            pixel_aspect_width = (int)Math.Round((long)height * ((double)source_display_width / (double)cropped_height), 0); // TODO Check rounding and casting\r
+                            pixel_aspect_height = width;\r
+                        }\r
+                        else\r
+                        {\r
+                            int output_display_width = (int)Math.Round(width * (double)pixel_aspect_width / (double)pixel_aspect_height, 0); // TODO Check rounding and casting.\r
+                            pixel_aspect_width = output_display_width;\r
+                            pixel_aspect_height = width;\r
+                        }\r
+                    }\r
+\r
+                    /* Back to caller */\r
+                    output_width = width;\r
+                    output_height = height;\r
+                    break;\r
+            }\r
+\r
+            /* While x264 is smart enough to reduce fractions on its own, libavcodec
+             * needs some help with the math, so lose superfluous factors. */\r
+            hb_limit_rational64(out pixel_aspect_width, out pixel_aspect_height,\r
+                                pixel_aspect_width, pixel_aspect_height, 65535);\r
+            hb_reduce(out output_par_width, out output_par_height,\r
+                       (int)pixel_aspect_width, (int)pixel_aspect_height);\r
+        }\r
+\r
+        /// <summary>\r
+        /// The hb_set_anamorphic_size_native.\r
+        /// </summary>\r
+        /// <param name="job">\r
+        /// The job.\r
+        /// </param>\r
+        /// <param name="title">\r
+        /// The title.\r
+        /// </param>\r
+        /// <returns>\r
+        /// The <see cref="AnamorphicResult"/> object.\r
+        /// </returns>\r
+        public static AnamorphicResult hb_set_anamorphic_size_native(PictureSettingsJob job, PictureSettingsTitle title)\r
+        {\r
+            int outputHeight = 0;\r
+            int outputParHeight = 0;\r
+            int outputParWidth = 0;\r
+            int outputWidth = 0;\r
+\r
+            hb_job_s nativeJob = new hb_job_s\r
+                                     {\r
+                                         modulus = job.Modulus.HasValue ? job.Modulus.Value : 16,\r
+                                         anamorphic =\r
+                                             new hb_anamorphic_substruct\r
+                                                 {\r
+                                                     par_width = job.ParW,\r
+                                                     par_height = job.ParH,\r
+                                                     itu_par = 0,\r
+                                                     mode = (int)job.AnamorphicMode,\r
+                                                     dar_width = 0,\r
+                                                     dar_height = 0,\r
+                                                     keep_display_aspect = job.KeepDisplayAspect ? 1 : 0\r
+                                                 },\r
+                                         maxWidth = title.Width,\r
+                                         maxHeight = title.Height,\r
+                                         keep_ratio = job.KeepDisplayAspect ? 1 : 0,\r
+                                         width = job.Width,\r
+                                         height = job.Height,\r
+                                         crop = new[] { job.Crop.Top, job.Crop.Bottom, job.Crop.Left, job.Crop.Right }\r
+                                     };\r
+\r
+            hb_title_s title_s = new hb_title_s\r
+                                     {\r
+                                         crop = new[] { job.Crop.Top, job.Crop.Bottom, job.Crop.Left, job.Crop.Right },\r
+                                         width = title.Width,\r
+                                         height = title.Height,\r
+                                         pixel_aspect_width = title.ParW,\r
+                                         pixel_aspect_height = title.ParH,\r
+                                         aspect = 0\r
+                                     };\r
+\r
+            IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(hb_title_s)));\r
+            Marshal.StructureToPtr(title_s, pointer, false);\r
+            nativeJob.title = pointer;\r
+\r
+            HBFunctions.hb_set_anamorphic_size(\r
+                ref nativeJob, ref outputWidth, ref outputHeight, ref outputParWidth, ref outputParHeight);\r
+\r
+            return new AnamorphicResult { OutputWidth = outputWidth, OutputHeight = outputHeight, OutputParWidth = outputParWidth, OutputParHeight = outputParHeight };\r
+        }\r
+\r
+        /// <summary>\r
+        /// The hb_limit_rational 64.\r
+        /// </summary>\r
+        /// <param name="x">\r
+        /// The x.\r
+        /// </param>\r
+        /// <param name="y">\r
+        /// The y.\r
+        /// </param>\r
+        /// <param name="num">\r
+        /// The num.\r
+        /// </param>\r
+        /// <param name="den">\r
+        /// The den.\r
+        /// </param>\r
+        /// <param name="limit">\r
+        /// The limit.\r
+        /// </param>\r
+        private static void hb_limit_rational64(out long x, out long y, long num, long den, long limit)\r
+        {\r
+            hb_reduce64(out num, out den, num, den);\r
+            if (num < limit && den < limit)\r
+            {\r
+                x = num;\r
+                y = den;\r
+                return;\r
+            }\r
+\r
+            if (num > den)\r
+            {\r
+                double div = (double)limit / num;\r
+                num = limit;\r
+                den *= (int)Math.Round(div, 0); // TODO Check cast and rounding.\r
+            }\r
+            else\r
+            {\r
+                double div = (double)limit / den;\r
+                den = limit;\r
+                num *= (int)Math.Round(div, 0); // TODO Check cast and rounding.\r
+            }\r
+\r
+            x = num;\r
+            y = den;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Given a numerator (num) and a denominator (den), reduce them to an\r
+        /// equivalent fraction and store the result in x and y.\r
+        /// </summary>\r
+        /// <param name="x">\r
+        /// The x.\r
+        /// </param>\r
+        /// <param name="y">\r
+        /// The y.\r
+        /// </param>\r
+        /// <param name="num">\r
+        /// The num.\r
+        /// </param>\r
+        /// <param name="den">\r
+        /// The den.\r
+        /// </param>\r
+        private static void hb_reduce64(out long x, out long y, long num, long den)\r
+        {\r
+            // find the greatest common divisor of num & den by Euclid's algorithm\r
+            long n = num, d = den;\r
+            while (d != 0)\r
+            {\r
+                long t = d;\r
+                d = n % d;\r
+                n = t;\r
+            }\r
+\r
+            // at this point n is the gcd. if it's non-zero remove it from num\r
+            // and den. Otherwise just return the original values.\r
+            if (n != 0)\r
+            {\r
+                num /= n;\r
+                den /= n;\r
+            }\r
+\r
+            x = num;\r
+            y = den;\r
+        }\r
+\r
+        /// <summary>\r
+        /// Given a numerator (num) and a denominator (den), reduce them to an\r
+        /// equivalent fraction and store the result in x and y.\r
+        /// </summary>\r
+        /// <param name="x">\r
+        /// The x.\r
+        /// </param>\r
+        /// <param name="y">\r
+        /// The y.\r
+        /// </param>\r
+        /// <param name="num">\r
+        /// The num.\r
+        /// </param>\r
+        /// <param name="den">\r
+        /// The den.\r
+        /// </param>\r
+        private static void hb_reduce(out int x, out int y, int num, int den)\r
+        {\r
+            // find the greatest common divisor of num & den by Euclid's algorithm\r
+            int n = num, d = den;\r
+            while (d != 0)\r
+            {\r
+                int t = d;\r
+                d = n % d;\r
+                n = t;\r
+            }\r
+\r
+            // at this point n is the gcd. if it's non-zero remove it from num\r
+            // and den. Otherwise just return the original values.\r
+            if (n != 0)\r
+            {\r
+                x = num / n;\r
+                y = den / n;\r
+            }\r
+            else\r
+            {\r
+                x = num;\r
+                y = den;\r
+            }\r
+        }\r
+    }\r
+}\r