Skip to content

Commit cc63e6d

Browse files
committed
Improve the unit tests for patternal
Add test_quantification_date Add this-> to make the code easier to read WIP fix errors in test WIP Improve the unit test a lot Improve the unit test Add some doc
1 parent 5c059c1 commit cc63e6d

6 files changed

Lines changed: 325 additions & 30 deletions

File tree

cmake/avendish.tests.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,6 @@ if(BUILD_TESTING)
4747

4848
avnd_add_catch_test(test_gain tests/objects/gain.cpp)
4949
avnd_add_catch_test(test_patternal tests/objects/patternal.cpp)
50+
avnd_add_catch_test(test_quantification_date tests/test_quantification_date.cpp)
5051
endif()
5152

examples/Advanced/Patternal/Patternal.hpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@
88
namespace patternal
99
{
1010

11+
/**
12+
* A sequencer pattern.
13+
* Contains its note and its velocity on each beat.
14+
*/
1115
struct Pattern
1216
{
17+
/**
18+
* A note.
19+
*/
1320
int note;
21+
/**
22+
* Its velocity on each beat.
23+
*/
1424
boost::container::small_vector<uint8_t, 32> pattern;
1525
};
1626

@@ -30,20 +40,27 @@ struct Processor
3040
"]\n"
3141
"for a very simple drum rythm on kick and snare.")
3242
halp_meta(uuid, "6e89b53a-1645-4a9c-a26e-e6c7870a902c")
43+
3344
struct
3445
{
3546
struct
3647
{
48+
/**
49+
* A list of patterns to play.
50+
* Each note has a velocity that changes for each beat.
51+
*/
3752
std::vector<Pattern> value;
3853
} patterns;
3954
} inputs;
4055

56+
/**
57+
* Its MIDI output.
58+
*/
4159
struct
4260
{
4361
halp::midi_bus<"Out"> midi;
4462
} outputs;
4563

46-
using tick = halp::tick_musical;
4764
void operator()(halp::tick_musical tk)
4865
{
4966
// Find out where we are in the bar
@@ -56,16 +73,20 @@ struct Processor
5673
auto quants = tk.get_quantification_date(4. / pat.size());
5774
for(auto [pos, q] : quants)
5875
{
76+
// FIXME: The position returned by get_quantification_date is a negative timestamp.
5977
if(pos < tk.frames)
6078
{
6179
auto qq = std::abs(q % std::ssize(pat));
62-
if(uint8_t vel = pat[qq]; vel > 0)
80+
if(uint8_t velocity = pat[qq]; velocity > 0)
6381
{
6482
halp::midi_msg m;
65-
m.bytes = {144, (uint8_t)note, vel};
83+
// Note on:
84+
m.bytes = {144, (uint8_t)note, velocity};
6685
m.timestamp = pos;
6786
outputs.midi.midi_messages.push_back(m);
6887

88+
// FIXME: The note off should not be output right away.
89+
// Note off:
6990
m.bytes = {128, (uint8_t)note, 0};
7091
m.timestamp = pos;
7192
outputs.midi.midi_messages.push_back(m);

include/halp/audio.hpp

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,35 +201,83 @@ struct tick
201201
int frames{};
202202
};
203203

204+
/**
205+
* Contains the info about the current audio buffer and the bar and quarter notes it's
206+
* associated with, so that the musical audio rendering utilities can do their job of
207+
* playing back the musical notes, etc.
208+
* They need to know when we are in the score.
209+
*
210+
* The quarter notes have their index starting at 0.
211+
* The position of the bars are in quarters. (in 4/4, the first bar has position 0.0 and the
212+
* second one has a position of 4.0)
213+
*
214+
* This struct is usually created and destroyed thousands of times per second.
215+
*/
204216
struct tick_musical
205217
{
218+
/**
219+
* How many frames in the buffer.
220+
*/
206221
int frames{};
207222

223+
/**
224+
* The tempo in BPM.
225+
*/
208226
double tempo = 120.;
227+
/**
228+
* Time signature. Example: 4/4
229+
*/
209230
struct
210231
{
211232
int num;
212233
int denom;
213234
} signature;
214235

236+
/**
237+
* The total number of samples since the beginning of the playback of the score.
238+
*/
215239
int64_t position_in_frames{};
216240

241+
/**
242+
* Playback time since the beginning of the score.
243+
*/
217244
double position_in_nanoseconds{};
218245

219-
// Quarter note of the first sample in the buffer
246+
/**
247+
* Quarter note of the first sample in this buffer
248+
* This is a double.
249+
*
250+
* The first quarter note in a score has index 0.
251+
*
252+
* For example:
253+
* - 3.95 would be slightly before the 2nd bar.
254+
* - 4.05 would be slightly after the beginning of the 2nd bar.
255+
*/
220256
quarter_note start_position_in_quarters{};
221257

222-
// Quarter note of the first sample in the next buffer
223-
// (or one past the last sample of this buffer, e.g. a [closed; open) interval like C++ begin / end)
258+
/**
259+
* Quarter note of the first sample in the next buffer
260+
* (or one past the last sample of this buffer, e.g. a [closed; open) interval like C++ begin / end)
261+
*/
224262
quarter_note end_position_in_quarters{};
225263

226-
// Position of the last signature change in quarter notes (at the start of the tick)
264+
/**
265+
* Position of the last signature change in quarter notes (at the start of the tick)
266+
*
267+
* For example: 0.0 if the signature never changes in the score.
268+
* If we change the time signature at some, we'll give it the index (in quarter) of the
269+
* bar when it last changed.
270+
*/
227271
quarter_note last_signature_change{};
228272

229-
// Position of the last bar relative to start in quarter notes
273+
/**
274+
* Position of the last bar relative to start in quarter notes
275+
*/
230276
quarter_note bar_at_start{};
231277

232-
// Position of the last bar relative to end in quarter notes
278+
/**
279+
* Position of the last bar relative to end in quarter notes
280+
*/
233281
quarter_note bar_at_end{};
234282

235283
// If the division falls in the current tick, returns the corresponding frames
@@ -240,11 +288,11 @@ struct tick_musical
240288
[[nodiscard]] quantification_frames get_quantification_date(double div) const noexcept
241289
{
242290
quantification_frames frames;
243-
double start_in_bar = start_position_in_quarters - bar_at_start;
291+
double start_in_bar = this->start_position_in_quarters - bar_at_start;
244292
double end_in_bar = end_position_in_quarters - bar_at_start;
245293

246294
auto pos_to_frame = [this](double in_bar) {
247-
double start = start_position_in_quarters;
295+
double start = this->start_position_in_quarters;
248296
double musical_pos = in_bar + bar_at_start;
249297
double end = end_position_in_quarters;
250298

include/halp/midi.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
#include <algorithm>
1010
#include <string_view>
11+
#include <fmt/format.h>
12+
#include <fmt/ranges.h>
13+
#include <sstream>
1114

1215
HALP_MODULE_EXPORT
1316
namespace halp
@@ -17,13 +20,32 @@ struct midi_msg
1720
{
1821
boost::container::small_vector<uint8_t, 15> bytes;
1922
int64_t timestamp{};
23+
24+
// Equality operator.
25+
bool operator==(const midi_msg&) const = default;
26+
// auto operator<=>(const midi_msg&) const = default;
2027
};
28+
29+
std::ostream& operator<<(std::ostream &o, const midi_msg& message)
30+
{
31+
return o << "midi_msg{:bytes=" << fmt::format("{}", message.bytes) <<", :timestamp=" << message.timestamp << "}" << std::endl;
32+
}
33+
2134
struct midi_note_msg
2235
{
2336
uint8_t bytes[8];
2437
int64_t timestamp{};
38+
39+
// Equality operator.
40+
bool operator==(const midi_note_msg&) const = default;
41+
//auto operator<=>(const midi_note_msg&) const = default;
2542
};
2643

44+
std::ostream& operator<<(std::ostream &o, const midi_note_msg& message)
45+
{
46+
return o << "midi_note_msg{:bytes=" << fmt::format("{}", message.bytes) <<", :timestamp=" << message.timestamp << "}" << std::endl;
47+
}
48+
2749
template <static_string lit, typename MessageType = midi_msg>
2850
struct midi_bus
2951
{

0 commit comments

Comments
 (0)