Fixed tunings, can play actual SELCAL tones
This commit is contained in:
parent
e3335005d0
commit
1188afaf4b
32
src/code.cpp
32
src/code.cpp
@ -1,9 +1,41 @@
|
|||||||
#include "code.h"
|
#include "code.h"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <iterator>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace SELCAL {
|
namespace SELCAL {
|
||||||
|
|
||||||
Code::Code(std::string s) : code(s) {
|
Code::Code(std::string s) : code(s) {
|
||||||
|
std::transform(s.begin(), s.end(), s.begin(), ::toupper);
|
||||||
|
std::regex pattern(
|
||||||
|
"([0-9A-Z]{" + std::to_string(KEYS_PER_GROUP) + "})"
|
||||||
|
+ GROUP_SEPARATOR +
|
||||||
|
"([0-9A-Z]{" + std::to_string(KEYS_PER_GROUP) + "})"
|
||||||
|
);
|
||||||
|
|
||||||
|
std::smatch match;
|
||||||
|
if (std::regex_match(s, match, pattern)) {
|
||||||
|
// The first match[0] is always the entire string for a successful match
|
||||||
|
for (std::size_t i = 1; i < match.size(); ++i) {
|
||||||
|
std::ssub_match sub_match = match[i];
|
||||||
|
std::string piece = sub_match.str();
|
||||||
|
|
||||||
|
Group group;
|
||||||
|
std::transform(piece.begin(), piece.end(), group.begin(), [](char c) {
|
||||||
|
return static_cast<Key>(c);
|
||||||
|
});
|
||||||
|
groups.push_back(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new std::runtime_error("Could not parse SELCAL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Group>& Code::getGroups() const {
|
||||||
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Code::isValid() const {
|
bool Code::isValid() const {
|
||||||
|
|||||||
@ -51,11 +51,13 @@ class Code {
|
|||||||
public:
|
public:
|
||||||
Code(std::string s);
|
Code(std::string s);
|
||||||
|
|
||||||
|
const std::vector<Group>& getGroups() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isValid() const;
|
bool isValid() const;
|
||||||
|
|
||||||
const std::string code;
|
const std::string code;
|
||||||
const std::vector<Group> groups;
|
std::vector<Group> groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // SELCAL
|
} // SELCAL
|
||||||
|
|||||||
64
src/main.cpp
64
src/main.cpp
@ -10,6 +10,16 @@
|
|||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
SELCAL::Code code{"A5-CD"};
|
||||||
|
|
||||||
|
for (auto& group : code.getGroups()) {
|
||||||
|
std::cout
|
||||||
|
<< magic_enum::enum_name(group[0]) << " + "
|
||||||
|
<< magic_enum::enum_name(group[1])
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Synth synth;
|
Synth synth;
|
||||||
|
|
||||||
for(int i = 1; i < argc; ++i) {
|
for(int i = 1; i < argc; ++i) {
|
||||||
@ -21,7 +31,7 @@ int main(int argc, char** argv) {
|
|||||||
<< ":(" << program.bankNumber << ", " << program.programNumber << ")"
|
<< ":(" << program.bankNumber << ", " << program.programNumber << ")"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
if (program.name == "Tuba") {
|
if (program.name == "Square Wave") {
|
||||||
std::cout << "Loading program!" << std::endl;
|
std::cout << "Loading program!" << std::endl;
|
||||||
synth.loadProgram(program);
|
synth.loadProgram(program);
|
||||||
}
|
}
|
||||||
@ -67,41 +77,51 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
|
|
||||||
for (auto pair : keyFrequencies) {
|
for (auto pair : keyFrequencies) {
|
||||||
std::cout
|
|
||||||
<< magic_enum::enum_name(pair.first) << " = "
|
|
||||||
<< pair.second << " Hz "
|
|
||||||
<< " or MIDI key " << frequencyToMidi(pair.second)
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
// fluidsynth wants tunings in MIDI cents, which effectively means MIDI key * 100.
|
// fluidsynth wants tunings in MIDI cents, which effectively means MIDI key * 100.
|
||||||
// As we only care about the SELCAL 32 tones, only tune those specific keys. We don't
|
// As we only care about the SELCAL 32 tones, only tune those specific keys. We don't
|
||||||
// need to tune the full 128-key keyboard.
|
// need to tune the full 128-key keyboard.
|
||||||
constexpr double MIDI_CENT_SCALE = 100.0;
|
constexpr double MIDI_CENT_SCALE = 100.0;
|
||||||
const int keyIndex = static_cast<int>(pair.first);
|
const int keyIndex = static_cast<int>(pair.first);
|
||||||
tunings[keyIndex] = frequencyToMidi(pair.second * MIDI_CENT_SCALE);
|
tunings[keyIndex] = frequencyToMidi(pair.second) * MIDI_CENT_SCALE;
|
||||||
|
|
||||||
|
std::cout
|
||||||
|
<< magic_enum::enum_name(pair.first) << " = "
|
||||||
|
<< pair.second << " Hz "
|
||||||
|
<< " or MIDI key " << frequencyToMidi(pair.second) * MIDI_CENT_SCALE
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = synth.setTuning(tunings);
|
|
||||||
std::cout << "Set tuning: " << (success ? "success" : "failed") << std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
fluid_synth_t* raw_synth = synth.getSynth();
|
fluid_synth_t* raw_synth = synth.getSynth();
|
||||||
|
constexpr int ALL_CHANNELS = -1;
|
||||||
|
bool success;
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
int i, key;
|
|
||||||
for(i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
/* Generate a random key */
|
|
||||||
key = 30 + (int)(12.0f * rand() / (float) RAND_MAX);
|
|
||||||
|
|
||||||
/* Play a note */
|
success = synth.setTuning(tunings);
|
||||||
fluid_synth_noteon(raw_synth, 0, key, 100);
|
std::cout << "Set tuning: " << (success ? "success" : "failed") << std::endl;
|
||||||
|
|
||||||
/* Sleep for 1 second */
|
for (auto& group : code.getGroups()) {
|
||||||
|
fluid_synth_noteon(raw_synth, 0, static_cast<int>(group[0]), 100);
|
||||||
|
fluid_synth_noteon(raw_synth, 1, static_cast<int>(group[1]), 100);
|
||||||
std::this_thread::sleep_for(1s);
|
std::this_thread::sleep_for(1s);
|
||||||
|
|
||||||
/* Stop the note */
|
// Silence between tone groups
|
||||||
fluid_synth_noteoff(raw_synth, 0, key);
|
fluid_synth_all_notes_off(raw_synth, ALL_CHANNELS);
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
success = synth.resetTuning();
|
||||||
|
std::cout << "Set tuning: " << (success ? "success" : "failed") << std::endl;
|
||||||
|
|
||||||
|
for (auto& group : code.getGroups()) {
|
||||||
|
fluid_synth_noteon(raw_synth, 0, static_cast<int>(group[0]), 100);
|
||||||
|
fluid_synth_noteon(raw_synth, 1, static_cast<int>(group[1]), 100);
|
||||||
|
std::this_thread::sleep_for(1s);
|
||||||
|
|
||||||
|
// Silence between tone groups
|
||||||
|
fluid_synth_all_notes_off(raw_synth, ALL_CHANNELS);
|
||||||
|
std::this_thread::sleep_for(200ms);
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,6 +77,11 @@ bool Synth::setTuning(const std::array<double, NUM_MIDI_NOTES>& pitches) {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (result == FLUID_OK) {
|
||||||
|
result = fluid_synth_activate_tuning(synth, 0, 0, 0, 1);
|
||||||
|
result = fluid_synth_activate_tuning(synth, 1, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return result == FLUID_OK;
|
return result == FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user