openMSX
MidiInReader.cc
Go to the documentation of this file.
1#include "MidiInReader.hh"
2#include "MidiInConnector.hh"
3#include "PlugException.hh"
4#include "EventDistributor.hh"
5#include "Scheduler.hh"
6#include "FileOperations.hh"
7#include "checked_cast.hh"
8#include "serialize.hh"
9#include <array>
10#include <cstdio>
11#include <cerrno>
12#include <cstring>
13
14namespace openmsx {
15
17 Scheduler& scheduler_,
18 CommandController& commandController)
19 : eventDistributor(eventDistributor_), scheduler(scheduler_)
20 , readFilenameSetting(
21 commandController, "midi-in-readfilename",
22 "filename of the file where the MIDI input is read from",
23 "/dev/midi")
24{
25 eventDistributor.registerEventListener(EventType::MIDI_IN_READER, *this);
26}
27
29{
31}
32
33// Pluggable
34void MidiInReader::plugHelper(Connector& connector_, EmuTime::param /*time*/)
35{
36 file = FileOperations::openFile(readFilenameSetting.getString(), "rb");
37 if (!file) {
38 throw PlugException("Failed to open input: ", strerror(errno));
39 }
40
41 auto& midiConnector = checked_cast<MidiInConnector&>(connector_);
42 midiConnector.setDataBits(SerialDataInterface::DATA_8); // 8 data bits
43 midiConnector.setStopBits(SerialDataInterface::STOP_1); // 1 stop bit
44 midiConnector.setParityBit(false, SerialDataInterface::EVEN); // no parity
45
46 setConnector(&connector_); // base class will do this in a moment,
47 // but thread already needs it
48 thread = std::thread([this]() { run(); });
49}
50
51void MidiInReader::unplugHelper(EmuTime::param /*time*/)
52{
53 poller.abort();
54 thread.join();
55 file.reset();
56}
57
58std::string_view MidiInReader::getName() const
59{
60 return "midi-in-reader";
61}
62
63std::string_view MidiInReader::getDescription() const
64{
65 return "MIDI in file reader. Sends data from an input file to the "
66 "MIDI port it is connected to. The filename is set with "
67 "the 'midi-in-readfilename' setting.";
68}
69
70
71void MidiInReader::run()
72{
73 if (!file) return;
74 while (true) {
75#ifndef _WIN32
76 if (poller.poll(fileno(file.get()))) {
77 break;
78 }
79#endif
80 std::array<uint8_t, 1> buf;
81 size_t num = fread(buf.data(), sizeof(uint8_t), buf.size(), file.get());
82 if (poller.aborted()) {
83 break;
84 }
85 if (num != 1) {
86 continue;
87 }
88 assert(isPluggedIn());
89
90 {
91 std::lock_guard<std::mutex> lock(mutex);
92 queue.push_back(buf[0]);
93 }
94 eventDistributor.distributeEvent(MidiInReaderEvent());
95 }
96}
97
98// MidiInDevice
99void MidiInReader::signal(EmuTime::param time)
100{
101 auto* conn = checked_cast<MidiInConnector*>(getConnector());
102 if (!conn->acceptsData()) {
103 std::lock_guard<std::mutex> lock(mutex);
104 queue.clear();
105 return;
106 }
107 if (!conn->ready()) {
108 return;
109 }
110
111 uint8_t data;
112 {
113 std::lock_guard<std::mutex> lock(mutex);
114 if (queue.empty()) return;
115 data = queue.pop_front();
116 }
117 conn->recvByte(data, time);
118}
119
120// EventListener
121int MidiInReader::signalEvent(const Event& /*event*/)
122{
123 if (isPluggedIn()) {
124 signal(scheduler.getCurrentTime());
125 } else {
126 std::lock_guard<std::mutex> lock(mutex);
127 queue.clear();
128 }
129 return 0;
130}
131
132
133template<typename Archive>
134void MidiInReader::serialize(Archive& /*ar*/, unsigned /*version*/)
135{
136 // don't try to resume a previous logfile (see PrinterPortLogger)
137}
140
141} // namespace openmsx
bool empty() const
void push_back(U &&u)
Represents something you can plug devices into.
Definition: Connector.hh:21
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
zstring_view getString() const noexcept
void serialize(Archive &ar, unsigned version)
std::string_view getName() const override
Name used to identify this pluggable.
Definition: MidiInReader.cc:58
void plugHelper(Connector &connector, EmuTime::param time) override
Definition: MidiInReader.cc:34
std::string_view getDescription() const override
Description for this pluggable.
Definition: MidiInReader.cc:63
void unplugHelper(EmuTime::param time) override
Definition: MidiInReader.cc:51
MidiInReader(EventDistributor &eventDistributor, Scheduler &scheduler, CommandController &commandController)
Definition: MidiInReader.cc:16
~MidiInReader() override
Definition: MidiInReader.cc:28
void signal(EmuTime::param time) override
Definition: MidiInReader.cc:99
Thrown when a plug action fails.
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition: Pluggable.hh:49
void setConnector(Connector *conn)
Definition: Pluggable.hh:58
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition: Pluggable.hh:43
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
Definition: Poller.cc:43
bool aborted()
Returns true iff abort() was called.
Definition: Poller.hh:29
void abort()
Aborts a poll in progress and any future poll attempts.
Definition: Poller.cc:31
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Definition: Scheduler.cc:84
FILE_t openFile(zstring_view filename, zstring_view mode)
Call fopen() in a platform-independent manner.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition: Event.hh:450
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021