Fixed the stereo interleave and smoothed the audio generation considerably. master
Fixed the stereo interleave and smoothed the audio generation considerably.

--- a/Jump/Jump.csproj
+++ b/Jump/Jump.csproj
@@ -37,10 +37,10 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
+    <Reference Include="System.Drawing" />
     <Reference Include="OpenTK">
-      <HintPath>..\..\LearningOpenGL\libs\OpenTK.dll</HintPath>
+      <HintPath>..\..\opentk\Binaries\OpenTK\Debug\OpenTK.dll</HintPath>
     </Reference>
-    <Reference Include="System.Drawing" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Program.cs" />

--- a/Jump/Program.cs
+++ b/Jump/Program.cs
@@ -13,8 +13,8 @@
 
 class MainClass {
 	public const ushort COLOR_MASK = 0xF;
-	public const ushort NUM_ROOT_TONES = 12;
-	public const double EFFECT_TONE_DURATION = 0.033d;
+	public const ushort NUM_ROOT_TONES = 13;
+	public const double EFFECT_TONE_DURATION = 0.016d;
 
 	public static ToneSystem TwelveTone = ToneSystem.TwelveTone;
 	public static GameWindow window;
@@ -26,10 +26,24 @@
 	public static Vector3 targetColor;
 
 	public static UInt64 FrameCount = 0;
+	public static UInt64 UpdateCount = 0;
 
-	public static ushort fadeTimeout = 0;
+	public static ushort FaderTimeout = 0;
 
-	public static ushort[] effect_tones = new ushort[] { 0, 2, 4, 5, 7, 9, 11, 12, 11, 9, 7, 5, 4, 2, 0 };
+	public const double HARMONIC_ONE = 1.618033988749895d;
+	public const double HARMONIC_TWO = 2.618033988749895d;
+	public const double HARMONIC_THREE = 4.23606797749979d;
+	public const double HARMONIC_FOUR = 6.854101966249685d;
+
+	// public static ushort[] effect_tones = new ushort[] { 0, 2, 4, 5, 7, 9, 11, 12, 11, 9, 7, 5, 4, 2, 0 };
+	public static ushort[] effect_tones = new ushort[] { 0, 4, 7, 12, 12, 12, 11, 9, 7, 5, 4, 2, 0, 4, 0, 5, 0, 2, 0, 4, 0, 0 };
+
+	public static Harmonic[] effectHarmonics = new Harmonic[] {
+		new Harmonic(HARMONIC_ONE, 2),
+		new Harmonic(HARMONIC_TWO, 4),
+		new Harmonic(HARMONIC_THREE, 8),
+		new Harmonic(HARMONIC_FOUR, 16)
+	};
 
 	public static Dictionary<ushort, short[]> effects = new Dictionary<ushort, short[]>();
 
@@ -41,12 +55,19 @@
 
 			int idx = 0;
 
-			short lastAmp = 0;
+			SineSegment.SamplePoint[] startingAmplitudes = new SineSegment.SamplePoint[effectHarmonics.Length + 1];
 
-			foreach (var tone in effect_tones) {
-				var freq = TwelveTone.Tone(root + tone, 3);
-				short[] note = SineSegment.GetSineSegment(freq, EFFECT_TONE_DURATION, lastAmp);
-				lastAmp = note[note.Length - 1];
+			for (int i = 0; i < startingAmplitudes.Length; i++) {
+				startingAmplitudes[i] = new SineSegment.SamplePoint();
+			}
+
+			ushort tone;
+
+			for (int tIdx = 0; tIdx < effect_tones.Length; tIdx++) {
+				tone = effect_tones[tIdx];
+
+				var freq = TwelveTone.Tone(root + tone, 4);
+				short[] note = SineSegment.GetCompositeSineSegment(freq, EFFECT_TONE_DURATION, short.MaxValue / 2, startingAmplitudes, effectHarmonics);
 
 				if (notes == null) {
 					notes = new short[effect_tones.Length * note.Length];
@@ -56,13 +77,30 @@
 				idx += note.Length;
 			}
 
+			int fadeCount = (int)(EFFECT_TONE_DURATION * Constants.SampleRate) / 10;
+			double fadeStep = 2 / (double)fadeCount;
+			double fade = 1 - fadeStep;
+
+			while (fadeCount > 0)
+			{
+				notes[notes.Length - fadeCount] = (short)((double)(notes[notes.Length - fadeCount]) * fade);
+
+				if (fadeCount % 2 == 0) {
+					fade -= fadeStep;
+				}
+
+				fadeCount--;
+			}
+
 			effects[root] = notes;
 		}
 	}
 
 	public static void FrameUpdate(object sender, FrameEventArgs args) {
+		UpdateCount++;
+
 		if (keyDown != Key.Unknown) {
-			fadeTimeout = 0;
+			FaderTimeout = 0;
 
 			ushort ega = (ushort)((ushort)keyDown & COLOR_MASK);
 
@@ -86,10 +124,11 @@
 			keyDown = Key.Unknown;
 		}
 		else {
-			fadeTimeout++;
+			FaderTimeout++;
 
-			if (fadeTimeout > 300) {
+			if (FaderTimeout > 300) {
 				targetColor = Vector3.Zero;
+				FaderTimeout = 0;
 			}
 		}
 	}

--- a/Jump/SineSegment.cs
+++ b/Jump/SineSegment.cs
@@ -3,31 +3,105 @@
 
 namespace Jump {
 
+public struct Harmonic
+{
+	public double FrequencyMultiplier;
+	public short AmplitudeDivisor;
+
+	public Harmonic(double freqMul, short ampMul) {
+		this.FrequencyMultiplier = freqMul;
+		this.AmplitudeDivisor = ampMul;
+	}
+}
+
 public static class SineSegment {
-	public const double HARMONIC_ONE = 1.618033988749895d;
-	public const double HARMONIC_TWO = 2.618033988749895d;
-	public const double HARMONIC_THREE = 4.23606797749979d;
-	public const double HARMONIC_FOUR = 6.854101966249685d;
+	public struct SamplePoint {
+		public short Amplitude;
+		public sbyte Direction;
+	}
 
-	public static short[] GetSineSegment(double frequency, double duration, short startingAmplitude = 0) {
+	public static short[] GetCompositeSineSegment(double frequency, double duration, short maxAmplitude, SamplePoint[] startingPoints, Harmonic[] add_harmonics) {
+		SamplePoint baseStartAmplitude = startingPoints[0];
+		short[] baseSample = GetStereoSineSegment(frequency, duration, maxAmplitude, ref baseStartAmplitude);
+		startingPoints[0] = baseStartAmplitude;
+
+		if (add_harmonics != null)
+		{
+			short[] harmonicSample;
+			for (int hIdx = 0; hIdx < add_harmonics.Length; hIdx++) {
+				Harmonic harmonic = add_harmonics[hIdx];
+
+				if (harmonic.AmplitudeDivisor == 0) {
+					throw new DivideByZeroException(string.Format(
+							"Invalid Harmonic({0}, {1}): AmplitudeDivisor must be non-zero.",
+							harmonic.FrequencyMultiplier, harmonic.AmplitudeDivisor
+						));
+				}
+
+				short harmonicMaxAmplitude = (short)(maxAmplitude / harmonic.AmplitudeDivisor);
+				SamplePoint harmonicStartAmplitude = startingPoints[1 + hIdx];
+
+				harmonicSample = GetStereoSineSegment(
+					frequency * harmonic.FrequencyMultiplier,
+					duration,
+					harmonicMaxAmplitude,
+					ref harmonicStartAmplitude
+				);
+
+				startingPoints[1 + hIdx] = harmonicStartAmplitude;
+
+				int sIdx = 0;
+
+				while (sIdx < baseSample.Length && sIdx < harmonicSample.Length) {
+					baseSample[sIdx] += harmonicSample[sIdx];
+					sIdx++;
+				}
+			}
+		}
+
+		return baseSample;
+	}
+
+	public static short[] GetStereoSineSegment(double frequency, double duration, short maxAmplitude, ref SamplePoint startingAmplitude) {
 		short[] samples;
 
-		int sampleCount = (int)(duration * Constants.SampleRate);
+		int sampleCount = (int)(duration * Constants.SampleRate)  * 2;
 		samples = new short[sampleCount];
 
-		int startIdx = 0;
+		double startIdx = 0;
 
-		if (startingAmplitude != 0) {
-			double asin = Math.Asin((double)startingAmplitude / (double)short.MaxValue);
-			startIdx = (int)(asin * Constants.SampleRate / Math.PI / frequency);
+		if (startingAmplitude.Amplitude != 0) {
+			double asin = Math.Asin((double)startingAmplitude.Amplitude / (double)maxAmplitude);
+			if (startingAmplitude.Direction < 0) {
+				if (asin >= 0) {
+					asin = Math.PI - asin;
+				}
+				else if (asin < 0) {
+					asin = -Math.PI - asin;
+				}
+			}
+
+			startIdx = asin * (double)Constants.SampleRate / Math.PI / frequency + 1;
 		}
 
-		for (int idx = 0; idx < sampleCount; idx++) {
-			samples[idx] = (short)(Math.Sin(Math.PI * frequency * (idx + startIdx) / Constants.SampleRate) * short.MaxValue / 2);
-			samples[idx] += (short)(Math.Sin(Math.PI * HARMONIC_ONE * frequency * (idx + startIdx) / Constants.SampleRate) * short.MaxValue / 4);
-			samples[idx] += (short)(Math.Sin(Math.PI * HARMONIC_TWO * frequency * (idx + startIdx) / Constants.SampleRate) * short.MaxValue / 8);
-			samples[idx] += (short)(Math.Sin(Math.PI * HARMONIC_THREE * frequency * (idx + startIdx) / Constants.SampleRate) * short.MaxValue / 16);
-			samples[idx] += (short)(Math.Sin(Math.PI * HARMONIC_FOUR * frequency * (idx + startIdx) / Constants.SampleRate) * short.MaxValue / 32);
+		for (int idx = 0; idx < sampleCount; ) {
+			short sample = (short)(Math.Sin(Math.PI * frequency * ((double)idx / 2d + startIdx) / (double)Constants.SampleRate) * (double)maxAmplitude);
+			// Left Side
+			samples[idx++] = sample;
+			// Right Side
+			samples[idx++] = sample;
+		}
+
+		startingAmplitude.Amplitude = samples[samples.Length - 1];
+
+		if (samples[samples.Length - 1] > samples[samples.Length - 3]) {
+			startingAmplitude.Direction = 1;
+		}
+		else if (samples[samples.Length - 1] < samples[samples.Length - 3]) {
+			startingAmplitude.Direction = -1;
+		}
+		else {
+			startingAmplitude.Direction = 0;
 		}
 
 		return samples;

--- a/Jump/TonePlayer.cs
+++ b/Jump/TonePlayer.cs
@@ -20,7 +20,7 @@
 			this.buffer = 0;
 		}
 		this.buffer = AL.GenBuffer();
-		AL.BufferData(this.buffer, ALFormat.Stereo16, audioData, audioData.Length * 2, Constants.SampleRate);
+		AL.BufferData(this.buffer, ALFormat.Stereo16, audioData, audioData.Length * sizeof(short), Constants.SampleRate);
 	}
 
 	public void Stop() {

--- a/Jump/ToneSystem.cs
+++ b/Jump/ToneSystem.cs
@@ -52,13 +52,12 @@
 			octave++;
 		}
 
-		// TODO: Replace Math.Pow with an integer-optimized version.
-
 		int octaveShift = octave - CentralOctave;
 
 		double multiplier;
 
 		if (octaveShift < 0) {
+			// TODO: Replace Math.Pow with an integer-optimized version.
 			multiplier = Math.Pow(2, octaveShift);
 		}
 		else {