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 <regex>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace SELCAL {
|
||||
|
||||
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 {
|
||||
|
||||
@ -51,11 +51,13 @@ class Code {
|
||||
public:
|
||||
Code(std::string s);
|
||||
|
||||
const std::vector<Group>& getGroups() const;
|
||||
|
||||
private:
|
||||
bool isValid() const;
|
||||
|
||||
const std::string code;
|
||||
const std::vector<Group> groups;
|
||||
std::vector<Group> groups;
|
||||
};
|
||||
|
||||
} // SELCAL
|
||||
|
||||
64
src/main.cpp
64
src/main.cpp
@ -10,6 +10,16 @@
|
||||
|
||||
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;
|
||||
|
||||
for(int i = 1; i < argc; ++i) {
|
||||
@ -21,7 +31,7 @@ int main(int argc, char** argv) {
|
||||
<< ":(" << program.bankNumber << ", " << program.programNumber << ")"
|
||||
<< std::endl;
|
||||
|
||||
if (program.name == "Tuba") {
|
||||
if (program.name == "Square Wave") {
|
||||
std::cout << "Loading program!" << std::endl;
|
||||
synth.loadProgram(program);
|
||||
}
|
||||
@ -67,41 +77,51 @@ int main(int argc, char** argv) {
|
||||
|
||||
|
||||
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.
|
||||
// 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.
|
||||
constexpr double MIDI_CENT_SCALE = 100.0;
|
||||
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();
|
||||
constexpr int ALL_CHANNELS = -1;
|
||||
bool success;
|
||||
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 */
|
||||
fluid_synth_noteon(raw_synth, 0, key, 100);
|
||||
success = synth.setTuning(tunings);
|
||||
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);
|
||||
|
||||
/* Stop the note */
|
||||
fluid_synth_noteoff(raw_synth, 0, key);
|
||||
// Silence between tone groups
|
||||
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
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user