Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: celtera/avendish
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 1d5326cf0729ead86c16fb0d358320a988db2fcf
Choose a base ref
..
head repository: celtera/avendish
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: cc63e6dc24c61d07ef146be32d499eb30421f729
Choose a head ref
Showing with 64 additions and 17 deletions.
  1. +9 −2 include/halp/audio.hpp
  2. +55 −15 tests/objects/patternal.cpp
11 changes: 9 additions & 2 deletions include/halp/audio.hpp
Original file line number Diff line number Diff line change
@@ -220,6 +220,9 @@ struct tick_musical
*/
int frames{};

/**
* The tempo in BPM.
*/
double tempo = 120.;
/**
* Time signature. Example: 4/4
@@ -267,10 +270,14 @@ struct tick_musical
*/
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
70 changes: 55 additions & 15 deletions tests/objects/patternal.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <cmath> // std::fmod
#include <algorithm> // std::max
#include <catch2/catch_all.hpp>

#include <halp/audio.hpp>
@@ -72,6 +74,8 @@ TEST_CASE("MIDI messages are output properly", "[advanced][patternal]")
static constexpr double ticksPerSecond = 1.0 / tickDuration;
static constexpr double testDuration = 3.0; // seconds
static constexpr double NS_PER_S = 1000000000;
static constexpr double durationOfAQuarter = 0.5; // seconds
static constexpr int quartersPerBar = 4;

Processor patternalProcessor;
patternalProcessor.inputs.patterns.value = {
@@ -82,30 +86,42 @@ TEST_CASE("MIDI messages are output properly", "[advanced][patternal]")

// Check the output on each tick:
const int totalNumberOfTicks = (int) ticksPerSecond * testDuration;
int64_t pos_in_frames = 0;
double pos_in_ns = 0;
for (int tickIndex = 0; tickIndex < totalNumberOfTicks; tickIndex++) {
int64_t posInFrames = 0;
double posInNs = 0;
double previousMaxQuarter = 0; // The previous max quarter number during the previous tick.

for (int tickIndex = 0; tickIndex < totalNumberOfTicks; tickIndex++) {
// Debug info
INFO("tick number " << tickIndex << " / " << totalNumberOfTicks);

// Calculate stuff:
int shouldPlayBeat = -1; // Index of the beat we should play now, or -1 if none.
// INFO("Test tick " << tickIndex);
pos_in_frames += bufferSize;
pos_in_ns += tickDuration / NS_PER_S;
posInFrames += bufferSize;
posInNs += tickDuration / NS_PER_S;
double timeNow = tickIndex * tickDuration;
double timeAtEndOfTick = (tickIndex + 1) * tickDuration;
double startPosInQuarters = timeNow / durationOfAQuarter;
double endPosInQuarters = (timeNow + tickDuration) / durationOfAQuarter;
double barAtStart = std::fmod(startPosInQuarters, quartersPerBar);
double barAtEnd = std::fmod(endPosInQuarters, quartersPerBar);
double currentMaxQuarter = std::max(startPosInQuarters, endPosInQuarters);

// Populate the tick_musical:
tick_musical tk;
tk.tempo = 120; // 120 BPM. One beat lasts 500 ms.
tk.signature.num = 4;
tk.signature.denom = 4;
tk.signature.denom = quartersPerBar;
tk.frames = bufferSize;
tk.position_in_nanoseconds = pos_in_ns; // We don't really need to set this pos in ns.
tk.position_in_frames = pos_in_frames;
tk.position_in_nanoseconds = posInNs; // We don't really need to set this pos in ns.
tk.position_in_frames = posInFrames;
tk.last_signature_change = 0; // The signature never changes.
tk.start_position_in_quarters = TODO;
tk.end_position_in_quarters = TODO;
tk.bar_at_start = TODO;
tk.bar_at_end = TODO;
tk.start_position_in_quarters = startPosInQuarters;
tk.end_position_in_quarters = endPosInQuarters;
tk.bar_at_start = barAtStart;
tk.bar_at_end = barAtEnd;

// Process it:
patternalProcessor(tk);

// Test the 1st tick:
@@ -139,12 +155,36 @@ TEST_CASE("MIDI messages are output properly", "[advanced][patternal]")
REQUIRE(patternalProcessor.outputs.midi.midi_messages.size() == 0);
}

else {
// FIXME: At some point, there should be some other notes.
// INFO("tick number " << tickIndex << " out of " << totalNumberOfTicks);
else if (currentMaxQuarter != previousMaxQuarter) {
// We assume there won't be two new quarters within the same buffer - at 120 BPM
INFO("quarter number: " << currentMaxQuarter);
if (currentMaxQuarter == 1) {
REQUIRE(patternalProcessor.outputs.midi.midi_messages.size() == 4);
// A hi-hat note off:
midi_msg note0;
makeNote(note0, noteHiHat, velocityZero, -2147483648);
REQUIRE(patternalProcessor.outputs.midi.midi_messages[0] == note0);
// Hi-hat note on:
midi_msg note1;
makeNote(note1, noteHiHat, velocityFull, -2147483648);
REQUIRE(patternalProcessor.outputs.midi.midi_messages[1] == note1);
// Snare note on:
midi_msg note2;
makeNote(note2, noteSnare, velocityFull, -2147483648);
REQUIRE(patternalProcessor.outputs.midi.midi_messages[2] == note2);
// A bass drum note off:
midi_msg note3;
makeNote(note3, noteBassDrum, velocityZero, -2147483648);
REQUIRE(patternalProcessor.outputs.midi.midi_messages[3] == note3);
}
} else {
REQUIRE(patternalProcessor.outputs.midi.midi_messages.size() == 0);
}
// FIXME: At some point, there should be some other notes.
// TODO: check the other ticks

// Last operations before the next tick:
previousMaxQuarter = currentMaxQuarter;
}
}