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