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)); + } + }; +} +