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.
25 #include "pbd/error.h"
26 #include "pbd/compose.h"
27 #include "pbd/windows_timer_utils.h"
29 #include "winmmemidi_io.h"
34 using namespace ARDOUR;
36 WinMMEMidiIO::WinMMEMidiIO()
40 , m_changed_callback (0)
43 pthread_mutex_init (&m_device_lock, 0);
46 WinMMEMidiIO::~WinMMEMidiIO()
48 pthread_mutex_lock (&m_device_lock);
50 pthread_mutex_unlock (&m_device_lock);
51 pthread_mutex_destroy (&m_device_lock);
55 WinMMEMidiIO::cleanup()
57 DEBUG_MIDI ("MIDI cleanup\n");
60 destroy_input_devices ();
61 destroy_output_devices ();
65 WinMMEMidiIO::dequeue_input_event (uint32_t port,
66 uint64_t timestamp_start,
67 uint64_t timestamp_end,
75 assert(port < m_inputs.size());
77 // m_inputs access should be protected by trylock
78 return m_inputs[port]->dequeue_midi_event (
79 timestamp_start, timestamp_end, timestamp, d, s);
83 WinMMEMidiIO::enqueue_output_event (uint32_t port,
91 assert(port < m_outputs.size());
93 // m_outputs access should be protected by trylock
94 return m_outputs[port]->enqueue_midi_event (timestamp, d, s);
99 WinMMEMidiIO::port_id (uint32_t port, bool input)
101 std::stringstream ss;
104 ss << "system:midi_capture_";
107 ss << "system:midi_playback_";
113 std::string 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::clear_device_info ()
206 for (std::vector<MidiDeviceInfo*>::iterator i = m_device_info.begin();
207 i != m_device_info.end();
211 m_device_info.clear();
215 WinMMEMidiIO::get_input_name_from_index (int index, std::string& name)
217 MIDIINCAPS capabilities;
218 MMRESULT result = midiInGetDevCaps(index, &capabilities, sizeof(capabilities));
220 if (result == MMSYSERR_NOERROR) {
221 DEBUG_MIDI(string_compose("Input Device: name : %1, mid : %2, pid : %3\n",
222 capabilities.szPname,
226 name = Glib::locale_to_utf8 (capabilities.szPname);
229 DEBUG_MIDI ("Unable to get WinMME input device capabilities\n");
235 WinMMEMidiIO::get_output_name_from_index (int index, std::string& name)
237 MIDIOUTCAPS capabilities;
238 MMRESULT result = midiOutGetDevCaps(index, &capabilities, sizeof(capabilities));
239 if (result == MMSYSERR_NOERROR) {
240 DEBUG_MIDI(string_compose("Output Device: name : %1, mid : %2, pid : %3\n",
241 capabilities.szPname,
245 name = Glib::locale_to_utf8 (capabilities.szPname);
248 DEBUG_MIDI ("Unable to get WinMME output device capabilities\n");
254 WinMMEMidiIO::update_device_info ()
256 std::set<std::string> device_names;
258 int in_count = midiInGetNumDevs ();
260 for (int i = 0; i < in_count; ++i) {
261 std::string input_name;
262 if (get_input_name_from_index(i, input_name)) {
263 device_names.insert(input_name);
267 int out_count = midiOutGetNumDevs ();
269 for (int i = 0; i < out_count; ++i) {
270 std::string output_name;
271 if (get_output_name_from_index(i, output_name)) {
272 device_names.insert(output_name);
276 clear_device_info ();
278 for (std::set<std::string>::const_iterator i = device_names.begin();
279 i != device_names.end();
281 m_device_info.push_back(new MidiDeviceInfo(*i));
286 WinMMEMidiIO::get_device_info (const std::string& name)
288 for (std::vector<MidiDeviceInfo*>::const_iterator i = m_device_info.begin();
289 i != m_device_info.end();
291 if ((*i)->device_name == name) {
299 WinMMEMidiIO::create_input_devices ()
301 int srcCount = midiInGetNumDevs ();
303 DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
305 for (int i = 0; i < srcCount; ++i) {
306 std::string input_name;
307 if (!get_input_name_from_index (i, input_name)) {
308 DEBUG_MIDI ("Unable to get MIDI input name from index\n");
312 MidiDeviceInfo* info = get_device_info (input_name);
315 DEBUG_MIDI ("Unable to MIDI device info from name\n");
320 DEBUG_MIDI(string_compose(
321 "MIDI input device %1 not enabled, not opening device\n", input_name));
326 WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
328 m_inputs.push_back (midi_input);
332 DEBUG_MIDI ("Unable to create MIDI input\n");
338 WinMMEMidiIO::create_output_devices ()
340 int dstCount = midiOutGetNumDevs ();
342 DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
344 for (int i = 0; i < dstCount; ++i) {
345 std::string output_name;
346 if (!get_output_name_from_index (i, output_name)) {
347 DEBUG_MIDI ("Unable to get MIDI output name from index\n");
351 MidiDeviceInfo* info = get_device_info (output_name);
354 DEBUG_MIDI ("Unable to MIDI device info from name\n");
359 DEBUG_MIDI(string_compose(
360 "MIDI output device %1 not enabled, not opening device\n", output_name));
365 WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
367 m_outputs.push_back(midi_output);
370 DEBUG_MIDI ("Unable to create MIDI output\n");
377 WinMMEMidiIO::destroy_input_devices ()
379 while (!m_inputs.empty ()) {
380 WinMMEMidiInputDevice* midi_input = m_inputs.back ();
381 // assert(midi_input->stopped ());
382 m_inputs.pop_back ();
388 WinMMEMidiIO::destroy_output_devices ()
390 while (!m_outputs.empty ()) {
391 WinMMEMidiOutputDevice* midi_output = m_outputs.back ();
392 // assert(midi_output->stopped ());
393 m_outputs.pop_back ();
399 WinMMEMidiIO::discover()
405 if (pthread_mutex_trylock (&m_device_lock)) {
411 create_input_devices ();
412 create_output_devices ();
414 if (!(m_inputs.size () || m_outputs.size ())) {
415 DEBUG_MIDI ("No midi inputs or outputs\n");
416 pthread_mutex_unlock (&m_device_lock);
420 DEBUG_MIDI (string_compose ("Discovered %1 inputs and %2 outputs\n",
424 if (m_changed_callback) {
425 m_changed_callback(m_changed_arg);
429 pthread_mutex_unlock (&m_device_lock);