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