Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using Microsoft.Xna.Framework;
- namespace Power
- {
- /// <summary>
- /// Represents an XACT RPC curve.
- /// </summary>
- public class RPCCurve
- {
- // X and Y represents X and Y coordinates, Z represents the curve type
- List<Vector3> points = new List<Vector3>();
- public RPCCurve()
- {
- }
- public RPCCurve(params Vector3[] points)
- {
- for (int i = 0; i < points.Length; i++)
- AddPoint(points[i].X, points[i].Y, (int)points[i].Z);
- }
- /*
- In a .xap file (the XACT project file) an RPC curve is represented as as bunch of RPC points with something that looks like this:
- RPC Point
- {
- X = 1200.000000;
- Y = -200.000000;
- Curve = 3;
- }
- The integer for Curve desginates with of the 4 curve functions to use for this point to the next point.
- 0 is linear, 1 is fast, 2 is slow, 3 is Sin/Cos (the same order they appear in the drop down in the XACT RPC Curve GUI).
- You can also rip these values directly from the XACT RPC Curve GUI.
- X corresponds to the variable, Y corresponds to the parameter, curve is as described above
- Just drop those values straight into this function to add a point to this RPC curve.
- */
- public void AddPoint(float x, float y, int curve)
- {
- points.Add(new Vector3(x, y, curve));
- points.Sort(PointSorter);
- }
- // Makes sure the points are sorted correctly
- int PointSorter(Vector3 left, Vector3 right)
- {
- return left.X.CompareTo(right.X);
- }
- // gets the y value based on the given X position of the curve
- public float GetY(float xPosition)
- {
- if (xPosition <= points[0].X)
- return points[0].Y;
- if (xPosition >= points[points.Count - 1].X)
- return points[points.Count - 1].Y;
- // loop over the points to find where this xPosition is contained between
- for (int i = 0; i < points.Count - 1; i++)
- {
- if (xPosition < points[i].X || xPosition >= points[i + 1].X)
- continue;
- Vector2 p0 = new Vector2(points[i].X, points[i].Y);
- Vector2 p1 = new Vector2(points[i + 1].X, points[i + 1].Y);
- int curve = (int)points[i].Z;
- switch (curve)
- {
- // Linear interpolation. from wikipedia linear interpolation
- case 0 :
- return p0.Y + (xPosition - p0.X) * ((p1.Y - p0.Y) / (p1.X - p0.X));
- // Fast interpolation, x^2 with parabola apex at p1. from Kazooie, equation in gmail and DC logs
- case 1 :
- return (p0.Y - p1.Y) / (float)Math.Pow(p0.X - p1.X,2) * (float)Math.Pow(xPosition - p1.X, 2) + p1.Y;
- // Slow interpolation, x^2 with parabola apex at p0. from Kazooie, equation in gmail and DC logs
- case 2 :
- return (p1.Y - p0.Y) / (float)Math.Pow(p1.X - p0.X,2) * (float)Math.Pow(xPosition - p0.X, 2) + p0.Y;
- // Sin/Cos interpolation. Actually just a quarter of an ellipse and doesn't use sin or cos at all. From Kazooie, equation in gmail and DC logs
- case 3 :
- // swap the points around as required by the function
- if (p0.Y > p1.Y)
- {
- Vector2 temp = p0;
- p0 = p1;
- p1 = temp;
- }
- return p0.Y + (p1.Y - p0.Y) * (float)Math.Sqrt((1 - (float)Math.Pow(xPosition - p1.X, 2) / (float)Math.Pow(p1.X - p0.X, 2)));
- // Logarithmic interpolation. Not in XACT, but it's here as a bonus. From Kazooie, equation in gmail and DC logs
- case 4:
- float factor1 = 1f;
- float yAdd1 = p0.Y;
- // swap the points around as required by the function
- if (p0.Y > p1.Y)
- {
- yAdd1 = p0.Y;
- factor1 = -1;
- float kemp2 = p0.Y;
- p0.Y = p1.Y;
- p1.Y = kemp2;
- }
- return factor1 * (float)Math.Log(xPosition - p0.X + 1, (float)Math.Exp((float)Math.Log(p1.X - p0.X) / (p1.Y - p0.Y))) + yAdd1;
- // Exponential interpolation. Not in XACT, but it's here as a bonus. From Kazooie, equation in gmail and DC logs
- case 5:
- float factor2 = 1f;
- float yAdd2 = p0.Y - 1;
- // swap the points around as required by the function
- if (p0.Y > p1.Y)
- {
- factor2 = -1;
- yAdd2 = p0.Y + 1;
- float kemp2 = p0.Y;
- p0.Y = p1.Y;
- p1.Y = kemp2;
- }
- return factor2 * (float)Math.Pow((float)Math.Exp((float)Math.Log(p1.Y - p0.Y + 1) / (p1.X - p0.X)), xPosition - p0.X) + yAdd2;
- default :
- throw new Exception("Curve value not valid for point: " + curve);
- }
- }
- throw new Exception("RPC curve error, didn't find xPosition on curve: " + xPosition);
- }
- }
- /// <summary>
- /// Provides static functions to convert XACT values to SoundEffect values
- /// </summary>
- public class XACTToSEConverter
- {
- // converts XACT db levels (-96db to 6db) to SoundEffect volume levels (0 to 1)
- public static float XACTVolumeToSoundEffectVolume(float xactVolume)
- {
- // How was this calculated? I ran the XACT cue at a known db and a SoundEffect at a known volume
- // I then matched the two up using Audacity to work out when the two sounds were playing at the same volume
- // I then graphed a ton of these values and solved the equation in a stats program
- // it took a long, long time to get this function, so enjoy it!
- return 0.98320878f * (float)Math.Exp(0.11532328f * xactVolume);
- }
- // converts XACT pitch levels (-12 to 12) to SoundEffect pitch levels (-1 to 1)
- public static float XACTPitchToSoundEffectPitch(float xactPitch)
- {
- // XACT does pitch in semi-tones, SoundEffect does it in octaves for some arbitrary reason
- // there are 12 semi-tones in an octave, hence the simple conversion.
- return xactPitch / 12f;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement