26 void add_port(
const std::string&
id,
const std::string& name,
bool is_input =
true) {
28 std::lock_guard<std::mutex> lk(mu_);
29 remove_locked(
id, is_input);
30 ports_.push_back({id, name, is_input, !is_input});
36 void remove_port(
const std::string&
id,
bool is_input =
true) {
38 std::lock_guard<std::mutex> lk(mu_);
39 remove_locked(
id, is_input);
47 std::lock_guard<std::mutex> lk(mu_);
48 ports_ = std::move(ports);
54 std::lock_guard<std::mutex> lk(mu_);
63 std::vector<std::shared_ptr<InputState>> targets;
65 std::lock_guard<std::mutex> lk(mu_);
66 for (
auto& s : inputs_) {
67 if (s->open && s->port_id ==
id)
72 for (
auto& s : targets) {
86 std::lock_guard<std::mutex> lk(mu_);
87 for (
auto& s : inputs_) {
91 inputs_.erase(std::remove_if(inputs_.begin(), inputs_.end(),
92 [](
const std::shared_ptr<InputState>& s) { return !s->open; }),
98 std::lock_guard<std::mutex> lk(mu_);
100 for (
auto& s : inputs_)
101 if (s->open && s->port_id ==
id)
108 std::lock_guard<std::mutex> lk(mu_);
114 std::lock_guard<std::mutex> lk(mu_);
115 failing_opens_ = count;
126 return std::make_unique<Input>(
this);
130 return std::make_unique<Output>();
134 std::lock_guard<std::mutex> lk(mu_);
135 port_change_cb_ = std::move(cb);
145 class Input :
public MidiInput {
147 explicit Input(MockMidiSystem* owner)
148 : owner_(owner), state_(
std::make_shared<InputState>()) {}
154 std::lock_guard<std::mutex> lk(owner_->mu_);
155 if (owner_->failing_opens_ > 0) {
156 --owner_->failing_opens_;
160 std::any_of(owner_->ports_.begin(), owner_->ports_.end(),
161 [&](
const MidiPortInfo& p) { return p.is_input && p.id == port_id; });
164 state_->port_id = port_id;
165 state_->callback = std::move(callback);
167 owner_->inputs_.push_back(state_);
168 ++owner_->total_opens_;
172 void close()
override {
173 std::lock_guard<std::mutex> lk(owner_->mu_);
176 state_->open =
false;
177 auto&
v = owner_->inputs_;
178 v.erase(std::remove(
v.begin(),
v.end(), state_),
v.end());
181 bool is_open()
const override {
182 std::lock_guard<std::mutex> lk(owner_->mu_);
187 MockMidiSystem* owner_;
188 std::shared_ptr<InputState> state_;
193 bool open(
const std::string&)
override {
197 void close()
override {
200 bool is_open()
const override {
203 void send(
const MidiEvent&)
override {}
209 std::vector<MidiPortInfo> list(
bool inputs)
const {
210 std::lock_guard<std::mutex> lk(mu_);
211 std::vector<MidiPortInfo> out;
212 for (
auto& p : ports_)
213 if (
p.is_input == inputs)
218 void remove_locked(
const std::string&
id,
bool is_input) {
219 ports_.erase(std::remove_if(ports_.begin(), ports_.end(),
220 [&](
const MidiPortInfo& p) {
221 return p.id == id && p.is_input == is_input;
226 mutable std::mutex mu_;
227 std::vector<MidiPortInfo> ports_;
228 std::vector<std::shared_ptr<InputState>> inputs_;
230 int total_opens_ = 0;
231 int failing_opens_ = 0;
virtual bool is_open() const =0
std::function< void()> PortChangeCallback
Register a callback for MIDI port changes (device plug/unplug).
Definition device.hpp:62
Definition mock_midi_system.hpp:23
void add_port(const std::string &id, const std::string &name, bool is_input=true)
Add (or replace) a port and notify the port-change callback.
Definition mock_midi_system.hpp:26
std::vector< MidiPortInfo > enumerate_outputs() override
Definition mock_midi_system.hpp:121
std::vector< MidiPortInfo > enumerate_inputs() override
Definition mock_midi_system.hpp:118
std::unique_ptr< MidiOutput > create_output() override
Definition mock_midi_system.hpp:129
std::unique_ptr< MidiInput > create_input() override
Definition mock_midi_system.hpp:125
int total_opens() const
Total successful input opens since construction.
Definition mock_midi_system.hpp:107
void remove_port(const std::string &id, bool is_input=true)
Remove a port and notify the port-change callback.
Definition mock_midi_system.hpp:36
void notify()
Definition mock_midi_system.hpp:51
void fail_next_opens(int count)
Make the next count open attempts fail, to model a busy device.
Definition mock_midi_system.hpp:113
int open_input_count(const std::string &id) const
Number of currently open inputs on id.
Definition mock_midi_system.hpp:97
void set_ports_silently(std::vector< MidiPortInfo > ports)
Change the port list without notifying, to model a notification that never arrived.
Definition mock_midi_system.hpp:46
void drop_connections(const std::string &id)
Sever the connection of every open input on id while the port stays listed, as when an OS replaces an...
Definition mock_midi_system.hpp:85
void set_port_change_callback(PortChangeCallback cb) override
Definition mock_midi_system.hpp:133
int inject(const std::string &id, const MidiEvent &event)
Deliver event to every open input on id. Returns how many received it.
Definition mock_midi_system.hpp:62
@ MidiOutput
Definition live_dsp_telemetry.hpp:42
Definition custom_node_events.hpp:26
std::function< void(const MidiEvent &event)> MidiInputCallback
Definition device.hpp:21
@ p
Definition input_events.hpp:40
@ v
Definition input_events.hpp:41
Timestamped MIDI event combining a choc::midi::ShortMessage with timing info.
Definition message.hpp:32