reflexion 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/midi.cpp +82 -0
  3. data/.doc/ext/reflex/native.cpp +4 -0
  4. data/.doc/ext/reflex/note_event.cpp +121 -0
  5. data/.doc/ext/reflex/reflex.cpp +23 -2
  6. data/.doc/ext/reflex/view.cpp +11 -16
  7. data/.doc/ext/reflex/window.cpp +24 -0
  8. data/ChangeLog.md +8 -0
  9. data/Rakefile +7 -0
  10. data/VERSION +1 -1
  11. data/ext/reflex/midi.cpp +87 -0
  12. data/ext/reflex/native.cpp +4 -0
  13. data/ext/reflex/note_event.cpp +130 -0
  14. data/ext/reflex/reflex.cpp +24 -2
  15. data/ext/reflex/view.cpp +11 -16
  16. data/ext/reflex/window.cpp +27 -0
  17. data/include/reflex/event.h +39 -2
  18. data/include/reflex/gamepad.h +2 -2
  19. data/include/reflex/midi.h +53 -0
  20. data/include/reflex/reflex.h +2 -0
  21. data/include/reflex/ruby/event.h +11 -0
  22. data/include/reflex/ruby/midi.h +84 -0
  23. data/include/reflex/ruby/window.h +27 -0
  24. data/include/reflex/view.h +9 -1
  25. data/include/reflex/window.h +6 -0
  26. data/lib/reflex/note_event.rb +34 -0
  27. data/lib/reflex/view.rb +2 -1
  28. data/lib/reflex.rb +9 -8
  29. data/reflex.gemspec +3 -3
  30. data/src/application.cpp +3 -0
  31. data/src/event.cpp +95 -7
  32. data/src/event.h +5 -0
  33. data/src/gamepad.cpp +14 -14
  34. data/src/gamepad.h +9 -9
  35. data/src/ios/event.mm +10 -2
  36. data/src/ios/gamepad.mm +2 -1
  37. data/src/midi.cpp +379 -0
  38. data/src/midi.h +32 -0
  39. data/src/osx/event.h +0 -3
  40. data/src/osx/event.mm +6 -6
  41. data/src/osx/gamepad_gc.mm +1 -1
  42. data/src/osx/gamepad_hid.mm +1 -1
  43. data/src/queue.h +71 -0
  44. data/src/reflex.cpp +18 -0
  45. data/src/timer.cpp +3 -10
  46. data/src/view.cpp +39 -0
  47. data/src/view.h +2 -0
  48. data/src/win32/event.cpp +5 -5
  49. data/src/win32/event.h +0 -2
  50. data/src/win32/gamepad.cpp +1 -1
  51. data/src/window.cpp +61 -10
  52. data/src/window.h +2 -0
  53. data/test/test_capture_event.rb +20 -16
  54. data/test/test_key_event.rb +8 -1
  55. data/test/test_note_event.rb +43 -0
  56. data/test/test_view.rb +24 -12
  57. metadata +29 -14
data/src/event.cpp CHANGED
@@ -17,14 +17,14 @@ namespace Reflex
17
17
  struct Event::Data
18
18
  {
19
19
 
20
- bool blocked;
21
-
22
20
  double time;
23
21
 
22
+ bool blocked;
23
+
24
24
  Data* parent = NULL;
25
25
 
26
- Data (bool blocked = false, double time = Xot::time())
27
- : blocked(blocked), time(time)
26
+ Data (double time = -1, bool blocked = false)
27
+ : time(time >= 0 ? time : Xot::time()), blocked(blocked)
28
28
  {
29
29
  }
30
30
 
@@ -37,7 +37,8 @@ namespace Reflex
37
37
  };// Event::Data
38
38
 
39
39
 
40
- Event::Event ()
40
+ Event::Event (double time)
41
+ : self(new Data(time))
41
42
  {
42
43
  }
43
44
 
@@ -562,8 +563,9 @@ namespace Reflex
562
563
  }
563
564
 
564
565
  KeyEvent::KeyEvent (
565
- Action action, const char* chars, int code, uint modifiers, int repeat)
566
- : self(new Data(action, chars, code, modifiers, repeat))
566
+ Action action, const char* chars, int code, uint modifiers, int repeat,
567
+ double time)
568
+ : Event(time), self(new Data(action, chars, code, modifiers, repeat))
567
569
  {
568
570
  }
569
571
 
@@ -866,6 +868,92 @@ namespace Reflex
866
868
  }
867
869
 
868
870
 
871
+ struct NoteEvent::Data
872
+ {
873
+
874
+ Action action = ACTION_NONE;
875
+
876
+ int channel = 0;
877
+
878
+ int note = 0;
879
+
880
+ float velocity = 0;
881
+
882
+ bool captured = false;
883
+
884
+ };// NoteEvent::Data
885
+
886
+
887
+ void
888
+ NoteEvent_set_captured (NoteEvent* pthis, bool captured)
889
+ {
890
+ pthis->self->captured = captured;
891
+ }
892
+
893
+
894
+ NoteEvent::NoteEvent ()
895
+ {
896
+ }
897
+
898
+ NoteEvent::NoteEvent (
899
+ Action action, int channel, int note, float velocity, double time)
900
+ : Event(time)
901
+ {
902
+ self->action = action;
903
+ self->channel = channel;
904
+ self->note = note;
905
+ self->velocity = velocity;
906
+ }
907
+
908
+ NoteEvent::NoteEvent (const NoteEvent* src)
909
+ : Event(src), self(new Data(*src->self))
910
+ {
911
+ }
912
+
913
+ NoteEvent
914
+ NoteEvent::dup () const
915
+ {
916
+ return NoteEvent(this);
917
+ }
918
+
919
+ NoteEvent::Action
920
+ NoteEvent::action () const
921
+ {
922
+ return self->action;
923
+ }
924
+
925
+ int
926
+ NoteEvent::channel () const
927
+ {
928
+ return self->channel;
929
+ }
930
+
931
+ int
932
+ NoteEvent::note () const
933
+ {
934
+ return self->note;
935
+ }
936
+
937
+ float
938
+ NoteEvent::frequency () const
939
+ {
940
+ static const int A4 = 69;
941
+ return 440 * std::pow(2.0, (note() - A4) / 12.0);
942
+ }
943
+
944
+ float
945
+ NoteEvent::velocity () const
946
+ {
947
+ return self->velocity;
948
+ }
949
+
950
+ bool
951
+ NoteEvent::is_captured () const
952
+ {
953
+ return self->captured;
954
+ }
955
+
956
+
869
957
  struct CaptureEvent::Data
870
958
  {
871
959
 
data/src/event.h CHANGED
@@ -19,6 +19,8 @@ namespace Reflex
19
19
  void DrawEvent_set_bounds (DrawEvent* pthis, const Bounds& bounds);
20
20
 
21
21
 
22
+ uint KeyEvent_get_modifiers ();
23
+
22
24
  void KeyEvent_set_chars (KeyEvent* pthis, const char* chars);
23
25
 
24
26
  void KeyEvent_set_captured (KeyEvent* pthis, bool captured);
@@ -47,6 +49,9 @@ namespace Reflex
47
49
  void WheelEvent_set_position (WheelEvent* pthis, const Point& position);
48
50
 
49
51
 
52
+ void NoteEvent_set_captured (NoteEvent* pthis, bool captured);
53
+
54
+
50
55
  }// Reflex
51
56
 
52
57
 
data/src/gamepad.cpp CHANGED
@@ -39,20 +39,6 @@ namespace Reflex
39
39
  }
40
40
 
41
41
 
42
- static Gamepad_CreateFun gamepad_create_fun = NULL;
43
-
44
- void
45
- Gamepad_set_create_fun (Gamepad_CreateFun fun)
46
- {
47
- gamepad_create_fun = fun;
48
- }
49
-
50
- Gamepad*
51
- Gamepad_create ()
52
- {
53
- return gamepad_create_fun ? gamepad_create_fun() : new Gamepad();
54
- }
55
-
56
42
  static Gamepad::List gamepads;
57
43
 
58
44
  void
@@ -107,6 +93,20 @@ namespace Reflex
107
93
  return 0.35;
108
94
  }
109
95
 
96
+ static Gamepad_CreateFun gamepad_create_fun = NULL;
97
+
98
+ void
99
+ Gamepad_set_create_fun (Gamepad_CreateFun fun)
100
+ {
101
+ gamepad_create_fun = fun;
102
+ }
103
+
104
+ Gamepad*
105
+ Gamepad_create ()
106
+ {
107
+ return gamepad_create_fun ? gamepad_create_fun() : new Gamepad();
108
+ }
109
+
110
110
 
111
111
  Gamepad::Gamepad ()
112
112
  {
data/src/gamepad.h CHANGED
@@ -1,7 +1,7 @@
1
1
  // -*- c++ -*-
2
2
  #pragma once
3
- #ifndef __REFLEX_SRC_DEVICE_H__
4
- #define __REFLEX_SRC_DEVICE_H__
3
+ #ifndef __REFLEX_SRC_GAMEPAD_H__
4
+ #define __REFLEX_SRC_GAMEPAD_H__
5
5
 
6
6
 
7
7
  #include <memory>
@@ -46,17 +46,10 @@ namespace Reflex
46
46
  };// Gamepad
47
47
 
48
48
 
49
- typedef Gamepad* (*Gamepad_CreateFun) ();
50
-
51
-
52
49
  void Gamepad_init (Application* app);
53
50
 
54
51
  void Gamepad_fin (Application* app);
55
52
 
56
- void Gamepad_set_create_fun (Gamepad_CreateFun fun);
57
-
58
- Gamepad* Gamepad_create ();
59
-
60
53
  void Gamepad_add (Application* app, Gamepad* gamepad);
61
54
 
62
55
  void Gamepad_remove (Application* app, Gamepad* gamepad);
@@ -68,6 +61,13 @@ namespace Reflex
68
61
  float Gamepad_get_button_press_threshold ();
69
62
 
70
63
 
64
+ typedef Gamepad* (*Gamepad_CreateFun) ();
65
+
66
+ void Gamepad_set_create_fun (Gamepad_CreateFun fun);
67
+
68
+ Gamepad* Gamepad_create ();
69
+
70
+
71
71
  }// Reflex
72
72
 
73
73
 
data/src/ios/event.mm CHANGED
@@ -54,10 +54,11 @@ namespace Reflex
54
54
  static uint
55
55
  get_modifiers (const UIEvent* event)
56
56
  {
57
- assert(event);
57
+ if (!event) return 0;
58
58
 
59
59
  NSInteger flags = 0;
60
- if (@available(iOS 13.4, *)) flags = event.modifierFlags;
60
+ if (@available(iOS 13.4, *))
61
+ flags = event.modifierFlags;
61
62
 
62
63
  return
63
64
  (flags & UIKeyModifierAlphaShift) ? MOD_CAPS : 0 |
@@ -68,6 +69,13 @@ namespace Reflex
68
69
  (flags & UIKeyModifierNumericPad) ? MOD_NUMPAD : 0;
69
70
  }
70
71
 
72
+ uint
73
+ KeyEvent_get_modifiers ()
74
+ {
75
+ return get_modifiers(nil);
76
+ }
77
+
78
+
71
79
  NativePointerEvent::NativePointerEvent (
72
80
  NSSet* touches, UIEvent* event, UIView* view)
73
81
  {
data/src/ios/gamepad.mm CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  #import <GameController/GameController.h>
6
6
  #include "reflex/exception.h"
7
+ #include "../event.h"
7
8
  #include "window.h"
8
9
 
9
10
 
@@ -63,7 +64,7 @@ namespace Reflex
63
64
  if (!win) return;
64
65
 
65
66
  auto action = pressed ? KeyEvent::DOWN : KeyEvent::UP;
66
- KeyEvent e(action, NULL, key_code, 0, 0);
67
+ KeyEvent e(action, NULL, key_code, KeyEvent_get_modifiers(), 0);
67
68
  Window_call_key_event(win, &e);
68
69
  }
69
70
 
data/src/midi.cpp ADDED
@@ -0,0 +1,379 @@
1
+ #include "midi.h"
2
+
3
+
4
+ #include <algorithm>
5
+ #include <RtMidi.h>
6
+ #include <xot/time.h>
7
+ #include "reflex/exception.h"
8
+ #include "reflex/debug.h"
9
+ #include "queue.h"
10
+ #include "event.h"
11
+ #include "application.h"
12
+ #include "window.h"
13
+
14
+
15
+ namespace Reflex
16
+ {
17
+
18
+
19
+ struct MIDI::Data
20
+ {
21
+
22
+ RtMidiIn input;
23
+
24
+ String name;
25
+
26
+ double time = 0;
27
+
28
+ ~Data ()
29
+ {
30
+ input.closePort();
31
+ }
32
+
33
+ };// MIDI::Data
34
+
35
+
36
+ static void
37
+ call_note_event (
38
+ MIDI* midi, bool on,
39
+ int channel, int note, float velocity, double time)
40
+ {
41
+ NoteEvent e(
42
+ on ? NoteEvent::ON : NoteEvent::OFF,
43
+ channel, note, velocity, time);
44
+
45
+ midi->on_note(&e);
46
+ if (e.is_blocked()) return;
47
+
48
+ switch ((int) e.action())
49
+ {
50
+ case NoteEvent::ON: midi->on_note_on(&e); break;
51
+ case NoteEvent::OFF: midi->on_note_off(&e); break;
52
+ }
53
+ if (e.is_blocked()) return;
54
+
55
+ Window* win = Window_get_active();
56
+ if (!win) return;
57
+
58
+ Window_call_note_event(win, &e);
59
+ }
60
+
61
+
62
+ struct MIDIEvent
63
+ {
64
+
65
+ typedef std::vector<unsigned char> Message;
66
+
67
+ enum Type {UNKNOWN, MESSAGE, ERROR};
68
+
69
+ Type type = UNKNOWN;
70
+
71
+ MIDI::Ref midi;
72
+
73
+ Message message;
74
+
75
+ RtMidiError error;
76
+
77
+ double time = 0;
78
+
79
+ MIDIEvent ()
80
+ : error("")
81
+ {
82
+ }
83
+
84
+ MIDIEvent (MIDI* midi, const Message& message, double time)
85
+ : type(MESSAGE), midi(midi), message(message), error(""), time(time)
86
+ {
87
+ }
88
+
89
+ MIDIEvent (MIDI* midi, const RtMidiError& error)
90
+ : type(ERROR), midi(midi), error(error)
91
+ {
92
+ }
93
+
94
+ };// MIDIEvent
95
+
96
+
97
+ static Queue<MIDIEvent> queue;
98
+
99
+ static void
100
+ dispatch_midi_event (MIDIEvent* event)
101
+ {
102
+ switch (event->type)
103
+ {
104
+ case MIDIEvent::MESSAGE:
105
+ {
106
+ auto& bytes = event->message;
107
+ switch (bytes[0] >> 4)
108
+ {
109
+ case 0x9:
110
+ call_note_event(
111
+ event->midi, true,
112
+ bytes[0] & 0xf, bytes[1], bytes[2] / 127.f, event->time);
113
+ break;
114
+
115
+ case 0x8:
116
+ call_note_event(
117
+ event->midi, false,
118
+ bytes[0] & 0xf, bytes[1], bytes[2] / 127.f, event->time);
119
+ break;
120
+ }
121
+ break;
122
+ }
123
+
124
+ case MIDIEvent::ERROR:
125
+ {
126
+ system_error(
127
+ __FILE__, __LINE__,
128
+ Xot::stringf("MIDI: %s", event->error.what()).c_str());
129
+ break;
130
+ }
131
+
132
+ case MIDIEvent::UNKNOWN:
133
+ invalid_state_error(__FILE__, __LINE__);
134
+ }
135
+ }
136
+
137
+ static void
138
+ process_midi_events ()
139
+ {
140
+ MIDIEvent event;
141
+ while (queue.try_pop(&event))
142
+ dispatch_midi_event(&event);
143
+ }
144
+
145
+ static void
146
+ midi_callback (double dt, MIDIEvent::Message* message, void* data)
147
+ {
148
+ MIDI* midi = (MIDI*) data;
149
+ MIDI::Data* self = midi->self.get();
150
+
151
+ if (self->time == 0)
152
+ self->time = Xot::time();
153
+ else
154
+ self->time += dt;
155
+
156
+ queue.push(MIDIEvent(midi, *message, self->time));
157
+ }
158
+
159
+ static void
160
+ error_callback (RtMidiError::Type type, const std::string& message, void* data)
161
+ {
162
+ MIDI* midi = (MIDI*) data;
163
+
164
+ queue.push(MIDIEvent(midi, RtMidiError(message, type)));
165
+ }
166
+
167
+ static MIDI_CreateFun midi_create_fun = NULL;
168
+
169
+ void
170
+ MIDI_set_create_fun (MIDI_CreateFun fun)
171
+ {
172
+ midi_create_fun = fun;
173
+ }
174
+
175
+ static MIDI*
176
+ create_midi ()
177
+ {
178
+ return midi_create_fun ? midi_create_fun() : new MIDI();
179
+ }
180
+
181
+ static void
182
+ open_midi (MIDI* midi, uint port)
183
+ {
184
+ MIDI::Data* self = midi->self.get();
185
+
186
+ if (port >= self->input.getPortCount())
187
+ argument_error(__FILE__, __LINE__);
188
+
189
+ self->name = self->input.getPortName(port);
190
+ self->input.setCallback(midi_callback, midi);
191
+ self->input.setErrorCallback(error_callback, midi);
192
+ self->input.openPort(port);
193
+ self->input.ignoreTypes(false, false, false);
194
+ }
195
+
196
+ static MIDI::List midis;
197
+
198
+ static void
199
+ add_midi (MIDI* midi)
200
+ {
201
+ midis.emplace_back(midi);
202
+ Application_call_device_connect(app(), midi);
203
+ }
204
+
205
+ static void
206
+ remove_midi (MIDI* midi)
207
+ {
208
+ MIDI::Ref ref = midi;
209
+ auto it = std::find(midis.begin(), midis.end(), ref);
210
+ if (it == midis.end()) return;
211
+
212
+ midis.erase(it);
213
+ Application_call_device_disconnect(app(), ref);
214
+ }
215
+
216
+
217
+ struct MIDIDeviceManager
218
+ {
219
+
220
+ RtMidiIn manager;
221
+
222
+ uint duplicated_port_name_count = 0;
223
+
224
+ MIDIDeviceManager ()
225
+ {
226
+ update();
227
+ }
228
+
229
+ ~MIDIDeviceManager ()
230
+ {
231
+ for (auto& midi : midis)
232
+ Application_call_device_disconnect(app(), midi);
233
+ }
234
+
235
+ void update ()
236
+ {
237
+ uint count = manager.getPortCount() - duplicated_port_name_count;
238
+ if (count > midis.size())
239
+ on_connect();
240
+ else if (count < midis.size())
241
+ on_disconnect();
242
+ }
243
+
244
+ void on_connect ()
245
+ {
246
+ std::set<String> names;
247
+ for (auto& midi : midis)
248
+ names.emplace(midi->self->name);
249
+
250
+ each_port([&](int port, auto& name)
251
+ {
252
+ if (names.contains(name)) return;
253
+
254
+ MIDI* midi = create_midi();
255
+ open_midi(midi, port);
256
+ add_midi(midi);
257
+ });
258
+
259
+ update_duplicated_port_name_count();
260
+ }
261
+
262
+ void on_disconnect ()
263
+ {
264
+ std::set<String> port_names;
265
+ get_port_names(&port_names);
266
+
267
+ while (true)
268
+ {
269
+ auto it = std::find_if(
270
+ midis.begin(), midis.end(),
271
+ [&](auto& midi) {return !port_names.contains(midi->self->name);});
272
+ if (it == midis.end()) break;
273
+
274
+ remove_midi(*it);
275
+ }
276
+
277
+ update_duplicated_port_name_count();
278
+ }
279
+
280
+ void update_duplicated_port_name_count ()
281
+ {
282
+ std::set<String> port_names;
283
+ get_port_names(&port_names);
284
+
285
+ duplicated_port_name_count =
286
+ manager.getPortCount() - (uint) port_names.size();
287
+ }
288
+
289
+ void get_port_names (std::set<String>* names)
290
+ {
291
+ each_port([&](int, auto& name) {names->emplace(name);});
292
+ }
293
+
294
+ void each_port (std::function<void(int, const std::string&)> fun)
295
+ {
296
+ uint size = manager.getPortCount();
297
+ for (uint i = 0; i < size; ++i)
298
+ fun(i, manager.getPortName(i));
299
+ }
300
+
301
+ };// MIDIDeviceManager
302
+
303
+
304
+ static std::unique_ptr<MIDIDeviceManager> manager;
305
+
306
+ void
307
+ MIDI_init (Application* app)
308
+ {
309
+ if (manager)
310
+ invalid_state_error(__FILE__, __LINE__);
311
+
312
+ manager.reset(new MIDIDeviceManager());
313
+ }
314
+
315
+ void
316
+ MIDI_fin (Application* app)
317
+ {
318
+ if (!manager)
319
+ invalid_state_error(__FILE__, __LINE__);
320
+
321
+ manager.reset();
322
+ }
323
+
324
+ void
325
+ MIDI_process_events ()
326
+ {
327
+ process_midi_events();
328
+
329
+ static double prev_time = 0;
330
+ if (manager && Xot::time() - prev_time > 0.5)
331
+ {
332
+ manager->update();
333
+ prev_time = Xot::time();
334
+ }
335
+ }
336
+
337
+
338
+ MIDI::MIDI ()
339
+ {
340
+ }
341
+
342
+ MIDI::~MIDI ()
343
+ {
344
+ }
345
+
346
+ const char*
347
+ MIDI::name () const
348
+ {
349
+ return self->name;
350
+ }
351
+
352
+ void
353
+ MIDI::on_note (NoteEvent* e)
354
+ {
355
+ }
356
+
357
+ void
358
+ MIDI::on_note_on (NoteEvent* e)
359
+ {
360
+ }
361
+
362
+ void
363
+ MIDI::on_note_off (NoteEvent* e)
364
+ {
365
+ }
366
+
367
+ MIDI::operator bool () const
368
+ {
369
+ return self->input.isPortOpen();
370
+ }
371
+
372
+ const MIDI::List&
373
+ MIDI::all ()
374
+ {
375
+ return midis;
376
+ }
377
+
378
+
379
+ }// Reflex
data/src/midi.h ADDED
@@ -0,0 +1,32 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __REFLEX_SRC_MIDI_H__
4
+ #define __REFLEX_SRC_MIDI_H__
5
+
6
+
7
+ #include "reflex/midi.h"
8
+
9
+
10
+ namespace Reflex
11
+ {
12
+
13
+
14
+ class Application;
15
+
16
+
17
+ void MIDI_init (Application* app);
18
+
19
+ void MIDI_fin (Application* app);
20
+
21
+ void MIDI_process_events ();
22
+
23
+
24
+ typedef MIDI* (*MIDI_CreateFun) ();
25
+
26
+ void MIDI_set_create_fun (MIDI_CreateFun fun);
27
+
28
+
29
+ }// Reflex
30
+
31
+
32
+ #endif//EOH
data/src/osx/event.h CHANGED
@@ -53,9 +53,6 @@ namespace Reflex
53
53
  };// NativeWheelEvent
54
54
 
55
55
 
56
- uint get_key_modifiers ();
57
-
58
-
59
56
  }// Reflex
60
57
 
61
58
 
data/src/osx/event.mm CHANGED
@@ -28,12 +28,6 @@ namespace Reflex
28
28
  (flags & NSFunctionKeyMask) ? MOD_FUNCTION : 0;
29
29
  }
30
30
 
31
- uint
32
- get_key_modifiers ()
33
- {
34
- return get_modifiers(nil);
35
- }
36
-
37
31
  static Point
38
32
  get_pointer_position (NSEvent* e, NSView* view)
39
33
  {
@@ -44,6 +38,12 @@ namespace Reflex
44
38
  return Point(p.x, p.y);
45
39
  }
46
40
 
41
+ uint
42
+ KeyEvent_get_modifiers ()
43
+ {
44
+ return get_modifiers(nil);
45
+ }
46
+
47
47
 
48
48
  static const char*
49
49
  get_chars (NSEvent* e)