Remove unnecessary 0 checks before delete; see http://www.parashift.com/c++-faq-lite...
[ardour.git] / libs / surfaces / mackie / mackie_control_protocol_poll.cc
1 #include "mackie_control_protocol.h"
2
3 #include "midi_byte_array.h"
4 #include "surface_port.h"
5
6 #include <pbd/pthread_utils.h>
7 #include <pbd/error.h>
8
9 #include <midi++/types.h>
10 #include <midi++/port.h>
11 #include <midi++/manager.h>
12 #include "i18n.h"
13
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <poll.h>
17 #include <errno.h>
18
19 #include <iostream>
20 #include <string>
21 #include <vector>
22
23 using namespace std;
24 using namespace Mackie;
25 using namespace PBD;
26
27 const char * MackieControlProtocol::default_port_name = "mcu";
28
29 bool MackieControlProtocol::probe()
30 {
31         if ( MIDI::Manager::instance()->port( default_port_name ) == 0 )
32         {
33                 error << "No port called mcu. Add it to ardour.rc." << endmsg;
34                 return false;
35         }
36         else
37         {
38                 return true;
39         }
40 }
41
42 void * MackieControlProtocol::monitor_work()
43 {
44         PBD::notify_gui_about_thread_creation (pthread_self(), X_("Mackie"));
45
46         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
47         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
48
49         // read from midi ports
50         while ( _polling )
51         {
52                 try
53                 {
54                         if ( poll_ports() )
55                         {
56                                 try { read_ports(); }
57                                 catch ( exception & e ) {
58                                         cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl;
59                                         _ports_changed = true;
60                                         update_ports();
61                                 }
62                         }
63                         // poll for session data that needs to go to the unit
64                         poll_session_data();
65                 }
66                 catch ( exception & e )
67                 {
68                         cout << "caught exception in MackieControlProtocol::monitor_work " << e.what() << endl;
69                 }
70         }
71
72         // TODO ports and pfd and nfds should be in a separate class
73         delete[] pfd;
74         pfd = 0;
75         nfds = 0;
76
77         return (void*) 0;
78 }
79
80 void MackieControlProtocol::update_ports()
81 {
82 #ifdef DEBUG
83         cout << "MackieControlProtocol::update_ports" << endl;
84 #endif
85         if ( _ports_changed )
86         {
87                 Glib::Mutex::Lock ul( update_mutex );
88                 // yes, this is a double-test locking paradigm, or whatever it's called
89                 // because we don't *always* need to acquire the lock for the first test
90 #ifdef DEBUG
91                 cout << "MackieControlProtocol::update_ports lock acquired" << endl;
92 #endif
93                 if ( _ports_changed )
94                 {
95                         // create new pollfd structures
96                         delete[] pfd;
97                         pfd = new pollfd[_ports.size()];
98 #ifdef DEBUG
99                         cout << "pfd: " << pfd << endl;
100 #endif
101                         nfds = 0;
102                         for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
103                         {
104                                 // add the port any handler
105                                 (*it)->connect_any();
106 #ifdef DEBUG
107                                 cout << "adding pollfd for port " << (*it)->port().name() << " to pollfd " << nfds << endl;
108 #endif
109                                 pfd[nfds].fd = (*it)->port().selectable();
110                                 pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
111                                 ++nfds;
112                         }
113                         _ports_changed = false;
114                 }
115 #ifdef DEBUG
116                 cout << "MackieControlProtocol::update_ports signal" << endl;
117 #endif
118                 update_cond.signal();
119         }
120 #ifdef DEBUG
121         cout << "MackieControlProtocol::update_ports finish" << endl;
122 #endif
123 }
124
125 void MackieControlProtocol::read_ports()
126 {
127         /* now read any data on the ports */
128         Glib::Mutex::Lock lock( update_mutex );
129         for ( int p = 0; p < nfds; ++p )
130         {
131                 // this will cause handle_midi_any in the MackiePort to be triggered
132                 // for alsa/raw ports
133                 // alsa/sequencer ports trigger the midi parser off poll
134                 if ( (pfd[p].revents & POLLIN) > 0 )
135                 {
136                         // avoid deadlocking?
137                         // doesn't seem to make a difference
138                         //lock.release();
139                         _ports[p]->read();
140                         //lock.acquire();
141                 }
142         }
143 }
144
145 bool MackieControlProtocol::poll_ports()
146 {
147         int timeout = 10; // milliseconds
148         int no_ports_sleep = 1000; // milliseconds
149
150         Glib::Mutex::Lock lock( update_mutex );
151         // if there are no ports
152         if ( nfds < 1 )
153         {
154                 lock.release();
155 #ifdef DEBUG
156                 cout << "poll_ports no ports" << endl;
157 #endif
158                 usleep( no_ports_sleep * 1000 );
159                 return false;
160         }
161
162         int retval = ::poll( pfd, nfds, timeout );
163         if ( retval < 0 )
164         {
165                 // gdb at work, perhaps
166                 if ( errno != EINTR )
167                 {
168                         error << string_compose(_("Mackie MIDI thread poll failed (%1)"), strerror( errno ) ) << endmsg;
169                 }
170                 return false;
171         }
172         
173         return retval > 0;
174 }
175
176 void MackieControlProtocol::handle_port_inactive( SurfacePort * port )
177 {
178         // port gone away. So stop polling it ASAP
179         {
180                 // delete the port instance
181                 Glib::Mutex::Lock lock( update_mutex );
182                 MackiePorts::iterator it = find( _ports.begin(), _ports.end(), port );
183                 if ( it != _ports.end() )
184                 {
185                         delete *it;
186                         _ports.erase( it );
187                 }
188         }
189         _ports_changed = true;
190         update_ports();
191         
192         // TODO all the rebuilding of surfaces and so on
193 }
194
195 void MackieControlProtocol::handle_port_active( SurfacePort * port )
196 {
197         // no need to re-add port because it was already added
198         // during the init phase. So just update the local surface
199         // representation and send the representation to 
200         // all existing ports
201         
202         // TODO update bank size
203         
204         // TODO rebuild surface, to have new units
205         
206         // finally update session state to the surface
207         // TODO but this is also done in set_active, and
208         // in fact update_surface won't execute unless
209 #ifdef DEBUG
210         cout << "update_surface in handle_port_active" << endl;
211 #endif
212         // _active == true
213         update_surface();
214 }
215
216 void MackieControlProtocol::handle_port_init( Mackie::SurfacePort * sport )
217 {
218 #ifdef DEBUG
219         cout << "MackieControlProtocol::handle_port_init" << endl;
220 #endif
221         _ports_changed = true;
222         update_ports();
223 #ifdef DEBUG
224         cout << "MackieControlProtocol::handle_port_init finish" << endl;
225 #endif
226 }