94c674d073728ee16cd8f75e5bab1f9a8f11f144
[ardour.git] / libs / backends / wavesaudio / waves_audiobackend.midi.cc
1 /*\r
2     Copyright (C) 2014 Waves Audio Ltd.\r
3 \r
4     This program is free software; you can redistribute it and/or modify\r
5     it under the terms of the GNU General Public License as published by\r
6     the Free Software Foundation; either version 2 of the License, or\r
7     (at your option) any later version.\r
8 \r
9     This program is distributed in the hope that it will be useful,\r
10     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
12     GNU General Public License for more details.\r
13 \r
14     You should have received a copy of the GNU General Public License\r
15     along with this program; if not, write to the Free Software\r
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
17 \r
18 */\r
19 \r
20 #include <boost/assign/list_of.hpp>\r
21 \r
22 #include "waves_audiobackend.h"\r
23 #include "waves_midiport.h"\r
24 #include "waves_midi_event.h"\r
25 #include "waves_midi_buffer.h"\r
26 \r
27 using namespace ARDOUR;\r
28 \r
29 #ifdef __MACOS__\r
30 \r
31 const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("CoreMIDI");\r
32 \r
33 #elif _WINDOWS\r
34 \r
35 const std::vector<std::string> WavesAudioBackend::__available_midi_options = boost::assign::list_of ("None") ("Multimedia Extensions");\r
36 \r
37 #endif\r
38 \r
39 \r
40 std::vector<std::string> \r
41 WavesAudioBackend::enumerate_midi_options () const\r
42 {\r
43     // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::enumerate_midi_options ()" << std::endl;\r
44     return __available_midi_options;\r
45 }\r
46 \r
47 \r
48 int \r
49 WavesAudioBackend::set_midi_option (const std::string& option)\r
50 {\r
51     // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::set_midi_option ( " << option << " )" << std::endl;\r
52     if (option == __available_midi_options[0]) {\r
53         _use_midi = false;\r
54         // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;\r
55     }\r
56     else if (option == __available_midi_options[1]) {\r
57         _use_midi = true;\r
58         // COMMENTED DBG LOGS */ std::cout << "\tNO MIDI system used)" << std::endl;\r
59     }\r
60     else {\r
61         std::cerr << "WavesAudioBackend::set_midi_option (): Invalid MIDI option!" << std::endl;\r
62         return -1;\r
63     }\r
64 \r
65     return 0;\r
66 }\r
67 \r
68 \r
69 std::string\r
70 WavesAudioBackend::midi_option () const\r
71 {\r
72     // COMMENTED DBG LOGS */ std::cout << "WavesAudioBackend::midi_option ():" << std::endl;\r
73     return * (__available_midi_options.begin () + (_use_midi?1:0));\r
74 }\r
75 \r
76 \r
77 int\r
78 WavesAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buffer, void* port_buffer, uint32_t event_index)\r
79 {\r
80     // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_get ():" << std::endl;\r
81 \r
82     if (buffer == NULL) {\r
83         std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'buffer' argument!\n";\r
84         return -1;\r
85     }\r
86 \r
87     if (port_buffer == NULL) {\r
88         std::cerr << "WavesAudioBackend::midi_event_get () : NULL in the 'port_buffer' argument!\n";\r
89         return -1;\r
90     }\r
91 \r
92     WavesMidiBuffer& source = * (WavesMidiBuffer*)port_buffer;\r
93 \r
94     if (event_index >= source.size ()) {\r
95         std::cerr << "WavesAudioBackend::midi_event_get () : 'event_index' is out of the number of events stored in 'port_buffer'!\n";\r
96         return -1;\r
97     }\r
98 \r
99     WavesMidiEvent* waves_midi_event = source[event_index];\r
100 \r
101     timestamp = waves_midi_event->timestamp ();\r
102     size = waves_midi_event->size ();\r
103     *buffer = waves_midi_event->data ();\r
104 \r
105     return 0;\r
106 }\r
107 \r
108 \r
109 int\r
110 WavesAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)\r
111 {\r
112     // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_event_put ():" << std::endl;\r
113     if (buffer == NULL) {\r
114         std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'buffer' argument!\n";\r
115         return -1;\r
116     }\r
117 \r
118     if (port_buffer == NULL) {\r
119         std::cerr << "WavesAudioBackend::midi_event_put () : NULL in the 'port_buffer' argument!\n";\r
120         return -1;\r
121     }\r
122 \r
123     WavesMidiBuffer& target = * (WavesMidiBuffer*)port_buffer;\r
124     // COMMENTED FREQUENT DBG LOGS */ std::cout << "\t [" << target.name () << "]"<< std::endl;\r
125 \r
126     if (target.size () && (pframes_t)target.back ()->timestamp () > timestamp) {\r
127         std::cerr << "WavesAudioBackend::midi_event_put (): The MIDI Event to put is a bit late!" << std::endl;\r
128         std::cerr << "\tprev timestamp is " << (pframes_t)target.back ()->timestamp () << " as the current one is " << timestamp << std::endl;\r
129         return -1;\r
130     }\r
131 \r
132     target.push_back (new WavesMidiEvent (timestamp, buffer, size));\r
133     return 0;\r
134 }\r
135 \r
136 \r
137 uint32_t\r
138 WavesAudioBackend::get_midi_event_count (void* port_buffer)\r
139 {\r
140     // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::get_midi_event_count (): " << std::endl;\r
141     \r
142     if (port_buffer == NULL) {\r
143         std::cerr << "WavesAudioBackend::get_midi_event_count () : NULL in the 'port_buffer' argument!\n";\r
144         return -1;\r
145     }\r
146 \r
147     // COMMENTED FREQUENT DBG LOGS */ std::cout << "\tcount = " << (* (WavesMidiBuffer*)port_buffer).size () << std::endl;\r
148 \r
149     return (* (WavesMidiBuffer*)port_buffer).size ();\r
150 }\r
151 \r
152 \r
153 void\r
154 WavesAudioBackend::midi_clear (void* port_buffer)\r
155 {\r
156     // COMMENTED FREQUENT DBG LOGS */ std::cout << "WavesAudioBackend::midi_clear (): " << std::endl;\r
157     if (port_buffer == NULL) {\r
158         std::cerr << "WavesAudioBackend::midi_clear () : NULL in the 'port_buffer' argument!\n";\r
159         return;\r
160     }\r
161 \r
162     (* (WavesMidiBuffer*)port_buffer).clear ();\r
163 }\r
164 \r
165 \r
166 void\r
167 WavesAudioBackend::_changed_midi_devices ()\r
168 {\r
169     if (_midi_device_manager.stream (false)) {\r
170         std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (false) failed!" << std::endl;\r
171         return;\r
172     }\r
173 \r
174     _midi_device_manager.stop ();\r
175 \r
176     if (_midi_device_manager.start () != 0) {\r
177         std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.start () failed!" << std::endl;\r
178         return;\r
179     }\r
180 \r
181     if (_register_system_midi_ports () != 0) {\r
182         std::cerr << "WavesAudioBackend::_changed_midi_devices (): _register_system_midi_ports () failed!" << std::endl;\r
183         return;\r
184     }\r
185     \r
186     manager.registration_callback ();\r
187 \r
188     if (_midi_device_manager.stream (true)) {\r
189         std::cerr << "WavesAudioBackend::_changed_midi_devices (): _midi_device_manager.stream (true) failed!" << std::endl;\r
190         return;\r
191     }\r
192 }\r
193 \r
194 \r
195 void\r
196 WavesAudioBackend::_unregister_system_midi_ports ()\r
197 {\r
198     // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_unregister_system_midi_ports ()" << std::endl;\r
199     std::vector<WavesMidiPort*> physical_midi_ports = _physical_midi_inputs;\r
200     physical_midi_ports.insert (physical_midi_ports.begin (), _physical_midi_outputs.begin (), _physical_midi_outputs.end ());\r
201 \r
202     for (std::vector<WavesMidiPort*>::const_iterator it = physical_midi_ports.begin (); it != physical_midi_ports.end (); ++it) {\r
203         std::vector<WavesDataPort*>::iterator port_iterator = std::find (_ports.begin (), _ports.end (), *it);\r
204         if (port_iterator == _ports.end ()) {\r
205             std::cerr << "WavesAudioBackend::_unregister_system_midi_ports (): Failed to find port [" << (*it)->name () << "]!"  << std::endl;\r
206         }\r
207         else\r
208             _ports.erase (port_iterator);\r
209         delete *it;\r
210     }\r
211     _physical_midi_inputs.clear ();\r
212     _physical_midi_outputs.clear ();\r
213 }\r
214 \r
215 \r
216 int\r
217 WavesAudioBackend::_register_system_midi_ports ()\r
218 {\r
219     // COMMENTED DBG LOGS */ std::cout  << "WavesAudioBackend::_register_system_midi_ports ()" << std::endl;\r
220 \r
221     LatencyRange lr = {0,0};\r
222     lr.min = lr.max = _buffer_size;\r
223 \r
224     for (size_t i = 0; i<_ports.size ();)    {\r
225         WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (_ports[i]);\r
226         if (!midi_port || !midi_port->is_physical () || !midi_port->is_terminal ()) {\r
227             ++i;\r
228             continue;\r
229         }\r
230 \r
231         if ((midi_port->is_input () && !midi_port->midi_device ()->is_output ()) ||\r
232             (midi_port->is_output () && !midi_port->midi_device ()->is_input ())) {\r
233             disconnect_all (midi_port);\r
234             unregister_port (midi_port);\r
235             continue; // to be here for further additions in the end of this loop\r
236         }\r
237 \r
238         ++i;\r
239     }\r
240 \r
241     const std::vector<WavesMidiDevice *>&  devices = _midi_device_manager.devices ();\r
242 \r
243     for (std::vector<WavesMidiDevice*>::const_iterator it = devices.begin (); it != devices.end (); ++it) {\r
244         if ((*it)->is_input ()) {\r
245             std::string port_name = "system_midi:" + (*it)->name () + " capture";\r
246             WavesDataPort* port = _find_port (port_name);\r
247             WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);\r
248             if (midi_port && (midi_port->type () != DataType::MIDI || \r
249                 midi_port->midi_device () != *it || \r
250                 !midi_port->is_output () || \r
251                 !midi_port->is_physical () ||\r
252                 !midi_port->is_terminal ())) {\r
253                 std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;\r
254                 disconnect_all (midi_port);\r
255                 unregister_port (midi_port);\r
256                 port = NULL;\r
257             }\r
258 \r
259             if (port == NULL) {\r
260                 port = _register_port ( port_name, DataType::MIDI , static_cast<ARDOUR::PortFlags> (IsOutput | IsPhysical | IsTerminal));\r
261                 if (port == NULL) {\r
262                     return -1;\r
263                 }\r
264                 ((WavesMidiPort*)port)->set_midi_device (*it);\r
265             }\r
266             port->set_latency_range (lr, false); \r
267         }\r
268 \r
269         if ((*it)->is_output ()) {\r
270             std::string port_name = "system_midi:" + (*it)->name () + " playback";\r
271             WavesDataPort* port = _find_port (port_name);\r
272             WavesMidiPort* midi_port = dynamic_cast<WavesMidiPort*> (port);\r
273             if (midi_port && (midi_port->type () != DataType::MIDI || \r
274                 midi_port->midi_device () != *it || \r
275                 !midi_port->is_input () || \r
276                 !midi_port->is_physical () ||\r
277                 !midi_port->is_terminal ())) {\r
278                 std::cerr << "WavesAudioBackend::_register_system_midi_ports (): the port [" << midi_port->name () << "] is inconsystently constructed!" << std::endl;\r
279                 disconnect_all (midi_port);\r
280                 unregister_port (midi_port);\r
281             }\r
282 \r
283             if (port == NULL) {\r
284                 port = _register_port (port_name,\r
285                                        DataType::MIDI,\r
286                                        static_cast<ARDOUR::PortFlags> (IsInput | IsPhysical | IsTerminal));\r
287                 if (port == NULL) {\r
288                     return -1;\r
289                 }\r
290             }\r
291 \r
292             ((WavesMidiPort*)port)->set_midi_device ((*it));\r
293             port->set_latency_range (lr, true);\r
294         }\r
295     }\r
296     \r
297     return 0;\r
298 }\r
299 \r
300 \r
301 int\r
302 WavesAudioBackend::_read_midi_data_from_devices ()\r
303 {\r
304     // COMMENTED FREQUENT DBG LOGS */ std::cout  << "WavesAudioBackend::_read_midi_data_from_devices ():" << std::endl;\r
305     if (!_midi_device_manager.is_streaming ())\r
306         return 0;\r
307     \r
308     _midi_device_manager.do_read ();\r
309 \r
310     for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_inputs.begin (); it != _physical_midi_inputs.end (); ++it) {\r
311         WavesMidiDevice* midi_device = (*it)->midi_device ();\r
312         \r
313         WavesMidiBuffer& waves_midi_buffer = (*it)->buffer ();\r
314         waves_midi_buffer.clear ();\r
315         \r
316         while (WavesMidiEvent *waves_midi_event = midi_device->dequeue_input_waves_midi_event ()) {\r
317             int32_t timestamp_st = _buffer_size - (_sample_time_at_cycle_start - waves_midi_event->timestamp ());\r
318             \r
319             if (timestamp_st < 0) {\r
320                 timestamp_st = 0;\r
321             }\r
322             else if (timestamp_st >= (int32_t)_buffer_size) {\r
323                 timestamp_st = _buffer_size - 1;\r
324             }\r
325             waves_midi_event->set_timestamp (timestamp_st);\r
326             waves_midi_buffer.push_back (waves_midi_event);\r
327         }\r
328     }\r
329     return 0;\r
330 }\r
331 \r
332 \r
333 int\r
334 WavesAudioBackend::_write_midi_data_to_devices (pframes_t nframes)\r
335 {\r
336     if (!_midi_device_manager.is_streaming ())\r
337         return 0;\r
338     \r
339     for (std::vector<WavesMidiPort*>::iterator it = _physical_midi_outputs.begin (); it != _physical_midi_outputs.end (); ++it) {\r
340         WavesMidiDevice* midi_device = (*it)->midi_device (); \r
341         WavesMidiBuffer &waves_midi_buffer = * (WavesMidiBuffer*) (*it)->get_buffer (nframes);\r
342 \r
343         for (WavesMidiBufferIterator it = waves_midi_buffer.begin (); it != waves_midi_buffer.end ();) {\r
344              WavesMidiEvent* waves_midi_event = *it;\r
345             \r
346             waves_midi_buffer.erase (it);\r
347             \r
348             waves_midi_event->set_timestamp (_sample_time_at_cycle_start + waves_midi_event->timestamp () + nframes);\r
349             midi_device->enqueue_output_waves_midi_event (waves_midi_event);\r
350        }\r
351     }\r
352     _midi_device_manager.do_write ();\r
353     return 0;\r
354 }\r