Skip to content

Commit

Permalink
Merge pull request #7 from scrime-u-bordeaux/temp/rblard2022-07-13
Browse files Browse the repository at this point in the history
Chronology parameter struct, temporal resolution, detachEndings and more
  • Loading branch information
josephlarralde authored Jul 14, 2022
2 parents 4bc270d + 2b56113 commit fe66230
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 37 deletions.
121 changes: 89 additions & 32 deletions src/core/Chronology.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,50 @@
#include <list>
#include "Events.h"

namespace ChronologyParams{
struct parameters{
bool unmeet; // Indicates whether or not to displace end events when possible
// ONLY RELEVANT FOR MODEL DATA. DISABLE FOR COMMANDS.

bool complete; // Indicates whether or not to complete empty sets when possible
// ONLY RELEVANT FOR MODEL DATA. DISABLE FOR COMMANDS.

bool detach; // Indicates whether or not to place the end events that have been
// clustered together with their beginning into the next ending set.

int temporalResolution; // Time threshold under which the events will be considered simultaneous
// and merged in a single set.
// MIDI Standard is 0.

uint64_t date; // Unused for now, purpose unknown
};

static parameters const default_params = {
.unmeet = true,
.complete = false,
.detach = true,
.temporalResolution = 0,
.date = 0
};

static parameters const no_unmeet = {
.unmeet = false,
.complete = false,
.detach = true,
.temporalResolution = 0,
.date = 0
};
}

template <typename T>
class Chronology {
private:

// ---------------------------------------------------------------------------
// ------------------------------DATA TYPES-----------------------------------
// ---------------------------------------------------------------------------

private:

// Describes a place where a set containing at least one beginning event
// was left without immediate ending

Expand All @@ -26,13 +62,7 @@ class Chronology {
// ----------------------------PRIVATE FIELDS---------------------------------
// ---------------------------------------------------------------------------

bool unmeet; // Indicates whether or not to displace end events when possible
// ONLY RELEVANT FOR MODEL DATA. DISABLE FOR COMMANDS.

bool complete; // Indicates whether or not to complete empty sets when possible
// ONLY RELEVANT FOR MODEL DATA. DISABLE FOR COMMANDS.

uint64_t date; // Unused for now, purpose unknown
ChronologyParams::parameters params;

Events::Set<T> inputSet; // Set containing the most recent input

Expand All @@ -50,21 +80,6 @@ class Chronology {
// ---------------------------PRIVATE METHODS---------------------------------
// ---------------------------------------------------------------------------

void mergeSets(Events::Set<T>& greaterSet, Events::Set<T> const& mergedSet) {
greaterSet.events.insert(
greaterSet.events.end(),
mergedSet.events.begin(),
mergedSet.events.end()
);
}

// Determines if compEvent is an ending event matching refEvent

bool isMatchingEnd(T const& refEvent, T const& compEvent) {
return Events::correspond<T>(refEvent, compEvent)
&& !Events::isStart<T>(compEvent);
}

// Shifts ending events contained in the inputSet into the insertSet
// if they match start events contained in the bufferSet

Expand All @@ -76,7 +91,7 @@ class Chronology {
if (Events::isStart<T>(bufferEvent)) {
auto it = inputSet.events.begin();
while (it != inputSet.events.end()) {
if (isMatchingEnd(bufferEvent,*it)) {
if (Events::isMatchingEnd(bufferEvent,*it)) {
insertSet.events.push_back(*it);
it = inputSet.events.erase(it);
} else {
Expand Down Expand Up @@ -116,7 +131,7 @@ class Chronology {
// The inputSet is ALSO an ending set. So they can be merged.
if (!Events::hasStart<T>(inputSet)) {

mergeSets(bufferSet,inputSet);
Events::mergeSets(bufferSet,inputSet);
if (last) fifo.push_back(bufferSet);
return;

Expand Down Expand Up @@ -147,7 +162,7 @@ class Chronology {
Events::Set<T> insertSet{inputSet.dt, {}};

// If unmeet is enabled, try to fill the empty set.
if (unmeet) constructInsertSet(inputSet,bufferSet,insertSet);
if (params.unmeet) constructInsertSet(inputSet,bufferSet,insertSet);

// Push the set regardless to stay consistent with the format.
fifo.push_back(insertSet);
Expand All @@ -168,10 +183,43 @@ class Chronology {
// AFTER checking for incomplete events one last time.

void lastPush() {
if (complete) checkForEventCompletion();
if (params.complete) checkForEventCompletion();
genericPushLogic(true);
}

// Move the ending of any events that have been synchronized with their start
// (i.e., that do not happen)
// into the following ending set.

void detachEndings(){
std::vector<T> starts;
std::vector<T> leftoverEndings;
for(Events::Set<T>& set : fifo){
starts.clear();

if(!leftoverEndings.empty()){
Events::mergeSets(set,leftoverEndings);
leftoverEndings.clear();
}

int eventIndex = 0;

for(T const& event : set.events){
if(Events::isStart<T>(event)) starts.push_back(event);
else{
for(T const& startEvent : starts){
if(Events::isMatchingEnd(startEvent,event)){
leftoverEndings.push_back(event);
set.events.erase(set.events.begin()+eventIndex);
eventIndex--;
break;
}
}
}
eventIndex++;
}
}
}

// ---------------------------------------------------------------------------

Expand All @@ -188,15 +236,18 @@ class Chronology {
// ------------------------CONSTRUCTORS/DESTRUCTORS---------------------------
// ---------------------------------------------------------------------------

Chronology() : unmeet(true), date(0), complete(false) {}
Chronology(bool _complete) : unmeet(true), date(0), complete(_complete) {}
Chronology(bool _unmeet, bool _complete) : unmeet(_unmeet), date(0), complete(_complete) {}
Chronology() : params(ChronologyParams::default_params) {}
Chronology(ChronologyParams::parameters initParams) : params(initParams) {}
~Chronology() {}

// ---------------------------------------------------------------------------
// -----------------------------PUBLIC METHODS--------------------------------
// ---------------------------------------------------------------------------

std::list<Events::Set<noteData>>::iterator begin() { return fifo.begin(); }

std::list<Events::Set<noteData>>::iterator end() { return fifo.end(); }

// Called when a new event is added to the chronology.

void pushEvent(int dt, T const& data) {
Expand All @@ -212,9 +263,9 @@ class Chronology {
// Before doing anything else, check whether the current inputSet
// can complete a previously incomplete event.

if (complete) checkForEventCompletion();
if (params.complete) checkForEventCompletion();

if (dt > 0) { // Event begins at a different time ; inputSet and bufferSet will change
if (dt > params.temporalResolution) { // Event begins at a different time ; inputSet and bufferSet will change

genericPushLogic(false);

Expand Down Expand Up @@ -242,10 +293,16 @@ class Chronology {
fifo.push_back({1, {}});
}

// Ensure no start events are in the same set as their ending.

if (params.detach) detachEndings();

// Reset the inner sets.

bufferSet.events.clear();
inputSet.events.clear();

//std::cout << *this << std::endl;
}

// Self-explanatory.
Expand Down
29 changes: 29 additions & 0 deletions src/core/Events.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,22 @@ std::ostream& operator<<(std::ostream& os, struct Set<T> const &s){
return os;
}

// Self-explanatory

template <typename T>
bool isStart(T const& e) { return true; }

template <typename T>
bool correspond(T const& e1, T const& e2) { return false; }

// Determines if compEvent is an ending event matching refEvent

template <typename T>
bool isMatchingEnd(T const& refEvent, T const& compEvent) {
return Events::correspond<T>(refEvent, compEvent)
&& !Events::isStart<T>(compEvent);
}

template <typename T>
bool hasStart(std::vector<T> const& events) {
for (auto& e : events)
Expand All @@ -44,6 +54,25 @@ bool hasStart(std::vector<T> const& events) {
return false;
}

template <typename T>
void mergeSets(Events::Set<T>& greaterSet, Events::Set<T> const& mergedSet) {
greaterSet.events.insert(
greaterSet.events.end(),
mergedSet.events.begin(),
mergedSet.events.end()
);
}

template <typename T>

void mergeSets(Events::Set<T>& greaterSet, std::vector<T> const& mergedSet){
greaterSet.events.insert(
greaterSet.events.end(),
mergedSet.begin(),
mergedSet.end()
);
}

template <typename T>
bool hasStart(Set<T> const& set) { return hasStart<T>(set.events); }

Expand Down
17 changes: 15 additions & 2 deletions src/core/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ class Renderer {
// ----------------------CONSTRUCTORS/DESTRUCTORS---------------------------
// -------------------------------------------------------------------------

Renderer() : lastEventPulled(false), modelEvents(Chronology<Model>(false)) {}
Renderer(bool completeEvents) : lastEventPulled(false), modelEvents(Chronology<Model>(completeEvents)) {}
Renderer() : lastEventPulled(false), modelEvents(Chronology<Model>()) {}
Renderer(ChronologyParams::parameters params) :
lastEventPulled(false), modelEvents(Chronology<Model>(params)) {}

// -------------------------------------------------------------------------
// ---------------------------PUBLIC METHODS--------------------------------
Expand Down Expand Up @@ -149,8 +150,16 @@ class Renderer {
if (map3.find(key) == map3.end() && !lastEventPulled)
throw std::runtime_error("INVALID MAP ENTRY FOR KEY");
} catch (std::runtime_error e) {
// Original idea (early 2022) :
// This can only happen if two controllers pressed the same key on the same channel
// This should not happen

// Update 08/07/22 ; this is FAR more common than we thought.
// For example, this happens if the system is launched with a key already held;
// The release of that key will trigger the exception because no note was associated with the key.

// This causes an instant segfault in the ossia binding.
// So the question is, should we keep it that way ?
std::cout << e.what() << std::endl;
exit(1);
}
Expand All @@ -177,6 +186,10 @@ class Renderer {
modelEvents = newPartition;
}

Chronology<Model> getPartition(){
return modelEvents;
}

};

#endif /* MFP_RENDERER_H */
25 changes: 22 additions & 3 deletions src/impl/MFPEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,25 @@
#define MFP_MFPEVENTS_H

#include <iostream>
#include <string>
#include <cstdint>
#include <vector>
#include "../core/Events.h"

std::string noteNames[12] = {"A","A#","B","C","C#","D","D#","E","F","F#","G","G#"};

std::string convertIdToNoteName(uint8_t id){
if(id < 21 || id > 108) return "??";

uint8_t relativeId = id - 21;

uint8_t name = (relativeId % 12);
uint8_t pitch = (relativeId / 12);
if(name > 2) pitch++;

return noteNames[name]+std::to_string(pitch);
}

// NB : commandKey and noteKey structs are for use as std::map keys

struct commandData {
Expand All @@ -16,8 +31,10 @@ struct commandData {
};

std::ostream& operator<<(std::ostream& os, struct commandData const &cmd){
std::string name = convertIdToNoteName(cmd.id);
return os << "[ pressed : " << cmd.pressed << " , " <<
"id : " << int(cmd.id) << " , " <<
"id : " << int(cmd.id) <<
" (" << name << "), " <<
"velocity : " << int(cmd.velocity) << " , " <<
"channel : " << int(cmd.channel) << " ]";
}
Expand All @@ -44,8 +61,10 @@ struct noteData {
};

std::ostream& operator<<(std::ostream& os, struct noteData const &note){
std::string name = convertIdToNoteName(note.pitch);
return os << "[ on : " << note.on << " , " <<
"id : " << int(note.pitch) << " , " <<
"pitch : " << int(note.pitch) <<
" (" << name << "), " <<
"velocity : " << int(note.velocity) << " , " <<
"channel : " << int(note.channel) << " ]";
}
Expand Down Expand Up @@ -95,4 +114,4 @@ noteKey Events::keyFromData<noteData, noteKey>(noteData const& note) {
}


#endif /* MFP_MFPEVENTS_H */
#endif /* MFP_MFPEVENTS_H */
7 changes: 7 additions & 0 deletions src/impl/MFPRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "MFPEvents.h"
#include "../core/Renderer.h"
#include "../core/Chronology.h"

/*
// INHERITANCE
Expand Down Expand Up @@ -57,6 +58,10 @@ class MFPRenderer {
}

public:

MFPRenderer() : renderer() {}
MFPRenderer(ChronologyParams::parameters params) : renderer(params) {}

void pushEvent(int dt, noteData event) { renderer.pushEvent(dt, event); }

void finalize() { renderer.finalize(); }
Expand All @@ -78,6 +83,8 @@ class MFPRenderer {
void clear() { renderer.clear(); }

void setPartition(Chronology<noteData> const newPartition){ renderer.setPartition(newPartition); }

Chronology<noteData> getPartition() { return renderer.getPartition(); }
};
//*/

Expand Down

0 comments on commit fe66230

Please sign in to comment.