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.
26 #include "pbd/error.h"
27 #include "pbd/compose.h"
28 #include "pbd/windows_timer_utils.h"
30 #include "winmmemidi_io.h"
35 using namespace ARDOUR;
37 WinMMEMidiIO::WinMMEMidiIO()
41 , m_changed_callback (0)
44 pthread_mutex_init (&m_device_lock, 0);
47 WinMMEMidiIO::~WinMMEMidiIO()
49 pthread_mutex_lock (&m_device_lock);
51 pthread_mutex_unlock (&m_device_lock);
52 pthread_mutex_destroy (&m_device_lock);
56 WinMMEMidiIO::cleanup()
58 DEBUG_MIDI ("MIDI cleanup\n");
61 destroy_input_devices ();
62 destroy_output_devices ();
66 WinMMEMidiIO::dequeue_input_event (uint32_t port,
67 uint64_t timestamp_start,
68 uint64_t timestamp_end,
76 assert(port < m_inputs.size());
78 // m_inputs access should be protected by trylock
79 return m_inputs[port]->dequeue_midi_event (
80 timestamp_start, timestamp_end, timestamp, d, s);
84 WinMMEMidiIO::enqueue_output_event (uint32_t port,
92 assert(port < m_outputs.size());
94 // m_outputs access should be protected by trylock
95 return m_outputs[port]->enqueue_midi_event (timestamp, d, s);
100 WinMMEMidiIO::port_id (uint32_t port, bool input)
102 std::stringstream ss;
105 ss << "system:midi_capture_";
108 ss << "system:midi_playback_";
114 std::string WinMMEMidiIO::port_name(uint32_t port, bool input)
117 if (port < m_inputs.size ()) {
118 return m_inputs[port]->name ();
121 if (port < m_outputs.size ()) {
122 return m_outputs[port]->name ();
129 WinMMEMidiIO::start ()
132 DEBUG_MIDI ("MIDI driver already started\n");
137 DEBUG_MIDI ("Starting MIDI driver\n");
139 PBD::MMTIMERS::set_min_resolution();
146 WinMMEMidiIO::stop ()
149 DEBUG_MIDI ("MIDI driver already stopped\n");
152 DEBUG_MIDI ("Stopping MIDI driver\n");
155 pthread_mutex_lock (&m_device_lock);
157 pthread_mutex_unlock (&m_device_lock);
159 PBD::MMTIMERS::reset_resolution();
163 WinMMEMidiIO::start_devices ()
165 for (std::vector<WinMMEMidiInputDevice*>::iterator i = m_inputs.begin ();
168 if (!(*i)->start ()) {
169 PBD::error << string_compose (_("Unable to start MIDI input device %1\n"),
170 (*i)->name ()) << endmsg;
173 for (std::vector<WinMMEMidiOutputDevice*>::iterator i = m_outputs.begin ();
176 if (!(*i)->start ()) {
177 PBD::error << string_compose (_ ("Unable to start MIDI output device %1\n"),
178 (*i)->name ()) << endmsg;
184 WinMMEMidiIO::stop_devices ()
186 for (std::vector<WinMMEMidiInputDevice*>::iterator i = m_inputs.begin ();
189 if (!(*i)->stop ()) {
190 PBD::error << string_compose (_ ("Unable to stop MIDI input device %1\n"),
191 (*i)->name ()) << endmsg;
194 for (std::vector<WinMMEMidiOutputDevice*>::iterator i = m_outputs.begin ();
197 if (!(*i)->stop ()) {
198 PBD::error << string_compose (_ ("Unable to stop MIDI output device %1\n"),
199 (*i)->name ()) << endmsg;
205 WinMMEMidiIO::clear_device_info ()
207 for (std::vector<MidiDeviceInfo*>::iterator i = m_device_info.begin();
208 i != m_device_info.end();
212 m_device_info.clear();
216 WinMMEMidiIO::get_input_name_from_index (int index, std::string& name)
218 MIDIINCAPS capabilities;
219 MMRESULT result = midiInGetDevCaps(index, &capabilities, sizeof(capabilities));
221 if (result == MMSYSERR_NOERROR) {
222 DEBUG_MIDI(string_compose("Input Device: name : %1, mid : %2, pid : %3\n",
223 capabilities.szPname,
227 name = Glib::locale_to_utf8 (capabilities.szPname);
230 DEBUG_MIDI ("Unable to get WinMME input device capabilities\n");
236 WinMMEMidiIO::get_output_name_from_index (int index, std::string& name)
238 MIDIOUTCAPS capabilities;
239 MMRESULT result = midiOutGetDevCaps(index, &capabilities, sizeof(capabilities));
240 if (result == MMSYSERR_NOERROR) {
241 DEBUG_MIDI(string_compose("Output Device: name : %1, mid : %2, pid : %3\n",
242 capabilities.szPname,
246 name = Glib::locale_to_utf8 (capabilities.szPname);
249 DEBUG_MIDI ("Unable to get WinMME output device capabilities\n");
255 WinMMEMidiIO::update_device_info ()
257 std::set<std::string> device_names;
259 int in_count = midiInGetNumDevs ();
261 for (int i = 0; i < in_count; ++i) {
262 std::string input_name;
263 if (get_input_name_from_index(i, input_name)) {
264 device_names.insert(input_name);
268 int out_count = midiOutGetNumDevs ();
270 for (int i = 0; i < out_count; ++i) {
271 std::string output_name;
272 if (get_output_name_from_index(i, output_name)) {
273 device_names.insert(output_name);
277 clear_device_info ();
279 for (std::set<std::string>::const_iterator i = device_names.begin();
280 i != device_names.end();
282 m_device_info.push_back(new MidiDeviceInfo(*i));
287 WinMMEMidiIO::get_device_info (const std::string& name)
289 for (std::vector<MidiDeviceInfo*>::const_iterator i = m_device_info.begin();
290 i != m_device_info.end();
292 if ((*i)->device_name == name) {
300 WinMMEMidiIO::create_input_devices ()
302 int srcCount = midiInGetNumDevs ();
304 DEBUG_MIDI (string_compose ("MidiIn count: %1\n", srcCount));
306 for (int i = 0; i < srcCount; ++i) {
307 std::string input_name;
308 if (!get_input_name_from_index (i, input_name)) {
309 DEBUG_MIDI ("Unable to get MIDI input name from index\n");
313 MidiDeviceInfo* info = get_device_info (input_name);
316 DEBUG_MIDI ("Unable to MIDI device info from name\n");
321 DEBUG_MIDI(string_compose(
322 "MIDI input device %1 not enabled, not opening device\n", input_name));
327 WinMMEMidiInputDevice* midi_input = new WinMMEMidiInputDevice (i);
329 m_inputs.push_back (midi_input);
333 DEBUG_MIDI ("Unable to create MIDI input\n");
339 WinMMEMidiIO::create_output_devices ()
341 int dstCount = midiOutGetNumDevs ();
343 DEBUG_MIDI (string_compose ("MidiOut count: %1\n", dstCount));
345 for (int i = 0; i < dstCount; ++i) {
346 std::string output_name;
347 if (!get_output_name_from_index (i, output_name)) {
348 DEBUG_MIDI ("Unable to get MIDI output name from index\n");
352 MidiDeviceInfo* info = get_device_info (output_name);
355 DEBUG_MIDI ("Unable to MIDI device info from name\n");
360 DEBUG_MIDI(string_compose(
361 "MIDI output device %1 not enabled, not opening device\n", output_name));
366 WinMMEMidiOutputDevice* midi_output = new WinMMEMidiOutputDevice(i);
368 m_outputs.push_back(midi_output);
371 DEBUG_MIDI ("Unable to create MIDI output\n");
378 WinMMEMidiIO::destroy_input_devices ()
380 while (!m_inputs.empty ()) {
381 WinMMEMidiInputDevice* midi_input = m_inputs.back ();
382 // assert(midi_input->stopped ());
383 m_inputs.pop_back ();
389 WinMMEMidiIO::destroy_output_devices ()
391 while (!m_outputs.empty ()) {
392 WinMMEMidiOutputDevice* midi_output = m_outputs.back ();
393 // assert(midi_output->stopped ());
394 m_outputs.pop_back ();
400 WinMMEMidiIO::discover()
406 if (pthread_mutex_trylock (&m_device_lock)) {
412 create_input_devices ();
413 create_output_devices ();
415 if (!(m_inputs.size () || m_outputs.size ())) {
416 DEBUG_MIDI ("No midi inputs or outputs\n");
417 pthread_mutex_unlock (&m_device_lock);
421 DEBUG_MIDI (string_compose ("Discovered %1 inputs and %2 outputs\n",
425 if (m_changed_callback) {
426 m_changed_callback(m_changed_arg);
430 pthread_mutex_unlock (&m_device_lock);