Skip to content
Open
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
18 changes: 18 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Left
AlignOperands: Align
AlignTrailingComments: true
AllowShortBlocksOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
BreakBeforeBraces: Attach
BreakConstructorInitializers: AfterColon
IncludeBlocks: Preserve
IndentGotoLabels: false
IndentPPDirectives: BeforeHash
IndentWidth: 4
InsertBraces: true
ColumnLimit: 0
PointerAlignment: Left
AllowShortEnumsOnASingleLine: true
11 changes: 6 additions & 5 deletions Source/BufferedMidiMessage.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
#include "JuceHeader.h"

class BufferedMidiMessage {
public:
BufferedMidiMessage(const juce::MidiMessage& message, unsigned long long time) : message(message), time(time) {}
~BufferedMidiMessage() {}
public:
BufferedMidiMessage(const juce::MidiMessage& message, unsigned long long time) :
message(message), time(time) {}
~BufferedMidiMessage() {}

juce::MidiMessage message;
unsigned long long time;
juce::MidiMessage message;
unsigned long long time;
};
30 changes: 13 additions & 17 deletions Source/BufferedNote.cpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
#include "BufferedNote.h"

BufferedNote::BufferedNote(const juce::MidiMessage& noteOnMessage, unsigned long long startTime)
{
this->pitch = noteOnMessage.getNoteNumber();
this->velocity = noteOnMessage.getVelocity();
this->startTime = startTime;
this->endTime = std::optional<unsigned long long>();
BufferedNote::BufferedNote(const juce::MidiMessage& noteOnMessage, unsigned long long startTime) {
this->pitch = noteOnMessage.getNoteNumber();
this->velocity = noteOnMessage.getVelocity();
this->startTime = startTime;
this->endTime = std::optional<unsigned long long>();
}

std::optional<unsigned long long> BufferedNote::length()
{
if (endTime.has_value()) {
return startTime - endTime.value();
}
else {
return std::optional<int>();
}
std::optional<unsigned long long> BufferedNote::length() {
if (endTime.has_value()) {
return startTime - endTime.value();
} else {
return std::optional<int>();
}
}

bool BufferedNote::hasEnd()
{
return endTime.has_value();
bool BufferedNote::hasEnd() {
return endTime.has_value();
}
28 changes: 15 additions & 13 deletions Source/BufferedNote.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
#include "JuceHeader.h"

class BufferedNote {
public:
BufferedNote(const juce::MidiMessage& noteOnMessage, unsigned long long startTime);
BufferedNote(int pitch, int velocity, unsigned long long startTime, unsigned long long endTime) : pitch(pitch), velocity(velocity), startTime(startTime), endTime(endTime) {}
BufferedNote(int pitch, int velocity, unsigned long long startTime) : pitch(pitch), velocity(velocity), startTime(startTime), endTime(std::optional<unsigned long long>()) {}
~BufferedNote() {}
public:
BufferedNote(const juce::MidiMessage& noteOnMessage, unsigned long long startTime);
BufferedNote(int pitch, int velocity, unsigned long long startTime, unsigned long long endTime) :
pitch(pitch), velocity(velocity), startTime(startTime), endTime(endTime) {}
BufferedNote(int pitch, int velocity, unsigned long long startTime) :
pitch(pitch), velocity(velocity), startTime(startTime), endTime(std::optional<unsigned long long>()) {}
~BufferedNote() {}

int pitch;
int velocity;
unsigned long long startTime;
int endDelay = 0;
std::optional<unsigned long long> endTime;
std::optional<unsigned long long> length();
bool hasEnd();
int pitch;
int velocity;
unsigned long long startTime;
int endDelay = 0;
std::optional<unsigned long long> endTime;
std::optional<unsigned long long> length();
bool hasEnd();

bool allowLegato = false;
bool allowLegato = false;
};
21 changes: 8 additions & 13 deletions Source/ConfigParserUtil.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
#include "ConfigParserUtil.h"

int ConfigParserUtil::keyNameToNumber(const juce::String& keyName, const int octaveForMiddleC)
{
static const char* const noteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "", "Db", "", "Eb", "", "", "Gb", "", "Ab", "", "Bb" };
int ConfigParserUtil::keyNameToNumber(const juce::String& keyName, const int octaveForMiddleC) {
static const char* const noteNames[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "", "Db", "", "Eb", "", "", "Gb", "", "Ab", "", "Bb"};

int keyNumber, octave = 0, numPos = keyName.indexOfAnyOf("01234567890-");

if (numPos == 0)
keyNumber = keyName.getIntValue(); //apparently already a number!
else
{
if (numPos > 0)
{
if (numPos == 0) {
keyNumber = keyName.getIntValue(); // apparently already a number!
} else {
if (numPos > 0) {
octave = keyName.substring(numPos).getIntValue() - octaveForMiddleC + 5;
}
else
{
octave = octaveForMiddleC; //default to octave of middle C if none found
} else {
octave = octaveForMiddleC; // default to octave of middle C if none found
numPos = keyName.length();
}

Expand Down
6 changes: 3 additions & 3 deletions Source/ConfigParserUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "JuceHeader.h"

class ConfigParserUtil {
public:
// Adapted from https://forum.juce.com/t/midimessage-keynametonumber/9904
static int keyNameToNumber(const juce::String& keyName, const int octaveForMiddleC);
public:
// Adapted from https://forum.juce.com/t/midimessage-keynametonumber/9904
static int keyNameToNumber(const juce::String& keyName, const int octaveForMiddleC);
};
175 changes: 86 additions & 89 deletions Source/Configuration.cpp
Original file line number Diff line number Diff line change
@@ -1,134 +1,131 @@
#include "Configuration.h"
#include "InputTreeRootNode.h"
#include "ConfigParserUtil.h"
#include "InputTreeRootNode.h"

Configuration::Configuration() : Configuration("<foresight version=\"0\" name=\"None\">\n <settings>\n <latency>0</latency>\n </settings>\n <input></input>\n <output></output>\n</foresight>")
{
Configuration::Configuration() :
Configuration("<foresight version=\"0\" name=\"None\">\n <settings>\n <latency>0</latency>\n </settings>\n <input></input>\n <output></output>\n</foresight>") {
}

Configuration::Configuration(const std::string& xml)
{
this->xml = xml;
Configuration::Configuration(const std::string& xml) {
this->xml = xml;

std::unique_ptr<juce::XmlDocument> xmlDocument = std::make_unique<juce::XmlDocument>(xml);
std::unique_ptr<juce::XmlElement> rootElement = xmlDocument->getDocumentElementIfTagMatches("foresight");
std::unique_ptr<juce::XmlDocument> xmlDocument = std::make_unique<juce::XmlDocument>(xml);
std::unique_ptr<juce::XmlElement> rootElement = xmlDocument->getDocumentElementIfTagMatches("foresight");

// Header
// Header

if (!rootElement) throw std::exception(xmlDocument->getLastParseError().toStdString().c_str());
if (!rootElement) {
throw std::exception(xmlDocument->getLastParseError().toStdString().c_str());
}

version = rootElement->getIntAttribute("version", 0);
name = rootElement->getStringAttribute("name").toStdString();
version = rootElement->getIntAttribute("version", 0);
name = rootElement->getStringAttribute("name").toStdString();

if (version > CURRENT_CONFIG_VERSION) throw std::exception("This configuration was created for a newer version of Foresight. Please update the plugin to use this configuration.");
if (version > CURRENT_CONFIG_VERSION) {
throw std::exception("This configuration was created for a newer version of Foresight. Please update the plugin to use this configuration.");
}

// Settings
// Settings

juce::XmlElement* settingsRootElement = rootElement->getChildByName("settings");
juce::XmlElement* settingsRootElement = rootElement->getChildByName("settings");

if (settingsRootElement) {
// Latency
juce::XmlElement* latencySettingElement = settingsRootElement->getChildByName("latency");
if (latencySettingElement) latency = std::stod(latencySettingElement->getAllSubText().toStdString()) / 1000.0;
if (settingsRootElement) {
// Latency
juce::XmlElement* latencySettingElement = settingsRootElement->getChildByName("latency");
if (latencySettingElement) {
latency = std::stod(latencySettingElement->getAllSubText().toStdString()) / 1000.0;
}

// Range
for (const auto& rangeElement : settingsRootElement->getChildWithTagNameIterator("range")) {
std::string rangeModeText = rangeElement->getStringAttribute("boundary", "lower").toStdString();
int* targetVariable = rangeModeText == "upper" ? &rangeUpperBoundary : &rangeLowerBoundary;
int noteNumber = ConfigParserUtil::keyNameToNumber(rangeElement->getAllSubText(), 3);
*targetVariable = noteNumber;
}
// Range
for (const auto& rangeElement : settingsRootElement->getChildWithTagNameIterator("range")) {
std::string rangeModeText = rangeElement->getStringAttribute("boundary", "lower").toStdString();
int* targetVariable = rangeModeText == "upper" ? &rangeUpperBoundary : &rangeLowerBoundary;
int noteNumber = ConfigParserUtil::keyNameToNumber(rangeElement->getAllSubText(), 3);
*targetVariable = noteNumber;
}

// Blocklist
for (const auto& blockElement : settingsRootElement->getChildWithTagNameIterator("block")) {
juce::String targetText = blockElement->getAllSubText();
if (targetText.startsWith("CC")) {
blocked.insert(targetText.trim().toStdString());
}
else {
blocked.insert(std::to_string(ConfigParserUtil::keyNameToNumber(targetText, 3)));
}
}
}
// Blocklist
for (const auto& blockElement : settingsRootElement->getChildWithTagNameIterator("block")) {
juce::String targetText = blockElement->getAllSubText();
if (targetText.startsWith("CC")) {
blocked.insert(targetText.trim().toStdString());
} else {
blocked.insert(std::to_string(ConfigParserUtil::keyNameToNumber(targetText, 3)));
}
}
}

// Input
// Input

juce::XmlElement* inputTreeRootElement = rootElement->getChildByName("input");
juce::XmlElement* inputTreeRootElement = rootElement->getChildByName("input");

if (!inputTreeRootElement) throw std::exception("No <input> node found.");
if (!inputTreeRootElement) {
throw std::exception("No <input> node found.");
}

inputTreeRoot = std::make_unique<InputTreeRootNode>(*inputTreeRootElement);
inputTreeRoot = std::make_unique<InputTreeRootNode>(*inputTreeRootElement);

// Output
// Output

juce::XmlElement* outputListRootElement = rootElement->getChildByName("output");
juce::XmlElement* outputListRootElement = rootElement->getChildByName("output");

if (!outputListRootElement) throw std::exception("No <output> node found.");
if (!outputListRootElement) {
throw std::exception("No <output> node found.");
}

for (const auto& tagElement : outputListRootElement->getChildIterator()) {
std::string tagName = tagElement->getStringAttribute("name").toStdString();
for (const auto& tagElement : outputListRootElement->getChildIterator()) {
std::string tagName = tagElement->getStringAttribute("name").toStdString();

for (const auto& setElement : tagElement->getChildIterator()) {
outputList[tagName].emplace_back(*setElement);
}
}
for (const auto& setElement : tagElement->getChildIterator()) {
outputList[tagName].emplace_back(*setElement);
}
}
}

std::string Configuration::getSourceXML()
{
return xml;
std::string Configuration::getSourceXML() {
return xml;
}

std::string Configuration::getName()
{
return name;
std::string Configuration::getName() {
return name;
}

double Configuration::getLatencySeconds()
{
return latency;
double Configuration::getLatencySeconds() {
return latency;
}

double Configuration::getSampleRate()
{
return lastSampleRate;
double Configuration::getSampleRate() {
return lastSampleRate;
}

void Configuration::updateSampleRate(double sampleRate)
{
lastSampleRate = sampleRate;
void Configuration::updateSampleRate(double sampleRate) {
lastSampleRate = sampleRate;
}

int Configuration::getLatencySamples()
{
return (int)std::round(latency * lastSampleRate);
int Configuration::getLatencySamples() {
return (int)std::round(latency * lastSampleRate);
}

bool Configuration::isInRange(int noteNumber)
{
return noteNumber >= rangeLowerBoundary && noteNumber <= rangeUpperBoundary;
bool Configuration::isInRange(int noteNumber) {
return noteNumber >= rangeLowerBoundary && noteNumber <= rangeUpperBoundary;
}

bool Configuration::isBlocked(const juce::MidiMessage& message)
{
if (message.isController()) {
std::string ccString = "CC" + std::to_string(message.getControllerNumber());
return blocked.contains(ccString);
}
else if (message.isNoteOnOrOff()) {
return blocked.contains(std::to_string(message.getNoteNumber()));
}

return false;
bool Configuration::isBlocked(const juce::MidiMessage& message) {
if (message.isController()) {
std::string ccString = "CC" + std::to_string(message.getControllerNumber());
return blocked.contains(ccString);
} else if (message.isNoteOnOrOff()) {
return blocked.contains(std::to_string(message.getNoteNumber()));
}

return false;
}

std::unordered_set<std::string> Configuration::getTagsForNote(NoteContext& context)
{
inputTreeRoot->visit(context);
return context.getTags();
std::unordered_set<std::string> Configuration::getTagsForNote(NoteContext& context) {
inputTreeRoot->visit(context);
return context.getTags();
}

std::vector<OutputListNode> Configuration::getOutputNodes(const std::string& tag)
{
return outputList[tag];
std::vector<OutputListNode> Configuration::getOutputNodes(const std::string& tag) {
return outputList[tag];
}
Loading