builtin port fix
This commit is contained in:
parent
25b446a5cc
commit
f46a866613
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `port` function have proper semantics now
|
||||||
|
|
||||||
## [0.4.0]
|
## [0.4.0]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -1637,8 +1637,8 @@ static Result<Value> builtin_port(Interpreter &interpreter, std::vector<Value> a
|
|||||||
for (auto const& [key, port] : Context::established_connections) {
|
for (auto const& [key, port] : Context::established_connections) {
|
||||||
if (port == interpreter.current_context->port) {
|
if (port == interpreter.current_context->port) {
|
||||||
return std::visit(Overloaded {
|
return std::visit(Overloaded {
|
||||||
[](midi::connections::Virtual_Port) { return Value(Symbol("virtual")); },
|
[](midi::Virtual_Port) { return Value(Symbol("virtual")); },
|
||||||
[](midi::connections::Established_Port port) { return Value(Number(port)); },
|
[](midi::Established_Port port) { return Value(Number(port)); },
|
||||||
}, key);
|
}, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1647,14 +1647,14 @@ static Result<Value> builtin_port(Interpreter &interpreter, std::vector<Value> a
|
|||||||
|
|
||||||
if (auto a = match<Number>(args)) {
|
if (auto a = match<Number>(args)) {
|
||||||
auto [port_number] = *a;
|
auto [port_number] = *a;
|
||||||
Try(interpreter.current_context->connect(port_number.floor().as_int()));
|
Try(interpreter.current_context->connect(midi::Established_Port(port_number.floor().as_int())));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto a = match<Symbol>(args)) {
|
if (auto a = match<Symbol>(args)) {
|
||||||
auto [port_type] = *a;
|
auto [port_type] = *a;
|
||||||
if (port_type == "virtual") {
|
if (port_type == "virtual") {
|
||||||
Try(interpreter.current_context->connect(std::nullopt));
|
Try(interpreter.current_context->connect(midi::Virtual_Port{}));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@ std::chrono::duration<float> Context::length_to_duration(std::optional<Number> l
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct std::hash<midi::connections::Key>
|
struct std::hash<midi::Port>
|
||||||
{
|
{
|
||||||
std::size_t operator()(midi::connections::Key const& value) const
|
std::size_t operator()(midi::Port const& value) const
|
||||||
{
|
{
|
||||||
using namespace midi::connections;
|
using namespace midi;
|
||||||
return hash_combine(value.index(), std::visit(Overloaded {
|
return hash_combine(value.index(), std::visit(Overloaded {
|
||||||
[](Virtual_Port) { return 0u; },
|
[](Virtual_Port) { return 0u; },
|
||||||
[](Established_Port port) { return port; },
|
[](Established_Port port) { return port; },
|
||||||
@ -26,35 +26,33 @@ struct std::hash<midi::connections::Key>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<midi::connections::Key, std::shared_ptr<midi::Connection>> Context::established_connections;
|
std::unordered_map<midi::Port, std::shared_ptr<midi::Connection>> Context::established_connections;
|
||||||
|
|
||||||
/// Establish connection to given port
|
/// Establish connection to given port
|
||||||
std::optional<Error> Context::connect(std::optional<Port_Number> port_number)
|
std::optional<Error> Context::connect(std::optional<midi::Port> desired_port)
|
||||||
{
|
{
|
||||||
// FIXME This function doesn't support creating virtual ports when established ports are available
|
// FIXME This function doesn't support creating virtual ports when established ports are available
|
||||||
using namespace midi::connections;
|
if (!desired_port) {
|
||||||
auto const key = port_number ? Key(*port_number) : Key(Virtual_Port{});
|
if (not established_connections.empty()) {
|
||||||
|
port = established_connections.begin()->second;
|
||||||
if (auto it = established_connections.find(key); it != established_connections.end()) {
|
return std::nullopt;
|
||||||
port = it->second;
|
}
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port_number) {
|
|
||||||
auto connection = std::make_shared<midi::Rt_Midi>();
|
auto connection = std::make_shared<midi::Rt_Midi>();
|
||||||
connection->connect_output(*port_number);
|
established_connections[connection->establish_any_connection()] = connection;
|
||||||
established_connections[*port_number] = connection;
|
|
||||||
port = connection;
|
port = connection;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto connection = std::make_shared<midi::Rt_Midi>();
|
if (auto it = established_connections.find(*desired_port); it != established_connections.end()) {
|
||||||
if (connection->connect_or_create_output()) {
|
port = it->second;
|
||||||
established_connections[0u] = connection;
|
return std::nullopt;
|
||||||
} else {
|
|
||||||
established_connections[Virtual_Port{}] = connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto connection = std::make_shared<midi::Rt_Midi>();
|
||||||
|
connection->connect(*desired_port);
|
||||||
|
established_connections[*desired_port] = connection;
|
||||||
port = connection;
|
port = connection;
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,17 +9,6 @@
|
|||||||
#include <musique/value/note.hh>
|
#include <musique/value/note.hh>
|
||||||
#include <musique/value/number.hh>
|
#include <musique/value/number.hh>
|
||||||
|
|
||||||
namespace midi::connections
|
|
||||||
{
|
|
||||||
using Established_Port = unsigned int;
|
|
||||||
|
|
||||||
struct Virtual_Port
|
|
||||||
{
|
|
||||||
bool operator==(Virtual_Port const&) const = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
using Key = std::variant<Established_Port, Virtual_Port>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Context holds default values for music related actions
|
/// Context holds default values for music related actions
|
||||||
struct Context
|
struct Context
|
||||||
@ -39,12 +28,12 @@ struct Context
|
|||||||
using Port_Number = unsigned int;
|
using Port_Number = unsigned int;
|
||||||
|
|
||||||
/// Connections that have been established so far
|
/// Connections that have been established so far
|
||||||
static std::unordered_map<midi::connections::Key, std::shared_ptr<midi::Connection>> established_connections;
|
static std::unordered_map<midi::Port, std::shared_ptr<midi::Connection>> established_connections;
|
||||||
|
|
||||||
/// Establish connection to given port
|
/// Establish connection to given port
|
||||||
///
|
///
|
||||||
/// If port number wasn't provided connect to first existing one or create one
|
/// If port number wasn't provided connect to first existing one or create one
|
||||||
std::optional<Error> connect(std::optional<Port_Number>);
|
std::optional<Error> connect(std::optional<midi::Port>);
|
||||||
|
|
||||||
/// Fills empty places in Note like octave and length with default values from context
|
/// Fills empty places in Note like octave and length with default values from context
|
||||||
Note fill(Note) const;
|
Note fill(Note) const;
|
||||||
|
@ -169,7 +169,7 @@ struct Runner
|
|||||||
ensure(the == nullptr, "Only one instance of runner is supported");
|
ensure(the == nullptr, "Only one instance of runner is supported");
|
||||||
the = this;
|
the = this;
|
||||||
|
|
||||||
interpreter.current_context->connect(std::nullopt);
|
// interpreter.current_context->connect(std::nullopt);
|
||||||
|
|
||||||
Env::global->force_define("say", +[](Interpreter &interpreter, std::vector<Value> args) -> Result<Value> {
|
Env::global->force_define("say", +[](Interpreter &interpreter, std::vector<Value> args) -> Result<Value> {
|
||||||
for (auto it = args.begin(); it != args.end(); ++it) {
|
for (auto it = args.begin(); it != args.end(); ++it) {
|
||||||
|
@ -4,10 +4,20 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
// Documentation of midi messages available at http://midi.teragonaudio.com/tech/midispec.htm
|
// Documentation of midi messages available at http://midi.teragonaudio.com/tech/midispec.htm
|
||||||
namespace midi
|
namespace midi
|
||||||
{
|
{
|
||||||
|
using Established_Port = unsigned int;
|
||||||
|
|
||||||
|
struct Virtual_Port
|
||||||
|
{
|
||||||
|
bool operator==(Virtual_Port const&) const = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Port = std::variant<Established_Port, Virtual_Port>;
|
||||||
|
|
||||||
struct Connection
|
struct Connection
|
||||||
{
|
{
|
||||||
virtual ~Connection() = default;
|
virtual ~Connection() = default;
|
||||||
@ -26,18 +36,15 @@ namespace midi
|
|||||||
{
|
{
|
||||||
~Rt_Midi() override = default;
|
~Rt_Midi() override = default;
|
||||||
|
|
||||||
bool connect_or_create_output();
|
/// Connect to existing MIDI output or create virtual port
|
||||||
|
Port establish_any_connection();
|
||||||
|
|
||||||
/// Connect with MIDI virtual port
|
/// Connect to given port
|
||||||
void connect_output();
|
void connect(Port port);
|
||||||
|
|
||||||
/// Connect with specific MIDI port for outputing MIDI messages
|
|
||||||
void connect_output(unsigned target);
|
|
||||||
|
|
||||||
/// List available ports
|
/// List available ports
|
||||||
void list_ports(std::ostream &out) const;
|
void list_ports(std::ostream &out) const;
|
||||||
|
|
||||||
|
|
||||||
bool supports_output() const override;
|
bool supports_output() const override;
|
||||||
|
|
||||||
void send_note_on (uint8_t channel, uint8_t note_number, uint8_t velocity) override;
|
void send_note_on (uint8_t channel, uint8_t note_number, uint8_t velocity) override;
|
||||||
@ -45,6 +52,7 @@ namespace midi
|
|||||||
void send_program_change(uint8_t channel, uint8_t program) override;
|
void send_program_change(uint8_t channel, uint8_t program) override;
|
||||||
void send_controller_change(uint8_t channel, uint8_t controller_number, uint8_t value) override;
|
void send_controller_change(uint8_t channel, uint8_t controller_number, uint8_t value) override;
|
||||||
|
|
||||||
|
|
||||||
std::optional<RtMidiOut> output;
|
std::optional<RtMidiOut> output;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,15 +34,16 @@ try {
|
|||||||
std::exit(33);
|
std::exit(33);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool midi::Rt_Midi::connect_or_create_output()
|
midi::Port midi::Rt_Midi::establish_any_connection()
|
||||||
try {
|
try {
|
||||||
output.emplace();
|
output.emplace();
|
||||||
if (output->getPortCount()) {
|
if (output->getPortCount()) {
|
||||||
output->openPort(0);
|
output->openPort(0, "Musique");
|
||||||
return true;
|
return Established_Port { 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
output->openVirtualPort("Musique");
|
output->openVirtualPort("Musique");
|
||||||
return false;
|
return Virtual_Port{};
|
||||||
}
|
}
|
||||||
catch (RtMidiError &error) {
|
catch (RtMidiError &error) {
|
||||||
// TODO(error)
|
// TODO(error)
|
||||||
@ -50,23 +51,22 @@ catch (RtMidiError &error) {
|
|||||||
std::exit(33);
|
std::exit(33);
|
||||||
}
|
}
|
||||||
|
|
||||||
void midi::Rt_Midi::connect_output()
|
void midi::Rt_Midi::connect(midi::Port port)
|
||||||
try {
|
try {
|
||||||
ensure(not output.has_value(), "Reconeccting is not supported yet");
|
std::visit(Overloaded{
|
||||||
output.emplace();
|
[this](midi::Virtual_Port) {
|
||||||
output->openVirtualPort("Musique");
|
output.emplace();
|
||||||
} catch (RtMidiError &error) {
|
output->openVirtualPort("Musique");
|
||||||
// TODO(error)
|
},
|
||||||
std::cerr << "Failed to use MIDI connection: " << error.getMessage() << std::endl;
|
[this](midi::Established_Port port) {
|
||||||
std::exit(33);
|
output.emplace();
|
||||||
|
output->openPort(port, "Musique");
|
||||||
|
},
|
||||||
|
}, port);
|
||||||
|
output->setClientName("Musique");
|
||||||
|
output->setPortName("Musique");
|
||||||
}
|
}
|
||||||
|
catch (RtMidiError &error) {
|
||||||
void midi::Rt_Midi::connect_output(unsigned target)
|
|
||||||
try {
|
|
||||||
ensure(not output.has_value(), "Reconeccting is not supported yet");
|
|
||||||
output.emplace();
|
|
||||||
output->openPort(target);
|
|
||||||
} catch (RtMidiError &error) {
|
|
||||||
// TODO(error)
|
// TODO(error)
|
||||||
std::cerr << "Failed to use MIDI connection: " << error.getMessage() << std::endl;
|
std::cerr << "Failed to use MIDI connection: " << error.getMessage() << std::endl;
|
||||||
std::exit(33);
|
std::exit(33);
|
||||||
|
Loading…
Reference in New Issue
Block a user