Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
musical_typing.hpp
Go to the documentation of this file.
1#pragma once
2
28
30
31#include <algorithm>
32#include <functional>
33#include <unordered_map>
34
35namespace pulp::view {
36
38 public:
41 void set_base_note(int note) {
42 base_note_ = note;
43 }
44 int base_note() const {
45 return base_note_;
46 }
47
48 std::function<void(int note, float velocity)> on_note_on;
49 std::function<void(int note)> on_note_off;
50 float velocity = 0.8f;
51 static constexpr float kVelStep = 1.0f / 16.0f; // c / v keyboard velocity step
52
56 bool handle_key(const KeyEvent& e) {
57 if (e.modifiers & (kModCmd | kModCtrl | kModAlt | kModMeta))
58 return false;
59
60 if (e.key == KeyCode::z || e.key == KeyCode::x) {
61 if (e.is_down && !e.is_repeat)
62 set_octave_shift(octave_shift_ + (e.key == KeyCode::x ? 1 : -1));
63 return true;
64 }
65 // c / v lower / raise the velocity (the design's VELOCITY −c / +v keys),
66 // mirroring the z / x octave keys.
67 if (e.key == KeyCode::c || e.key == KeyCode::v) {
68 if (e.is_down && !e.is_repeat)
69 velocity =
70 std::clamp(velocity + (e.key == KeyCode::v ? kVelStep : -kVelStep), 0.0f, 1.0f);
71 return true;
72 }
73 const int semi = semitone_for_key(e.key);
74 if (semi < 0)
75 return false;
76
77 const int kc = static_cast<int>(e.key);
78 if (e.is_down) {
79 if (held_.count(kc))
80 return true; // auto-repeat — already sounding
81 const int note = std::clamp(base_note_ + octave_shift_ * 12 + semi, 0, 127);
82 held_[kc] = note;
83 if (on_note_on)
84 on_note_on(note, velocity);
85 } else {
86 auto it = held_.find(kc);
87 if (it != held_.end()) {
88 if (on_note_off)
89 on_note_off(it->second);
90 held_.erase(it);
91 }
92 }
93 return true;
94 }
95
98 int octave_shift() const {
99 return octave_shift_;
100 }
101
111 void set_octave_shift(int s) {
112 const int lo = -((base_note_ + 11) / 12); // reach C-2 (base > C2)
113 const int hi = std::max(5, (92 - base_note_ + 11) / 12); // reach G8 (low roots)
114 octave_shift_ = std::clamp(s, lo, hi);
115 }
116
120 for (const auto& [kc, note] : held_)
121 if (on_note_off)
122 on_note_off(note);
123 held_.clear();
124 }
125
126 bool any_held() const {
127 return !held_.empty();
128 }
129
132 switch (k) {
133 case KeyCode::a:
134 return 0;
135 case KeyCode::w:
136 return 1;
137 case KeyCode::s:
138 return 2;
139 case KeyCode::e:
140 return 3;
141 case KeyCode::d:
142 return 4;
143 case KeyCode::f:
144 return 5;
145 case KeyCode::t:
146 return 6;
147 case KeyCode::g:
148 return 7;
149 case KeyCode::y:
150 return 8;
151 case KeyCode::h:
152 return 9;
153 case KeyCode::u:
154 return 10;
155 case KeyCode::j:
156 return 11;
157 case KeyCode::k:
158 return 12;
159 case KeyCode::o:
160 return 13;
161 case KeyCode::l:
162 return 14;
163 case KeyCode::p:
164 return 15;
166 return 16;
168 return 17;
169 default:
170 return -1;
171 }
172 }
173
174 private:
175 int base_note_ = 60;
176 int octave_shift_ = 0;
177 std::unordered_map<int, int> held_; // keyCode -> note currently sounding
178};
179
180} // namespace pulp::view
Definition musical_typing.hpp:37
int base_note() const
Definition musical_typing.hpp:44
static int semitone_for_key(KeyCode k)
QWERTY key -> semitone offset within the layout, or -1 if not a note key.
Definition musical_typing.hpp:131
bool any_held() const
Definition musical_typing.hpp:126
void all_notes_off()
Release every held note (focus loss / capture disabled).
Definition musical_typing.hpp:119
static constexpr float kVelStep
Definition musical_typing.hpp:51
float velocity
Definition musical_typing.hpp:50
int octave_shift() const
Current octave shift (in octaves; z/x decrement/increment).
Definition musical_typing.hpp:98
void set_octave_shift(int s)
Set the octave shift directly.
Definition musical_typing.hpp:111
void set_base_note(int note)
MIDI note for the first key ('a').
Definition musical_typing.hpp:41
std::function< void(int note)> on_note_off
Definition musical_typing.hpp:49
bool handle_key(const KeyEvent &e)
Feed a key event.
Definition musical_typing.hpp:56
std::function< void(int note, float velocity)> on_note_on
Definition musical_typing.hpp:48
Input event types with modifier keys and pointer IDs.
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
@ kModCmd
Command (macOS) — alias for platform primary modifier.
Definition input_events.hpp:21
@ kModMeta
Windows key / Command key.
Definition input_events.hpp:20
@ kModAlt
Alt / Option.
Definition input_events.hpp:19
@ kModCtrl
Control key (Ctrl on Windows/Linux).
Definition input_events.hpp:18
KeyCode
Definition input_events.hpp:35
@ s
Definition input_events.hpp:41
@ a
Definition input_events.hpp:39
@ h
Definition input_events.hpp:39
@ l
Definition input_events.hpp:40
@ j
Definition input_events.hpp:40
@ y
Definition input_events.hpp:42
@ c
Definition input_events.hpp:39
@ apostrophe
Definition input_events.hpp:50
@ semicolon
Definition input_events.hpp:50
@ u
Definition input_events.hpp:41
@ d
Definition input_events.hpp:39
@ p
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ f
Definition input_events.hpp:39
@ x
Definition input_events.hpp:41
@ v
Definition input_events.hpp:41
@ g
Definition input_events.hpp:39
@ o
Definition input_events.hpp:40
@ e
Definition input_events.hpp:39
@ t
Definition input_events.hpp:41
@ w
Definition input_events.hpp:41
@ z
Definition input_events.hpp:42
Rich key event with key code, modifiers, and repeat state.
Definition input_events.hpp:193