fix thinko when dealing with non-MIDI tracks
[ardour.git] / libs / ardour / midi_ui.cc
1 /*
2  * Copyright (C) 2009-2017 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2010-2011 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2011-2014 David Robillard <d@drobilla.net>
5  * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 #include <cstdlib>
22
23 #include <sigc++/signal.h>
24
25 #include "pbd/pthread_utils.h"
26
27 #include "ardour/async_midi_port.h"
28 #include "ardour/debug.h"
29 #include "ardour/audioengine.h"
30 #include "ardour/midi_port.h"
31 #include "ardour/midiport_manager.h"
32 #include "ardour/midi_ui.h"
33 #include "ardour/session.h"
34 #include "ardour/session_event.h"
35 #include "ardour/types.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40 using namespace Glib;
41
42 #include "pbd/i18n.h"
43
44 MidiControlUI* MidiControlUI::_instance = 0;
45
46 #include "pbd/abstract_ui.cc"  /* instantiate the template */
47
48 MidiControlUI::MidiControlUI (Session& s)
49         : AbstractUI<MidiUIRequest> (X_("midiUI"))
50         , _session (s)
51 {
52         _instance = this;
53 }
54
55 MidiControlUI::~MidiControlUI ()
56 {
57         /* stop the thread */
58         quit ();
59         /* drop all ports as GIO::Sources */
60         clear_ports ();
61         /* we no longer exist */
62         _instance = 0;
63 }
64
65 void*
66 MidiControlUI::request_factory (uint32_t num_requests)
67 {
68         /* AbstractUI<T>::request_buffer_factory() is a template method only
69            instantiated in this source module. To provide something visible for
70            use when registering the factory, we have this static method that is
71            template-free.
72         */
73         return request_buffer_factory (num_requests);
74 }
75
76 void
77 MidiControlUI::do_request (MidiUIRequest* req)
78 {
79         if (req->type == Quit) {
80                 BaseUI::quit ();
81         } else if (req->type == CallSlot) {
82                 req->the_slot ();
83         }
84 }
85
86 bool
87 MidiControlUI::midi_input_handler (IOCondition ioc, boost::weak_ptr<AsyncMIDIPort> wport)
88 {
89         boost::shared_ptr<AsyncMIDIPort> port = wport.lock ();
90         if (!port) {
91                 return false;
92         }
93
94         DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on  %1\n", boost::shared_ptr<ARDOUR::Port> (port)->name()));
95
96         if (ioc & ~IO_IN) {
97                 return false;
98         }
99
100         if (ioc & IO_IN) {
101
102                 port->clear ();
103                 DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", boost::shared_ptr<ARDOUR::Port>(port)->name()));
104                 samplepos_t now = _session.engine().sample_time();
105                 port->parse (now);
106         }
107
108         return true;
109 }
110
111 void
112 MidiControlUI::clear_ports ()
113 {
114 }
115
116 void
117 MidiControlUI::reset_ports ()
118 {
119         vector<boost::shared_ptr<AsyncMIDIPort> > ports;
120         boost::shared_ptr<AsyncMIDIPort> p;
121
122         if ((p = boost::dynamic_pointer_cast<AsyncMIDIPort> (_session.midi_input_port()))) {
123                 ports.push_back (p);
124         }
125
126
127         if ((p = boost::dynamic_pointer_cast<AsyncMIDIPort> (_session.mmc_input_port()))) {
128                 ports.push_back (p);
129         }
130
131         if ((p = boost::dynamic_pointer_cast<AsyncMIDIPort> (_session.scene_input_port()))) {
132                 ports.push_back (p);
133         }
134
135         if (ports.empty()) {
136                 return;
137         }
138
139         for (vector<boost::shared_ptr<AsyncMIDIPort> >::const_iterator pi = ports.begin(); pi != ports.end(); ++pi) {
140                 (*pi)->xthread().set_receive_handler (sigc::bind (
141                                         sigc::mem_fun (this, &MidiControlUI::midi_input_handler), boost::weak_ptr<AsyncMIDIPort>(*pi)));
142                 (*pi)->xthread().attach (_main_loop->get_context());
143         }
144 }
145
146 void
147 MidiControlUI::thread_init ()
148 {
149         pthread_set_name (X_("midiUI"));
150
151         PBD::notify_event_loops_about_thread_creation (pthread_self(), X_("midiUI"), 2048);
152         SessionEvent::create_per_thread_pool (X_("midiUI"), 128);
153
154         set_thread_priority ();
155
156         reset_ports ();
157 }
158