2 Copyright (C) 2004 Paul Davis
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.
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.
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.
28 #include <midi++/types.h>
29 #include <midi++/port.h>
30 #include <midi++/manager.h>
31 #include <pbd/error.h>
32 #include <pbd/lockmonitor.h>
33 #include <pbd/pthread_utils.h>
35 #include <ardour/configuration.h>
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audio_track.h>
39 #include <ardour/diskstream.h>
44 using namespace ARDOUR;
45 //using namespace sigc;
48 Session::init_feedback ()
50 if (pipe (feedback_request_pipe) != 0) {
51 error << string_compose (_("cannot create feedback request pipe (%1)"),
57 if (fcntl (feedback_request_pipe[0], F_SETFL, O_NONBLOCK)) {
58 error << string_compose(_("UI: cannot set O_NONBLOCK on " "signal read pipe (%1)"), strerror (errno)) << endmsg;
62 if (fcntl (feedback_request_pipe[1], F_SETFL, O_NONBLOCK)) {
63 error << string_compose(_("UI: cannot set O_NONBLOCK on " "signal write pipe (%1)"), strerror (errno)) << endmsg;
68 midi_feedback = false;
70 /* add possible feedback functions here */
72 feedback_functions.push_back (mem_fun (*this, &Session::feedback_generic_midi_function));
74 if (pthread_create_and_store ("feedback", &feedback_thread, 0, _feedback_thread_work, this)) {
75 error << _("Session: could not create feedback thread") << endmsg;
83 Session::poke_feedback (FeedbackRequest::Type why)
86 return !(write (feedback_request_pipe[1], &c, 1) == 1);
90 Session::start_feedback ()
92 return poke_feedback (FeedbackRequest::Start);
96 Session::stop_feedback ()
98 return poke_feedback (FeedbackRequest::Stop);
102 Session::terminate_feedback ()
105 poke_feedback (FeedbackRequest::Quit);
106 pthread_join (feedback_thread, &status);
110 Session::_feedback_thread_work (void* arg)
112 return static_cast<Session*> (arg)->feedback_thread_work ();
116 Session::feedback_thread_work ()
118 PBD::ThreadCreated (pthread_self(), X_("Feedback"));
119 struct pollfd pfd[1];
122 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
123 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
125 if (active_feedback) {
126 /* XXX use Config->feedback_interval_usecs()*/;
127 timeout = max (5, (int) Config->get_midi_feedback_interval_ms());
134 pfd[0].fd = feedback_request_pipe[0];
135 pfd[0].events = POLLIN|POLLHUP|POLLERR;
137 if (poll (pfd, 1, timeout) < 0) {
138 if (errno == EINTR) {
141 error << string_compose (_("Feedback thread poll failed (%1)"),
147 if (pfd[0].revents & ~POLLIN) {
148 error << _("Error on feedback thread request pipe") << endmsg;
152 if (pfd[0].revents & POLLIN) {
156 /* empty the pipe of all current requests */
159 size_t nread = read (feedback_request_pipe[0], &req, sizeof (req));
162 switch ((FeedbackRequest::Type) req) {
164 case FeedbackRequest::Start:
165 timeout = max (5, (int) Config->get_midi_feedback_interval_ms());
169 case FeedbackRequest::Stop:
171 if (active_feedback) {
176 case FeedbackRequest::Quit:
177 pthread_exit_pbd (0);
185 } else if (nread == 0) {
187 } else if (errno == EAGAIN) {
190 fatal << _("Error reading from feedback request pipe") << endmsg;
196 if (!active_feedback || transport_stopped()) {
200 for (list<FeedbackFunctionPtr>::iterator i = feedback_functions.begin(); i != feedback_functions.end(); ) {
202 list<FeedbackFunctionPtr>::iterator tmp;
208 feedback_functions.erase (i);
219 Session::feedback_generic_midi_function ()
221 const int32_t bufsize = 16 * 1024;
222 int32_t bsize = bufsize;
223 MIDI::byte* buf = new MIDI::byte[bufsize];
224 MIDI::byte* end = buf;
227 RWLockMonitor lm (route_lock, false, __LINE__, __FILE__);
229 for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
230 end = (*i)->write_midi_feedback (end, bsize);
239 deliver_midi (_midi_port, buf, (int32_t) (end - buf));
241 //cerr << "MIDI feedback: wrote " << (int32_t) (end - buf) << " to midi port\n";