Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test patternal 3 #54

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,7 @@ Documentation/Doc_sources/score-documentation/site

.vscode

*.patch
.*.swp

docs/doxygen
2,658 changes: 2,658 additions & 0 deletions Doxyfile

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cmake/avendish.tests.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ if(BUILD_TESTING)

avnd_add_catch_test(test_gain tests/objects/gain.cpp)
avnd_add_catch_test(test_patternal tests/objects/patternal.cpp)
avnd_add_catch_test(test_quantification_date tests/test_quantification_date.cpp)
endif()

Binary file added docs/sequence-patternal.dia
Binary file not shown.
Binary file added docs/sequence-patternal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 24 additions & 3 deletions examples/Advanced/Patternal/Patternal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,19 @@
namespace patternal
{

/**
* A sequencer pattern.
* Contains its note and its velocity on each beat.
*/
struct Pattern
{
/**
* A note.
*/
int note;
/**
* Its velocity on each beat.
*/
boost::container::small_vector<uint8_t, 32> pattern;
};

Expand All @@ -30,20 +40,27 @@ struct Processor
"]\n"
"for a very simple drum rythm on kick and snare.")
halp_meta(uuid, "6e89b53a-1645-4a9c-a26e-e6c7870a902c")

struct
{
struct
{
/**
* A list of patterns to play.
* Each note has a velocity that changes for each beat.
*/
std::vector<Pattern> value;
} patterns;
} inputs;

/**
* Its MIDI output.
*/
struct
{
halp::midi_bus<"Out"> midi;
} outputs;

using tick = halp::tick_musical;
void operator()(halp::tick_musical tk)
{
// Find out where we are in the bar
Expand All @@ -56,16 +73,20 @@ struct Processor
auto quants = tk.get_quantification_date(4. / pat.size());
for(auto [pos, q] : quants)
{
// FIXME: The position returned by get_quantification_date is a negative timestamp.
if(pos < tk.frames)
{
auto qq = std::abs(q % std::ssize(pat));
if(uint8_t vel = pat[qq]; vel > 0)
if(uint8_t velocity = pat[qq]; velocity > 0)
{
halp::midi_msg m;
m.bytes = {144, (uint8_t)note, vel};
// Note on:
m.bytes = {144, (uint8_t)note, velocity};
m.timestamp = pos;
outputs.midi.midi_messages.push_back(m);

// FIXME: The note off should not be output right away.
// Note off:
m.bytes = {128, (uint8_t)note, 0};
m.timestamp = pos;
outputs.midi.midi_messages.push_back(m);
Expand Down
64 changes: 56 additions & 8 deletions include/halp/audio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,35 +201,83 @@ struct tick
int frames{};
};

/**
* Contains the info about the current audio buffer and the bar and quarter notes it's
* associated with, so that the musical audio rendering utilities can do their job of
* playing back the musical notes, etc.
* They need to know when we are in the score.
*
* The quarter notes have their index starting at 0.
* The position of the bars are in quarters. (in 4/4, the first bar has position 0.0 and the
* second one has a position of 4.0)
*
* This struct is usually created and destroyed thousands of times per second.
*/
struct tick_musical
{
/**
* How many frames in the buffer.
*/
int frames{};

/**
* The tempo in BPM.
*/
double tempo = 120.;
/**
* Time signature. Example: 4/4
*/
struct
{
int num;
int denom;
} signature;

/**
* The total number of samples since the beginning of the playback of the score.
*/
int64_t position_in_frames{};

/**
* Playback time since the beginning of the score.
*/
double position_in_nanoseconds{};

// Quarter note of the first sample in the buffer
/**
* Quarter note of the first sample in this buffer
* This is a double.
*
* The first quarter note in a score has index 0.
*
* For example:
* - 3.95 would be slightly before the 2nd bar.
* - 4.05 would be slightly after the beginning of the 2nd bar.
*/
quarter_note start_position_in_quarters{};

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

// Position of the last signature change in quarter notes (at the start of the tick)
/**
* Position of the last signature change in quarter notes (at the start of the tick)
*
* For example: 0.0 if the signature never changes in the score.
* If we change the time signature at some, we'll give it the index (in quarter) of the
* bar when it last changed.
*/
quarter_note last_signature_change{};

// Position of the last bar relative to start in quarter notes
/**
* Position of the last bar relative to start in quarter notes
*/
quarter_note bar_at_start{};

// Position of the last bar relative to end in quarter notes
/**
* Position of the last bar relative to end in quarter notes
*/
quarter_note bar_at_end{};

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

auto pos_to_frame = [this](double in_bar) {
double start = start_position_in_quarters;
double start = this->start_position_in_quarters;
double musical_pos = in_bar + bar_at_start;
double end = end_position_in_quarters;

Expand Down
22 changes: 22 additions & 0 deletions include/halp/midi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <algorithm>
#include <string_view>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <sstream>

HALP_MODULE_EXPORT
namespace halp
Expand All @@ -17,13 +20,32 @@ struct midi_msg
{
boost::container::small_vector<uint8_t, 15> bytes;
int64_t timestamp{};

// Equality operator.
bool operator==(const midi_msg&) const = default;
// auto operator<=>(const midi_msg&) const = default;
};

std::ostream& operator<<(std::ostream &o, const midi_msg& message)
{
return o << "midi_msg{:bytes=" << fmt::format("{}", message.bytes) <<", :timestamp=" << message.timestamp << "}" << std::endl;
}

struct midi_note_msg
{
uint8_t bytes[8];
int64_t timestamp{};

// Equality operator.
bool operator==(const midi_note_msg&) const = default;
//auto operator<=>(const midi_note_msg&) const = default;
};

std::ostream& operator<<(std::ostream &o, const midi_note_msg& message)
{
return o << "midi_note_msg{:bytes=" << fmt::format("{}", message.bytes) <<", :timestamp=" << message.timestamp << "}" << std::endl;
}

template <static_string lit, typename MessageType = midi_msg>
struct midi_bus
{
Expand Down
Loading
Loading