Initial commit
Initial commit

file:b/Jump.sln (new)
--- /dev/null
+++ b/Jump.sln
@@ -1,1 +1,53 @@
+

+Microsoft Visual Studio Solution File, Format Version 12.00

+# Visual Studio 2012

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jump", "Jump\Jump.csproj", "{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|x86 = Debug|x86

+		Release|x86 = Release|x86

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}.Debug|x86.ActiveCfg = Debug|x86

+		{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}.Debug|x86.Build.0 = Debug|x86

+		{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}.Release|x86.ActiveCfg = Release|x86

+		{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}.Release|x86.Build.0 = Release|x86

+	EndGlobalSection

+	GlobalSection(MonoDevelopProperties) = preSolution

+		Policies = $0

+		$0.TextStylePolicy = $1

+		$1.inheritsSet = null

+		$1.scope = text/x-csharp

+		$0.CSharpFormattingPolicy = $2

+		$2.IndentNamespaceBody = False

+		$2.IndentSwitchBody = True

+		$2.IndentBlocksInsideExpressions = True

+		$2.NamespaceBraceStyle = EndOfLine

+		$2.ClassBraceStyle = EndOfLine

+		$2.InterfaceBraceStyle = EndOfLine

+		$2.StructBraceStyle = EndOfLine

+		$2.EnumBraceStyle = EndOfLine

+		$2.MethodBraceStyle = EndOfLine

+		$2.ConstructorBraceStyle = EndOfLine

+		$2.DestructorBraceStyle = EndOfLine

+		$2.ElseNewLinePlacement = NewLine

+		$2.CatchNewLinePlacement = NewLine

+		$2.FinallyNewLinePlacement = NewLine

+		$2.WhileNewLinePlacement = NewLine

+		$2.BeforeMethodDeclarationParentheses = False

+		$2.BeforeMethodCallParentheses = False

+		$2.BeforeConstructorDeclarationParentheses = False

+		$2.BeforeIndexerDeclarationBracket = False

+		$2.BeforeDelegateDeclarationParentheses = False

+		$2.AfterDelegateDeclarationParameterComma = True

+		$2.NewParentheses = False

+		$2.SpacesBeforeBrackets = False

+		$2.BlankLinesBeforeFirstDeclaration = 1

+		$2.BlankLinesBetweenEventFields = 1

+		$2.inheritsSet = Mono

+		$2.inheritsScope = text/x-csharp

+		$2.scope = text/x-csharp

+	EndGlobalSection

+EndGlobal

 

file:b/Jump/Constants.cs (new)
--- /dev/null
+++ b/Jump/Constants.cs
@@ -1,1 +1,10 @@
+using System;
 
+namespace Jump {
+
+public static class Constants {
+	public const int SampleRate = 48000;
+}
+}
+
+

file:b/Jump/Jump.csproj (new)
--- /dev/null
+++ b/Jump/Jump.csproj
@@ -1,1 +1,54 @@
-
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProjectGuid>{34176A0B-A4AE-4E8A-B967-C3C23BAD9A7D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>Jump</RootNamespace>
+    <AssemblyName>Jump</AssemblyName>
+    <UseMSBuildEngine>False</UseMSBuildEngine>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <EnvironmentVariables>
+      <EnvironmentVariables>
+        <Variable name="__GL_THREADED_OPTIMIZATIONS" value="0" />
+      </EnvironmentVariables>
+    </EnvironmentVariables>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="OpenTK">
+      <HintPath>..\..\LearningOpenGL\libs\OpenTK.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ToneSystem.cs" />
+    <Compile Include="TwelveToneNote.cs" />
+    <Compile Include="Constants.cs" />
+    <Compile Include="SineSegment.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>

file:b/Jump/Program.cs (new)
--- /dev/null
+++ b/Jump/Program.cs
@@ -1,1 +1,193 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Threading;
+using OpenTK;
+using OpenTK.Audio;
+using OpenTK.Audio.OpenAL;
+using OpenTK.Graphics;
+using OpenTK.Graphics.OpenGL;
+using OpenTK.Input;
 
+namespace Jump {
+
+public sealed class TonePlayer : IDisposable {
+	public ALSourceState State {
+		get;
+		private set;
+	}
+
+	private int buffer;
+	private readonly int source;
+
+	public void BufferData(short[] audioData) {
+		if (this.buffer != 0) {
+			AL.DeleteBuffer(this.buffer);
+			this.buffer = 0;
+		}
+		this.buffer = AL.GenBuffer();
+		AL.BufferData(this.buffer, ALFormat.Stereo16, audioData, audioData.Length * 2, Constants.SampleRate);
+	}
+
+	public void Stop() {
+		AL.SourceStop(this.source);
+	}
+
+	public void PlayBuffer() {
+		AL.Source(this.source, ALSourcei.Buffer, this.buffer);
+		AL.SourcePlay(this.source);
+		State = ALSourceState.Playing;
+	}
+
+	public void PlayBufferSync() {
+		this.PlayBuffer();
+
+		this.WaitToStopPlaying();
+	}
+
+	public void WaitToStopPlaying() {
+		do {
+			int state;
+			Thread.Sleep(31);
+			AL.GetSource(source, ALGetSourcei.SourceState, out state);
+			State = (ALSourceState)state;
+		}
+		while (State == ALSourceState.Playing);
+	}
+
+	public TonePlayer() {
+		this.buffer = AL.GenBuffer();
+		this.source = AL.GenSource();
+	}
+
+	public void Dispose() {
+		this.Stop();
+		AL.DeleteBuffer(this.buffer);
+		AL.DeleteSource(this.source);
+	}
+}
+
+class MainClass {
+	public const ushort COLOR_MASK = 0xF;
+	public const ushort NUM_ROOT_TONES = 12;
+	public const double EFFECT_TONE_DURATION = 0.033d;
+
+	public static ToneSystem TwelveTone = ToneSystem.TwelveTone;
+	public static GameWindow window;
+	public static Key keyDown;
+	public static AudioContext audio;
+	public static TonePlayer player;
+
+	public static Vector3 currentColor;
+	public static Vector3 targetColor;
+
+	public static UInt64 FrameCount = 0;
+
+	public static ushort fadeTimeout = 0;
+
+	public static ushort[] effect_tones = new ushort[] { 0, 2, 4, 5, 7, 9, 11, 12, 11, 9, 7, 5, 4, 2, 0 };
+
+	public static Dictionary<ushort, short[]> effects = new Dictionary<ushort, short[]>();
+
+	public static void EffectsInit() {
+		for (ushort root = 0; root < NUM_ROOT_TONES; root++) {
+			short[] notes;
+
+			notes = null;
+
+			int idx = 0;
+
+			short lastAmp = 0;
+
+			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];
+
+				if (notes == null) {
+					notes = new short[effect_tones.Length * note.Length];
+				}
+
+				note.CopyTo(notes, idx);
+				idx += note.Length;
+			}
+
+			effects[root] = notes;
+		}
+	}
+
+	public static void FrameUpdate(object sender, FrameEventArgs args) {
+		if (keyDown != Key.Unknown) {
+			fadeTimeout = 0;
+
+			ushort ega = (ushort)((ushort)keyDown & COLOR_MASK);
+
+			// Make an EVA color out of it!
+			targetColor.X = (85 * (((ega >> 4) & 2) | (ega >> 2) & 1)) / 256f;
+			targetColor.Y = (85 * (((ega >> 3) & 2) | (ega >> 1) & 1)) / 256f;
+			targetColor.Z = (85 * (((ega >> 2) & 2) | (ega >> 0) & 1)) / 256f;
+
+			ushort root = (ushort)((ushort)keyDown % NUM_ROOT_TONES);
+
+			if (player.State == ALSourceState.Playing) {
+				player.Stop();
+			}
+
+			short[] notes = effects[root];
+
+			player.BufferData(notes);
+
+			player.PlayBuffer();
+
+			keyDown = Key.Unknown;
+		}
+		else {
+			fadeTimeout++;
+
+			if (fadeTimeout > 300) {
+				targetColor = Vector3.Zero;
+			}
+		}
+	}
+
+	public static void FrameRender(object sender, FrameEventArgs args) {
+		FrameCount++;
+
+		if (targetColor != currentColor) {
+			currentColor = Vector3.Lerp(currentColor, targetColor, .0625f);
+		}
+
+		GL.ClearColor(currentColor.X, currentColor.Y, currentColor.Z, 1);
+		GL.Clear(ClearBufferMask.ColorBufferBit);
+
+		window.SwapBuffers();
+	}
+
+	public static void Main(string[] args) {
+		using (window = new GameWindow(1280, 720, new GraphicsMode(32, 8, 0, 0), "Jump"))
+		using (audio = new AudioContext())
+		using (player = new TonePlayer()) {
+			window.Load += (object s, EventArgs a) => {
+				EffectsInit();
+
+				window.VSync = VSyncMode.Off;
+				window.WindowBorder = WindowBorder.Resizable;
+
+				window.UpdateFrame += FrameUpdate;
+				window.RenderFrame += FrameRender;
+
+				window.Resize += (object _s, EventArgs _a) => GL.Viewport(window.ClientRectangle);
+
+				window.KeyDown += (object _s, OpenTK.Input.KeyboardKeyEventArgs _a) => {
+					if (_a.Key == Key.Escape)
+						window.Exit();
+					keyDown = _a.Key;
+				};
+			};
+
+			window.Run(60, 60);
+		}
+	}
+}
+}
+

--- /dev/null
+++ b/Jump/Properties/AssemblyInfo.cs
@@ -1,1 +1,28 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
 
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("Jump")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("toadicus")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
+

--- /dev/null
+++ b/Jump/SineSegment.cs
@@ -1,1 +1,38 @@
+using System;
+using System.Collections.Generic;
 
+namespace Jump {
+
+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 static short[] GetSineSegment(double frequency, double duration, short startingAmplitude = 0) {
+		short[] samples;
+
+		int sampleCount = (int)(duration * Constants.SampleRate);
+		samples = new short[sampleCount];
+
+		int startIdx = 0;
+
+		if (startingAmplitude != 0) {
+			double asin = Math.Asin((double)startingAmplitude / (double)short.MaxValue);
+			startIdx = (int)(asin * Constants.SampleRate / Math.PI / frequency);
+		}
+
+		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);
+		}
+
+		return samples;
+	}
+}
+}
+
+

--- /dev/null
+++ b/Jump/ToneSystem.cs
@@ -1,1 +1,111 @@
+using System;
+using System.Collections.Generic;
 
+namespace Jump {
+
+public class ToneSystem {
+	public const double DEFAULT_A4 = 440d;
+	public const ushort DEFAULT_TONES_PER_OCTAVE = 12;
+	public const ushort DEFAULT_CENTRAL_OCTAVE = 4;
+	public const ushort DEFAULT_PIVOT_TONE = 3;
+
+	public static ToneSystem TwelveTone = new ToneSystem(DEFAULT_TONES_PER_OCTAVE, DEFAULT_A4);
+
+	private ushort _tonesPerOctave;
+
+	public ushort TonesPerOctave {
+		get {
+			return this._tonesPerOctave;
+		}
+		protected set {
+			this._tonesPerOctave = value;
+			this.ToneBase = Math.Pow(2, 1d / (double)value);
+			this.rebuildTones();
+		}
+	}
+
+	public double ToneBase {
+		get;
+		protected set;
+	}
+
+	public double A4 {
+		get;
+		protected set;
+	}
+
+	protected List<double> _centralTones;
+
+	public IList<double> CentralTones {
+		get;
+		protected set;
+	}
+
+	public ushort CentralOctave {
+		get;
+		protected set;
+	}
+
+	public double Tone(int toneIdx, ushort octave, ushort pivotTone) {
+		while (toneIdx >= this._centralTones.Count) {
+			toneIdx -= this._centralTones.Count;
+			octave++;
+		}
+
+		// TODO: Replace Math.Pow with an integer-optimized version.
+
+		int octaveShift = octave - CentralOctave;
+
+		double multiplier;
+
+		if (octaveShift < 0) {
+			multiplier = Math.Pow(2, octaveShift);
+		}
+		else {
+			multiplier = 1 << octaveShift;
+		}
+
+		return this._centralTones[toneIdx] * multiplier;
+	}
+
+	public double Tone(int toneIdx, ushort octave) {
+		return this.Tone(toneIdx, octave, DEFAULT_PIVOT_TONE);
+	}
+
+	private void rebuildTones() {
+		this._centralTones.Clear();
+
+		for (ushort t = 0; t < this._tonesPerOctave; t++) {
+			this._centralTones.Add(this.A4 * Math.Pow(this.ToneBase, t));
+		}
+	}
+
+	public ToneSystem(ushort tonesPerOctave, double centralA, ushort centralOctave) {
+		this.A4 = centralA;
+		this.CentralOctave = centralOctave;
+		this._centralTones = new List<double>();
+		this.CentralTones = this._centralTones.AsReadOnly();
+		this.TonesPerOctave = tonesPerOctave;
+	}
+
+	public ToneSystem(ushort tonesPerOctave, double centralA) : this(tonesPerOctave, centralA, DEFAULT_CENTRAL_OCTAVE) {
+	}
+
+	public ToneSystem(ushort tonesPerOctave, ushort centralOctave) : this(tonesPerOctave, DEFAULT_A4, centralOctave) {
+	}
+
+	public ToneSystem(double a4, ushort centralOctave) : this(DEFAULT_TONES_PER_OCTAVE, a4, centralOctave) {
+	}
+
+	public ToneSystem(ushort tonesPerOctave) : this(tonesPerOctave, DEFAULT_A4, DEFAULT_CENTRAL_OCTAVE) {
+	}
+
+	public ToneSystem(double a4) : this(DEFAULT_TONES_PER_OCTAVE, a4, DEFAULT_CENTRAL_OCTAVE) {
+	}
+
+	public ToneSystem() : this(DEFAULT_TONES_PER_OCTAVE, DEFAULT_A4, DEFAULT_CENTRAL_OCTAVE) {
+	}
+}
+}
+
+

--- /dev/null
+++ b/Jump/TwelveToneNote.cs
@@ -1,1 +1,26 @@
+using System;
 
+namespace Jump {
+
+public enum TwelveToneNote : ushort {
+	A = 0,
+	As = 1,
+	Bf = 1,
+	B = 2,
+	C = 3,
+	Cs = 4,
+	Df = 4,
+	D = 5,
+	Ds = 6,
+	Ef = 6,
+	E = 7,
+	F = 8,
+	Fs = 9,
+	Gf = 9,
+	G = 10,
+	Gs = 11,
+	Af = 11
+}
+}
+
+