diff --git a/common/sketchbook.hpp b/common/sketchbook.hpp
index bdcdb0a72547acd7eb3c439c392b986aa0702208..5b7e8a9315e637ba65730d203a1847532371946b 100644
--- a/common/sketchbook.hpp
+++ b/common/sketchbook.hpp
@@ -7,6 +7,7 @@
 #include <random>
 #include <vector>
 #include <array>
+#include <deque>
 
 #include "simple/support.hpp"
 #include "simple/graphical.hpp"
@@ -76,9 +77,6 @@ class Program
 	using duration = std::chrono::duration<float>;
 
 	private:
-	template <typename T>
-	using o = std::optional<T>;
-	static constexpr auto no = std::nullopt;
 
 	using draw_fun = std::function<void(frame)>;
 	using draw_loop_fun = std::function<void(frame, duration delta_time)>;
@@ -104,7 +102,7 @@ class Program
 	const int argc;
 	const char * const * const argv;
 
-	o<duration> frametime = no;
+	std::optional<duration> frametime = std::nullopt;
 	std::string name = "";
 	int2 size = int2(400,400);
 
@@ -173,6 +171,7 @@ int main(int argc, char const* argv[]) try
 	sdlcore::initializer interactions(sdlcore::system_flag::event);
 
 	// TODO: make optional
+	// TODO: improve simple musical to work comfortably with any type, not just mono 8 bit (even that is a pain as you can see)
 	musical::initializer music;
 	using namespace musical;
 	device_with_callback ocean
@@ -186,26 +185,31 @@ int main(int argc, char const* argv[]) try
 			std::fill(buffer.begin(), buffer.end(), device.silence());
 
 			auto lock = std::scoped_lock(program.dam);
-			const float tick = 1.f/device.obtained().get_frequency();
-			for(auto&& wave : program.waves)
+			const auto tick = Program::duration(1.f/device.obtained().get_frequency());
+			std::transform(buffer.begin(), buffer.end(), buffer.begin(), [&program,&tick](auto v)
 			{
-				if(wave && wave.remaining.count() >= tick)
+				int8_t typed_v = 0;
+				memcpy(&typed_v, &v, 1);
+				float new_v = 0;
+
+				for(auto&& wave : program.waves)
 				{
-					float remaining = wave.remaining.count() / wave.total.count();
-					float progress = 1.f - remaining;
-					int remaining_ticks = std::min(buffer.size, int(wave.remaining.count() / tick));
-					auto step = tick/wave.total.count();
-					std::transform(buffer.begin(), buffer.begin() + remaining_ticks, buffer.begin(), [&](auto v)
+					if(wave && wave.remaining >= tick)
 					{
+						wave.remaining -= tick;
+						if(wave.remaining < tick)
+							wave.remaining = 0s;
 
-						progress += step;
-						return v + (wave.function(progress) * 127);
-					});
-					wave.remaining = (1.f - progress) * wave.total;
-					if(wave.remaining.count() < tick)
-						wave.remaining = 0s;
+						new_v += wave.function(1.f - (wave.remaining.count()/wave.total.count())) * 127.f;
+					}
 				}
-			}
+				new_v = new_v + float(typed_v);
+				new_v = std::clamp(new_v, -127.f,127.f);
+
+				typed_v = new_v;
+				memcpy(&v, &typed_v, 1);
+				return v;
+			});
 		}
 	);
 	ocean.play();
diff --git a/notanorgan.cpp b/notanorgan.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..767d4079066bcfa9e72b2d4ac0f288e36b3763dd
--- /dev/null
+++ b/notanorgan.cpp
@@ -0,0 +1,104 @@
+#include <cstdio>
+#include <cerrno>
+#include <thread>
+#include <chrono>
+#include <cmath>
+#include <algorithm>
+#include <iostream>
+
+#include "common/sketchbook.hpp"
+
+using namespace std::literals;
+using namespace musical;
+using namespace common;
+
+using support::wrap;
+
+constexpr std::array<std::array<float,19>,4> notes {{
+	{
+		51.91, 55.00, 58.27, 61.74, 65.41, 69.30,
+		73.42, 77.78, 82.41, 87.31, 92.50, 98.00,
+		103.83, 110.00, 116.54, 123.47, 130.81,
+		138.59, 146.83,
+	},
+
+	{
+		155.56, 164.81, 174.61, 185.00, 196.00,
+		207.65, 220.00, 233.08, 246.94, 261.63,
+		277.18, 293.66, 311.13, 329.63, 349.23,
+		369.99, 392.00, 415.30, 440.00,
+	},
+
+	{
+		466.16, 493.88, 523.25, 554.37, 587.33,
+		622.25, 659.25, 698.46, 739.99, 783.99,
+		830.61, 880.00, 932.33, 987.77, 1046.50,
+		1108.73, 1174.66, 1244.51, 1318.51,
+	},
+
+	{
+		1396.91, 1479.98, 1567.98, 1661.22,
+		1760.00, 1864.66, 1975.53, 2093.00,
+		2217.46, 2349.32, 2489.02, 2637.02,
+		2793.83, 2959.96, 3135.96, 3322.44,
+		3520.00, 3729.31, 3951.07,
+	},
+}};
+
+constexpr std::array<scancode,19> keys {
+	scancode::a,
+	scancode::w,
+	scancode::s,
+	scancode::e,
+	scancode::d,
+	scancode::r,
+	scancode::f,
+	scancode::t,
+	scancode::g,
+	scancode::y,
+	scancode::h,
+	scancode::u,
+	scancode::j,
+	scancode::i,
+	scancode::k,
+	scancode::o,
+	scancode::l,
+	scancode::p,
+	scancode::semicolon
+};
+auto get_key_index(scancode key)
+{
+	auto it = std::find(keys.begin(), keys.end(), key);
+	return keys.end() != it ? std::optional(it - keys.begin()) : std::nullopt;
+};
+
+float sinus(float angle)
+{
+	return rotate(float2::i(), protractor<>::tau(wrap(angle,1.f))).y();
+}
+
+void start(Program& program)
+{
+	program.key_down = [&program](scancode key, auto){
+		auto level =
+			pressed(scancode::lshift) ? 1 :
+			pressed(scancode::lctrl) ? 2 :
+			pressed(scancode::lalt) ? 3 :
+			0;
+		auto index = get_key_index(key);
+		if(index)
+		{
+			auto wave = [note=notes[level][*index]](auto ratio)
+			{
+				constexpr float fade_in = 2;
+				constexpr float fade_out = 2;
+				float fade = std::min(ratio*fade_in, (1-ratio)*fade_out);
+				return lerp(0.f,sinus(ratio * note), std::min(fade, 1.f));
+			};
+
+			int canal = 32;
+			while(canal --> 0 && !program.request_wave({std::move(wave), 1000ms}, canal));
+		}
+	};
+}
+