2 * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "pbd/error.h"
25 #include "pbd/compose.h"
26 #include "pbd/windows_timer_utils.h"
28 #include "winmmemidi_io.h"
33 using namespace ARDOUR;
35 WinMMEMidiIO::WinMMEMidiIO()
39 , m_changed_callback (0)
42 pthread_mutex_init (&m_device_lock, 0);
45 WinMMEMidiIO::~WinMMEMidiIO()
47 pthread_mutex_lock (&m_device_lock);
49 pthread_mutex_unlock (&m_device_lock);
50 pthread_mutex_destroy (&m_device_lock);
54 WinMMEMidiIO::cleanup()
56 DEBUG_MIDI ("MIDI cleanup\n");
59 destroy_input_devices ();
60 destroy_output_devices ();
64 WinMMEMidiIO::dequeue_input_event (uint32_t port,
65 uint64_t timestamp_start,
66 uint64_t timestamp_end,
74 assert(port < m_inputs.size());
76 // m_inputs access should be protected by trylock
77 return m_inputs[port]->dequeue_midi_event (
78 timestamp_start, timestamp_end, timestamp, d, s);
82 WinMMEMidiIO::enqueue_output_event (uint32_t port,
90 assert(port < m_outputs.size());
92 // m_outputs access should be protected by trylock
93 return m_outputs[port]->enqueue_midi_event (timestamp, d, s);
98 WinMMEMidiIO::port_id (uint32_t port, bool input)
100 std::stringstream ss;
103 ss << "system:midi_capture_";
106 ss << "system:midi_playback_";
113 WinMMEMidiIO::port_name (uint32_t port, bool input)
116 if (port < m_inputs.size ()) {
117 return m_inputs[port]->name ();
120 if (port < m_outputs.size ()) {
121 return m_outputs[port]->name ();
128 WinMMEMidiIO::start ()
131 DEBUG_MIDI ("MIDI driver already started\n");
136 DEBUG_MIDI ("Starting MIDI driver\n");
138 PBD::MMTIMERS::set_min_resolution();
145 WinMMEMidiIO::stop ()
148 DEBUG_MIDI ("MIDI driver already stopped\n");
151 DEBUG_MIDI ("Stopping MIDI driver\n");
154 pthread_mutex_lock (&m_device_lock);
156 pthread_mutex_unlock (&m_device_lock);
158 PBD::MMTIMERS::reset_resolution();
162 WinMMEMidiIO::start_devices ()
164 for (std::vector<WinMMEMidiInputDevice*>::iterator i = m_inputs.begin ();
167 if (!(*i)->start ()) {
168 PBD::error << string_compose (_("Unable to start MIDI input device %1\n"),
169 (*i)->name ()) << endmsg;
172 for (std::vector<WinMMEMidiOutputDevice*>::iterator i = m_outputs.begin ();
175 if (!(*i)->start ()) {
176 PBD::error << string_compose (_ ("Unable to start MIDI output device %1\n"),
177 (*i)->name ()) << endmsg;
183 WinMMEMidiIO::stop_devices ()
185 for (std::vector<WinMMEMidiInputDevice*>::iterator i = m_inputs.begin ();
188 if (!(*i)->stop ()) {
189 PBD::error << string_compose (_ ("Unable to stop MIDI input device %1\n"),
190 (*i)->name ()) << endmsg;
193 for (std::vector<WinMMEMidiOutputDevice*>::iterator i = m_outputs.begin ();
196 if (!(*i)->stop ()) {
197 PBD::error << string_compose (_ ("Unable to stop MIDI output device %1\n"),
198 (*i)->name ()) << endmsg;
204 WinMMEMidiIO::create_input_devices ()
206 int srcCount = midiInGetNumDevs ();
208 DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
210 for (int i = 0; i < srcCount; ++i) {
212 WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
214 m_inputs.push_back (midi_input);
218 DEBUG_MIDI ("Unable to create MIDI input\n");
224 WinMMEMidiIO::create_output_devices ()
226 int dstCount = midiOutGetNumDevs ();
228 DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
230 for (int i = 0; i < dstCount; ++i) {
232 WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
234 m_outputs.push_back(midi_output);
237 DEBUG_MIDI ("Unable to create MIDI output\n");
244 WinMMEMidiIO::destroy_input_devices ()
246 while (!m_inputs.empty ()) {
247 WinMMEMidiInputDevice* midi_input = m_inputs.back ();
248 // assert(midi_input->stopped ());
249 m_inputs.pop_back ();
255 WinMMEMidiIO::destroy_output_devices ()
257 while (!m_outputs.empty ()) {
258 WinMMEMidiOutputDevice* midi_output = m_outputs.back ();
259 // assert(midi_output->stopped ());
260 m_outputs.pop_back ();
266 WinMMEMidiIO::discover()
272 if (pthread_mutex_trylock (&m_device_lock)) {
278 create_input_devices ();
279 create_output_devices ();
281 if (!(m_inputs.size () || m_outputs.size ())) {
282 DEBUG_MIDI ("No midi inputs or outputs\n");
283 pthread_mutex_unlock (&m_device_lock);
287 DEBUG_MIDI (string_compose ("Discovered %1 inputs and %2 outputs\n",
291 if (m_changed_callback) {
292 m_changed_callback(m_changed_arg);
296 pthread_mutex_unlock (&m_device_lock);