Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
midievent.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "ase/midievent.hh"
3#include "internal.hh"
4#include "sortnet.hh"
5#include <cstring>
6
7#define EDEBUG(...) Ase::debug ("event", __VA_ARGS__)
8
9namespace Ase {
10
11// == MidiEvent ==
12MidiEvent::MidiEvent (const MidiEvent &other) :
13 MidiEvent()
14{
15 *this = other;
16}
17
18MidiEvent::MidiEvent (MidiEventType etype)
19{
20 memset ((void*) this, 0, sizeof (*this));
21 type = etype;
22 // one main design consideration is minimized size
23 static_assert (sizeof (MidiEvent) <= 2 * sizeof (void*));
24}
25
26MidiEvent&
27MidiEvent::operator= (const MidiEvent &other)
28{
29 if (this != &other)
30 memcpy ((void*) this, &other, sizeof (*this));
31 return *this;
32}
33
36MidiEvent::message () const
37{
38 if (type == MidiEvent::CONTROL_CHANGE)
39 {
40 if (param >= uint (MidiMessage::ALL_SOUND_OFF) &&
41 param <= uint (MidiMessage::POLY_MODE_ON))
42 return MidiMessage (param);
43 }
44 return MidiMessage (type);
45}
46
48MidiEvent::to_string () const
49{
50 const char *et = nullptr;
51 switch (type)
52 {
53 case PARAM_VALUE:
54 return string_format ("%4u ch=%-2u %s param=%d pvalue=%.5f",
55 frame, channel, "PARAM_VALUE", param, pvalue);
56 case NOTE_OFF: if (!et) et = "NOTE_OFF";
57 /* fall-through */
58 case NOTE_ON: if (!et) et = "NOTE_ON";
59 /* fall-through */
60 case AFTERTOUCH: if (!et) et = "AFTERTOUCH";
61 return string_format ("%4u ch=%-2u %-10s pitch=%d vel=%f tune=%f id=%x",
62 frame, channel, et, key, velocity, tuning, noteid);
63 case CONTROL_CHANGE: if (!et) et = "CONTROL_CHANGE";
64 return string_format ("%4u ch=%-2u %s control=%d value=%f (%02x) {%u}",
65 frame, channel, et, param, value, cval, fragment);
66 case PROGRAM_CHANGE: if (!et) et = "PROGRAM_CHANGE";
67 return string_format ("%4u ch=%-2u %s program=%d",
68 frame, channel, et, param);
69 case CHANNEL_PRESSURE: if (!et) et = "CHANNEL_PRESSURE";
70 /* fall-through */
71 case PITCH_BEND: if (!et) et = "PITCH_BEND";
72 return string_format ("%4u ch=%-2u %s value=%+f",
73 frame, channel, et, value);
74 case SYSEX: if (!et) et = "SYSEX";
75 return string_format ("%4u %s (unhandled)", frame, et);
76 }
77 static_assert (sizeof (MidiEvent) >= 2 * sizeof (uint64_t));
78 const uint64_t *uu = reinterpret_cast<const uint64_t*> (this);
79 return string_format ("%4u MidiEvent-%u (%08x %08x)", frame, type, uu[0], uu[1]);
80}
81
82MidiEvent
83make_note_on (uint16 chnl, uint8 mkey, float velo, float tune, uint nid)
84{
85 MidiEvent ev (velo > 0 ? MidiEvent::NOTE_ON : MidiEvent::NOTE_OFF);
86 ev.channel = chnl;
87 ev.key = mkey;
88 ev.velocity = velo;
89 ev.tuning = tune;
90 ev.noteid = nid;
91 return ev;
92}
93
94MidiEvent
95make_note_off (uint16 chnl, uint8 mkey, float velo, float tune, uint nid)
96{
97 MidiEvent ev (MidiEvent::NOTE_OFF);
98 ev.channel = chnl;
99 ev.key = mkey;
100 ev.velocity = velo;
101 ev.tuning = tune;
102 ev.noteid = nid;
103 return ev;
104}
105
106MidiEvent
107make_aftertouch (uint16 chnl, uint8 mkey, float velo, float tune, uint nid)
108{
109 MidiEvent ev (MidiEvent::AFTERTOUCH);
110 ev.channel = chnl;
111 ev.key = mkey;
112 ev.velocity = velo;
113 ev.tuning = tune;
114 ev.noteid = nid;
115 return ev;
116}
117
118MidiEvent
119make_pressure (uint16 chnl, float velo)
120{
121 MidiEvent ev (MidiEvent::CHANNEL_PRESSURE);
122 ev.channel = chnl;
123 ev.velocity = velo;
124 return ev;
125}
126
127MidiEvent
128make_control (uint16 chnl, uint prm, float val)
129{
130 MidiEvent ev (MidiEvent::CONTROL_CHANGE);
131 ev.channel = chnl;
132 ev.param = prm;
133 ev.value = val;
134 ev.cval = ev.value * 127;
135 return ev;
136}
137
138MidiEvent
139make_control8 (uint16 chnl, uint prm, uint8 cval)
140{
141 MidiEvent ev (MidiEvent::CONTROL_CHANGE);
142 ev.channel = chnl;
143 ev.param = prm;
144 ev.cval = cval;
145 ev.value = ev.cval * (1.0 / 127.0);
146 return ev;
147}
148
149MidiEvent
150make_program (uint16 chnl, uint prgrm)
151{
152 MidiEvent ev (MidiEvent::PROGRAM_CHANGE);
153 ev.channel = chnl;
154 ev.param = prgrm;
155 return ev;
156}
157
158MidiEvent
159make_pitch_bend (uint16 chnl, float val)
160{
161 MidiEvent ev (MidiEvent::PITCH_BEND);
162 ev.channel = chnl;
163 ev.value = val;
164 return ev;
165}
166
167MidiEvent
168make_param_value (uint param, double pvalue)
169{
170 MidiEvent ev (MidiEvent::PARAM_VALUE);
171 ev.channel = 0xf;
172 ev.param = param;
173 ev.pvalue = pvalue;
174 return ev;
175}
176
177// == MidiEventOutput ==
178MidiEventOutput::MidiEventOutput ()
179{}
180
182void
183MidiEventOutput::append (int16_t frame, const MidiEvent &event)
184{
185 const bool out_of_order_event = append_unsorted (frame, event);
186 assert_return (!out_of_order_event);
187}
188
191bool
192MidiEventOutput::append_unsorted (int16_t frame, const MidiEvent &event)
193{
194 // we discard timing information by ignoring negative frame offsets here (#26)
195 // when we implement recording, we might want to preserve the exact timestamp
196 frame = std::max<int16_t> (frame, 0);
197 const int64_t last_event_stamp = !events_.empty() ? events_.back().frame : 0;
198 events_.push_back (event);
199 events_.back().frame = frame;
200 return frame < last_event_stamp;
201}
202
204void
205MidiEventOutput::ensure_order ()
206{
207 fixed_sort (events_.begin(), events_.end(), [] (const MidiEvent &a, const MidiEvent &b) -> bool {
208 return a.frame < b.frame;
209 });
210}
211
214MidiEventOutput::last_frame () const
215{
216 return !events_.empty() ? events_.back().frame : 0;
217}
218
219} // Ase
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
memcpy
memset
The Anklang C++ API namespace.
Definition api.hh:9
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
MidiMessage
Extended type information for MidiEvent.
Definition midievent.hh:28
void fixed_sort(RandomIt first, RandomIt last, Compare comp=std::less< typename std::iterator_traits< RandomIt >::value_type >())
Use sorting networks to sort containers <= 16 elements without allocations.
Definition sortnet.hh:193
@ NOTE_OFF
Ase internal Parameter update.
@ CONTROL_CHANGE
Control Change.
@ AFTERTOUCH
Key Pressure, polyphonic aftertouch.
@ CHANNEL_PRESSURE
Channel Aftertouch.
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
typedef uint64_t
MidiEvent data structure.
Definition midievent.hh:50
uint channel
0…15 for standard events
Definition midievent.hh:54