1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4   Rosegarden
5   A sequencer and musical notation editor.
6   Copyright 2000-2021 the Rosegarden development team.
7   See the AUTHORS file for more details.
8 
9   This program is free software; you can redistribute it and/or
10   modify it under the terms of the GNU General Public License as
11   published by the Free Software Foundation; either version 2 of the
12   License, or (at your option) any later version.  See the file
13   COPYING included with this distribution for more information.
14 */
15 
16 #ifdef __GNUG__
17 #pragma GCC diagnostic ignored "-Wswitch-enum"
18 #endif
19 
20 #define RG_MODULE_STRING "[AlsaDriver]"
21 
22 #include "misc/Debug.h"
23 #include <cstdlib>
24 #include <cstdio>
25 #include <algorithm>
26 
27 #include "rosegarden-version.h"
28 
29 #ifdef HAVE_ALSA
30 
31 // ALSA
32 #include <alsa/asoundlib.h>
33 #include <alsa/seq_event.h>
34 #include <alsa/version.h>
35 #include <alsa/seq.h>
36 
37 #include "AlsaDriver.h"
38 #include "AlsaPort.h"
39 #include "MappedInstrument.h"
40 #include "Midi.h"
41 #include "MappedStudio.h"
42 #include "misc/Strings.h"
43 #include "misc/ConfigGroups.h"
44 #include "MappedCommon.h"
45 #include "MappedEvent.h"
46 #include "Audit.h"
47 #include "AudioPlayQueue.h"
48 #include "base/levenshtein.hpp"
49 #include "SequencerDataBlock.h"
50 #include "PlayableAudioFile.h"
51 #include "ExternalController.h"
52 #include "gui/application/RosegardenMainWindow.h"
53 #include "base/QEvents.h"
54 #include "sequencer/RosegardenSequencer.h"
55 
56 #include <QCoreApplication>
57 #include <QMutex>
58 #include <QSettings>
59 #include <QTime>
60 
61 #include <pthread.h>
62 #include <math.h>
63 #include <unistd.h>
64 
65 
66 // #define DEBUG_ALSA 1
67 // #define DEBUG_PROCESS_MIDI_OUT 1
68 //#define DEBUG_PROCESS_SOFT_SYNTH_OUT 1
69 //#define MTC_DEBUG 1
70 
71 // This driver implements MIDI in and out via the ALSA (www.alsa-project.org)
72 // sequencer interface.
73 
74 #define AUTO_TIMER_NAME "(auto)"
75 #define LOCKED QMutexLocker rg_alsa_locker(&m_mutex)
76 
77 // Rosegarden does not handle note-off velocity.  The MIDI spec recommends
78 // using 64 in that case.  One user has reported problems with 0 which
79 // was being used previously.  See Bug #1426.
80 #define NOTE_OFF_VELOCITY 64
81 
82 namespace Rosegarden
83 {
84 
85 #ifdef HAVE_LIBJACK
86 static size_t debug_jack_frame_count = 0;
87 #endif
88 
89 #define FAILURE_REPORT_COUNT 256
90 static MappedEvent::FailureCode failureReports[FAILURE_REPORT_COUNT];
91 static int failureReportWriteIndex = 0;
92 static int failureReportReadIndex = 0;
93 
94 namespace {
95     enum ClientClass {
96         System, Internal, OSSSequencer, Hardware, Software, Invalid };
97 
getClass(int clientId)98     ClientClass getClass(int clientId)
99     {
100         // From https://alsa.opensrc.org/Aconnect
101         //   0..63: for internal use (0 = system, 63 = OSS sequencer emulation)
102         //   64..127: device drivers (up to 8 for each card)
103         //   128..?: user applications
104 
105         if (clientId < 0)
106             return Invalid;
107         if (clientId == 0)
108             return System;
109         if (clientId < 63)
110             return Internal;
111         if (clientId == 63)
112             return OSSSequencer;
113         if (clientId < 128)
114             return Hardware;
115         if (clientId < 256)
116             return Software;
117 
118         return Invalid;
119     }
120 }
121 
AlsaDriver(MappedStudio * studio)122 AlsaDriver::AlsaDriver(MappedStudio *studio):
123     SoundDriver(studio,
124                 QString("[ALSA library version ") +
125                 SND_LIB_VERSION_STR +
126                 ", module version " +
127                 strtoqstr(getAlsaVersion()) +
128                 ", kernel version " +
129                 strtoqstr(getKernelVersionString()) +
130                 "]"),
131     m_startPlayback(false),
132     m_midiHandle(nullptr),
133     m_client( -1),
134     m_inputPort( -1),
135     m_syncOutputPort( -1),
136     m_externalControllerPort( -1),
137     m_queue( -1),
138     m_maxClients( -1),
139     m_maxPorts( -1),
140     m_maxQueues( -1),
141     m_midiInputPortConnected(false),
142     m_midiSyncAutoConnect(false),
143     m_alsaPlayStartTime(0, 0),
144     m_alsaRecordStartTime(0, 0),
145     m_loopStartTime(0, 0),
146     m_loopEndTime(0, 0),
147     m_eat_mtc(0),
148     m_looping(false),
149     m_haveShutdown(false)
150 #ifdef HAVE_LIBJACK
151     , m_jackDriver(nullptr)
152 #endif
153     , m_queueRunning(false)
154     , m_portCheckNeeded(false),
155     m_needJackStart(NeedNoJackStart),
156     m_doTimerChecks(false),
157     m_firstTimerCheck(true),
158     m_timerRatio(0),
159     m_timerRatioCalculated(false),
160     m_debug(false),
161     m_midiClockEnabled(false),
162     m_midiSyncStatus(TRANSPORT_OFF),
163     m_mmcStatus(TRANSPORT_OFF),
164     m_mtcStatus(TRANSPORT_OFF)
165 {
166     // Create a log that the user can easily see through the preferences
167     // even in a release build.
168     AUDIT << "Rosegarden " << VERSION << " - AlsaDriver " << m_name << '\n';
169     RG_DEBUG << "ctor: Rosegarden " << VERSION << " - AlsaDriver " << m_name;
170 
171     m_pendSysExcMap = new DeviceEventMap();
172 
173     QSettings settings;
174     settings.beginGroup(GeneralOptionsConfigGroup);
175     // Accept transport CCs (116-118)
176     m_acceptTransportCCs = settings.value("acceptTransportCCs", true).toBool();
177     settings.endGroup();
178 
179 #ifndef NDEBUG
180     // Debugging Mode
181     settings.beginGroup(GeneralOptionsConfigGroup);
182     const QString debugAlsaDriver = "debug_AlsaDriver";
183     m_debug = settings.value(debugAlsaDriver, false).toBool();
184     // Write it to the file to make it easier to find.
185     settings.setValue(debugAlsaDriver, m_debug);
186     settings.endGroup();
187 #endif
188 }
189 
~AlsaDriver()190 AlsaDriver::~AlsaDriver()
191 {
192     if (!m_haveShutdown) {
193         RG_WARNING << "dtor: WARNING: AlsaDriver::shutdown() was not called before destructor, calling now";
194         shutdown();
195     }
196 
197     // Flush incomplete system exclusive events and delete the map.
198     clearPendSysExcMap();
199 
200     delete m_pendSysExcMap;
201 }
202 
203 int
checkAlsaError(int rc,const char * message)204 AlsaDriver::checkAlsaError(int rc, const char *
205 #ifdef DEBUG_ALSA
206                            message
207 #endif
208                            )
209 {
210 #ifdef DEBUG_ALSA
211     if (rc < 0) {
212         RG_WARNING << "AlsaDriver::"
213                    << message
214                    << ": " << rc
215                    << " (" << snd_strerror(rc) << ")";
216     }
217 #endif
218     return rc;
219 }
220 
221 void
shutdown()222 AlsaDriver::shutdown()
223 {
224     RG_DEBUG << "shutdown(): shutting down...";
225 
226     if (m_midiHandle) {
227         processNotesOff(getAlsaTime(), true, true);
228     }
229 
230 #ifdef HAVE_LIBJACK
231     delete m_jackDriver;
232     m_jackDriver = nullptr;
233 #endif
234 
235     if (m_midiHandle) {
236 
237         RG_DEBUG << "shutdown(): stopping queue...";
238 
239         checkAlsaError(snd_seq_stop_queue(m_midiHandle, m_queue, nullptr), "shutdown(): stopping queue");
240         checkAlsaError(snd_seq_drain_output(m_midiHandle), "shutdown(): drain output");
241 
242         RG_DEBUG << "shutdown(): closing MIDI handle...";
243 
244         snd_seq_close(m_midiHandle);
245 
246         m_midiHandle = nullptr;
247     }
248 
249     DataBlockRepository::clear();
250 
251     clearDevices();
252 
253     m_haveShutdown = true;
254 }
255 
256 void
setLoop(const RealTime & loopStart,const RealTime & loopEnd)257 AlsaDriver::setLoop(const RealTime &loopStart, const RealTime &loopEnd)
258 {
259     m_loopStartTime = loopStart;
260     m_loopEndTime = loopEnd;
261 
262     // currently we use this simple test for looping - it might need
263     // to get more sophisticated in the future.
264     //
265     if (m_loopStartTime != m_loopEndTime)
266         m_looping = true;
267     else
268         m_looping = false;
269 }
270 
271 void
getSystemInfo()272 AlsaDriver::getSystemInfo()
273 {
274     int err;
275     snd_seq_system_info_t *sysinfo;
276 
277     snd_seq_system_info_alloca(&sysinfo);
278 
279     if ((err = snd_seq_system_info(m_midiHandle, sysinfo)) < 0) {
280         RG_WARNING << "getSystemInfo(): Error: " << snd_strerror(err);
281         reportFailure(MappedEvent::FailureALSACallFailed);
282         m_maxQueues = 0;
283         m_maxClients = 0;
284         m_maxPorts = 0;
285         return ;
286     }
287 
288     m_maxQueues = snd_seq_system_info_get_queues(sysinfo);
289     m_maxClients = snd_seq_system_info_get_clients(sysinfo);
290     m_maxPorts = snd_seq_system_info_get_ports(sysinfo);
291 }
292 
293 void
showQueueStatus(int queue)294 AlsaDriver::showQueueStatus(int queue)
295 {
296     int err, idx, min, max;
297     snd_seq_queue_status_t *status;
298 
299     snd_seq_queue_status_alloca(&status);
300     min = queue < 0 ? 0 : queue;
301     max = queue < 0 ? m_maxQueues : queue + 1;
302 
303     for (idx = min; idx < max; ++idx) {
304         if ((err = snd_seq_get_queue_status(m_midiHandle, idx, status)) < 0) {
305 
306             if (err == -ENOENT)
307                 continue;
308 
309             RG_WARNING << "showQueueStatus(): Client " << idx << " info error: " << snd_strerror(err);
310 
311             reportFailure(MappedEvent::FailureALSACallFailed);
312             return ;
313         }
314 
315 #ifdef DEBUG_ALSA
316         RG_DEBUG << "showQueueStatus(): Queue " << snd_seq_queue_status_get_queue(status);
317         RG_DEBUG << "showQueueStatus(): Tick       = " << snd_seq_queue_status_get_tick_time(status);
318         RG_DEBUG << "showQueueStatus(): Realtime   = " << snd_seq_queue_status_get_real_time(status)->tv_sec << "." << snd_seq_queue_status_get_real_time(status)->tv_nsec;
319         RG_DEBUG << "showQueueStatus(): Flags      = 0x" << snd_seq_queue_status_get_status(status);
320 #endif
321 
322     }
323 
324 }
325 
326 
327 void
generateTimerList()328 AlsaDriver::generateTimerList()
329 {
330     // Enumerate the available timers
331 
332     snd_timer_t *timerHandle;
333 
334     snd_timer_id_t *timerId;
335     snd_timer_info_t *timerInfo;
336 
337     snd_timer_id_alloca(&timerId);
338     snd_timer_info_alloca(&timerInfo);
339 
340     snd_timer_query_t *timerQuery;
341     char timerName[64];
342 
343     m_timers.clear();
344 
345     if (snd_timer_query_open(&timerQuery, "hw", 0) >= 0) {
346 
347         snd_timer_id_set_class(timerId, SND_TIMER_CLASS_NONE);
348 
349         while (1) {
350 
351             if (snd_timer_query_next_device(timerQuery, timerId) < 0)
352                 break;
353             if (snd_timer_id_get_class(timerId) < 0)
354                 break;
355 
356             AlsaTimerInfo info = {
357                 snd_timer_id_get_class(timerId),
358                 snd_timer_id_get_sclass(timerId),
359                 snd_timer_id_get_card(timerId),
360                 snd_timer_id_get_device(timerId),
361                 snd_timer_id_get_subdevice(timerId),
362                 "",
363                 0
364             };
365 
366             if (info.card < 0)
367                 info.card = 0;
368             if (info.device < 0)
369                 info.device = 0;
370             if (info.subdevice < 0)
371                 info.subdevice = 0;
372 
373             //RG_DEBUG << "generateTimerList(): got timer: class " << info.clas;
374 
375             sprintf(timerName, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i",
376                     info.clas, info.sclas, info.card, info.device, info.subdevice);
377 
378             if (snd_timer_open(&timerHandle, timerName, SND_TIMER_OPEN_NONBLOCK) < 0) {
379                 RG_WARNING << "generateTimerList(): Failed to open timer: " << timerName;
380                 continue;
381             }
382 
383             if (snd_timer_info(timerHandle, timerInfo) < 0)
384                 continue;
385 
386             info.name = snd_timer_info_get_name(timerInfo);
387             info.resolution = snd_timer_info_get_resolution(timerInfo);
388             snd_timer_close(timerHandle);
389 
390             //RG_DEBUG << "generateTimerList(): adding timer: " << info.name;
391 
392             m_timers.push_back(info);
393         }
394 
395         snd_timer_query_close(timerQuery);
396     }
397 }
398 
399 
400 std::string
getAutoTimer(bool & wantTimerChecks)401 AlsaDriver::getAutoTimer(bool &wantTimerChecks)
402 {
403     // Look for the apparent best-choice timer.
404 
405     if (m_timers.empty())
406         return "";
407 
408     // The system RTC timer ought to be good, but it doesn't look like
409     // a very safe choice -- we've seen some system lockups apparently
410     // connected with use of this timer on 2.6 kernels.  So we avoid
411     // using that as an auto option.
412 
413     // Looks like our most reliable options for timers are, in order:
414     //
415     // 1. System timer if at 1000Hz, with timer checks (i.e. automatic
416     //    drift correction against PCM frame count).  Only available
417     //    when JACK is running.
418     //
419     // 2. PCM playback timer currently in use by JACK (no drift, but
420     //    suffers from jitter).
421     //
422     // 3. System timer if at 1000Hz.
423     //
424     // 4. System RTC timer.
425     //
426     // 5. System timer.
427 
428     // As of Linux kernel 2.6.13 (?) the default system timer
429     // resolution has been reduced from 1000Hz to 250Hz, giving us
430     // only 4ms accuracy instead of 1ms.  This may be better than the
431     // 10ms available from the stock 2.4 kernel, but it's not enough
432     // for really solid MIDI timing.  If JACK is running at 44.1 or
433     // 48KHz with a buffer size less than 256 frames, then the PCM
434     // timer will give us less jitter.  Even at 256 frames, it may be
435     // preferable in practice just because it's simpler.
436 
437     // However, we can't safely choose the PCM timer over the system
438     // timer unless the latter has really awful resolution, because we
439     // don't know for certain which PCM JACK is using.  We guess at
440     // hw:0 for the moment, which gives us a stuck timer problem if
441     // it's actually using something else.  So if the system timer
442     // runs at 250Hz, we really have to choose it anyway and just give
443     // a warning.
444 
445     bool pcmTimerAccepted = false;
446     wantTimerChecks = false; // for most options
447 
448     bool rtcCouldBeOK = false;
449 
450 #ifdef HAVE_LIBJACK
451     if (m_jackDriver) {
452         wantTimerChecks = true;
453         pcmTimerAccepted = true;
454     }
455 #endif
456 
457     // look for a high frequency system timer
458 
459     for (std::vector<AlsaTimerInfo>::iterator i = m_timers.begin();
460          i != m_timers.end(); ++i) {
461         if (i->sclas != SND_TIMER_SCLASS_NONE)
462             continue;
463         if (i->clas == SND_TIMER_CLASS_GLOBAL) {
464             if (i->device == SND_TIMER_GLOBAL_SYSTEM) {
465                 long hz = 1000000000 / i->resolution;
466                 if (hz >= 750) {
467                     return i->name;
468                 }
469             }
470         }
471     }
472 
473     // Look for the system RTC timer if available.  This has been
474     // known to hang some real-time kernels, but reports suggest that
475     // recent kernels are OK.  Avoid if the kernel is older than
476     // 2.6.20 or the ALSA driver is older than 1.0.14.
477 
478     if (versionIsAtLeast(getAlsaVersion(),
479                          1, 0, 14) &&
480         versionIsAtLeast(getKernelVersionString(),
481                          2, 6, 20)) {
482 
483         rtcCouldBeOK = true;
484 
485         for (std::vector<AlsaTimerInfo>::iterator i = m_timers.begin();
486              i != m_timers.end(); ++i) {
487             if (i->sclas != SND_TIMER_SCLASS_NONE) continue;
488             if (i->clas == SND_TIMER_CLASS_GLOBAL) {
489                 if (i->device == SND_TIMER_GLOBAL_RTC) {
490                     return i->name;
491                 }
492             }
493         }
494     }
495 
496     // look for the first PCM playback timer; that's all we know about
497     // for now (until JACK becomes able to tell us which PCM it's on)
498 
499     if (pcmTimerAccepted) {
500 
501         for (std::vector<AlsaTimerInfo>::iterator i = m_timers.begin();
502              i != m_timers.end(); ++i) {
503             if (i->sclas != SND_TIMER_SCLASS_NONE)
504                 continue;
505             if (i->clas == SND_TIMER_CLASS_PCM) {
506                 if (i->resolution != 0) {
507                     long hz = 1000000000 / i->resolution;
508                     if (hz >= 750) {
509                         wantTimerChecks = false; // pointless with PCM timer
510                         return i->name;
511                     } else {
512                         AUDIT << "PCM timer: inadequate resolution " << i->resolution << '\n';
513                         RG_DEBUG << "getAutoTimer(): PCM timer: inadequate resolution " << i->resolution;
514                     }
515                 }
516             }
517         }
518     }
519 
520     // next look for slow, unpopular 100Hz (2.4) or 250Hz (2.6) system timer
521 
522     for (std::vector<AlsaTimerInfo>::iterator i = m_timers.begin();
523          i != m_timers.end(); ++i) {
524         if (i->sclas != SND_TIMER_SCLASS_NONE)
525             continue;
526         if (i->clas == SND_TIMER_CLASS_GLOBAL) {
527             if (i->device == SND_TIMER_GLOBAL_SYSTEM) {
528                 AUDIT << "Using low-resolution system timer, sending a warning" << '\n';
529                 RG_DEBUG << "getAutoTimer(): Using low-resolution system timer, sending a warning";
530                 if (rtcCouldBeOK) {
531                     reportFailure(MappedEvent::WarningImpreciseTimerTryRTC);
532                 } else {
533                     reportFailure(MappedEvent::WarningImpreciseTimer);
534                 }
535                 return i->name;
536             }
537         }
538     }
539 
540     // falling back to something that almost certainly won't work,
541     // if for any reason all of the above failed
542 
543     return m_timers.begin()->name;
544 }
545 
546 
547 
548 void
generatePortList()549 AlsaDriver::generatePortList()
550 {
551     AlsaPortVector alsaPorts;
552 
553     snd_seq_client_info_t *cinfo;
554     snd_seq_port_info_t *pinfo;
555     int client;
556     unsigned int writeCap = SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE;
557     unsigned int readCap = SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_READ;
558 
559     snd_seq_client_info_alloca(&cinfo);
560     snd_seq_client_info_set_client(cinfo, -1);
561 
562     AUDIT << '\n';
563     AUDIT << "  ALSA Client information:\n";
564     AUDIT << '\n';
565     RG_DEBUG << "generatePortList(): ALSA Client information:";
566 
567     // Get only the client ports we're interested in and store them
568     // for sorting and then device creation.
569     //
570     while (snd_seq_query_next_client(m_midiHandle, cinfo) >= 0) {
571         client = snd_seq_client_info_get_client(cinfo);
572         snd_seq_port_info_alloca(&pinfo);
573         snd_seq_port_info_set_client(pinfo, client);
574         snd_seq_port_info_set_port(pinfo, -1);
575 
576         // Ignore ourselves and the system client
577         //
578         if (client == m_client || client == 0)
579             continue;
580 
581         while (snd_seq_query_next_port(m_midiHandle, pinfo) >= 0) {
582 
583             int client = snd_seq_port_info_get_client(pinfo);
584             int port = snd_seq_port_info_get_port(pinfo);
585             unsigned int clientType = snd_seq_client_info_get_type(cinfo);
586             unsigned int portType = snd_seq_port_info_get_type(pinfo);
587             unsigned int capability = snd_seq_port_info_get_capability(pinfo);
588 
589             if ((((capability & writeCap) == writeCap) ||
590                  ((capability & readCap) == readCap)) &&
591                 ((capability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0)) {
592                 AUDIT << "    "
593                       << client << ","
594                       << port << " - ("
595                       << snd_seq_client_info_get_name(cinfo) << ", "
596                       << snd_seq_port_info_get_name(pinfo) << ")";
597                 RG_DEBUG << "    "
598                       << client << ","
599                       << port << " - ("
600                       << snd_seq_client_info_get_name(cinfo) << ", "
601                       << snd_seq_port_info_get_name(pinfo) << ")";
602 
603                 PortDirection direction;
604 
605                 if ((capability & SND_SEQ_PORT_CAP_DUPLEX) ||
606                     ((capability & SND_SEQ_PORT_CAP_WRITE) &&
607                      (capability & SND_SEQ_PORT_CAP_READ))) {
608                     direction = Duplex;
609                     AUDIT << "\t\t\t(DUPLEX)";
610                     RG_DEBUG << "        (DUPLEX)";
611                 } else if (capability & SND_SEQ_PORT_CAP_WRITE) {
612                     direction = WriteOnly;
613                     AUDIT << "\t\t(WRITE ONLY)";
614                     RG_DEBUG << "        (WRITE ONLY)";
615                 } else {
616                     direction = ReadOnly;
617                     AUDIT << "\t\t(READ ONLY)";
618                     RG_DEBUG << "        (READ ONLY)";
619                 }
620 
621                 AUDIT << " [ctype " << clientType << ", ptype " << portType << ", cap " << capability << "]";
622                 RG_DEBUG << "        [ctype " << clientType << ", ptype " << portType << ", cap " << capability << "]";
623 
624                 // Generate a unique name using the client id
625                 //
626                 char portId[40];
627                 sprintf(portId, "%d:%d ", client, port);
628 
629                 std::string fullClientName =
630                     std::string(snd_seq_client_info_get_name(cinfo));
631 
632                 std::string fullPortName =
633                     std::string(snd_seq_port_info_get_name(pinfo));
634 
635                 std::string name;
636 
637                 // If the first part of the client name is the same as the
638                 // start of the port name, just use the port name.  otherwise
639                 // concatenate.
640                 //
641                 int firstSpace = fullClientName.find(" ");
642 
643                 // If no space is found then we try to match the whole string
644                 //
645                 if (firstSpace < 0)
646                     firstSpace = int(fullClientName.length());
647 
648                 if (firstSpace > 0 &&
649                     int(fullPortName.length()) >= firstSpace &&
650                     fullPortName.substr(0, firstSpace) ==
651                     fullClientName.substr(0, firstSpace)) {
652                     name = portId + fullPortName;
653                 } else {
654                     name = portId + fullClientName + ": " + fullPortName;
655                 }
656 
657                 // Sanity check for length
658                 //
659                 if (name.length() > 35)
660                     name = portId + fullPortName;
661 
662                 if (direction == WriteOnly) {
663                     name += " (write)";
664                 } else if (direction == ReadOnly) {
665                     name += " (read)";
666                 } else if (direction == Duplex) {
667                     name += " (duplex)";
668                 }
669 
670                 QSharedPointer<AlsaPortDescription> portDescription(
671                     new AlsaPortDescription(
672                                             Instrument::Midi,
673                                             name,
674                                             client,
675                                             port,
676                                             clientType,
677                                             portType,
678                                             capability,
679                                             direction));
680 
681                 //if (newPorts  &&
682                 //    (getPortName(ClientPortPair(client, port)) == "")) {
683                 //    newPorts->push_back(portDescription);
684                 //}
685 
686                 alsaPorts.push_back(portDescription);
687 
688                 AUDIT << '\n';
689             }
690         }
691     }
692 
693     AUDIT << '\n';
694 
695     // Ok now sort by duplexicity
696     //
697     std::sort(alsaPorts.begin(), alsaPorts.end(), AlsaPortCmp());
698     m_alsaPorts = alsaPorts;
699 }
700 
701 
702 void
generateFixedInstruments()703 AlsaDriver::generateFixedInstruments()
704 {
705     // Create a number of soft synth Instruments
706     //
707     MappedInstrument *instr;
708     char number[100];
709     InstrumentId first;
710     int count;
711     getSoftSynthInstrumentNumbers(first, count);
712 
713     // soft-synth device takes id to match first soft-synth instrument
714     // number, for easy identification & consistency with GUI
715     DeviceId ssiDeviceId = first;
716 
717     for (int i = 0; i < count; ++i) {
718         sprintf(number, " #%d", i + 1);
719         std::string name = QObject::tr("Synth plugin").toStdString() + std::string(number);
720         instr = new MappedInstrument(Instrument::SoftSynth,
721                                      i,
722                                      first + i,
723                                      name,
724                                      ssiDeviceId);
725         m_instruments.push_back(instr);
726 
727         m_studio->createObject(MappedObject::AudioFader,
728                                first + i);
729     }
730 
731     MappedDevice *device =
732         new MappedDevice(ssiDeviceId,
733                          Device::SoftSynth,
734                          "Synth plugin",
735                          "Soft synth connection");
736     m_devices.push_back(device);
737 
738     // Create a number of audio Instruments - these are just
739     // logical Instruments anyway and so we can create as
740     // many as we like and then use them for Tracks.
741     //
742     // Note that unlike in earlier versions of Rosegarden, we always
743     // have exactly one soft synth device and one audio device (even
744     // if audio output is not actually working, the device is still
745     // present).
746     //
747     std::string audioName;
748     getAudioInstrumentNumbers(first, count);
749 
750     // audio device takes id to match first audio instrument
751     // number, for easy identification & consistency with GUI
752     DeviceId audioDeviceId = first;
753 
754     for (int i = 0; i < count; ++i) {
755         sprintf(number, " #%d", i + 1);
756         audioName = QObject::tr("Audio").toStdString() + std::string(number);
757         instr = new MappedInstrument(Instrument::Audio,
758                                      i,
759                                      first + i,
760                                      audioName,
761                                      audioDeviceId);
762         m_instruments.push_back(instr);
763 
764         // Create a fader with a matching id - this is the starting
765         // point for all audio faders.
766         //
767         m_studio->createObject(MappedObject::AudioFader, first + i);
768     }
769 
770     // Create audio device
771     //
772     device =
773         new MappedDevice(audioDeviceId,
774                          Device::Audio,
775                          "Audio",
776                          "Audio connection");
777     m_devices.push_back(device);
778 }
779 
780 MappedDevice *
createMidiDevice(DeviceId deviceId,MidiDevice::DeviceDirection reqDirection)781 AlsaDriver::createMidiDevice(DeviceId deviceId,
782                              MidiDevice::DeviceDirection reqDirection)
783 {
784     std::string connectionName = "";
785     const char *deviceName = "unnamed";
786 
787     if (reqDirection == MidiDevice::Play) {
788 
789         QString portName = QString("out %1 - %2")
790             .arg(m_outputPorts.size() + 1)
791             .arg(deviceName);
792 
793         int outputPort = checkAlsaError(snd_seq_create_simple_port
794                                         (m_midiHandle,
795                                          portName.toLocal8Bit(),
796                                          SND_SEQ_PORT_CAP_READ |
797                                          SND_SEQ_PORT_CAP_SUBS_READ,
798                                          SND_SEQ_PORT_TYPE_APPLICATION |
799                                          SND_SEQ_PORT_TYPE_SOFTWARE |
800                                          SND_SEQ_PORT_TYPE_MIDI_GENERIC),
801                                         "createMidiDevice - can't create output port");
802 
803         if (outputPort >= 0) {
804 
805             RG_DEBUG << "createMidiDevice(): CREATED OUTPUT PORT " << outputPort << ":" << portName << " for device " << deviceId;
806 
807             m_outputPorts[deviceId] = outputPort;
808         }
809     }
810 
811     MappedDevice *device = new MappedDevice(deviceId,
812                                             Device::Midi,
813                                             deviceName,
814                                             connectionName);
815     device->setDirection(reqDirection);
816     return device;
817 }
818 
819 void
addInstrumentsForDevice(MappedDevice * device,InstrumentId base)820 AlsaDriver::addInstrumentsForDevice(MappedDevice *device, InstrumentId base)
821 {
822     std::string channelName;
823     char number[100];
824 
825     for (int channel = 0; channel < 16; ++channel) {
826 
827         // name is just number, derive rest from device at gui
828         sprintf(number, "#%d", channel + 1);
829         channelName = std::string(number);
830 
831         if (channel == 9) channelName = std::string("#10[D]");
832 
833         MappedInstrument *instr = new MappedInstrument
834             (Instrument::Midi, channel, base++, channelName, device->getId());
835         m_instruments.push_back(instr);
836     }
837 }
838 
839 void
clearDevices()840 AlsaDriver::clearDevices()
841 {
842     for (size_t i = 0; i < m_instruments.size(); ++i) {
843         delete m_instruments[i];
844     }
845     m_instruments.clear();
846 
847     for (size_t i = 0; i < m_devices.size(); ++i) {
848         delete m_devices[i];
849     }
850     m_devices.clear();
851 
852     m_devicePortMap.clear();
853 }
854 
855 bool
addDevice(Device::DeviceType type,DeviceId deviceId,InstrumentId baseInstrumentId,MidiDevice::DeviceDirection direction)856 AlsaDriver::addDevice(Device::DeviceType type,
857                       DeviceId deviceId,
858                       InstrumentId baseInstrumentId,
859                       MidiDevice::DeviceDirection direction)
860 {
861     RG_DEBUG << "addDevice(" << type << "," << direction << ")";
862 
863     if (type == Device::Midi) {
864 
865         MappedDevice *device = createMidiDevice(deviceId, direction);
866         if (!device) {
867             RG_WARNING << "addDevice(): WARNING: Device creation failed, type: " << type << " deviceId: " << deviceId << " baseInstrumentId: " << baseInstrumentId << " direction: " << direction;
868         } else {
869             addInstrumentsForDevice(device, baseInstrumentId);
870             m_devices.push_back(device);
871 
872             if (direction == MidiDevice::Record) {
873                 setRecordDevice(device->getId(), true);
874             }
875 
876             return true;
877         }
878     }
879 
880     return false;
881 }
882 
883 void
removeDevice(DeviceId id)884 AlsaDriver::removeDevice(DeviceId id)
885 {
886     DeviceIntMap::iterator i1 = m_outputPorts.find(id);
887     if (i1 == m_outputPorts.end()) {
888         RG_WARNING << "removeDevice(): WARNING: Cannot find device " << id << " in port map";
889         return ;
890     }
891     checkAlsaError( snd_seq_delete_port(m_midiHandle, i1->second),
892                     "removeDevice");
893     m_outputPorts.erase(i1);
894 
895     // ??? Consider using findDevice() instead.
896     for (MappedDeviceList::iterator i = m_devices.end();
897          i != m_devices.begin(); ) {
898 
899         --i;
900 
901         if ((*i)->getId() == id) {
902             delete *i;
903             // ??? This invalidates i, but then we keep using it in this
904             //     loop.  There should be a break after this.  Or if we
905             //     really want to continue looking for matches, then we
906             //     need to use the "decrement before use" idiom.  A reverse
907             //     iterator should simplify.
908             m_devices.erase(i);
909         }
910     }
911 
912     for (MappedInstrumentList::iterator i = m_instruments.end();
913          i != m_instruments.begin(); ) {
914 
915         --i;
916 
917         if ((*i)->getDevice() == id) {
918             delete *i;
919             // ??? This invalidates i, but then we keep using it in this
920             //     loop.  There should be a break after this.  Or if we
921             //     really want to continue looking for matches, then we
922             //     need to use the "decrement before use" idiom.  A reverse
923             //     iterator should simplify.
924             m_instruments.erase(i);
925         }
926     }
927 }
928 
929 void
removeAllDevices()930 AlsaDriver::removeAllDevices()
931 {
932     while (!m_outputPorts.empty()) {
933         checkAlsaError(snd_seq_delete_port(m_midiHandle,
934                                            m_outputPorts.begin()->second),
935                        "removeAllDevices");
936         m_outputPorts.erase(m_outputPorts.begin());
937     }
938 
939     clearDevices();
940 }
941 
942 void
renameDevice(DeviceId id,QString name)943 AlsaDriver::renameDevice(DeviceId id, QString name)
944 {
945     DeviceIntMap::iterator i = m_outputPorts.find(id);
946     if (i == m_outputPorts.end()) {
947         RG_WARNING << "renameDevice(): WARNING: Cannot find device " << id << " in port map";
948         return ;
949     }
950 
951     snd_seq_port_info_t *pinfo;
952     snd_seq_port_info_alloca(&pinfo);
953     snd_seq_get_port_info(m_midiHandle, i->second, pinfo);
954 
955     QString oldName = snd_seq_port_info_get_name(pinfo);
956     int sep = oldName.indexOf(" - ");
957 
958     QString newName;
959     if (sep < 0) {
960         newName = oldName + " - " + name;
961     } else {
962         newName = oldName.left(sep + 3) + name;
963     }
964 
965     snd_seq_port_info_set_name(pinfo, newName.toLocal8Bit().data());
966     checkAlsaError(snd_seq_set_port_info(m_midiHandle, i->second, pinfo),
967                    "renameDevice");
968 
969     MappedDevice *device = findDevice(id);
970     if (device)
971         device->setName(qstrtostr(newName));
972 
973     RG_DEBUG << "renameDevice(): Renamed " << m_client << ":" << i->second << " to " << name;
974 }
975 
976 ClientPortPair
getPortByName(std::string name)977 AlsaDriver::getPortByName(std::string name)
978 {
979     AUDIT << "AlsaDriver::getPortByName(\"" << name << "\")\n";
980     RG_DEBUG << "getPortByName(" << name << ")";
981 
982     // For each ALSA port...
983     for (size_t i = 0; i < m_alsaPorts.size(); ++i) {
984         //AUDIT << "  Comparing\n";
985         //AUDIT << "    \"" << name << "\" with\n";
986         //AUDIT << "    \"" << m_alsaPorts[i]->m_name << "\"\n";
987         //RG_DEBUG << "  Comparing" << name << "with";
988         //RG_DEBUG << "           " << m_alsaPorts[i]->m_name;
989 
990         if (m_alsaPorts[i]->m_name == name)
991             return ClientPortPair(m_alsaPorts[i]->m_client,
992                                   m_alsaPorts[i]->m_port);
993     }
994 
995     return ClientPortPair(-1, -1);
996 }
997 
998 std::string
getPortName(ClientPortPair port)999 AlsaDriver::getPortName(ClientPortPair port)
1000 {
1001     for (size_t i = 0; i < m_alsaPorts.size(); ++i) {
1002         if (m_alsaPorts[i]->m_client == port.client &&
1003             m_alsaPorts[i]->m_port == port.port) {
1004             return m_alsaPorts[i]->m_name;
1005         }
1006     }
1007     return "";
1008 }
1009 
1010 unsigned int
getConnections(Device::DeviceType type,MidiDevice::DeviceDirection direction)1011 AlsaDriver::getConnections(Device::DeviceType type,
1012                            MidiDevice::DeviceDirection direction)
1013 {
1014     if (type != Device::Midi)
1015         return 0;
1016 
1017     int count = 0;
1018     for (size_t j = 0; j < m_alsaPorts.size(); ++j) {
1019         if ((direction == MidiDevice::Play && m_alsaPorts[j]->isWriteable()) ||
1020             (direction == MidiDevice::Record && m_alsaPorts[j]->isReadable())) {
1021             ++count;
1022         }
1023     }
1024 
1025     return count;
1026 }
1027 
1028 QString
getConnection(Device::DeviceType type,MidiDevice::DeviceDirection direction,unsigned int connectionNo)1029 AlsaDriver::getConnection(Device::DeviceType type,
1030                           MidiDevice::DeviceDirection direction,
1031                           unsigned int connectionNo)
1032 {
1033     if (type != Device::Midi)
1034         return "";
1035 
1036     AlsaPortVector tempList;
1037     for (size_t j = 0; j < m_alsaPorts.size(); ++j) {
1038         if ((direction == MidiDevice::Play && m_alsaPorts[j]->isWriteable()) ||
1039             (direction == MidiDevice::Record && m_alsaPorts[j]->isReadable())) {
1040             tempList.push_back(m_alsaPorts[j]);
1041         }
1042     }
1043 
1044     if (connectionNo < (unsigned int)tempList.size()) {
1045         return strtoqstr(tempList[connectionNo]->m_name);
1046     }
1047 
1048     return "";
1049 }
1050 
1051 QString
getConnection(DeviceId id)1052 AlsaDriver::getConnection(DeviceId id)
1053 {
1054     if (m_devicePortMap.find(id) == m_devicePortMap.end()) return "";
1055     const ClientPortPair &pair = m_devicePortMap[id];
1056     return getPortName(pair).c_str();
1057 }
1058 
1059 void
setConnectionToDevice(MappedDevice & device,QString connection)1060 AlsaDriver::setConnectionToDevice(MappedDevice &device, QString connection)
1061 {
1062     ClientPortPair pair( -1, -1);
1063     if (connection != "") {
1064         pair = getPortByName(qstrtostr(connection));
1065     }
1066     setConnectionToDevice(device, connection, pair);
1067 }
1068 
1069 void
setConnectionToDevice(MappedDevice & device,QString connection,const ClientPortPair & pair)1070 AlsaDriver::setConnectionToDevice(MappedDevice &device, QString connection,
1071                                   const ClientPortPair &pair)
1072 {
1073 #ifdef DEBUG_ALSA
1074     RG_DEBUG << "setConnectionToDevice(): connection " << connection;
1075 #endif
1076 
1077     if (device.getDirection() == MidiDevice::Record) {
1078         // disconnect first
1079         setRecordDevice(device.getId(), false);
1080     }
1081 
1082     m_devicePortMap[device.getId()] = pair;
1083 
1084     QString prevConnection = strtoqstr(device.getConnection());
1085     device.setConnection(qstrtostr(connection));
1086 
1087     if (device.getDirection() == MidiDevice::Play) {
1088 
1089         DeviceIntMap::iterator j = m_outputPorts.find(device.getId());
1090 
1091         if (j != m_outputPorts.end()) {
1092 
1093             if (prevConnection != "") {
1094                 ClientPortPair prevPair = getPortByName(qstrtostr(prevConnection));
1095                 if (prevPair.client >= 0 && prevPair.port >= 0) {
1096 
1097                     RG_DEBUG << "setConnectionToDevice(): Disconnecting my port " << j->second << " from " << prevPair.client << ":" << prevPair.port << " on reconnection";
1098                     snd_seq_disconnect_to(m_midiHandle,
1099                                           j->second,
1100                                           prevPair.client,
1101                                           prevPair.port);
1102 
1103                     if (m_midiSyncAutoConnect) {
1104                         bool foundElsewhere = false;
1105                         for (MappedDeviceList::iterator k = m_devices.begin();
1106                              k != m_devices.end(); ++k) {
1107                             if ((*k)->getId() != device.getId()) {
1108                                 if ((*k)->getConnection() ==
1109                                     qstrtostr(prevConnection)) {
1110                                     foundElsewhere = true;
1111                                     break;
1112                                 }
1113                             }
1114                         }
1115                         if (!foundElsewhere) {
1116                             snd_seq_disconnect_to(m_midiHandle,
1117                                                   m_syncOutputPort,
1118                                                   pair.client,
1119                                                   pair.port);
1120                         }
1121                     }
1122                 }
1123             }
1124 
1125             if (pair.client >= 0  &&  pair.port >= 0) {
1126                 RG_DEBUG << "setConnectionToDevice(): Connecting my port " << j->second << " to " << pair.client << ":" << pair.port << " on reconnection";
1127                 snd_seq_connect_to(m_midiHandle,
1128                                    j->second,
1129                                    pair.client,
1130                                    pair.port);
1131                 if (m_midiSyncAutoConnect) {
1132                     snd_seq_connect_to(m_midiHandle,
1133                                        m_syncOutputPort,
1134                                        pair.client,
1135                                        pair.port);
1136                 }
1137             }
1138         }
1139     } else { // record device: reconnect
1140 
1141         setRecordDevice(device.getId(), true);
1142     }
1143 }
1144 
1145 void
setConnection(DeviceId id,QString connection)1146 AlsaDriver::setConnection(DeviceId id, QString connection)
1147 {
1148     ClientPortPair port(getPortByName(qstrtostr(connection)));
1149 
1150 #ifdef DEBUG_ALSA
1151     RG_DEBUG << "setConnection(" << id << "," << connection << ")";
1152 #endif
1153 
1154     if ((connection == "") || (port.client != -1 && port.port != -1)) {
1155 
1156 #ifdef DEBUG_ALSA
1157         if (connection == "") {
1158             RG_DEBUG << "setConnection(): empty connection, disconnecting";
1159         } else {
1160             RG_DEBUG << "setConnection(): found port";
1161         }
1162 #endif
1163 
1164         MappedDevice *device = findDevice(id);
1165         if (device)
1166             setConnectionToDevice(*device, connection, port);
1167 
1168     }
1169 }
1170 
1171 namespace
1172 {
1173     // Remove the client:port pair from the front of a name.
removeClientPort(QString name)1174     QString removeClientPort(QString name)
1175     {
1176         // 0123456789
1177         // 123:456 hello
1178 
1179         int colon = name.indexOf(":");
1180         // If the colon is not found or too far into the name, bail.
1181         if (colon < 0  ||  colon > 3)
1182             return name;
1183 
1184         int space = name.indexOf(" ");
1185         // If the space is not found or too far into the name, bail.
1186         if (space < 0  ||  space > 7)
1187             return name;
1188 
1189         return name.mid(space + 1);
1190     }
1191 
1192     // Parse a port name in the format: "client:port name" into client number,
1193     // port number, and name.
parsePortName(const QString & portName,int & clientNumber,int & portNumber,QString & name)1194     void parsePortName(const QString &portName,
1195                        int &clientNumber,
1196                        int &portNumber,
1197                        QString &name)
1198     {
1199         // Assume not parseable.
1200         clientNumber = -1;
1201         portNumber = -1;
1202         name = "";
1203 
1204         if (portName == "")
1205             return;
1206 
1207         // Extract the client, the number prior to the first colon.
1208         int colon = portName.indexOf(":");
1209         if (colon >= 0)
1210             clientNumber = portName.left(colon).toInt();
1211 
1212         // If the client number was found...
1213         if (clientNumber > 0) {
1214             // Extract the port, the number after the first colon.
1215             QString remainder = portName.mid(colon + 1);
1216             int space = remainder.indexOf(" ");
1217             if (space >= 0)
1218                 portNumber = remainder.left(space).toInt();
1219         }
1220 
1221         // Extract the name.
1222 
1223         // Port name starts after the first space.
1224         int firstSpace = portName.indexOf(" ");
1225         if (firstSpace >= 0)
1226             name = portName.mid(firstSpace + 1);
1227     }
1228 }
1229 
1230 void
setFirstConnection(DeviceId deviceId,bool recordDevice)1231 AlsaDriver::setFirstConnection(DeviceId deviceId, bool recordDevice)
1232 {
1233     AUDIT << "AlsaDriver::setFirstConnection()\n";
1234     RG_DEBUG << "setFirstConnection()";
1235 
1236     QSharedPointer<AlsaPortDescription> firstPort;
1237 
1238     // For each ALSA port...
1239     for (QSharedPointer<AlsaPortDescription> currentPort : m_alsaPorts) {
1240 
1241         AUDIT << "  Trying \"" << currentPort->m_name << "\"\n";
1242         RG_DEBUG << "  Trying" << currentPort->m_name;
1243 
1244         // If we're looking for a record device and this port isn't
1245         // readable, skip.
1246         if (recordDevice  &&  !currentPort->isReadable())
1247             continue;
1248         // If we're looking for a playback device and this port isn't
1249         // writeable, skip.
1250         if (!recordDevice  &&  !currentPort->isWriteable())
1251             continue;
1252 
1253         QString lcName = strtoqstr(currentPort->m_name).toLower();
1254 
1255         // Avoid "through" or "thru" ports so that we don't end up creating
1256         // a feedback loop.
1257         // ??? Might want to do this only in the record case.  That way
1258         //     a synth waiting on the other side of a thru port will be
1259         //     picked up.
1260         if (lcName.contains(" through ")  ||  lcName.contains(" thru "))
1261             continue;
1262 
1263         // No sense connecting to a control surface.
1264         if (lcName.contains("nanokontrol2"))
1265             continue;
1266 
1267         AUDIT << "  Going with it...\n";
1268         RG_DEBUG << "  Going with it...";
1269 
1270         // Take the first one we find.
1271         firstPort = currentPort;
1272         break;
1273     }
1274 
1275     // Connect to the firstPort
1276 
1277     if (firstPort) {
1278         // Find the device and make the connection.
1279 
1280         MappedDevice *device = findDevice(deviceId);
1281         if (device)
1282             setConnectionToDevice(
1283                     *device,
1284                     strtoqstr(firstPort->m_name),
1285                     ClientPortPair(firstPort->m_client, firstPort->m_port));
1286     }
1287 }
1288 
1289 void
setPlausibleConnection(DeviceId deviceId,QString idealConnection,bool recordDevice)1290 AlsaDriver::setPlausibleConnection(
1291         DeviceId deviceId, QString idealConnection, bool recordDevice)
1292 {
1293     // ??? Proposed simplified version that searches for the best fit and
1294     //     connects to it.
1295 
1296     AUDIT << "----------\n";
1297     AUDIT << "AlsaDriver::setPlausibleConnection()\n";
1298     AUDIT << "  Connection like \"" << idealConnection << "\" requested for device " << deviceId << '\n';
1299     RG_DEBUG << "----------";
1300     RG_DEBUG << "setPlausibleConnection()";
1301     RG_DEBUG << "  Connection like" << idealConnection << "requested for device " << deviceId;
1302 
1303     // If we are looking for "", bail.  connectSomething() will take over.
1304     if (idealConnection == "")
1305         return;
1306 
1307     int bestScore = 0;
1308     QSharedPointer<AlsaPortDescription> bestPort;
1309 
1310     int clientNumber;
1311     int portNumber;
1312     QString name;
1313     parsePortName(idealConnection, clientNumber, portNumber, name);
1314 
1315     // For each ALSA port...
1316     for (QSharedPointer<AlsaPortDescription> currentPort : m_alsaPorts) {
1317         AUDIT << "AlsaDriver::setPlausibleConnection(): Checking \"" << currentPort->m_name << "\"\n";
1318         RG_DEBUG << "setPlausibleConnection(): Checking" << currentPort->m_name;
1319 
1320         // If we're looking for a record device and this port isn't
1321         // readable, skip.
1322         if (recordDevice  &&  !currentPort->isReadable())
1323             continue;
1324         // If we're looking for a playback device and this port isn't
1325         // writeable, skip.
1326         if (!recordDevice  &&  !currentPort->isWriteable())
1327             continue;
1328 
1329         // Class mismatch, skip.
1330         if (getClass(currentPort->m_client) != getClass(clientNumber))
1331             continue;
1332 
1333         // If we're looking for a playback device and this one is already
1334         // connected, skip.
1335         if (!recordDevice  &&
1336             portInUse(currentPort->m_client, currentPort->m_port))
1337             continue;
1338 
1339         // Strip client:port from the front of the name.
1340         QString currentName = removeClientPort(strtoqstr(currentPort->m_name));
1341 
1342         int score = 25 - levenshtein_distance(
1343                 qstrtostr(currentName).size(),
1344                 qstrtostr(currentName),
1345                 qstrtostr(name).size(),
1346                 qstrtostr(name));
1347 
1348         // No sense connecting to something with a wildly different name.
1349         if (score < 20)
1350             continue;
1351 
1352         // Same port: +25
1353         if (currentPort->m_port == portNumber)
1354             score += 25;
1355 
1356         // Not connected to anything: +25
1357         if (!portInUse(currentPort->m_client, currentPort->m_port))
1358             score += 25;
1359 
1360         AUDIT << "  Final score: " << score << "\n";
1361         RG_DEBUG << "  Final score:" << score;
1362 
1363         if (score > bestScore) {
1364             bestScore = score;
1365             bestPort = currentPort;
1366         }
1367     }
1368 
1369     // Connect to the bestPort
1370 
1371     if (bestPort) {
1372         AUDIT << "Going with \"" << bestPort->m_name << "\"\n";
1373         RG_DEBUG << "Going with" << bestPort->m_name;
1374 
1375         // Find the device and make the connection.
1376         // ??? We need to remove the connecting from this routine.  Instead
1377         //     it should be called findPlausibleConnection() and return
1378         //     bestPort.  That should make it easier to unit test.
1379 
1380         MappedDevice *device = findDevice(deviceId);
1381         if (device)
1382             setConnectionToDevice(
1383                     *device,
1384                     strtoqstr(bestPort->m_name),
1385                     ClientPortPair(bestPort->m_client, bestPort->m_port));
1386     } else {
1387         AUDIT << "AlsaDriver::setPlausibleConnection(): nothing suitable available\n";
1388         RG_DEBUG << "setPlausibleConnection(): nothing suitable available";
1389     }
1390 }
1391 
1392 void
connectSomething()1393 AlsaDriver::connectSomething()
1394 {
1395     AUDIT << "AlsaDriver::connectSomething()\n";
1396     RG_DEBUG << "connectSomething()...";
1397 
1398     // Called after document load, if there are devices in the document but none
1399     // of them has managed to get itself connected to anything.  Tries to find
1400     // something suitable to connect one play, and one record device to, and
1401     // connects it.  If nothing very appropriate beckons, leaves unconnected.
1402 
1403 
1404     // *** Playback connection.
1405 
1406     MappedDevice *playbackDevice = nullptr;
1407 
1408     // For each Device in the Composition
1409     for (MappedDevice *device : m_devices) {
1410 
1411         // Not playback?  Try the next.
1412         if (device->getDirection() != MidiDevice::Play)
1413             continue;
1414 
1415         // If something is connected, give up.
1416         if (isConnected(device->getId())) {
1417             playbackDevice = nullptr;
1418             break;
1419         }
1420 
1421         // Take the first one we find.
1422         if (!playbackDevice)
1423             playbackDevice = device;
1424     }
1425 
1426     // Connect something for playback.  Worst case, we'll probably connect
1427     // to a virtual MIDI through port.
1428     if (playbackDevice)
1429         setFirstConnection(
1430                 playbackDevice->getId(),  // deviceId
1431                 false);  // recordDevice
1432 
1433 
1434     // *** Record connection.
1435 
1436     MappedDevice *recordDevice = nullptr;
1437 
1438     // For each Device in the Composition
1439     for (MappedDevice *device : m_devices) {
1440 
1441         // Not a record device?  Try the next.
1442         if (device->getDirection() != MidiDevice::Record)
1443             continue;
1444 
1445         // If something is connected, give up.
1446         if (isConnected(device->getId())) {
1447             recordDevice = nullptr;
1448             break;
1449         }
1450 
1451         // Take the first one we find.
1452         if (!recordDevice)
1453             recordDevice = device;
1454     }
1455 
1456     // Connect something for record.  Worst case, we'll probably connect
1457     // to a virtual MIDI through port.
1458     if (recordDevice)
1459         setFirstConnection(
1460                 recordDevice->getId(),  // deviceId
1461                 true);  // recordDevice
1462 }
1463 
1464 void
checkTimerSync(size_t frames)1465 AlsaDriver::checkTimerSync(size_t frames)
1466 {
1467     if (!m_doTimerChecks)
1468         return ;
1469 
1470 #ifdef HAVE_LIBJACK
1471 
1472     if (!m_jackDriver || !m_queueRunning || frames == 0 ||
1473         (m_mtcStatus == TRANSPORT_FOLLOWER)) {
1474         m_firstTimerCheck = true;
1475         return ;
1476     }
1477 
1478     static RealTime startAlsaTime;
1479     static size_t startJackFrames = 0;
1480     static size_t lastJackFrames = 0;
1481 
1482     size_t nowJackFrames = m_jackDriver->getFramesProcessed();
1483     RealTime nowAlsaTime = getAlsaTime();
1484 
1485     if (m_firstTimerCheck ||
1486         (nowJackFrames <= lastJackFrames) ||
1487         (nowAlsaTime <= startAlsaTime)) {
1488 
1489         startAlsaTime = nowAlsaTime;
1490         startJackFrames = nowJackFrames;
1491         lastJackFrames = nowJackFrames;
1492 
1493         m_firstTimerCheck = false;
1494         return ;
1495     }
1496 
1497     RealTime jackDiff = RealTime::frame2RealTime
1498         (nowJackFrames - startJackFrames,
1499          m_jackDriver->getSampleRate());
1500 
1501     RealTime alsaDiff = nowAlsaTime - startAlsaTime;
1502 
1503     if (alsaDiff > RealTime(10, 0)) {
1504 
1505 #ifdef DEBUG_ALSA
1506         if (!m_playing) {
1507             RG_DEBUG << "checkTimerSync(): ALSA:" << startAlsaTime << "\t->" << nowAlsaTime << "\nJACK: " << startJackFrames << "\t\t-> " << nowJackFrames;
1508             RG_DEBUG << "checkTimerSync(): ALSA diff:  " << alsaDiff << "\nJACK diff:  " << jackDiff;
1509         }
1510 #endif
1511 
1512         double ratio = (jackDiff - alsaDiff) / alsaDiff;
1513 
1514         if (fabs(ratio) > 0.1) {
1515 #ifdef DEBUG_ALSA
1516             if (!m_playing) {
1517                 RG_DEBUG << "checkTimerSync(): Ignoring excessive ratio " << ratio << ", hoping for a more likely result next time";
1518             }
1519 #endif
1520 
1521         } else if (fabs(ratio) > 0.000001) {
1522 
1523 #ifdef DEBUG_ALSA
1524             if (alsaDiff > RealTime::zeroTime && jackDiff > RealTime::zeroTime) {
1525                 if (!m_playing) {
1526                     if (jackDiff < alsaDiff) {
1527                         RG_DEBUG << "checkTimerSync(): <<<< ALSA timer is faster by " << 100.0 * ((alsaDiff - jackDiff) / alsaDiff) << "% (1/" << int(1.0 / ratio) << ")";
1528                     } else {
1529                         RG_DEBUG << "checkTimerSync(): >>>> JACK timer is faster by " << 100.0 * ((jackDiff - alsaDiff) / alsaDiff) << "% (1/" << int(1.0 / ratio) << ")";
1530                     }
1531                 }
1532             }
1533 #endif
1534 
1535             m_timerRatio = ratio;
1536             m_timerRatioCalculated = true;
1537         }
1538 
1539         m_firstTimerCheck = true;
1540     }
1541 #endif
1542 }
1543 
1544 
1545 unsigned int
getTimers()1546 AlsaDriver::getTimers()
1547 {
1548     return (unsigned int)m_timers.size() + 1; // one extra for auto
1549 }
1550 
1551 QString
getTimer(unsigned int n)1552 AlsaDriver::getTimer(unsigned int n)
1553 {
1554     if (n == 0)
1555         return AUTO_TIMER_NAME;
1556     else
1557         return strtoqstr(m_timers[n -1].name);
1558 }
1559 
1560 QString
getCurrentTimer()1561 AlsaDriver::getCurrentTimer()
1562 {
1563     return m_currentTimer;
1564 }
1565 
1566 void
setCurrentTimer(QString timer)1567 AlsaDriver::setCurrentTimer(QString timer)
1568 {
1569     QSettings settings;
1570     bool skip = settings.value("ALSA/SkipSetCurrentTimer", false).toBool();
1571     // Write back out so we can find it.
1572     settings.setValue("ALSA/SkipSetCurrentTimer", skip);
1573     if (skip)
1574         return;
1575 
1576     // No change?  Bail.
1577     if (timer == m_currentTimer)
1578         return;
1579 
1580     m_currentTimer = timer;
1581     settings.setValue(SequencerOptionsConfigGroup + "/" + "timer",
1582                       m_currentTimer);
1583 
1584     RG_DEBUG << "setCurrentTimer(" << timer << ")";
1585 
1586     std::string name(qstrtostr(timer));
1587 
1588     if (name == AUTO_TIMER_NAME) {
1589         name = getAutoTimer(m_doTimerChecks);
1590     } else {
1591         m_doTimerChecks = false;
1592     }
1593     m_timerRatioCalculated = false;
1594 
1595     // Stop and restart the queue around the timer change.  We don't
1596     // call stopClocks/startClocks here because they do the wrong
1597     // thing if we're currently playing and on the JACK transport.
1598 
1599     m_queueRunning = false;
1600     checkAlsaError(snd_seq_stop_queue(m_midiHandle, m_queue, nullptr), "setCurrentTimer(): stopping queue");
1601     checkAlsaError(snd_seq_drain_output(m_midiHandle), "setCurrentTimer(): draining output to stop queue");
1602 
1603     snd_seq_event_t event;
1604     snd_seq_ev_clear(&event);
1605     snd_seq_real_time_t z = { 0, 0 };
1606     snd_seq_ev_set_queue_pos_real(&event, m_queue, &z);
1607     snd_seq_ev_set_direct(&event);
1608     checkAlsaError(snd_seq_control_queue(m_midiHandle, m_queue, SND_SEQ_EVENT_SETPOS_TIME,
1609                                          0, &event), "setCurrentTimer(): control queue");
1610     checkAlsaError(snd_seq_drain_output(m_midiHandle), "setCurrentTimer(): draining output to control queue");
1611     m_alsaPlayStartTime = RealTime::zeroTime;
1612 
1613     for (size_t i = 0; i < m_timers.size(); ++i) {
1614         if (m_timers[i].name == name) {
1615 
1616             snd_seq_queue_timer_t *timer;
1617             snd_timer_id_t *timerid;
1618 
1619             snd_seq_queue_timer_alloca(&timer);
1620             snd_seq_get_queue_timer(m_midiHandle, m_queue, timer);
1621 
1622             snd_timer_id_alloca(&timerid);
1623             snd_timer_id_set_class(timerid, m_timers[i].clas);
1624             snd_timer_id_set_sclass(timerid, m_timers[i].sclas);
1625             snd_timer_id_set_card(timerid, m_timers[i].card);
1626             snd_timer_id_set_device(timerid, m_timers[i].device);
1627             snd_timer_id_set_subdevice(timerid, m_timers[i].subdevice);
1628 
1629             snd_seq_queue_timer_set_id(timer, timerid);
1630             snd_seq_set_queue_timer(m_midiHandle, m_queue, timer);
1631 
1632             if (m_doTimerChecks) {
1633                 AUDIT << "    Current timer set to \"" << name << "\" with timer checks\n";
1634                 RG_DEBUG << "setCurrentTimer(): Current timer set to \"" << name << "\" with timer checks";
1635             } else {
1636                 AUDIT << "    Current timer set to \"" << name << "\"\n";
1637                 RG_DEBUG << "setCurrentTimer(): Current timer set to \"" << name << "\"";
1638             }
1639 
1640             if (m_timers[i].clas == SND_TIMER_CLASS_GLOBAL &&
1641                 m_timers[i].device == SND_TIMER_GLOBAL_SYSTEM) {
1642                 long hz = 1000000000 / m_timers[i].resolution;
1643                 if (hz < 900) {
1644                     AUDIT << "    WARNING: using system timer with only " << hz << "Hz resolution!\n";
1645                     RG_WARNING << "setCurrentTimer(): WARNING: using system timer with only " << hz << "Hz resolution!";
1646                 }
1647             }
1648 
1649             break;
1650         }
1651     }
1652 
1653 #ifdef HAVE_LIBJACK
1654     if (m_jackDriver)
1655         m_jackDriver->prebufferAudio();
1656 #endif
1657 
1658     checkAlsaError(snd_seq_continue_queue(m_midiHandle, m_queue, nullptr), "checkAlsaError(): continue queue");
1659     checkAlsaError(snd_seq_drain_output(m_midiHandle), "setCurrentTimer(): draining output to continue queue");
1660     m_queueRunning = true;
1661 
1662     m_firstTimerCheck = true;
1663 }
1664 
1665 bool
initialise()1666 AlsaDriver::initialise()
1667 {
1668     bool result = true;
1669 
1670     initialiseAudio();
1671     result = initialiseMidi();
1672 
1673     return result;
1674 }
1675 
1676 void
configureExternalControllerPort()1677 AlsaDriver::configureExternalControllerPort()
1678 {
1679     if (ExternalController::isEnabled()) {
1680         // For each ALSA port, look for a control surface...
1681         for (QSharedPointer<AlsaPortDescription> currentPort : m_alsaPorts) {
1682 
1683             // Skip ports we cannot read from.
1684             if (!currentPort->isReadable())
1685                 continue;
1686 
1687             // Check if the port is already connected to something.
1688             snd_seq_addr_t addr;
1689             addr.client = currentPort->m_client;
1690             addr.port = currentPort->m_port;
1691             snd_seq_query_subscribe_t *subscribers;
1692             // On stack, so no need to free.
1693             snd_seq_query_subscribe_alloca(&subscribers);
1694             snd_seq_query_subscribe_set_root(subscribers, &addr);
1695             snd_seq_query_subscribe_set_type(subscribers, SND_SEQ_QUERY_SUBS_READ);
1696             snd_seq_query_subscribe_set_index(subscribers, 0);
1697             // Perform the query.  We have to at least query once for
1698             // num_subs to be valid.
1699             snd_seq_query_port_subscribers(m_midiHandle, subscribers);
1700             // Already connected to something?  Try the next.
1701             if (snd_seq_query_subscribe_get_num_subs(subscribers) != 0)
1702                 continue;
1703 
1704             QString lcName = strtoqstr(currentPort->m_name).toLower();
1705 
1706             // Found the Korg nanoKONTROL2?
1707             if (lcName.contains("nanokontrol2")) {
1708                 // Connect it to the external controller port.
1709                 // nanoKONTROL2 -> rg
1710                 snd_seq_connect_from(m_midiHandle,
1711                         m_externalControllerPort,  // my_port
1712                         currentPort->m_client,  // src_client
1713                         currentPort->m_port);  // src_port
1714                 // rg -> nanoKONTROL2 (for LEDs)
1715                 snd_seq_connect_to(m_midiHandle,
1716                         m_externalControllerPort,  // my_port
1717                         currentPort->m_client,  // dest_client
1718                         currentPort->m_port);  // dest_port
1719 
1720                 ExternalController::self().setType(
1721                         ExternalController::CT_KorgNanoKontrol2);
1722 
1723                 break;
1724             }
1725         }
1726     }
1727 }
1728 
1729 bool
initialiseMidi()1730 AlsaDriver::initialiseMidi()
1731 {
1732     // Create a non-blocking handle.
1733     //
1734     if (snd_seq_open(&m_midiHandle,
1735                      "default",
1736                      SND_SEQ_OPEN_DUPLEX,
1737                      SND_SEQ_NONBLOCK) < 0) {
1738         AUDIT << "AlsaDriver::initialiseMidi() - "
1739               << "couldn't open sequencer - " << snd_strerror(errno)
1740               << " - perhaps you need to modprobe snd-seq-midi.\n";
1741         RG_WARNING << "initialiseMidi(): WARNING: couldn't open sequencer - "
1742                    << snd_strerror(errno)
1743                    << " - perhaps you need to modprobe snd-seq-midi.";
1744         reportFailure(MappedEvent::FailureALSACallFailed);
1745         return false;
1746     }
1747 
1748     // Set the client name.  Note that we depend on knowing this name
1749     // elsewhere, e.g. in setPlausibleConnection below.  If it is ever
1750     // changed, we may have to check for other occurrences
1751     //
1752     snd_seq_set_client_name(m_midiHandle, "rosegarden");
1753 
1754     if ((m_client = snd_seq_client_id(m_midiHandle)) < 0) {
1755         RG_WARNING << "initialiseMidi(): WARNING: Can't create client";
1756         return false;
1757     }
1758 
1759     // Create a queue
1760     //
1761     if ((m_queue = snd_seq_alloc_named_queue(m_midiHandle,
1762                                              "Rosegarden queue")) < 0) {
1763         RG_WARNING << "initialiseMidi(): WARNING: Can't allocate queue";
1764         return false;
1765     }
1766 
1767     // Create the input port
1768     //
1769     snd_seq_port_info_t *pinfo;
1770 
1771     snd_seq_port_info_alloca(&pinfo);
1772     snd_seq_port_info_set_capability(pinfo,
1773                                      SND_SEQ_PORT_CAP_WRITE |
1774                                      SND_SEQ_PORT_CAP_SUBS_WRITE );
1775     snd_seq_port_info_set_type(pinfo, SND_SEQ_PORT_TYPE_APPLICATION |
1776                                SND_SEQ_PORT_TYPE_SOFTWARE |
1777                                SND_SEQ_PORT_TYPE_MIDI_GENERIC);
1778     snd_seq_port_info_set_midi_channels(pinfo, 16);
1779     /* we want to know when the events got delivered to us */
1780     snd_seq_port_info_set_timestamping(pinfo, 1);
1781     snd_seq_port_info_set_timestamp_real(pinfo, 1);
1782     snd_seq_port_info_set_timestamp_queue(pinfo, m_queue);
1783     snd_seq_port_info_set_name(pinfo, "record in");
1784 
1785     if (checkAlsaError(snd_seq_create_port(m_midiHandle, pinfo),
1786                        "initialiseMidi - can't create input port") < 0)
1787         return false;
1788     m_inputPort = snd_seq_port_info_get_port(pinfo);
1789 
1790     // Subscribe the input port to the ALSA Announce port
1791     // to receive notifications when clients, ports and subscriptions change
1792     snd_seq_connect_from( m_midiHandle, m_inputPort,
1793                           SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE );
1794 
1795     m_midiInputPortConnected = true;
1796 
1797 #define POOL_DEBUG 0
1798 
1799 #if POOL_DEBUG
1800     snd_seq_client_pool_t *poolInfo;
1801     snd_seq_client_pool_malloc(&poolInfo);
1802     snd_seq_get_client_pool(m_midiHandle, poolInfo);
1803     RG_DEBUG << "initialiseMidi() before setting pool sizes...";
1804     RG_DEBUG << "  input pool: " << snd_seq_client_pool_get_input_pool(poolInfo);
1805     RG_DEBUG << "  output pool: " << snd_seq_client_pool_get_output_pool(poolInfo);
1806     RG_DEBUG << "  output room: " << snd_seq_client_pool_get_output_room(poolInfo);
1807 #endif
1808 
1809     // Increase memory pool size.
1810     // Normally these are 200, 500, and 0 respectively.
1811 
1812     // valgrind shows errors here.  They appear to be harmless.
1813 
1814     if (checkAlsaError(snd_seq_set_client_pool_input(m_midiHandle, 2000),
1815                        "AlsaDriver::initialiseMidi(): can't set input pool size") < 0)
1816         return false;
1817 
1818     if (checkAlsaError(snd_seq_set_client_pool_output(m_midiHandle, 2000),
1819                        "AlsaDriver::initialiseMidi(): can't set output pool size") < 0)
1820         return false;
1821 
1822     if (checkAlsaError(snd_seq_set_client_pool_output_room(m_midiHandle, 2000),
1823                        "AlsaDriver::initialiseMidi(): can't set output pool room") < 0)
1824         return false;
1825 
1826 #if POOL_DEBUG
1827     snd_seq_get_client_pool(m_midiHandle, poolInfo);
1828     RG_DEBUG << "initialiseMidi() after setting pool sizes...";
1829     RG_DEBUG << "  input pool: " << snd_seq_client_pool_get_input_pool(poolInfo);
1830     RG_DEBUG << "  output pool: " << snd_seq_client_pool_get_output_pool(poolInfo);
1831     RG_DEBUG << "  output room: " << snd_seq_client_pool_get_output_room(poolInfo);
1832     snd_seq_client_pool_free(poolInfo);
1833 #endif
1834 
1835     // Create sync output now as well
1836     m_syncOutputPort = checkAlsaError(snd_seq_create_simple_port
1837                                       (m_midiHandle,
1838                                        "sync out",
1839                                        SND_SEQ_PORT_CAP_READ |
1840                                        SND_SEQ_PORT_CAP_SUBS_READ,
1841                                        SND_SEQ_PORT_TYPE_APPLICATION |
1842                                        SND_SEQ_PORT_TYPE_SOFTWARE |
1843                                        SND_SEQ_PORT_TYPE_MIDI_GENERIC),
1844                                       "initialiseMidi - can't create sync output port");
1845 
1846     getSystemInfo();
1847 
1848     // Update m_alsaPorts.
1849     generatePortList();
1850     generateFixedInstruments();
1851 
1852     if (ExternalController::isEnabled()) {
1853         // Create external controller port.
1854         // See configureExternalControllerPort().
1855         m_externalControllerPort = checkAlsaError(
1856                 snd_seq_create_simple_port(
1857                     m_midiHandle,
1858                     "external controller",
1859                     SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE |
1860                         SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE,
1861                     SND_SEQ_PORT_TYPE_APPLICATION | SND_SEQ_PORT_TYPE_SOFTWARE |
1862                         SND_SEQ_PORT_TYPE_MIDI_GENERIC),
1863                 "initialiseMidi() - Can't create \"external controller\" port.");
1864     }
1865 
1866     // This will cause deadlock if it tries to talk to connected
1867     // control surfaces (see KorgNanoKontrol2::init()) using
1868     // RosegardenSequencer.  To fix, this can be called just after
1869     // the call to newDocument() in RosegardenMainWindow's ctor.
1870     // The call will have to be made via RosegardenSequencer since
1871     // it owns the AlsaDriver instance.  However, we need to redesign
1872     // AlsaDriver's handling of the external controller port, so we
1873     // might not need to worry about deadlocks when we are done.  See
1874     // the commit entitled "Fix deadlock" around October 2020.
1875     configureExternalControllerPort();
1876 
1877     // Modify status with MIDI success
1878     //
1879     m_driverStatus |= MIDI_OK;
1880 
1881     generateTimerList();
1882 
1883     QSettings settings;
1884     const QString timer = settings.value(
1885             SequencerOptionsConfigGroup + "/" + "timer",
1886             AUTO_TIMER_NAME).toString();
1887 
1888     setCurrentTimer(timer);
1889 
1890     // Start the timer
1891     if (checkAlsaError(snd_seq_start_queue(m_midiHandle, m_queue, nullptr),
1892                        "initialiseMidi(): couldn't start queue") < 0) {
1893         reportFailure(MappedEvent::FailureALSACallFailed);
1894         return false;
1895     }
1896 
1897     m_queueRunning = true;
1898 
1899     // process anything pending
1900     checkAlsaError(snd_seq_drain_output(m_midiHandle), "initialiseMidi(): couldn't drain output");
1901 
1902     AUDIT << "AlsaDriver::initialiseMidi() -  initialised MIDI subsystem\n\n";
1903     RG_DEBUG << "initialiseMidi() - initialised MIDI subsystem";
1904 
1905     return true;
1906 }
1907 
1908 // We don't even attempt to use ALSA audio.  We just use JACK instead.
1909 // See comment at the top of this file and jackProcess() for further
1910 // information on how we use this.
1911 //
1912 void
initialiseAudio()1913 AlsaDriver::initialiseAudio()
1914 {
1915 #ifdef HAVE_LIBJACK
1916     m_jackDriver = new JackDriver(this);
1917 
1918     if (m_jackDriver->isOK()) {
1919         m_driverStatus |= AUDIO_OK;
1920     } else {
1921         delete m_jackDriver;
1922         m_jackDriver = nullptr;
1923     }
1924 #endif
1925 }
1926 
1927 int
songPositionPointer(const RealTime & time)1928 AlsaDriver::songPositionPointer(const RealTime &time)
1929 {
1930     // The SPP is the MIDI Beat upon which to start the song.
1931     // Songs are always assumed to start on a MIDI Beat of 0.  Each MIDI
1932     // Beat spans 6 MIDI Clocks.  In other words, each MIDI Beat is a 16th
1933     // note (since there are 24 MIDI Clocks in a quarter note).
1934     // See the MIDI spec section 2, page 27.
1935 
1936     // 24 MIDI clocks per quarter note.
1937     // ??? This does not work if there are tempo changes.  See comments
1938     //     on m_midiClockInterval.
1939     const int midiClocks = lround(time / m_midiClockInterval);
1940 
1941     // Convert to MIDI beats.  Round down to the previous MIDI beat to avoid
1942     // skipping anything.
1943     return midiClocks / 6;
1944 }
1945 
1946 void
initialisePlayback(const RealTime & position)1947 AlsaDriver::initialisePlayback(const RealTime &position)
1948 {
1949 #ifdef DEBUG_ALSA
1950     RG_DEBUG << "initialisePlayback() begin...";
1951 #endif
1952 
1953     // now that we restart the queue at each play, the origin is always zero
1954     m_alsaPlayStartTime = RealTime::zeroTime;
1955     m_playStartPosition = position;
1956 
1957     m_startPlayback = true;
1958 
1959     m_mtcFirstTime = -1;
1960     m_mtcSigmaE = 0;
1961     m_mtcSigmaC = 0;
1962 
1963     if (m_mmcStatus == TRANSPORT_SOURCE) {
1964         sendMMC(127, MIDI_MMC_PLAY, true, "");
1965         m_eat_mtc = 0;
1966     }
1967 
1968     // If MIDI Sync is enabled then adjust for the MIDI Clock to
1969     // synchronise the sequencer with the clock.
1970     //
1971     if (m_midiSyncStatus == TRANSPORT_SOURCE) {
1972 
1973         // Note: CakeWalk PA 9.03 doesn't like this.  This causes it to go out
1974         //       of "Waiting for MIDI sync" mode, rendering MIDI sync
1975         //       impossible.
1976         sendSystemDirect(SND_SEQ_EVENT_STOP, nullptr);
1977 
1978         // Send the Song Position Pointer for MIDI CLOCK positioning
1979 
1980         // Get time from current alsa time to start of alsa timing,
1981         // add the initial starting point and convert to SPP.
1982         // ??? It doesn't seem appropriate for ALSA time to figure into
1983         //     the SPP computation.  SPP is relative only to Composition
1984         //     time.
1985 
1986         // Note: CakeWalk PA 9.03 does not adhere to the MIDI spec.  It treats
1987         //       SPP 1 as the beginning of the song.  The spec says 0 is the
1988         //       beginning.
1989 
1990         int spp = songPositionPointer(
1991                 getAlsaTime() - m_alsaPlayStartTime + m_playStartPosition);
1992         sendSystemDirect(SND_SEQ_EVENT_SONGPOS, &spp);
1993 
1994         // ??? The computed SPP might be significantly different from
1995         //     m_playStartPosition.  This will then knock us out of sync.
1996         //     We need to adjust m_playStartPosition to match the SPP
1997         //     exactly.  See Bug #1101.
1998         //
1999         //       m_playStartPosition = spp * 6 * m_midiClockInterval;
2000         //
2001         //     It's probably not safe to mess with m_playStartPosition
2002         //     here.  We probably need to work our way up the call chain
2003         //     to a safer place.
2004         //
2005         //     The workaround is to make sure you start playback on a
2006         //     beat.  Hold down Ctrl while positioning the playback
2007         //     position pointer.
2008 
2009         if (m_playStartPosition == RealTime::zeroTime)
2010             sendSystemDirect(SND_SEQ_EVENT_START, nullptr);
2011         else
2012             sendSystemDirect(SND_SEQ_EVENT_CONTINUE, nullptr);
2013 
2014         // A short delay is required to give the follower time to get
2015         // ready for the first clock.  The MIDI Spec (section 2, page 30)
2016         // recommends at least 1ms.  We'll go with 2ms to be safe.
2017         // Without this delay, follower sequencers will typically be
2018         // behind by one MIDI clock.
2019 
2020         // Shift the ALSA clock to get a 2ms delay before starting playback.
2021         m_alsaPlayStartTime.sec = 0;
2022         m_alsaPlayStartTime.nsec = 2000000;
2023     }
2024 
2025     // Since the MTC message is queued, it needs to know that
2026     // m_alsaPlayStartTime may have been modified by MIDI sync above.
2027     // So, we handle it after MIDI sync.
2028 
2029     if (m_mtcStatus == TRANSPORT_SOURCE) {
2030         // Queue up the MTC message.
2031         insertMTCFullFrame(position);
2032     }
2033 
2034 #ifdef HAVE_LIBJACK
2035     if (m_jackDriver) {
2036         m_needJackStart = NeedJackStart;
2037     }
2038 #endif
2039 
2040     // Erase recent noteoffs.  There shouldn't be any, but let's be
2041     // extra careful.
2042     m_recentNoteOffs.clear();
2043 }
2044 
2045 
2046 void
stopPlayback()2047 AlsaDriver::stopPlayback()
2048 {
2049 #ifdef DEBUG_ALSA
2050     RG_DEBUG << "stopPlayback() begin...";
2051 #endif
2052 
2053     if (m_midiSyncStatus == TRANSPORT_SOURCE) {
2054         sendSystemDirect(SND_SEQ_EVENT_STOP, nullptr);
2055     }
2056 
2057     if (m_mmcStatus == TRANSPORT_SOURCE) {
2058         sendMMC(127, MIDI_MMC_STOP, true, "");
2059         //<VN> need to throw away the next MTC event
2060         m_eat_mtc = 3;
2061     }
2062 
2063     allNotesOff();
2064     m_playing = false;
2065 
2066 #ifdef HAVE_LIBJACK
2067     if (m_jackDriver) {
2068         m_jackDriver->stopTransport();
2069         m_needJackStart = NeedNoJackStart;
2070     }
2071 #endif
2072 
2073     // Flush the output and input queues
2074     //
2075     snd_seq_remove_events_t *info;
2076     snd_seq_remove_events_alloca(&info);
2077     snd_seq_remove_events_set_condition(info, SND_SEQ_REMOVE_INPUT |
2078                                         SND_SEQ_REMOVE_OUTPUT);
2079     snd_seq_remove_events(m_midiHandle, info);
2080 
2081     // send sounds-off to all play devices
2082     //
2083     for (MappedDeviceList::iterator i = m_devices.begin(); i != m_devices.end(); ++i) {
2084         if ((*i)->getDirection() == MidiDevice::Play) {
2085             sendDeviceController((*i)->getId(),
2086                                  MIDI_CONTROLLER_SUSTAIN, 0);
2087             sendDeviceController((*i)->getId(),
2088                                  MIDI_CONTROLLER_ALL_NOTES_OFF, 0);
2089         }
2090     }
2091 
2092     punchOut();
2093 
2094     stopClocks(); // Resets ALSA timer to zero
2095 
2096     clearAudioQueue();
2097 
2098     startClocksApproved(); // restarts ALSA timer without starting JACK transport
2099 }
2100 
2101 void
punchOut()2102 AlsaDriver::punchOut()
2103 {
2104 #ifdef DEBUG_ALSA
2105     RG_DEBUG << "punchOut() begin...";
2106 #endif
2107 
2108     // Flush any incomplete System Exclusive received from ALSA devices
2109     clearPendSysExcMap();
2110 
2111 #ifdef HAVE_LIBJACK
2112     // Close any recording file
2113     if (m_recordStatus == RECORD_ON) {
2114         for (InstrumentSet::const_iterator i = m_recordingInstruments.begin();
2115              i != m_recordingInstruments.end(); ++i) {
2116 
2117             InstrumentId id = *i;
2118 
2119             if (id >= AudioInstrumentBase &&
2120                 id < MidiInstrumentBase) {
2121 
2122                 AudioFileId auid = 0;
2123                 if (m_jackDriver && m_jackDriver->closeRecordFile(id, auid)) {
2124 
2125 #ifdef DEBUG_ALSA
2126                     RG_DEBUG << "punchOut(): sending back to GUI for instrument " << id;
2127 #endif
2128 
2129                     // Create event to return to gui to say that we've
2130                     // completed an audio file and we can generate a
2131                     // preview for it now.
2132                     //
2133                     // nasty hack -- don't have right audio id here, and
2134                     // the sequencer will wipe out the instrument id and
2135                     // replace it with currently-selected one in gui --
2136                     // so use audio id slot to pass back instrument id
2137                     // and handle accordingly in gui
2138                     try {
2139                         MappedEvent *mE =
2140                             new MappedEvent(id,
2141                                             MappedEvent::AudioGeneratePreview,
2142                                             id % 256,
2143                                             id / 256);
2144 
2145                         // send completion event
2146                         insertMappedEventForReturn(mE);
2147                     } catch (...) {
2148                         ;
2149                     }
2150                 }
2151             }
2152         }
2153     }
2154 #endif
2155 
2156     // Change recorded state if any set
2157     //
2158     if (m_recordStatus == RECORD_ON)
2159         m_recordStatus = RECORD_OFF;
2160 
2161     m_recordingInstruments.clear();
2162 }
2163 
2164 void
resetPlayback(const RealTime & oldPosition,const RealTime & position)2165 AlsaDriver::resetPlayback(const RealTime &oldPosition, const RealTime &position)
2166 {
2167 #ifdef DEBUG_ALSA
2168     RG_DEBUG << "resetPlayback(" << oldPosition << "," << position << ")";
2169 #endif
2170 
2171     if (m_mmcStatus == TRANSPORT_SOURCE) {
2172         unsigned char t_sec = (unsigned char) position.sec % 60;
2173         unsigned char t_min = (unsigned char) (position.sec / 60) % 60;
2174         unsigned char t_hrs = (unsigned char) (position.sec / 3600);
2175 #define STUPID_BROKEN_EQUIPMENT
2176 #ifdef STUPID_BROKEN_EQUIPMENT
2177         // Some recorders assume you are talking in 30fps...
2178         unsigned char t_frm = (unsigned char) (position.nsec / 33333333U);
2179         unsigned char t_sbf = (unsigned char) ((position.nsec / 333333U) % 100U);
2180 #else
2181         // We always send at 25fps, it's the easiest to avoid rounding problems
2182         unsigned char t_frm = (unsigned char) (position.nsec / 40000000U);
2183         unsigned char t_sbf = (unsigned char) ((position.nsec / 400000U) % 100U);
2184 #endif
2185 
2186         RG_DEBUG << "resetPlayback(): Jump using MMC LOCATE to" << position;
2187         RG_DEBUG << "resetPlayback():   which is " << int(t_hrs) << ":" << int(t_min) << ":" << int(t_sec) << "." << int(t_frm) << "." << int(t_sbf);
2188         unsigned char locateDataArr[7] = {
2189             0x06,
2190             0x01,
2191             (unsigned char)(0x60 + t_hrs),    // (30fps flag) + hh
2192             t_min,         // mm
2193             t_sec,         // ss
2194             t_frm,         // frames
2195             t_sbf        // subframes
2196         };
2197 
2198         sendMMC(127, MIDI_MMC_LOCATE, true, std::string((const char *) locateDataArr, 7));
2199     }
2200 
2201     RealTime formerStartPosition = m_playStartPosition;
2202 
2203     m_playStartPosition = position;
2204     m_alsaPlayStartTime = getAlsaTime();
2205 
2206     // Reset note offs to correct positions
2207     //
2208     RealTime jump = position - oldPosition;
2209 
2210 #ifdef DEBUG_PROCESS_MIDI_OUT
2211     RG_DEBUG << "resetPlayback(): Currently " << m_noteOffQueue.size() << " in note off queue";
2212 #endif
2213 
2214     // modify the note offs that exist as they're relative to the
2215     // playStartPosition terms.
2216     //
2217     for (NoteOffQueue::iterator i = m_noteOffQueue.begin();
2218          i != m_noteOffQueue.end(); ++i) {
2219 
2220         // if we're fast forwarding then we bring the note off closer
2221         if (jump >= RealTime::zeroTime) {
2222 
2223             RealTime endTime = formerStartPosition + (*i)->realTime;
2224 
2225 #ifdef DEBUG_PROCESS_MIDI_OUT
2226             RG_DEBUG << "resetPlayback(): Forward jump of " << jump << ": adjusting note off from "
2227                       << (*i)->getRealTime() << " (absolute " << endTime
2228                       << ") to:";
2229 #endif
2230             (*i)->realTime = endTime - position;
2231 #ifdef DEBUG_PROCESS_MIDI_OUT
2232             RG_DEBUG << "resetPlayback():     " << (*i)->getRealTime();
2233 #endif
2234         } else // we're rewinding - kill the note immediately
2235             {
2236 #ifdef DEBUG_PROCESS_MIDI_OUT
2237                 RG_DEBUG << "resetPlayback(): Rewind by " << jump << ": setting note off to zero";
2238 #endif
2239                 (*i)->realTime = RealTime::zeroTime;
2240             }
2241     }
2242 
2243     pushRecentNoteOffs();
2244     processNotesOff(getAlsaTime(), true);
2245     checkAlsaError(snd_seq_drain_output(m_midiHandle), "resetPlayback(): draining");
2246 
2247     // Ensure we clear down output queue on reset - in the case of
2248     // MIDI clock where we might have a long queue of events already
2249     // posted.
2250     //
2251     snd_seq_remove_events_t *info;
2252     snd_seq_remove_events_alloca(&info);
2253     snd_seq_remove_events_set_condition(info, SND_SEQ_REMOVE_OUTPUT);
2254     snd_seq_remove_events(m_midiHandle, info);
2255 
2256     if (m_mtcStatus == TRANSPORT_SOURCE) {
2257         m_mtcFirstTime = -1;
2258         m_mtcSigmaE = 0;
2259         m_mtcSigmaC = 0;
2260         insertMTCFullFrame(position);
2261     }
2262 
2263 #ifdef HAVE_LIBJACK
2264     if (m_jackDriver) {
2265         m_jackDriver->clearSynthPluginEvents();
2266         m_needJackStart = NeedJackReposition;
2267     }
2268 #endif
2269 }
2270 
2271 void
setMIDIClockInterval(RealTime interval)2272 AlsaDriver::setMIDIClockInterval(RealTime interval)
2273 {
2274 #ifdef DEBUG_ALSA
2275     RG_DEBUG << "setMIDIClockInterval(" << interval << ")";
2276 #endif
2277 
2278     if (m_midiClockInterval == interval) return;
2279 
2280     // Reset the value
2281     //
2282     SoundDriver::setMIDIClockInterval(interval);
2283 
2284     // Return if the clock isn't enabled
2285     //
2286     if (!m_midiClockEnabled)
2287         return ;
2288 
2289     if (false)  // don't remove any events quite yet
2290         {
2291 
2292             // Remove all queued events (although we should filter this
2293             // down to just the clock events.
2294             //
2295             snd_seq_remove_events_t *info;
2296             snd_seq_remove_events_alloca(&info);
2297 
2298             //if (snd_seq_type_check(SND_SEQ_EVENT_CLOCK, SND_SEQ_EVFLG_CONTROL))
2299             //snd_seq_remove_events_set_event_type(info,
2300             snd_seq_remove_events_set_condition(info, SND_SEQ_REMOVE_OUTPUT);
2301             snd_seq_remove_events_set_event_type(info, SND_SEQ_EVFLG_CONTROL);
2302             RG_DEBUG << "setMIDIClockInterval(): MIDI CLOCK TYPE IS CONTROL";
2303             snd_seq_remove_events(m_midiHandle, info);
2304         }
2305 
2306 }
2307 
2308 void
clearPendSysExcMap()2309 AlsaDriver::clearPendSysExcMap()
2310 {
2311     // Flush incomplete system exclusive events and delete the map.
2312     if (!m_pendSysExcMap->empty()) {
2313         RG_WARNING << "clearPendSysExcMap(): WARNING: Erasing "
2314                    << m_pendSysExcMap->size() << " incomplete system exclusive message(s). ";
2315         DeviceEventMap::iterator pendIt = m_pendSysExcMap->begin();
2316         for(; pendIt != m_pendSysExcMap->end(); ++pendIt) {
2317             delete pendIt->second.first;
2318             m_pendSysExcMap->erase(pendIt->first);
2319         }
2320     }
2321 }
2322 
2323 void
pushRecentNoteOffs()2324 AlsaDriver::pushRecentNoteOffs()
2325 {
2326 #ifdef DEBUG_PROCESS_MIDI_OUT
2327     RG_DEBUG << "pushRecentNoteOffs(): have " << m_recentNoteOffs.size() << " in queue";
2328 #endif
2329 
2330     for (NoteOffQueue::iterator i = m_recentNoteOffs.begin();
2331          i != m_recentNoteOffs.end(); ++i) {
2332         (*i)->realTime = RealTime::zeroTime;
2333         m_noteOffQueue.insert(*i);
2334     }
2335 
2336     m_recentNoteOffs.clear();
2337 }
2338 
2339 // Remove recent noteoffs that are before time t
2340 void
cropRecentNoteOffs(const RealTime & t)2341 AlsaDriver::cropRecentNoteOffs(const RealTime &t)
2342 {
2343     while (!m_recentNoteOffs.empty()) {
2344         NoteOffEvent *ev = *m_recentNoteOffs.begin();
2345 #ifdef DEBUG_PROCESS_MIDI_OUT
2346         RG_DEBUG << "cropRecentNoteOffs(): " << ev->getRealTime() << " vs " << t;
2347 #endif
2348         if (ev->realTime >= t) break;
2349         delete ev;
2350         m_recentNoteOffs.erase(m_recentNoteOffs.begin());
2351     }
2352 }
2353 
2354 void
weedRecentNoteOffs(unsigned int pitch,MidiByte channel,InstrumentId instrument)2355 AlsaDriver::weedRecentNoteOffs(unsigned int pitch, MidiByte channel,
2356                                InstrumentId instrument)
2357 {
2358     for (NoteOffQueue::iterator i = m_recentNoteOffs.begin();
2359          i != m_recentNoteOffs.end(); ++i) {
2360         if ((*i)->pitch == pitch &&
2361             (*i)->channel == channel &&
2362             (*i)->instrumentId == instrument) {
2363 #ifdef DEBUG_PROCESS_MIDI_OUT
2364             RG_DEBUG << "weedRecentNoteOffs(): deleting one";
2365 #endif
2366             delete *i;
2367             m_recentNoteOffs.erase(i);
2368             break;
2369         }
2370     }
2371 }
2372 
2373 void
allNotesOff()2374 AlsaDriver::allNotesOff()
2375 {
2376     snd_seq_event_t event;
2377     ClientPortPair outputDevice;
2378     RealTime offTime;
2379 
2380     // drop any pending notes
2381     snd_seq_drop_output_buffer(m_midiHandle);
2382     snd_seq_drop_output(m_midiHandle);
2383 
2384     // prepare the event
2385     snd_seq_ev_clear(&event);
2386     offTime = getAlsaTime();
2387 
2388     for (NoteOffQueue::iterator it = m_noteOffQueue.begin();
2389          it != m_noteOffQueue.end(); ++it) {
2390         // Set destination according to connection for instrument
2391         //
2392         outputDevice = getPairForMappedInstrument((*it)->instrumentId);
2393         if (outputDevice.client < 0  ||  outputDevice.port < 0)
2394             continue;
2395 
2396         snd_seq_ev_set_subs(&event);
2397 
2398         // Set source according to port for device
2399         //
2400         int src = getOutputPortForMappedInstrument((*it)->instrumentId);
2401         if (src < 0)
2402             continue;
2403         snd_seq_ev_set_source(&event, src);
2404 
2405         snd_seq_ev_set_noteoff(&event,
2406                                (*it)->channel,
2407                                (*it)->pitch,
2408                                NOTE_OFF_VELOCITY);
2409 
2410         //snd_seq_event_output(m_midiHandle, &event);
2411         int error = snd_seq_event_output_direct(m_midiHandle, &event);
2412 
2413         if (error < 0) {
2414 #ifdef DEBUG_ALSA
2415             RG_WARNING << "allNotesOff() - can't send event";
2416 #endif
2417 
2418         }
2419 
2420         delete(*it);
2421     }
2422 
2423     m_noteOffQueue.erase(m_noteOffQueue.begin(), m_noteOffQueue.end());
2424 
2425     //RG_DEBUG << "allNotesOff() - queue size = " << m_noteOffQueue.size();
2426 
2427     // flush
2428     checkAlsaError(snd_seq_drain_output(m_midiHandle), "allNotesOff(): draining");
2429 }
2430 
2431 void
processNotesOff(const RealTime & time,bool now,bool everything)2432 AlsaDriver::processNotesOff(const RealTime &time, bool now, bool everything)
2433 {
2434     if (m_noteOffQueue.empty()) {
2435         return;
2436     }
2437 
2438     snd_seq_event_t alsaEvent;
2439 
2440     // prepare the event
2441     snd_seq_ev_clear(&alsaEvent);
2442 
2443     RealTime alsaTime = getAlsaTime();
2444 
2445 #ifdef DEBUG_PROCESS_MIDI_OUT
2446     RG_DEBUG << "processNotesOff(" << time << "): alsaTime = " << alsaTime << ", now = " << now;
2447 #endif
2448 
2449     // For each note-off event in the note-off queue
2450     while (m_noteOffQueue.begin() != m_noteOffQueue.end()) {
2451 
2452         NoteOffEvent *noteOff = *m_noteOffQueue.begin();
2453 
2454         if (noteOff->realTime > time) {
2455 #ifdef DEBUG_PROCESS_MIDI_OUT
2456             RG_DEBUG << "processNotesOff(): Note off time " << noteOff->getRealTime() << " is beyond current time " << time;
2457 #endif
2458             if (!everything) break;
2459         }
2460 
2461 #ifdef DEBUG_PROCESS_MIDI_OUT
2462         RG_DEBUG << "processNotesOff(" << time << "): found event at " << noteOff->getRealTime() << ", instr " << noteOff->getInstrument() << ", channel " << int(noteOff->getChannel()) << ", pitch " << int(noteOff->getPitch());
2463 #endif
2464 
2465         RealTime offTime = noteOff->realTime;
2466         if (offTime < RealTime::zeroTime) offTime = RealTime::zeroTime;
2467         bool scheduled = (offTime > alsaTime) && !now;
2468         if (!scheduled) offTime = RealTime::zeroTime;
2469 
2470         snd_seq_real_time_t alsaOffTime = { (unsigned int)offTime.sec,
2471                                             (unsigned int)offTime.nsec };
2472 
2473         snd_seq_ev_set_noteoff(&alsaEvent,
2474                                noteOff->channel,
2475                                noteOff->pitch,
2476                                NOTE_OFF_VELOCITY);
2477 
2478         bool isSoftSynth = (noteOff->instrumentId >= SoftSynthInstrumentBase);
2479 
2480         if (!isSoftSynth) {
2481 
2482             snd_seq_ev_set_subs(&alsaEvent);
2483 
2484             // Set source according to instrument
2485             //
2486             int src = getOutputPortForMappedInstrument(noteOff->instrumentId);
2487             if (src < 0) {
2488                 RG_WARNING << "processNotesOff(): WARNING: Note off has no output port (instr = " << noteOff->instrumentId << ")";
2489                 delete noteOff;
2490                 m_noteOffQueue.erase(m_noteOffQueue.begin());
2491                 continue;
2492             }
2493 
2494             snd_seq_ev_set_source(&alsaEvent, src);
2495 
2496             snd_seq_ev_set_subs(&alsaEvent);
2497 
2498             snd_seq_ev_schedule_real(&alsaEvent, m_queue, 0, &alsaOffTime);
2499 
2500             if (scheduled) {
2501                 snd_seq_event_output(m_midiHandle, &alsaEvent);
2502             } else {
2503                 snd_seq_event_output_direct(m_midiHandle, &alsaEvent);
2504             }
2505 
2506         } else {
2507 
2508             alsaEvent.time.time = alsaOffTime;
2509 
2510             processSoftSynthEventOut(noteOff->instrumentId, &alsaEvent, now);
2511         }
2512 
2513         if (!now) {
2514             m_recentNoteOffs.insert(noteOff);
2515         } else {
2516             delete noteOff;
2517         }
2518         m_noteOffQueue.erase(m_noteOffQueue.begin());
2519     }
2520 
2521     // We don't flush the queue here, as this is called nested from
2522     // processMidiOut, which does the flushing
2523 
2524 #ifdef DEBUG_PROCESS_MIDI_OUT
2525     RG_DEBUG << "processNotesOff() - queue size now: " << m_noteOffQueue.size();
2526 #endif
2527 }
2528 
2529 // Get the queue time and convert it to RealTime for the gui
2530 // to use.
2531 //
2532 RealTime
getSequencerTime()2533 AlsaDriver::getSequencerTime()
2534 {
2535     RealTime t(0, 0);
2536 
2537     t = getAlsaTime() + m_playStartPosition - m_alsaPlayStartTime;
2538 
2539     //RG_DEBUG << "getSequencerTime(): alsa time is " << getAlsaTime() << ", start time is " << m_alsaPlayStartTime << ", play start position is " << m_playStartPosition;
2540 
2541     return t;
2542 }
2543 
2544 // Gets the time of the ALSA queue
2545 //
2546 RealTime
getAlsaTime()2547 AlsaDriver::getAlsaTime()
2548 {
2549     RealTime sequencerTime(0, 0);
2550 
2551     snd_seq_queue_status_t *status;
2552     snd_seq_queue_status_alloca(&status);
2553 
2554     if (snd_seq_get_queue_status(m_midiHandle, m_queue, status) < 0) {
2555 #ifdef DEBUG_ALSA
2556         RG_DEBUG << "getAlsaTime() - can't get queue status";
2557 #endif
2558         return sequencerTime;
2559     }
2560 
2561     sequencerTime.sec = snd_seq_queue_status_get_real_time(status)->tv_sec;
2562     sequencerTime.nsec = snd_seq_queue_status_get_real_time(status)->tv_nsec;
2563 
2564     //RG_DEBUG << "getAlsaTime(): alsa time is " << sequencerTime;
2565 
2566     return sequencerTime;
2567 }
2568 
2569 
2570 bool
getMappedEventList(MappedEventList & mappedEventList)2571 AlsaDriver::getMappedEventList(MappedEventList &mappedEventList)
2572 {
2573     while (failureReportReadIndex != failureReportWriteIndex) {
2574         MappedEvent::FailureCode code = failureReports[failureReportReadIndex];
2575         //RG_DEBUG << "getMappedEventList(): failure code: " << code;
2576         MappedEvent *mE = new MappedEvent
2577             (0, MappedEvent::SystemFailure, code, 0);
2578         m_returnComposition.insert(mE);
2579         failureReportReadIndex =
2580             (failureReportReadIndex + 1) % FAILURE_REPORT_COUNT;
2581     }
2582 
2583     if (!m_returnComposition.empty()) {
2584         for (MappedEventList::iterator i = m_returnComposition.begin();
2585              i != m_returnComposition.end(); ++i) {
2586             mappedEventList.insert(new MappedEvent(**i));
2587         }
2588         m_returnComposition.clear();
2589     }
2590 
2591     // If the input port hasn't connected we shouldn't poll it
2592     //
2593     //    if (m_midiInputPortConnected == false) {
2594     //        return true;
2595     //    }
2596 
2597     RealTime eventTime(0, 0);
2598 
2599     //RG_DEBUG << "getMappedEventList(): looking for events";
2600 
2601     snd_seq_event_t *event;
2602 
2603     // The ALSA documentation indicates that snd_seq_event_input() "returns
2604     // the byte size of remaining events on the input buffer if an event is
2605     // successfully received."  This is not true.  snd_seq_event_input()
2606     // typically returns 1.  Not sure if this is "success" or the number of
2607     // events read, or something else.  But the point is that although this
2608     // code appears to be wrong per the ALSA docs, it is actually correct.
2609 
2610     // While there's an event available...
2611     while (snd_seq_event_input(m_midiHandle, &event) > 0) {
2612         //RG_DEBUG << "getMappedEventList(): found something";
2613 
2614         unsigned int channel = (unsigned int)event->data.note.channel;
2615         unsigned int chanNoteKey = ( channel << 8 ) +
2616             (unsigned int) event->data.note.note;
2617 #ifdef DEBUG_ALSA
2618         RG_DEBUG << "getMappedEventList(): Got note " << chanNoteKey
2619                  << " on channel " << channel;
2620 #endif
2621 
2622         const bool fromExternalController =
2623                 (event->dest.client == m_client  &&
2624                  event->dest.port == m_externalControllerPort);
2625 
2626         unsigned int deviceId = Device::NO_DEVICE;
2627 
2628         if (fromExternalController) {
2629             deviceId = Device::EXTERNAL_CONTROLLER;
2630         } else {
2631             for (MappedDeviceList::iterator i = m_devices.begin();
2632                  i != m_devices.end(); ++i) {
2633                 ClientPortPair pair(m_devicePortMap[(*i)->getId()]);
2634                 if (((*i)->getDirection() == MidiDevice::Record) &&
2635                     ( pair.client == event->source.client ) &&
2636                     ( pair.port == event->source.port )) {
2637                     deviceId = (*i)->getId();
2638                     break;
2639                 }
2640             }
2641         }
2642 
2643         eventTime.sec = event->time.time.tv_sec;
2644         eventTime.nsec = event->time.time.tv_nsec;
2645         eventTime = eventTime - m_alsaRecordStartTime + m_playStartPosition;
2646 
2647 #ifdef DEBUG_ALSA
2648         if (!fromExternalController) {
2649             RG_DEBUG << "getMappedEventList(): Received normal event: type " << int(event->type) << ", chan " << channel << ", note " << int(event->data.note.note) << ", time " << eventTime;
2650         }
2651 #endif
2652 
2653         switch (event->type) {
2654         case SND_SEQ_EVENT_NOTE:
2655         case SND_SEQ_EVENT_NOTEON:
2656             //RG_DEBUG << "AD::gMEL()  NOTEON channel:" << channel << " pitch:" << event->data.note.note << " velocity:" << event->data.note.velocity;
2657 
2658             if (fromExternalController)
2659                 continue;
2660             if (event->data.note.velocity > 0) {
2661                 MappedEvent *mE = new MappedEvent();
2662                 mE->setType(MappedEvent::MidiNote);
2663                 mE->setPitch(event->data.note.note);
2664                 mE->setVelocity(event->data.note.velocity);
2665                 mE->setEventTime(eventTime);
2666                 mE->setRecordedChannel(channel);
2667                 mE->setRecordedDevice(deviceId);
2668 
2669                 // Negative duration - we need to hear the NOTE ON
2670                 // so we must insert it now with a negative duration
2671                 // and pick and mix against the following NOTE OFF
2672                 // when we create the recorded segment.
2673                 //
2674                 mE->setDuration(RealTime( -1, 0));
2675 
2676                 // Create a copy of this when we insert the NOTE ON -
2677                 // keeping a copy alive on the m_noteOnMap.
2678                 //
2679                 // We shake out the two NOTE Ons after we've recorded
2680                 // them.
2681                 //
2682                 mappedEventList.insert(new MappedEvent(mE));
2683                 m_noteOnMap[deviceId].insert(std::pair<unsigned int, MappedEvent*>(chanNoteKey, mE));
2684 
2685                 break;
2686             }
2687 
2688             // fall-through
2689             // NOTEON with velocity 0 is treated as a NOTEOFF
2690 
2691         case SND_SEQ_EVENT_NOTEOFF: {
2692             //RG_DEBUG << "AD::gMEL()  NOTEOFF channel:" << channel << " pitch:" << event->data.note.note;
2693 
2694             if (fromExternalController)
2695                 continue;
2696 
2697             // Check the note on map for any note on events to close.
2698             // find() prevents inadvertently adding an entry to the map.
2699             // Since this is commented out, that must not have been an
2700             // issue.
2701             //NoteOnMap::iterator noteOnMapIt = m_noteOnMap.find(deviceId);
2702             ChannelNoteOnMap::iterator noteOnIt = m_noteOnMap[deviceId].find(chanNoteKey);
2703 
2704             // If a corresponding note on was found
2705             if (noteOnIt != m_noteOnMap[deviceId].end()) {
2706 
2707                 // Work with the MappedEvent in the map.  We will transform
2708                 // it into a note off and insert it into the mapped event
2709                 // list.
2710                 MappedEvent *mE = noteOnIt->second;
2711 
2712                 // Compute correct duration for the NOTE OFF
2713                 RealTime duration = eventTime - mE->getEventTime();
2714 
2715 #ifdef DEBUG_ALSA
2716                 RG_DEBUG << "getMappedEventList(): NOTE OFF: found NOTE ON at " << mE->getEventTime();
2717 #endif
2718 
2719                 // Fix zero duration record bug.
2720                 if (duration <= RealTime::zeroTime) {
2721                     duration = RealTime::fromMilliseconds(1);
2722 
2723                     // ??? It seems odd that we only set the event time for
2724                     //     the note off in this case.  Otherwise it gets the
2725                     //     event time of the matching note on.  That seems
2726                     //     pretty misleading.  I guess a note-off's event time
2727                     //     plus duration is its event time.  But if we see the
2728                     //     duration is one millisecond, the eventTime will be
2729                     //     the actual note-off event time.
2730                     mE->setEventTime(eventTime);
2731                 }
2732 
2733                 // Transform the note-on in the map to a note-off by setting
2734                 // the velocity to 0.
2735                 mE->setVelocity(0);
2736 
2737                 // Set duration correctly for recovery later.
2738                 mE->setDuration(duration);
2739 
2740                 // Insert this note-off into the mapped event list.
2741                 mappedEventList.insert(mE);
2742 
2743                 // reset the reference
2744                 // Remove the MappedEvent from the note on map.
2745                 m_noteOnMap[deviceId].erase(noteOnIt);
2746 
2747             }
2748         }
2749             break;
2750 
2751         case SND_SEQ_EVENT_KEYPRESS: {
2752             if (fromExternalController)
2753                 continue;
2754 
2755             // Fix for 632964 by Pedro Lopez-Cabanillas (20030523)
2756             //
2757             MappedEvent *mE = new MappedEvent();
2758             mE->setType(MappedEvent::MidiKeyPressure);
2759             mE->setEventTime(eventTime);
2760             mE->setData1(event->data.note.note);
2761             mE->setData2(event->data.note.velocity);
2762             mE->setRecordedChannel(channel);
2763             mE->setRecordedDevice(deviceId);
2764             mappedEventList.insert(mE);
2765         }
2766             break;
2767 
2768         case SND_SEQ_EVENT_CONTROLLER: {
2769             if (handleTransportCCs(event->data.control.param,
2770                                    event->data.control.value))
2771                 break;
2772 
2773             // Convert to MappedEvent and add to list.
2774             MappedEvent *mE = new MappedEvent();
2775             mE->setType(MappedEvent::MidiController);
2776             mE->setEventTime(eventTime);
2777             mE->setData1(event->data.control.param);
2778             mE->setData2(event->data.control.value);
2779             mE->setRecordedChannel(channel);
2780             mE->setRecordedDevice(deviceId);
2781             mappedEventList.insert(mE);
2782         }
2783             break;
2784 
2785         case SND_SEQ_EVENT_PGMCHANGE: {
2786             MappedEvent *mE = new MappedEvent();
2787             mE->setType(MappedEvent::MidiProgramChange);
2788             mE->setEventTime(eventTime);
2789             mE->setData1(event->data.control.value);
2790             mE->setRecordedChannel(channel);
2791             mE->setRecordedDevice(deviceId);
2792             mappedEventList.insert(mE);
2793 
2794         }
2795             break;
2796 
2797         case SND_SEQ_EVENT_PITCHBEND: {
2798             // ??? This breaks our ability to process high precision
2799             //     faders from control surfaces!
2800             if (fromExternalController)
2801                 continue;
2802 
2803             // Fix for 711889 by Pedro Lopez-Cabanillas (20030523)
2804             //
2805             int s = event->data.control.value + 8192;
2806             int d1 = (s >> 7) & 0x7f; // data1 = MSB
2807             int d2 = s & 0x7f; // data2 = LSB
2808             MappedEvent *mE = new MappedEvent();
2809             mE->setType(MappedEvent::MidiPitchBend);
2810             mE->setEventTime(eventTime);
2811             mE->setData1(d1);
2812             mE->setData2(d2);
2813             mE->setRecordedChannel(channel);
2814             mE->setRecordedDevice(deviceId);
2815             mappedEventList.insert(mE);
2816         }
2817             break;
2818 
2819         case SND_SEQ_EVENT_CHANPRESS: {
2820             if (fromExternalController)
2821                 continue;
2822 
2823             // Fixed by Pedro Lopez-Cabanillas (20030523)
2824             //
2825             int s = event->data.control.value & 0x7f;
2826             MappedEvent *mE = new MappedEvent();
2827             mE->setType(MappedEvent::MidiChannelPressure);
2828             mE->setEventTime(eventTime);
2829             mE->setData1(s);
2830             mE->setRecordedChannel(channel);
2831             mE->setRecordedDevice(deviceId);
2832             mappedEventList.insert(mE);
2833         }
2834             break;
2835 
2836         case SND_SEQ_EVENT_SYSEX:
2837 
2838             // ??? This breaks our ability to process sysex from
2839             //     control surfaces!  I think it is clear that AlsaDriver
2840             //     knows too much about the external controller port.
2841             //     It needs to take a more hands-off approach and let the
2842             //     ExternalController class do all the work.
2843             if (fromExternalController)
2844                 continue;
2845 
2846             if (!testForMTCSysex(event) &&
2847                 !testForMMCSysex(event)) {
2848 
2849                 // Bundle up the data into a block on the MappedEvent
2850                 //
2851                 std::string data;
2852                 char *ptr = (char*)(event->data.ext.ptr);
2853                 for (unsigned int i = 0; i < event->data.ext.len; ++i)
2854                     data += *(ptr++);
2855 
2856 #ifdef DEBUG_ALSA
2857 
2858                 if ((MidiByte)(data[1]) == MIDI_SYSEX_RT) {
2859                     RG_DEBUG << "getMappedEventList(): REALTIME SYSEX";
2860                     for (unsigned int ii = 0; ii < event->data.ext.len; ++ii) {
2861                         printf("B %d = %02x\n", ii, ((char*)(event->data.ext.ptr))[ii]);
2862                     }
2863                 } else {
2864                     RG_DEBUG << "getMappedEventList(): NON-REALTIME SYSEX";
2865                     for (unsigned int ii = 0; ii < event->data.ext.len; ++ii) {
2866                         printf("B %d = %02x\n", ii, ((char*)(event->data.ext.ptr))[ii]);
2867                     }
2868                 }
2869 #endif
2870 
2871                 // Thank you to Christoph Eckert for pointing out via
2872                 // Pedro Lopez-Cabanillas aseqmm code that we need to pool
2873                 // alsa system exclusive messages since they may be broken
2874                 // across several ALSA messages.
2875 
2876                 // Unfortunately, pooling these messages get very complicated
2877                 // since it creates many corner cases during this realtime
2878                 // activity that may involve possible bad data transmissions.
2879 
2880                 bool beginNewMessage = false;
2881                 if (data.length() > 0) {
2882                     // Check if at start of MIDI message
2883                     if (MidiByte(data.at(0)) == MIDI_SYSTEM_EXCLUSIVE) {
2884                         data.erase(0,1); // Skip (SYX). RG doesn't use it.
2885                         beginNewMessage = true;
2886                     }
2887                 }
2888 
2889                 std::string sysExcData;
2890                 MappedEvent *sysExcEvent = nullptr;
2891 
2892                 // Check to see if there are any pending System Exclusive Messages
2893                 if (!m_pendSysExcMap->empty()) {
2894                     // Check our map to see if we have a pending operations for
2895                     // the current deviceId.
2896                     DeviceEventMap::iterator pendIt = m_pendSysExcMap->find(deviceId);
2897 
2898                     if (pendIt != m_pendSysExcMap->end()) {
2899                         sysExcEvent = pendIt->second.first;
2900                         sysExcData = pendIt->second.second;
2901 
2902                         // Be optimistic that we won't have to re-add this afterwards.
2903                         // Also makes keeping track of this easier.
2904                         m_pendSysExcMap->erase(pendIt);
2905                     }
2906                 }
2907 
2908                 bool createNewEvent = false;
2909                 if (!sysExcEvent) {
2910                     // Did not find a pending (unfinished) System Exclusive message.
2911                     // Create a new event.
2912                     createNewEvent = true;
2913 
2914                     if (!beginNewMessage) {
2915                         RG_WARNING << "getMappedEventList(): WARNING: New ALSA message arrived with incorrect MIDI System Exclusive start byte.";
2916                         RG_WARNING << "getMappedEventList():          This is probably a bad transmission.";
2917                     }
2918                 } else {
2919                     // We found a pending (unfinished) System Exclusive message.
2920 
2921                     // Check if at start of MIDI message
2922                     if (!beginNewMessage) {
2923                         // Prepend pooled events to the current message data
2924 
2925                         if (sysExcData.size() > 0) {
2926                             data.insert(0, sysExcData);
2927                         }
2928                     } else {
2929                         // This is the start of a new message but have
2930                         // pending (incomplete) messages already.
2931                         createNewEvent = true;
2932 
2933                         // Decide how to handle previous (incomplete) message
2934                         if (sysExcData.size() > 0) {
2935                             RG_WARNING << "getMappedEventList(): WARNING: Sending an incomplete ALSA message to the composition.";
2936                             RG_WARNING << "getMappedEventList():          This is probably a bad transmission.";
2937 
2938                             // Push previous (incomplete) message to mapped event list
2939                             DataBlockRepository::setDataBlockForEvent(sysExcEvent, sysExcData);
2940                             mappedEventList.insert(sysExcEvent);
2941                         } else {
2942                             // Previous message has no meaningful data.
2943                             RG_WARNING << "getMappedEventList(): WARNING: Discarding meaningless incomplete ALSA message";
2944 
2945                             delete sysExcEvent;
2946                         }
2947                     }
2948                 }
2949 
2950                 if (createNewEvent) {
2951                     // Still need a current event to work with.  Create it.
2952                     sysExcEvent = new MappedEvent();
2953                     sysExcEvent->setType(MappedEvent::MidiSystemMessage);
2954                     sysExcEvent->setData1(MIDI_SYSTEM_EXCLUSIVE);
2955                     sysExcEvent->setRecordedDevice(deviceId);
2956                     sysExcEvent->setEventTime(eventTime);
2957                 }
2958 
2959                 // We need to check to see if this event completes the
2960                 // System Exclusive event.
2961 
2962                 bool pushOnMap = false;
2963                 if (!data.empty()) {
2964                     int lastChar = data.size() - 1;
2965 
2966                     // Check to see if we are at the end of a message.
2967                     if (MidiByte(data.at(lastChar)) == MIDI_END_OF_EXCLUSIVE) {
2968                         // Remove (EOX). RG doesn't use it.
2969                         data.erase(lastChar);
2970 
2971                         // Push message to mapped event list
2972                         DataBlockRepository::setDataBlockForEvent(sysExcEvent, data);
2973                         mappedEventList.insert(sysExcEvent);
2974                     } else {
2975 
2976                         pushOnMap = true;
2977                     }
2978                 } else {
2979                     // Data is empty.  Anyway we got here we need to put it back
2980                     // in the pending map.  This will resolve itself elsewhere.
2981                     // But if we are here, this is probably and error.
2982 
2983                     RG_WARNING << "getMappedEventList(): WARNING: ALSA message arrived with no useful System Exclusive data bytes";
2984                     RG_WARNING << "getMappedEventList():          This is probably a bad transmission";
2985 
2986                     pushOnMap = true;
2987                 }
2988 
2989                 if (pushOnMap) {
2990                     // Put the unfinished event back in the pending map.
2991                     m_pendSysExcMap->insert(std::make_pair(deviceId,
2992                                                            std::make_pair(sysExcEvent, data)));
2993 
2994                     if (beginNewMessage) {
2995                         RG_DEBUG << "getMappedEventList(): Encountered long System Exclusive Message (pooling message until transmission complete)";
2996                     }
2997                 }
2998             }
2999             break;
3000 
3001 
3002         case SND_SEQ_EVENT_SENSING:  // MIDI device is still there
3003             break;
3004 
3005         case SND_SEQ_EVENT_QFRAME:
3006             if (fromExternalController)
3007                 continue;
3008             if (m_mtcStatus == TRANSPORT_FOLLOWER) {
3009                 handleMTCQFrame(event->data.control.value, eventTime);
3010             }
3011             break;
3012 
3013         case SND_SEQ_EVENT_CLOCK:
3014 #ifdef DEBUG_ALSA
3015             RG_DEBUG << "getMappedEventList() - got realtime MIDI clock";
3016 #endif
3017             break;
3018 
3019         case SND_SEQ_EVENT_START:
3020             if (m_midiSyncStatus == TRANSPORT_FOLLOWER  &&  !isPlaying()) {
3021                 RosegardenSequencer::getInstance()->transportJump(
3022                         RosegardenSequencer::TransportStopAtTime,
3023                         RealTime::zeroTime);
3024                 RosegardenSequencer::getInstance()->transportChange(
3025                         RosegardenSequencer::TransportStart);
3026             }
3027 #ifdef DEBUG_ALSA
3028             RG_DEBUG << "getMappedEventList() - START";
3029 #endif
3030             break;
3031 
3032         case SND_SEQ_EVENT_CONTINUE:
3033             if (m_midiSyncStatus == TRANSPORT_FOLLOWER  &&  !isPlaying()) {
3034                 RosegardenSequencer::getInstance()->transportChange(
3035                         RosegardenSequencer::TransportPlay);
3036             }
3037 #ifdef DEBUG_ALSA
3038             RG_DEBUG << "getMappedEventList() - CONTINUE";
3039 #endif
3040             break;
3041 
3042         case SND_SEQ_EVENT_STOP:
3043             if (m_midiSyncStatus == TRANSPORT_FOLLOWER  &&  isPlaying()) {
3044                 RosegardenSequencer::getInstance()->transportChange(
3045                         RosegardenSequencer::TransportStop);
3046             }
3047 #ifdef DEBUG_ALSA
3048             RG_DEBUG << "getMappedEventList() - STOP";
3049 #endif
3050             break;
3051 
3052         case SND_SEQ_EVENT_SONGPOS:
3053 #ifdef DEBUG_ALSA
3054             RG_DEBUG << "getMappedEventList() - SONG POSITION";
3055 #endif
3056 
3057             break;
3058 
3059         case SND_SEQ_EVENT_CLIENT_START:
3060         case SND_SEQ_EVENT_CLIENT_EXIT:
3061         case SND_SEQ_EVENT_CLIENT_CHANGE:
3062         case SND_SEQ_EVENT_PORT_START:
3063         case SND_SEQ_EVENT_PORT_EXIT:
3064         case SND_SEQ_EVENT_PORT_CHANGE:
3065         case SND_SEQ_EVENT_PORT_SUBSCRIBED:
3066         case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
3067             // These cases are handled by checkForNewClients().
3068             m_portCheckNeeded = true;
3069 #ifdef DEBUG_ALSA
3070             RG_DEBUG << "getMappedEventList() - got announce event (" << int(event->type) << ")";
3071 #endif
3072 
3073             break;
3074         case SND_SEQ_EVENT_TICK:
3075         default:
3076 #ifdef DEBUG_ALSA
3077             RG_DEBUG << "getMappedEventList() - got unhandled MIDI event type from ALSA sequencer" << "(" << int(event->type) << ")";
3078 #endif
3079 
3080             break;
3081 
3082 
3083         }
3084     }
3085 
3086     if (m_mtcStatus == TRANSPORT_FOLLOWER && isPlaying()) {
3087 #ifdef MTC_DEBUG
3088         RG_DEBUG << "getMappedEventList(): seq time is " << getSequencerTime() << ", last MTC receive "
3089                  << m_mtcLastReceive << ", first time " << m_mtcFirstTime;
3090 #endif
3091 
3092         if (m_mtcFirstTime == 0) { // have received _some_ MTC quarter-frame info
3093             RealTime seqTime = getSequencerTime();
3094             if (m_mtcLastReceive < seqTime &&
3095                 seqTime - m_mtcLastReceive > RealTime(0, 500000000L)) {
3096                 RosegardenSequencer::getInstance()->transportJump(
3097                         RosegardenSequencer::TransportStopAtTime,
3098                         m_mtcLastEncoded);
3099             }
3100         }
3101     }
3102     return true;
3103 }
3104 
3105 // This should probably be a non-static private member.
3106 static int lock_count = 0;
3107 
3108 void
handleMTCQFrame(unsigned int data_byte,RealTime the_time)3109 AlsaDriver::handleMTCQFrame(unsigned int data_byte, RealTime the_time)
3110 {
3111     if (m_mtcStatus != TRANSPORT_FOLLOWER)
3112         return ;
3113 
3114     switch (data_byte & 0xF0) {
3115         /* Frame */
3116     case 0x00:
3117         /*
3118          * Reset everything
3119          */
3120         m_mtcReceiveTime = the_time;
3121         m_mtcFrames = data_byte & 0x0f;
3122         m_mtcSeconds = 0;
3123         m_mtcMinutes = 0;
3124         m_mtcHours = 0;
3125         m_mtcSMPTEType = 0;
3126 
3127         break;
3128 
3129     case 0x10:
3130         m_mtcFrames |= (data_byte & 0x0f) << 4;
3131         break;
3132 
3133         /* Seconds */
3134     case 0x20:
3135         m_mtcSeconds = data_byte & 0x0f;
3136         break;
3137     case 0x30:
3138         m_mtcSeconds |= (data_byte & 0x0f) << 4;
3139         break;
3140 
3141         /* Minutes */
3142     case 0x40:
3143         m_mtcMinutes = data_byte & 0x0f;
3144         break;
3145     case 0x50:
3146         m_mtcMinutes |= (data_byte & 0x0f) << 4;
3147         break;
3148 
3149         /* Hours and SMPTE type */
3150     case 0x60:
3151         m_mtcHours = data_byte & 0x0f;
3152         break;
3153 
3154     case 0x70: {
3155         m_mtcHours |= (data_byte & 0x01) << 4;
3156         m_mtcSMPTEType = (data_byte & 0x06) >> 1;
3157 
3158         int fps = 30;
3159         if (m_mtcSMPTEType == 0)
3160             fps = 24;
3161         else if (m_mtcSMPTEType == 1)
3162             fps = 25;
3163 
3164         /*
3165          * Ok, got all the bits now
3166          * (Assuming time is rolling forward)
3167          */
3168 
3169         /* correct for 2-frame lag */
3170         m_mtcFrames += 2;
3171         if (m_mtcFrames >= fps) {
3172             m_mtcFrames -= fps;
3173             if (++m_mtcSeconds == 60) {
3174                 m_mtcSeconds = 0;
3175                 if (++m_mtcMinutes == 60) {
3176                     m_mtcMinutes = 0;
3177                     ++m_mtcHours;
3178                 }
3179             }
3180         }
3181 
3182 #ifdef MTC_DEBUG
3183         printf("RG MTC: Got a complete sequence: %02d:%02d:%02d.%02d (type %d)\n",
3184                m_mtcHours,
3185                m_mtcMinutes,
3186                m_mtcSeconds,
3187                m_mtcFrames,
3188                m_mtcSMPTEType);
3189 #endif
3190 
3191         /* compute encoded time */
3192         m_mtcEncodedTime.sec = m_mtcSeconds +
3193             m_mtcMinutes * 60 +
3194             m_mtcHours * 60 * 60;
3195 
3196         switch (fps) {
3197         case 24:
3198             m_mtcEncodedTime.nsec = (int)
3199                 ((125000000UL * (unsigned)m_mtcFrames) / (unsigned) 3);
3200             break;
3201         case 25:
3202             m_mtcEncodedTime.nsec = (int)
3203                 (40000000UL * (unsigned)m_mtcFrames);
3204             break;
3205         case 30:
3206         default:
3207             m_mtcEncodedTime.nsec = (int)
3208                 ((100000000UL * (unsigned)m_mtcFrames) / (unsigned) 3);
3209             break;
3210         }
3211 
3212         /*
3213          * We only mess with the clock if we are playing
3214          */
3215         if (m_playing) {
3216 #ifdef MTC_DEBUG
3217             RG_DEBUG << "handleMTCQFrame(): RG MTC: Tstamp " << m_mtcEncodedTime << " Received @ " << m_mtcReceiveTime;
3218 #endif
3219 
3220             calibrateMTC();
3221 
3222             RealTime t_diff = m_mtcEncodedTime - m_mtcReceiveTime;
3223 #ifdef MTC_DEBUG
3224             RG_DEBUG << "handleMTCQFrame(): Diff: " << t_diff;
3225 #endif
3226 
3227             /* -ve diff means ALSA time ahead of MTC time */
3228 
3229             if (t_diff.sec > 0) {
3230                 tweakSkewForMTC(60000);
3231             } else if (t_diff.sec < 0) {
3232                 tweakSkewForMTC( -60000);
3233             } else {
3234                 /* "small" diff - use adaptive technique */
3235                 tweakSkewForMTC(t_diff.nsec / 1400);
3236                 if ((t_diff.nsec / 1000000) == 0) {
3237                     if (++lock_count == 3) {
3238                         printf("Got a lock @ %02d:%02d:%02d.%02d (type %d)\n",
3239                                m_mtcHours,
3240                                m_mtcMinutes,
3241                                m_mtcSeconds,
3242                                m_mtcFrames,
3243                                m_mtcSMPTEType);
3244                     }
3245                 } else {
3246                     lock_count = 0;
3247                 }
3248             }
3249 
3250         } else if (m_eat_mtc > 0) {
3251 #ifdef MTC_DEBUG
3252             RG_DEBUG << "handleMTCQFrame(): MTC: Received quarter frame just after issuing MMC stop - ignore it";
3253 #endif
3254 
3255             --m_eat_mtc;
3256         } else {
3257             /* If we're not playing, we should be. */
3258 #ifdef MTC_DEBUG
3259             RG_DEBUG << "handleMTCQFrame(): MTC: Received quarter frame while not playing - starting now";
3260 #endif
3261 
3262             tweakSkewForMTC(0);  /* JPM - reset it on start of playback, to be sure */
3263             RosegardenSequencer::getInstance()->transportJump(
3264                     RosegardenSequencer::TransportStartAtTime,
3265                     m_mtcEncodedTime);
3266         }
3267 
3268         break;
3269     }
3270 
3271         /* Oh dear, demented device! */
3272     default:
3273         break;
3274     }
3275 }
3276 
3277 void
insertMTCFullFrame(RealTime time)3278 AlsaDriver::insertMTCFullFrame(RealTime time)
3279 {
3280     snd_seq_event_t event;
3281 
3282     snd_seq_ev_clear(&event);
3283     snd_seq_ev_set_source(&event, m_syncOutputPort);
3284     snd_seq_ev_set_subs(&event);
3285 
3286     m_mtcEncodedTime = time;
3287     m_mtcSeconds = m_mtcEncodedTime.sec % 60;
3288     m_mtcMinutes = (m_mtcEncodedTime.sec / 60) % 60;
3289     m_mtcHours = (m_mtcEncodedTime.sec / 3600);
3290 
3291     // We always send at 25fps, it's the easiest to avoid rounding problems
3292     m_mtcFrames = (unsigned)m_mtcEncodedTime.nsec / 40000000U;
3293 
3294     time = time + m_alsaPlayStartTime - m_playStartPosition;
3295     snd_seq_real_time_t atime =
3296         { (unsigned int)time.sec, (unsigned int)time.nsec };
3297 
3298     unsigned char data[10] =
3299         { MIDI_SYSTEM_EXCLUSIVE,
3300           MIDI_SYSEX_RT, 127, 1, 1,
3301           0, 0, 0, 0,
3302           MIDI_END_OF_EXCLUSIVE };
3303 
3304     data[5] = ((unsigned char)m_mtcHours & 0x1f) + (1 << 5); // 1 indicates 25fps
3305     data[6] = (unsigned char)m_mtcMinutes;
3306     data[7] = (unsigned char)m_mtcSeconds;
3307     data[8] = (unsigned char)m_mtcFrames;
3308 
3309     snd_seq_ev_schedule_real(&event, m_queue, 0, &atime);
3310     snd_seq_ev_set_sysex(&event, 10, data);
3311 
3312     checkAlsaError(snd_seq_event_output(m_midiHandle, &event),
3313                    "insertMTCFullFrame event send");
3314 
3315     if (m_queueRunning) {
3316         checkAlsaError(snd_seq_drain_output(m_midiHandle), "insertMTCFullFrame drain");
3317     }
3318 }
3319 
3320 void
insertMTCQFrames(RealTime sliceStart,RealTime sliceEnd)3321 AlsaDriver::insertMTCQFrames(RealTime sliceStart, RealTime sliceEnd)
3322 {
3323     if (sliceStart == RealTime::zeroTime && sliceEnd == RealTime::zeroTime) {
3324         // not a real slice
3325         return ;
3326     }
3327 
3328     // We send at 25fps, it's the easiest to avoid rounding problems
3329     RealTime twoFrames(0, 80000000U);
3330     RealTime quarterFrame(0, 10000000U);
3331     int fps = 25;
3332 
3333 #ifdef MTC_DEBUG
3334     RG_DEBUG << "insertMTCQFrames(" << sliceStart << ","
3335              << sliceEnd << "): first time " << m_mtcFirstTime;
3336 #endif
3337 
3338     RealTime t;
3339 
3340     if (m_mtcFirstTime != 0) { // first time through, reset location
3341         m_mtcEncodedTime = sliceStart;
3342         t = sliceStart;
3343         m_mtcFirstTime = 0;
3344     } else {
3345         t = m_mtcEncodedTime + quarterFrame;
3346     }
3347 
3348     m_mtcSeconds = m_mtcEncodedTime.sec % 60;
3349     m_mtcMinutes = (m_mtcEncodedTime.sec / 60) % 60;
3350     m_mtcHours = (m_mtcEncodedTime.sec / 3600);
3351     m_mtcFrames = (unsigned)m_mtcEncodedTime.nsec / 40000000U; // 25fps
3352 
3353     std::string bytes = " ";
3354 
3355     int type = 0;
3356 
3357     while (m_mtcEncodedTime < sliceEnd) {
3358 
3359         snd_seq_event_t event;
3360         snd_seq_ev_clear(&event);
3361         snd_seq_ev_set_source(&event, m_syncOutputPort);
3362         snd_seq_ev_set_subs(&event);
3363 
3364 #ifdef MTC_DEBUG
3365         RG_DEBUG << "insertMTCQFrames(): Sending MTC quarter frame at " << t;
3366 #endif
3367 
3368         unsigned char c = (type << 4);
3369 
3370         switch (type) {
3371         case 0:
3372             c += ((unsigned char)m_mtcFrames & 0x0f);
3373             break;
3374         case 1:
3375             c += (((unsigned char)m_mtcFrames & 0xf0) >> 4);
3376             break;
3377         case 2:
3378             c += ((unsigned char)m_mtcSeconds & 0x0f);
3379             break;
3380         case 3:
3381             c += (((unsigned char)m_mtcSeconds & 0xf0) >> 4);
3382             break;
3383         case 4:
3384             c += ((unsigned char)m_mtcMinutes & 0x0f);
3385             break;
3386         case 5:
3387             c += (((unsigned char)m_mtcMinutes & 0xf0) >> 4);
3388             break;
3389         case 6:
3390             c += ((unsigned char)m_mtcHours & 0x0f);
3391             break;
3392         case 7:  // hours high nibble + smpte type
3393             c += (m_mtcHours >> 4) & 0x01;
3394             c += (1 << 1); // type 1 indicates 25fps
3395             break;
3396         }
3397 
3398         RealTime scheduleTime = t + m_alsaPlayStartTime - m_playStartPosition;
3399         snd_seq_real_time_t atime =
3400             { (unsigned int)scheduleTime.sec,
3401               (unsigned int)scheduleTime.nsec };
3402 
3403         event.type = SND_SEQ_EVENT_QFRAME;
3404         event.data.control.value = c;
3405 
3406         snd_seq_ev_schedule_real(&event, m_queue, 0, &atime);
3407 
3408         checkAlsaError(snd_seq_event_output(m_midiHandle, &event),
3409                        "insertMTCQFrames sending qframe event");
3410 
3411         if (++type == 8) {
3412             m_mtcFrames += 2;
3413             if (m_mtcFrames >= fps) {
3414                 m_mtcFrames -= fps;
3415                 if (++m_mtcSeconds == 60) {
3416                     m_mtcSeconds = 0;
3417                     if (++m_mtcMinutes == 60) {
3418                         m_mtcMinutes = 0;
3419                         ++m_mtcHours;
3420                     }
3421                 }
3422             }
3423             m_mtcEncodedTime = t;
3424             type = 0;
3425         }
3426 
3427         t = t + quarterFrame;
3428     }
3429 }
3430 
3431 bool
testForMTCSysex(const snd_seq_event_t * event)3432 AlsaDriver::testForMTCSysex(const snd_seq_event_t *event)
3433 {
3434     if (m_mtcStatus != TRANSPORT_FOLLOWER)
3435         return false;
3436 
3437     // At this point, and possibly for the foreseeable future, the only
3438     // sysex we're interested in is full-frame transport location
3439 
3440 #ifdef MTC_DEBUG
3441     RG_DEBUG << "testForMTCSysex(): MTC: testing sysex of length " << event->data.ext.len << ":";
3442     for (int i = 0; i < event->data.ext.len; ++i) {
3443         RG_DEBUG << "testForMTCSysex():     " << (int)*((unsigned char *)event->data.ext.ptr + i);
3444     }
3445 #endif
3446 
3447     if (event->data.ext.len != 10)
3448         return false;
3449 
3450     unsigned char *ptr = (unsigned char *)(event->data.ext.ptr);
3451 
3452     if (*ptr++ != MIDI_SYSTEM_EXCLUSIVE)
3453         return false;
3454     if (*ptr++ != MIDI_SYSEX_RT)
3455         return false;
3456     if (*ptr++ > 127)
3457         return false;
3458 
3459     // 01 01 for MTC full frame
3460 
3461     if (*ptr++ != 1)
3462         return false;
3463     if (*ptr++ != 1)
3464         return false;
3465 
3466     int htype = *ptr++;
3467     int min = *ptr++;
3468     int sec = *ptr++;
3469     int frame = *ptr++;
3470 
3471     if (*ptr != MIDI_END_OF_EXCLUSIVE)
3472         return false;
3473 
3474     int hour = (htype & 0x1f);
3475     int type = (htype & 0xe0) >> 5;
3476 
3477     m_mtcFrames = frame;
3478     m_mtcSeconds = sec;
3479     m_mtcMinutes = min;
3480     m_mtcHours = hour;
3481     m_mtcSMPTEType = type;
3482 
3483     int fps = 30;
3484     if (m_mtcSMPTEType == 0)
3485         fps = 24;
3486     else if (m_mtcSMPTEType == 1)
3487         fps = 25;
3488 
3489     m_mtcEncodedTime.sec = sec + min * 60 + hour * 60 * 60;
3490 
3491     switch (fps) {
3492     case 24:
3493         m_mtcEncodedTime.nsec = (int)
3494             ((125000000UL * (unsigned)m_mtcFrames) / (unsigned) 3);
3495         break;
3496     case 25:
3497         m_mtcEncodedTime.nsec = (int)
3498             (40000000UL * (unsigned)m_mtcFrames);
3499         break;
3500     case 30:
3501     default:
3502         m_mtcEncodedTime.nsec = (int)
3503             ((100000000UL * (unsigned)m_mtcFrames) / (unsigned) 3);
3504         break;
3505     }
3506 
3507 #ifdef MTC_DEBUG
3508     RG_DEBUG << "testForMTCSysex(): MTC: MTC sysex found (frame type " << type << "), jumping to " << m_mtcEncodedTime;
3509 #endif
3510 
3511     RosegardenSequencer::getInstance()->transportJump(
3512             RosegardenSequencer::TransportJumpToTime,
3513             m_mtcEncodedTime);
3514 
3515     return true;
3516 }
3517 
3518 static int last_factor = 0;
3519 static int bias_factor = 0;
3520 
3521 void
calibrateMTC()3522 AlsaDriver::calibrateMTC()
3523 {
3524     if (m_mtcFirstTime < 0)
3525         return ;
3526     else if (m_mtcFirstTime > 0) {
3527         --m_mtcFirstTime;
3528         m_mtcSigmaC = 0;
3529         m_mtcSigmaE = 0;
3530     } else {
3531         RealTime diff_e = m_mtcEncodedTime - m_mtcLastEncoded;
3532         RealTime diff_c = m_mtcReceiveTime - m_mtcLastReceive;
3533 
3534 #ifdef MTC_DEBUG
3535         printf("RG MTC: diffs %d %d %d\n", diff_c.nsec, diff_e.nsec, m_mtcSkew);
3536 #endif
3537 
3538         m_mtcSigmaE += ((long long int) diff_e.nsec) * m_mtcSkew;
3539         m_mtcSigmaC += diff_c.nsec;
3540 
3541 
3542         int t_bias = (m_mtcSigmaE / m_mtcSigmaC) - 0x10000;
3543 
3544 #ifdef MTC_DEBUG
3545         printf("RG MTC: sigmas %lld %lld %d\n", m_mtcSigmaE, m_mtcSigmaC, t_bias);
3546 #endif
3547 
3548         bias_factor = t_bias;
3549     }
3550 
3551     m_mtcLastReceive = m_mtcReceiveTime;
3552     m_mtcLastEncoded = m_mtcEncodedTime;
3553 
3554 }
3555 
3556 void
tweakSkewForMTC(int factor)3557 AlsaDriver::tweakSkewForMTC(int factor)
3558 {
3559 /*
3560 JPM: If CalibrateMTC malfunctions (which tends to happen if the timecode
3561 restarts a lot) then 'bias_factor' will be left in the range of 1.8 billion
3562 and the sequencer engine will be unusable until the program is quit and
3563 restarted.  Reset it to a sane default when called with factor of 0
3564 */
3565 
3566     if (factor == 0) {
3567         bias_factor = 0;
3568     }
3569 
3570     if (factor > 50000) {
3571         factor = 50000;
3572     } else if (factor < -50000) {
3573         factor = -50000;
3574     } else if (factor == last_factor) {
3575         return ;
3576     } else {
3577         if (m_mtcFirstTime == -1)
3578             m_mtcFirstTime = 5;
3579     }
3580     last_factor = factor;
3581 
3582     snd_seq_queue_tempo_t *q_ptr;
3583     snd_seq_queue_tempo_alloca(&q_ptr);
3584 
3585     snd_seq_get_queue_tempo( m_midiHandle, m_queue, q_ptr);
3586 
3587     unsigned int t_skew = snd_seq_queue_tempo_get_skew(q_ptr);
3588 #ifdef MTC_DEBUG
3589     RG_DEBUG << "tweakSkewForMTC(): RG MTC: skew: " << t_skew;
3590 #endif
3591 
3592     t_skew = 0x10000 + factor + bias_factor;
3593 
3594 #ifdef MTC_DEBUG
3595     RG_DEBUG << "tweakSkewForMTC():     changed to " << factor << "+" << bias_factor;
3596 #endif
3597 
3598     snd_seq_queue_tempo_set_skew(q_ptr, t_skew);
3599     snd_seq_set_queue_tempo( m_midiHandle, m_queue, q_ptr);
3600 
3601     m_mtcSkew = t_skew;
3602 }
3603 
3604 bool
testForMMCSysex(const snd_seq_event_t * event)3605 AlsaDriver::testForMMCSysex(const snd_seq_event_t *event)
3606 {
3607     if (m_mmcStatus != TRANSPORT_FOLLOWER)
3608         return false;
3609 
3610     if (event->data.ext.len != 6)
3611         return false;
3612 
3613     unsigned char *ptr = (unsigned char *)(event->data.ext.ptr);
3614 
3615     if (*ptr++ != MIDI_SYSTEM_EXCLUSIVE)
3616         return false;
3617     if (*ptr++ != MIDI_SYSEX_RT)
3618         return false;
3619     if (*ptr++ > 127)
3620         return false;
3621     if (*ptr++ != MIDI_SYSEX_RT_COMMAND)
3622         return false;
3623 
3624     int instruction = *ptr++;
3625 
3626     if (*ptr != MIDI_END_OF_EXCLUSIVE)
3627         return false;
3628 
3629     if (instruction == MIDI_MMC_PLAY ||
3630         instruction == MIDI_MMC_DEFERRED_PLAY) {
3631         RosegardenSequencer::getInstance()->transportChange(
3632                 RosegardenSequencer::TransportPlay);
3633     } else if (instruction == MIDI_MMC_STOP) {
3634         RosegardenSequencer::getInstance()->transportChange(
3635                 RosegardenSequencer::TransportStop);
3636     }
3637 
3638     return true;
3639 }
3640 
3641 void
processMidiOut(const MappedEventList & rgEventList,const RealTime & sliceStart,const RealTime & sliceEnd)3642 AlsaDriver::processMidiOut(const MappedEventList &rgEventList,
3643                            const RealTime &sliceStart,
3644                            const RealTime &sliceEnd)
3645 {
3646     LOCKED;
3647 
3648     // special case for unqueued events
3649     bool now = (sliceStart == RealTime::zeroTime && sliceEnd == RealTime::zeroTime);
3650 
3651 #ifdef DEBUG_PROCESS_MIDI_OUT
3652     RG_DEBUG << "processMidiOut(" << sliceStart << "," << sliceEnd << "), " << rgEventList.size() << " events, now is " << now;
3653 #endif
3654 
3655     if (!now) {
3656         // This 0.5 sec is arbitrary, but it must be larger than the
3657         // sequencer's read-ahead
3658         RealTime diff = RealTime::fromSeconds(0.5);
3659         RealTime cutoff = sliceStart - diff;
3660         cropRecentNoteOffs(cutoff - m_playStartPosition + m_alsaPlayStartTime);
3661     }
3662 
3663     // These won't change in this slice
3664     //
3665     if ((rgEventList.begin() != rgEventList.end())) {
3666         SequencerDataBlock::getInstance()->setVisual(*rgEventList.begin());
3667     }
3668 
3669     // A pointer to this is extracted from it and placed in "event".
3670     // We need this to stay alive so that the pointer continues to
3671     // be valid until "event" is finally used.  It might be possible to
3672     // move this to a smaller scope, but this loop is really big and
3673     // hard to follow.
3674     std::string sysExData;
3675 
3676     // NB the MappedEventList is implicitly ordered by time (std::multiset)
3677 
3678     // For each incoming mapped (Rosegarden) event
3679     for (MappedEvent *rgEvent : rgEventList) {
3680         // Skip all non-MIDI events.
3681         if (rgEvent->getType() >= MappedEvent::Audio)
3682             continue;
3683 
3684         if (rgEvent->getType() == MappedEvent::MidiNote &&
3685             rgEvent->getDuration() == RealTime::zeroTime &&
3686             rgEvent->getVelocity() == 0) {
3687             // NOTE OFF with duration zero is scheduled from the
3688             // internal segment mapper and we don't use that message
3689             // in realtime otherwise it is a duplicate.
3690             // When we receive a NOTE OFF message from MIDI input, the
3691             // duration is never zero but at least 1 msec (see the case
3692             // for SND_SEQ_EVENT_NOTEOFF in getMappedEventList).
3693             continue;
3694         }
3695 
3696         bool debug = throttledDebug();
3697         if (debug) {
3698             RG_DEBUG << "processMidiOut(): for each event...";
3699             QString eventType = "unknown";
3700             switch (rgEvent->getType()) {
3701                 case MappedEvent::MidiNote: eventType = "MidiNote"; break;
3702                 case MappedEvent::MidiNoteOneShot: eventType = "MidiNoteOneShot"; break;
3703                 case MappedEvent::MidiController: eventType = "MidiController"; break;
3704                 default: break;
3705             }
3706             RG_DEBUG << "processMidiOut():   MappedEvent Event Type: " << rgEvent->getType() << " (" << eventType << ")";
3707         }
3708 
3709         snd_seq_event_t alsaEvent;
3710         snd_seq_ev_clear(&alsaEvent);
3711 
3712         const bool isExternalController =
3713                 (rgEvent->getRecordedDevice() == Device::EXTERNAL_CONTROLLER);
3714 
3715         bool isSoftSynth = (!isExternalController &&
3716                             (rgEvent->getInstrument() >= SoftSynthInstrumentBase));
3717 
3718         RealTime outputTime = rgEvent->getEventTime() - m_playStartPosition +
3719             m_alsaPlayStartTime;
3720 
3721         if (now && !m_playing && m_queueRunning) {
3722             // stop queue to ensure exact timing and make sure the
3723             // event gets through right now
3724 #ifdef DEBUG_PROCESS_MIDI_OUT
3725             RG_DEBUG << "processMidiOut(): stopping queue for now-event";
3726 #endif
3727 
3728             checkAlsaError(snd_seq_stop_queue(m_midiHandle, m_queue, nullptr), "processMidiOut(): stop queue");
3729             checkAlsaError(snd_seq_drain_output(m_midiHandle), "processMidiOut(): draining");
3730         }
3731 
3732         RealTime alsaTimeNow = getAlsaTime();
3733 
3734         if (now) {
3735             if (!m_playing) {
3736                 outputTime = alsaTimeNow;
3737             } else if (outputTime < alsaTimeNow) {
3738                 // This isn't really necessary as ALSA will immediately
3739                 // send out events that are prior to the current time.
3740                 // And that's what we want anyway.
3741                 outputTime = alsaTimeNow;
3742             }
3743         }
3744 
3745 #ifdef DEBUG_PROCESS_MIDI_OUT
3746         RG_DEBUG << "processMidiOut[" << now << "]: event is at " << outputTime << " (" << outputTime - alsaTimeNow << " ahead of queue time), type " << int(rgEvent->getType()) << ", duration " << rgEvent->getDuration();
3747 #endif
3748 
3749         if (!m_queueRunning && outputTime < alsaTimeNow) {
3750             RealTime adjust = alsaTimeNow - outputTime;
3751             if (rgEvent->getDuration() > RealTime::zeroTime) {
3752                 if (rgEvent->getDuration() <= adjust) {
3753 #ifdef DEBUG_PROCESS_MIDI_OUT
3754                     RG_DEBUG << "processMidiOut[" << now << "]: too late for this event, abandoning it";
3755 #endif
3756 
3757                     continue;
3758                 } else {
3759 #ifdef DEBUG_PROCESS_MIDI_OUT
3760                     RG_DEBUG << "processMidiOut[" << now << "]: pushing event forward and reducing duration by " << adjust;
3761 #endif
3762 
3763                     rgEvent->setDuration(rgEvent->getDuration() - adjust);
3764                 }
3765             } else {
3766 #ifdef DEBUG_PROCESS_MIDI_OUT
3767                 RG_DEBUG << "processMidiOut[" << now << "]: pushing zero-duration event forward by " << adjust;
3768 #endif
3769 
3770             }
3771             outputTime = alsaTimeNow;
3772         }
3773 
3774         processNotesOff(outputTime, now);
3775 
3776 #if defined(DEBUG_PROCESS_MIDI_OUT)  &&  defined(HAVE_LIBJACK)
3777         if (m_jackDriver) {
3778             size_t frameCount = m_jackDriver->getFramesProcessed();
3779             size_t elapsed = frameCount - debug_jack_frame_count;
3780             RealTime rt = RealTime::frame2RealTime(elapsed, m_jackDriver->getSampleRate());
3781             rt = rt - getAlsaTime();
3782             RG_DEBUG << "processMidiOut[" << now << "]: JACK time is " << rt << " ahead of ALSA time";
3783         }
3784 #endif
3785 
3786         // Second and nanoseconds for ALSA
3787         //
3788         snd_seq_real_time_t time =
3789             { (unsigned int)outputTime.sec, (unsigned int)outputTime.nsec };
3790 
3791         if (!isSoftSynth) {
3792 
3793 #ifdef DEBUG_PROCESS_MIDI_OUT
3794             RG_DEBUG << "processMidiOut[" << now << "]: instrument " << rgEvent->getInstrument();
3795             RG_DEBUG << "processMidiOut():     pitch: " << (int)rgEvent->getPitch() << ", velocity " << (int)rgEvent->getVelocity() << ", duration " << rgEvent->getDuration();
3796 #endif
3797 
3798             snd_seq_ev_set_subs(&alsaEvent);
3799 
3800             // Set source according to port for device
3801             //
3802             int src;
3803 
3804             if (isExternalController) {
3805                 src = m_externalControllerPort;
3806             } else {
3807                 src = getOutputPortForMappedInstrument(rgEvent->getInstrument());
3808             }
3809 
3810             if (src < 0)
3811                 continue;
3812 
3813             snd_seq_ev_set_source(&alsaEvent, src);
3814 
3815             snd_seq_ev_schedule_real(&alsaEvent, m_queue, 0, &time);
3816 
3817         } else {
3818             alsaEvent.time.time = time;
3819         }
3820 
3821         MappedInstrument *instrument = getMappedInstrument(rgEvent->getInstrument());
3822 
3823         // set the stop time for Note Off
3824         //
3825         RealTime outputStopTime = outputTime + rgEvent->getDuration()
3826             - RealTime(0, 1); // notch it back 1nsec just to ensure
3827         // correct ordering against any other
3828         // note-ons at the same nominal time
3829         bool needNoteOff = false;
3830 
3831         MidiByte channel = 0;
3832 
3833         if (isExternalController) {
3834             channel = rgEvent->getRecordedChannel();
3835 #ifdef DEBUG_ALSA
3836             RG_DEBUG << "processMidiOut() - Event of type " << (int)(rgEvent->getType()) << " (data1 " << (int)rgEvent->getData1() << ", data2 " << (int)rgEvent->getData2() << ") for external controller channel " << (int)channel;
3837 #endif
3838         } else if (instrument != nullptr) {
3839             channel = rgEvent->getRecordedChannel();
3840 #ifdef DEBUG_ALSA
3841             RG_DEBUG << "processMidiOut() - Non-controller Event of type " << (int)(rgEvent->getType()) << " (data1 " << (int)rgEvent->getData1() << ", data2 " << (int)rgEvent->getData2() << ") for channel " << (int)rgEvent->getRecordedChannel();
3842 #endif
3843         } else {
3844 #ifdef DEBUG_ALSA
3845             RG_DEBUG << "processMidiOut() - No instrument for event of type "
3846                       << (int)rgEvent->getType() << " at " << rgEvent->getEventTime();
3847 #endif
3848             channel = 0;
3849         }
3850 
3851         // channel is a MidiByte which is unsigned.  This will never be true.
3852         //if (channel < 0) { continue; }
3853 
3854         switch (rgEvent->getType()) {
3855 
3856         case MappedEvent::MidiNote:
3857             if (rgEvent->getVelocity() == 0) {
3858                 snd_seq_ev_set_noteoff(&alsaEvent,
3859                                        channel,
3860                                        rgEvent->getPitch(),
3861                                        NOTE_OFF_VELOCITY);
3862                 break;
3863             }
3864 
3865             // !!! FALLTHROUGH
3866             //
3867             // MidiNote behaves exactly like MidiNoteOneShot, except that
3868             // a velocity of 0 results in a note-off instead of a note-on.
3869             //
3870             // Why "OneShot" is used to differentiate is unclear.  Renaming
3871             // may be in order.  A duration of RealTime(-1,0) results in
3872             // the sending of only a note-on and no note-off.  This seems
3873             // more like a kind of "one-shot" than treating a 0 velocity
3874             // in a special way.
3875 
3876         case MappedEvent::MidiNoteOneShot:
3877             snd_seq_ev_set_noteon(&alsaEvent,
3878                                   channel,
3879                                   rgEvent->getPitch(),
3880                                   rgEvent->getVelocity());
3881 
3882             // NOTE ON from MIDI input is scheduled with duration -1
3883             // and we don't use the NOTE OFF stack for MIDI input.
3884             if (rgEvent->getDuration() > RealTime(-1, 0)) {
3885                 needNoteOff = true;
3886             }
3887 
3888             if (!isSoftSynth) {
3889                 LevelInfo info;
3890                 info.level = rgEvent->getVelocity();
3891                 info.levelRight = 0;
3892                 SequencerDataBlock::getInstance()->setInstrumentLevel
3893                     (rgEvent->getInstrument(), info);
3894             }
3895 
3896             weedRecentNoteOffs(rgEvent->getPitch(), channel, rgEvent->getInstrument());
3897             break;
3898 
3899         case MappedEvent::MidiProgramChange:
3900             snd_seq_ev_set_pgmchange(&alsaEvent,
3901                                      channel,
3902                                      rgEvent->getData1());
3903             break;
3904 
3905         case MappedEvent::MidiKeyPressure:
3906             snd_seq_ev_set_keypress(&alsaEvent,
3907                                     channel,
3908                                     rgEvent->getData1(),
3909                                     rgEvent->getData2());
3910             break;
3911 
3912         case MappedEvent::MidiChannelPressure:
3913             snd_seq_ev_set_chanpress(&alsaEvent,
3914                                      channel,
3915                                      rgEvent->getData1());
3916             break;
3917 
3918         case MappedEvent::MidiPitchBend: {
3919             int d1 = (int)(rgEvent->getData1());
3920             int d2 = (int)(rgEvent->getData2());
3921             int value = ((d1 << 7) | d2) - 8192;
3922 
3923             // keep within -8192 to +8192
3924             //
3925             // if (value & 0x4000)
3926             //    value -= 0x8000;
3927 
3928             snd_seq_ev_set_pitchbend(&alsaEvent,
3929                                      channel,
3930                                      value);
3931         }
3932             break;
3933 
3934         case MappedEvent::MidiSystemMessage: {
3935             switch (rgEvent->getData1()) {
3936             case MIDI_SYSTEM_EXCLUSIVE: {
3937                 char out[2];
3938                 sprintf(out, "%c", MIDI_SYSTEM_EXCLUSIVE);
3939                 sysExData = out;
3940 
3941                 sysExData += DataBlockRepository::getDataBlockForEvent(rgEvent);
3942 
3943                 sprintf(out, "%c", MIDI_END_OF_EXCLUSIVE);
3944                 sysExData += out;
3945 
3946                 // Note: sysExData needs to stay around until this event
3947                 //   is actually sent.  event has a pointer to its contents.
3948                 snd_seq_ev_set_sysex(&alsaEvent,
3949                                      sysExData.length(),
3950                                      (char*)(sysExData.c_str()));
3951             }
3952                 break;
3953 
3954             case MIDI_TIMING_CLOCK: {
3955                 RealTime rt =
3956                     RealTime(time.tv_sec, time.tv_nsec);
3957 
3958                 //RG_DEBUG << "processMidiOut() - " << "send clock @ " << rt;
3959 
3960                 // Send out the sync port.
3961                 sendSystemQueued(SND_SEQ_EVENT_CLOCK, "", rt);
3962 
3963                 // Skip the usual processing since we aren't using
3964                 // alsaEvent.
3965                 continue;
3966 
3967             }
3968                 break;
3969 
3970             case MIDI_SYSTEM_RESET:
3971                 alsaEvent.type = SND_SEQ_EVENT_RESET;
3972                 break;
3973 
3974             default:
3975                 RG_WARNING << "processMidiOut(): WARNING: unrecognised system message";
3976                 break;
3977             }
3978         }
3979             break;
3980 
3981         case MappedEvent::MidiController:
3982             snd_seq_ev_set_controller(&alsaEvent,
3983                                       channel,
3984                                       rgEvent->getData1(),
3985                                       rgEvent->getData2());
3986             break;
3987 
3988             // These types do nothing here, so go on to the
3989             // next iteration.
3990         case MappedEvent::Audio:
3991         case MappedEvent::AudioCancel:
3992         case MappedEvent::AudioLevel:
3993         case MappedEvent::AudioStopped:
3994         case MappedEvent::SystemUpdateInstruments:
3995         case MappedEvent::SystemJackTransport:  //???
3996         case MappedEvent::SystemMMCTransport:
3997         case MappedEvent::SystemMIDIClock:
3998         case MappedEvent::SystemMIDISyncAuto:
3999         case MappedEvent::AudioGeneratePreview:
4000         case MappedEvent::Marker:
4001         case MappedEvent::Panic:
4002         case MappedEvent::SystemAudioFileFormat:
4003         case MappedEvent::SystemAudioPortCounts:
4004         case MappedEvent::SystemAudioPorts:
4005         case MappedEvent::SystemFailure:
4006         case MappedEvent::SystemMetronomeDevice:
4007         case MappedEvent::SystemMTCTransport:
4008         case MappedEvent::TimeSignature:
4009         case MappedEvent::Tempo:
4010         case MappedEvent::Text:
4011              continue;
4012 
4013         default:
4014         case MappedEvent::InvalidMappedEvent:
4015 #ifdef DEBUG_ALSA
4016             RG_DEBUG << "processMidiOut() - skipping unrecognised or invalid MappedEvent type";
4017 #endif
4018 
4019             continue;
4020         }
4021 
4022         if (debug) {
4023             QString eventType = "unknown";
4024             switch (alsaEvent.type) {
4025                 case SND_SEQ_EVENT_NOTEON: eventType = "SND_SEQ_EVENT_NOTEON"; break;
4026                 case SND_SEQ_EVENT_NOTEOFF: eventType = "SND_SEQ_EVENT_NOTEOFF"; break;
4027                 case SND_SEQ_EVENT_CONTROLLER: eventType = "SND_SEQ_EVENT_CONTROLLER"; break;
4028                 default: break;
4029             }
4030             RG_DEBUG << "  ALSA event type: " << alsaEvent.type << " (" << eventType << ")";
4031         }
4032 
4033         if (isSoftSynth) {
4034             if (debug)
4035                 RG_DEBUG << "  Calling processSoftSynthEventOut()...";
4036 
4037             processSoftSynthEventOut(rgEvent->getInstrument(), &alsaEvent, now);
4038 
4039         } else {
4040             if (debug)
4041                 RG_DEBUG << "  Calling snd_seq_event_output()...";
4042 
4043             int rc = snd_seq_event_output(m_midiHandle, &alsaEvent);
4044             checkAlsaError(rc, "processMidiOut(): output queued");
4045 
4046             if (debug)
4047                 RG_DEBUG << "  snd_seq_event_output() rc:" << rc;
4048 
4049             if (now) {
4050                 if (m_queueRunning && !m_playing) {
4051                     // restart queue
4052 #ifdef DEBUG_PROCESS_MIDI_OUT
4053                     RG_DEBUG << "processMidiOut(): restarting queue after now-event";
4054 #endif
4055 
4056                     checkAlsaError(snd_seq_continue_queue(m_midiHandle, m_queue, nullptr), "processMidiOut(): continue queue");
4057                 }
4058                 checkAlsaError(snd_seq_drain_output(m_midiHandle), "processMidiOut(): draining");
4059             }
4060         }
4061 
4062         // Add note to note off stack
4063         //
4064         if (needNoteOff) {
4065             NoteOffEvent *noteOffEvent =
4066                 new NoteOffEvent(outputStopTime,  // already calculated
4067                                  rgEvent->getPitch(),
4068                                  channel,
4069                                  rgEvent->getInstrument());
4070 
4071 #ifdef DEBUG_ALSA
4072             RG_DEBUG << "processMidiOut(): Adding NOTE OFF at " << outputStopTime;
4073 #endif
4074 
4075             m_noteOffQueue.insert(noteOffEvent);
4076         }
4077     }  // for each event
4078 
4079     processNotesOff(sliceEnd - m_playStartPosition + m_alsaPlayStartTime, now);
4080 
4081     if (m_mtcStatus == TRANSPORT_SOURCE) {
4082         insertMTCQFrames(sliceStart, sliceEnd);
4083     }
4084 
4085     if (m_queueRunning) {
4086 
4087         if (now && !m_playing) {
4088             // just to be sure
4089 #ifdef DEBUG_PROCESS_MIDI_OUT
4090             RG_DEBUG << "processMidiOut(): restarting queue after all now-events";
4091 #endif
4092 
4093             checkAlsaError(snd_seq_continue_queue(m_midiHandle, m_queue, nullptr), "processMidiOut(): continue queue");
4094         }
4095 
4096 #ifdef DEBUG_PROCESS_MIDI_OUT
4097         //RG_DEBUG << "processMidiOut(): m_queueRunning " << m_queueRunning << ", now " << now;
4098 #endif
4099         checkAlsaError(snd_seq_drain_output(m_midiHandle), "processMidiOut(): draining");
4100     }
4101 }
4102 
4103 void
processSoftSynthEventOut(InstrumentId id,const snd_seq_event_t * ev,bool now)4104 AlsaDriver::processSoftSynthEventOut(InstrumentId id, const snd_seq_event_t *ev, bool now)
4105 {
4106 #ifdef DEBUG_PROCESS_SOFT_SYNTH_OUT
4107     RG_DEBUG << "processSoftSynthEventOut(): instrument " << id << ", now " << now;
4108 #endif
4109 
4110 #ifdef HAVE_LIBJACK
4111 
4112     if (!m_jackDriver)
4113         return ;
4114     RunnablePluginInstance *synthPlugin = m_jackDriver->getSynthPlugin(id);
4115 
4116     if (synthPlugin) {
4117 
4118         RealTime t(ev->time.time.tv_sec, ev->time.time.tv_nsec);
4119 
4120         if (now)
4121             t = RealTime::zeroTime;
4122         else
4123             t = t + m_playStartPosition - m_alsaPlayStartTime;
4124 
4125 #ifdef DEBUG_PROCESS_SOFT_SYNTH_OUT
4126         RG_DEBUG << "processSoftSynthEventOut(): event time " << t;
4127 #endif
4128 
4129         synthPlugin->sendEvent(t, ev);
4130 
4131         if (now) {
4132 #ifdef DEBUG_PROCESS_SOFT_SYNTH_OUT
4133             RG_DEBUG << "processSoftSynthEventOut(): setting haveAsyncAudioEvent";
4134 #endif
4135 
4136             m_jackDriver->setHaveAsyncAudioEvent();
4137         }
4138     }
4139 #endif
4140 }
4141 
4142 void
startClocks()4143 AlsaDriver::startClocks()
4144 {
4145     int result;
4146 
4147 #ifdef DEBUG_ALSA
4148     RG_DEBUG << "startClocks() begin...";
4149 #endif
4150 
4151     if (m_needJackStart) {
4152 #ifdef DEBUG_ALSA
4153         RG_DEBUG << "startClocks: Need JACK start (m_playing = " << m_playing << ")";
4154 #endif
4155 
4156     }
4157 
4158 #ifdef HAVE_LIBJACK
4159 
4160     // New JACK transport scheme: The initialisePlayback,
4161     // resetPlayback and stopPlayback methods set m_needJackStart, and
4162     // then this method checks it and calls the appropriate JACK
4163     // transport start or relocate method, which calls back on
4164     // startClocksApproved when ready.  (Previously this method always
4165     // called the JACK transport start method, so we couldn't handle
4166     // moving the pointer when not playing, and we had to stop the
4167     // transport explicitly from resetPlayback when repositioning
4168     // during playback.)
4169 
4170     if (m_jackDriver) {
4171 
4172         // Don't need any locks on this, except for those that the
4173         // driver methods take and hold for themselves
4174 
4175         if (m_needJackStart != NeedNoJackStart) {
4176             if (m_needJackStart == NeedJackStart ||
4177                 m_playing) {
4178 #ifdef DEBUG_ALSA
4179                 RG_DEBUG << "startClocks(): playing, prebuffer audio";
4180 #endif
4181 
4182                 m_jackDriver->prebufferAudio();
4183             } else {
4184 #ifdef DEBUG_ALSA
4185                 RG_DEBUG << "startClocks(): prepare audio only";
4186 #endif
4187 
4188                 m_jackDriver->prepareAudio();
4189             }
4190             bool rv;
4191             if (m_needJackStart == NeedJackReposition) {
4192                 rv = m_jackDriver->relocateTransport();
4193             } else {
4194                 rv = m_jackDriver->startTransport();
4195                 if (!rv) {
4196 #ifdef DEBUG_ALSA
4197                     RG_DEBUG << "startClocks(): Waiting for startClocksApproved";
4198 #endif
4199                     // need to wait for transport sync
4200                     debug_jack_frame_count = m_jackDriver->getFramesProcessed();
4201                     return ;
4202                 }
4203             }
4204         }
4205     }
4206 #endif
4207 
4208     // Restart the timer
4209     if ((result = snd_seq_continue_queue(m_midiHandle, m_queue, nullptr)) < 0) {
4210         RG_WARNING << "startClocks(): WARNING: Couldn't start queue - " << snd_strerror(result);
4211         reportFailure(MappedEvent::FailureALSACallFailed);
4212     }
4213 
4214 #ifdef DEBUG_ALSA
4215     RG_DEBUG << "startClocks(): started clocks";
4216 #endif
4217 
4218     m_queueRunning = true;
4219 
4220 #ifdef HAVE_LIBJACK
4221 
4222     if (m_jackDriver) {
4223         debug_jack_frame_count = m_jackDriver->getFramesProcessed();
4224     }
4225 #endif
4226 
4227     // process pending MIDI events
4228     checkAlsaError(snd_seq_drain_output(m_midiHandle), "startClocks(): draining");
4229 }
4230 
4231 void
startClocksApproved()4232 AlsaDriver::startClocksApproved()
4233 {
4234     LOCKED;
4235 #ifdef DEBUG_ALSA
4236     RG_DEBUG << "startClocksApproved() begin...";
4237 #endif
4238 
4239     //!!!
4240     m_needJackStart = NeedNoJackStart;
4241     startClocks();
4242     return ;
4243 
4244     int result;
4245 
4246     // Restart the timer
4247     if ((result = snd_seq_continue_queue(m_midiHandle, m_queue, nullptr)) < 0) {
4248         RG_WARNING << "startClocksApproved(): WARNING: Couldn't start queue - " << snd_strerror(result);
4249         reportFailure(MappedEvent::FailureALSACallFailed);
4250     }
4251 
4252     m_queueRunning = true;
4253 
4254     // process pending MIDI events
4255     checkAlsaError(snd_seq_drain_output(m_midiHandle), "startClocksApproved(): draining");
4256 }
4257 
4258 void
stopClocks()4259 AlsaDriver::stopClocks()
4260 {
4261 #ifdef DEBUG_ALSA
4262     RG_DEBUG << "stopClocks() begin...";
4263 #endif
4264 
4265     if (checkAlsaError(snd_seq_stop_queue(m_midiHandle, m_queue, nullptr), "stopClocks(): stopping queue") < 0) {
4266         reportFailure(MappedEvent::FailureALSACallFailed);
4267     }
4268     checkAlsaError(snd_seq_drain_output(m_midiHandle), "stopClocks(): draining output to stop queue");
4269 
4270     m_queueRunning = false;
4271 
4272     // We used to call m_jackDriver->stop() from here, but we no
4273     // longer do -- it's now called from stopPlayback() so as to
4274     // handle repositioning during playback (when stopClocks is
4275     // necessary but stopPlayback and m_jackDriver->stop() are not).
4276 
4277     snd_seq_event_t event;
4278     snd_seq_ev_clear(&event);
4279     snd_seq_real_time_t z = { 0, 0 };
4280     snd_seq_ev_set_queue_pos_real(&event, m_queue, &z);
4281     snd_seq_ev_set_direct(&event);
4282     checkAlsaError(snd_seq_control_queue(m_midiHandle, m_queue, SND_SEQ_EVENT_SETPOS_TIME,
4283                                          0, &event), "stopClocks(): setting zpos to queue");
4284     // process that
4285     checkAlsaError(snd_seq_drain_output(m_midiHandle), "stopClocks(): draining output to zpos queue");
4286 
4287 #ifdef DEBUG_ALSA
4288     RG_DEBUG << "stopClocks(): ALSA time now is " << getAlsaTime();
4289 #endif
4290 
4291     m_alsaPlayStartTime = RealTime::zeroTime;
4292 }
4293 
4294 
4295 void
processEventsOut(const MappedEventList & rgEventList)4296 AlsaDriver::processEventsOut(const MappedEventList &rgEventList)
4297 {
4298     processEventsOut(rgEventList, RealTime::zeroTime, RealTime::zeroTime);
4299 }
4300 
4301 void
processEventsOut(const MappedEventList & rgEventList,const RealTime & sliceStart,const RealTime & sliceEnd)4302 AlsaDriver::processEventsOut(const MappedEventList &rgEventList,
4303                              const RealTime &sliceStart,
4304                              const RealTime &sliceEnd)
4305 {
4306     // special case for unqueued events
4307 #ifdef HAVE_LIBJACK
4308     const bool now = (sliceStart == RealTime::zeroTime && sliceEnd == RealTime::zeroTime);
4309 #endif
4310 
4311     if (m_startPlayback) {
4312         m_startPlayback = false;
4313         // This only records whether we're playing in principle,
4314         // not whether the clocks are actually ticking.  Contrariwise,
4315         // areClocksRunning tells us whether the clocks are ticking
4316         // but not whether we're actually playing (the clocks go even
4317         // when we're not).  Check both if you want to know whether
4318         // we're really rolling.
4319         m_playing = true;
4320 
4321         if (m_mtcStatus == TRANSPORT_FOLLOWER) {
4322             tweakSkewForMTC(0);
4323         }
4324     }
4325 
4326     AudioFile *audioFile = nullptr;
4327     bool haveNewAudio = false;
4328 
4329     // For each incoming event, insert audio events if we find them
4330     for (const MappedEvent *mappedEvent : rgEventList) {
4331 
4332 #ifdef HAVE_LIBJACK
4333 
4334         // Play an audio file
4335         //
4336         if (mappedEvent->getType() == MappedEvent::Audio) {
4337             if (!m_jackDriver)
4338                 continue;
4339 
4340             // This is used for handling asynchronous
4341             // (i.e. unexpected) audio events only
4342 
4343             if (mappedEvent->getEventTime() > RealTime( -120, 0)) {
4344                 // Not an asynchronous event
4345                 continue;
4346             }
4347 
4348             // Check for existence of file - if the sequencer has died
4349             // and been restarted then we're not always loaded up with
4350             // the audio file references we should have.  In the future
4351             // we could make this just get the gui to reload our files
4352             // when (or before) this fails.
4353             //
4354             audioFile = getAudioFile(mappedEvent->getAudioID());
4355 
4356             if (audioFile) {
4357                 MappedAudioFader *fader =
4358                     dynamic_cast<MappedAudioFader *>
4359                     (m_studio->getAudioFader(mappedEvent->getInstrument()));
4360 
4361                 if (!fader) {
4362                     RG_WARNING << "processEventsOut(): WARNING: No fader for audio instrument " << mappedEvent->getInstrument();
4363                     continue;
4364                 }
4365 
4366                 int channels = fader->getPropertyList(
4367                                                       MappedAudioFader::Channels)[0].toInt();
4368 
4369                 RealTime bufferLength = getAudioReadBufferLength();
4370                 size_t bufferFrames = (size_t)RealTime::realTime2Frame
4371                     (bufferLength, m_jackDriver->getSampleRate());
4372                 if (bufferFrames % size_t(m_jackDriver->getBufferSize())) {
4373                     bufferFrames /= size_t(m_jackDriver->getBufferSize());
4374                     bufferFrames ++;
4375                     bufferFrames *= size_t(m_jackDriver->getBufferSize());
4376                 }
4377 
4378                 //#define DEBUG_PLAYING_AUDIO
4379 #ifdef DEBUG_PLAYING_AUDIO
4380                 RG_DEBUG << "processEventsOut(): Creating playable audio file: id " << audioFile->getId() << ", event time " << mappedEvent->getEventTime() << ", time now " << getAlsaTime() << ", start marker " << mappedEvent->getAudioStartMarker() << ", duration " << mappedEvent->getDuration() << ", instrument " << mappedEvent->getInstrument() << " channels " << channels;
4381                 RG_DEBUG << "processEventsOut(): Read buffer length is " << bufferLength << " (" << bufferFrames << " frames)";
4382 #endif
4383 
4384                 PlayableAudioFile *paf = nullptr;
4385 
4386                 try {
4387                     paf = new PlayableAudioFile(mappedEvent->getInstrument(),
4388                                                 audioFile,
4389                                                 getSequencerTime() +
4390                                                 (RealTime(1, 0) / 4),
4391                                                 mappedEvent->getAudioStartMarker(),
4392                                                 mappedEvent->getDuration(),
4393                                                 bufferFrames,
4394                                                 m_smallFileSize * 1024,
4395                                                 channels,
4396                                                 m_jackDriver->getSampleRate());
4397                 } catch (...) {
4398                     continue;
4399                 }
4400 
4401                 if (mappedEvent->isAutoFading()) {
4402                     paf->setAutoFade(true);
4403                     paf->setFadeInTime(mappedEvent->getFadeInTime());
4404                     paf->setFadeOutTime(mappedEvent->getFadeInTime());
4405 
4406                     //#define DEBUG_AUTOFADING
4407 #ifdef DEBUG_AUTOFADING
4408 
4409                     RG_DEBUG << "processEventsOut(): PlayableAudioFile is AUTOFADING - "
4410                              << "in = " << mappedEvent->getFadeInTime()
4411                              << ", out = " << mappedEvent->getFadeOutTime();
4412 #endif
4413 
4414                 }
4415 #ifdef DEBUG_AUTOFADING
4416                 else {
4417                     RG_DEBUG << "processEventsOut(): PlayableAudioFile has no AUTOFADE";
4418                 }
4419 #endif
4420 
4421 
4422                 // segment runtime id
4423                 paf->setRuntimeSegmentId(mappedEvent->getRuntimeSegmentId());
4424 
4425                 m_audioQueue->addUnscheduled(paf);
4426 
4427                 haveNewAudio = true;
4428             } else {
4429 #ifdef DEBUG_ALSA
4430                 RG_DEBUG << "processEventsOut(): Can't find audio file reference.";
4431                 RG_DEBUG << "processEventsOut(): Try reloading the current Rosegarden file.";
4432 #else
4433                 ;
4434 #endif
4435 
4436             }
4437         }
4438 
4439         // Cancel a playing audio file preview (this is predicated on
4440         // runtime segment ID and optionally start time)
4441         //
4442         if (mappedEvent->getType() == MappedEvent::AudioCancel) {
4443             cancelAudioFile(mappedEvent);
4444         }
4445 #endif // HAVE_LIBJACK
4446 
4447         if (mappedEvent->getType() == MappedEvent::SystemMIDIClock) {
4448             switch ((int)mappedEvent->getData1()) {
4449             case 0:  // MIDI Clock and System messages: Off
4450                 m_midiClockEnabled = false;
4451 #ifdef DEBUG_ALSA
4452                 RG_DEBUG << "processEventsOut(): Rosegarden MIDI CLOCK, START and STOP DISABLED";
4453 #endif
4454 
4455                 m_midiSyncStatus = TRANSPORT_OFF;
4456                 break;
4457 
4458             case 1:  // MIDI Clock and System messages: Send MIDI Clock, Start and Stop
4459                 m_midiClockEnabled = true;
4460 #ifdef DEBUG_ALSA
4461                 RG_DEBUG << "processEventsOut(): Rosegarden send MIDI CLOCK, START and STOP ENABLED";
4462 #endif
4463 
4464                 m_midiSyncStatus = TRANSPORT_SOURCE;
4465                 break;
4466 
4467             case 2:  // MIDI Clock and System messages: Accept Start, Stop and Continue
4468                 m_midiClockEnabled = false;
4469 #ifdef DEBUG_ALSA
4470                 RG_DEBUG << "processEventsOut(): Rosegarden accept START and STOP ENABLED";
4471 #endif
4472 
4473                 m_midiSyncStatus = TRANSPORT_FOLLOWER;
4474                 break;
4475             }
4476         }
4477 
4478         if (mappedEvent->getType() == MappedEvent::SystemMIDISyncAuto) {
4479             if (mappedEvent->getData1()) {
4480                 m_midiSyncAutoConnect = true;
4481 #ifdef DEBUG_ALSA
4482                 RG_DEBUG << "processEventsOut(): Rosegarden MIDI SYNC AUTO ENABLED";
4483 #endif
4484 
4485                 for (DevicePortMap::iterator dpmi = m_devicePortMap.begin();
4486                      dpmi != m_devicePortMap.end(); ++dpmi) {
4487                     snd_seq_connect_to(m_midiHandle,
4488                                        m_syncOutputPort,
4489                                        dpmi->second.client,
4490                                        dpmi->second.port);
4491                 }
4492             } else {
4493                 m_midiSyncAutoConnect = false;
4494 #ifdef DEBUG_ALSA
4495                 RG_DEBUG << "processEventsOut(): Rosegarden MIDI SYNC AUTO DISABLED";
4496 #endif
4497             }
4498         }
4499 
4500 #ifdef HAVE_LIBJACK
4501         // Set the JACK transport
4502         if (mappedEvent->getType() == MappedEvent::SystemJackTransport) {
4503             bool enabled = false;
4504             bool source = false;
4505 
4506             switch ((int)mappedEvent->getData1()) {
4507             case 2:
4508                 source = true;
4509                 enabled = true;
4510 #ifdef DEBUG_ALSA
4511                 RG_DEBUG << "processEventsOut(): Rosegarden to follow JACK transport and request JACK timebase master role (not yet implemented)";
4512 #endif
4513                 break;
4514 
4515             case 1:
4516                 enabled = true;
4517 #ifdef DEBUG_ALSA
4518                 RG_DEBUG << "processEventsOut(): Rosegarden to follow JACK transport";
4519 #endif
4520                 break;
4521 
4522             case 0:
4523             default:
4524 #ifdef DEBUG_ALSA
4525                 RG_DEBUG << "processEventsOut(): Rosegarden to ignore JACK transport";
4526 #endif
4527                 break;
4528             }
4529 
4530             if (m_jackDriver) {
4531                 m_jackDriver->setTransportEnabled(enabled);
4532                 m_jackDriver->setTransportSource(source);
4533             }
4534         }
4535 #endif // HAVE_LIBJACK
4536 
4537 
4538         if (mappedEvent->getType() == MappedEvent::SystemMMCTransport) {
4539             switch ((int)mappedEvent->getData1()) {
4540             case 1:
4541 #ifdef DEBUG_ALSA
4542                 RG_DEBUG << "processEventsOut(): Rosegarden is MMC SOURCE";
4543 #endif
4544 
4545                 m_mmcStatus = TRANSPORT_SOURCE;
4546                 break;
4547 
4548             case 2:
4549 #ifdef DEBUG_ALSA
4550                 RG_DEBUG << "processEventsOut(): Rosegarden is MMC FOLLOWER";
4551 #endif
4552                 m_mmcStatus = TRANSPORT_FOLLOWER;
4553                 break;
4554 
4555             case 0:
4556             default:
4557 #ifdef DEBUG_ALSA
4558                 RG_DEBUG << "processEventsOut(): Rosegarden MMC Transport DISABLED";
4559 #endif
4560 
4561                 m_mmcStatus = TRANSPORT_OFF;
4562                 break;
4563             }
4564         }
4565 
4566         if (mappedEvent->getType() == MappedEvent::SystemMTCTransport) {
4567             switch ((int)mappedEvent->getData1()) {
4568             case 1:
4569 #ifdef DEBUG_ALSA
4570                 RG_DEBUG << "processEventsOut(): Rosegarden is MTC SOURCE";
4571 #endif
4572 
4573                 m_mtcStatus = TRANSPORT_SOURCE;
4574                 tweakSkewForMTC(0);
4575                 m_mtcFirstTime = -1;
4576                 break;
4577 
4578             case 2:
4579 #ifdef DEBUG_ALSA
4580                 RG_DEBUG << "processEventsOut(): Rosegarden is MTC FOLLOWER";
4581 #endif
4582 
4583                 m_mtcStatus = TRANSPORT_FOLLOWER;
4584                 m_mtcFirstTime = -1;
4585                 break;
4586 
4587             case 0:
4588             default:
4589 #ifdef DEBUG_ALSA
4590                 RG_DEBUG << "processEventsOut(): Rosegarden MTC Transport DISABLED";
4591 #endif
4592 
4593                 m_mtcStatus = TRANSPORT_OFF;
4594                 m_mtcFirstTime = -1;
4595                 break;
4596             }
4597         }
4598 
4599         //if (mappedEvent->getType() == MappedEvent::SystemAudioPortCounts) {
4600             // never actually used, I think?
4601         //}
4602 
4603         if (mappedEvent->getType() == MappedEvent::SystemAudioPorts) {
4604 #ifdef HAVE_LIBJACK
4605             if (m_jackDriver) {
4606                 int data = mappedEvent->getData1();
4607                 m_jackDriver->setAudioPorts(data & MappedEvent::FaderOuts,
4608                                             data & MappedEvent::SubmasterOuts);
4609             }
4610 #else
4611 #ifdef DEBUG_ALSA
4612             RG_DEBUG << "processEventsOut(): MappedEvent::SystemAudioPorts - no audio subsystem";
4613 #endif
4614 #endif
4615 
4616         }
4617 
4618         if (mappedEvent->getType() == MappedEvent::SystemAudioFileFormat) {
4619 #ifdef HAVE_LIBJACK
4620             int format = mappedEvent->getData1();
4621             switch (format) {
4622             case 0:
4623                 m_audioRecFileFormat = RIFFAudioFile::PCM;
4624                 break;
4625             case 1:
4626                 m_audioRecFileFormat = RIFFAudioFile::FLOAT;
4627                 break;
4628             default:
4629 #ifdef DEBUG_ALSA
4630                 RG_DEBUG << "processEventsOut(): MappedEvent::SystemAudioFileFormat - unexpected format number " << format;
4631 #endif
4632 
4633                 break;
4634             }
4635 #else
4636 #ifdef DEBUG_ALSA
4637             RG_DEBUG << "processEventsOut(): MappedEvent::SystemAudioFileFormat - no audio subsystem";
4638 #endif
4639 #endif
4640 
4641         }
4642 
4643         if (mappedEvent->getType() == MappedEvent::Panic) {
4644             for (const MappedDevice *device : m_devices) {
4645                 if (device->getDirection() == MidiDevice::Play) {
4646                     sendDeviceController(device->getId(),
4647                                          MIDI_CONTROLLER_SUSTAIN, 0);
4648                     sendDeviceController(device->getId(),
4649                                          MIDI_CONTROLLER_ALL_NOTES_OFF, 0);
4650                     sendDeviceController(device->getId(),
4651                                          MIDI_CONTROLLER_RESET, 0);
4652                 }
4653             }
4654         }
4655     }
4656 
4657     // Process Midi and Audio
4658     //
4659     processMidiOut(rgEventList, sliceStart, sliceEnd);
4660 
4661 #ifdef HAVE_LIBJACK
4662     if (m_jackDriver) {
4663         if (haveNewAudio) {
4664             if (now) {
4665                 m_jackDriver->prebufferAudio();
4666                 m_jackDriver->setHaveAsyncAudioEvent();
4667             }
4668             if (m_queueRunning) {
4669                 m_jackDriver->kickAudio();
4670             }
4671         }
4672     }
4673 #endif
4674 }
4675 
4676 bool
record(RecordStatus recordStatus,const std::vector<InstrumentId> & armedInstruments,const std::vector<QString> & audioFileNames)4677 AlsaDriver::record(RecordStatus recordStatus,
4678                    const std::vector<InstrumentId> &armedInstruments,
4679                    const std::vector<QString> &audioFileNames)
4680 {
4681     m_recordingInstruments.clear();
4682 
4683     clearPendSysExcMap();
4684 
4685     if (recordStatus == RECORD_ON) {
4686         // start recording
4687         m_recordStatus = RECORD_ON;
4688         m_alsaRecordStartTime = RealTime::zeroTime;
4689 
4690         unsigned int audioCount = 0;
4691 
4692         for (size_t i = 0; i < armedInstruments.size(); ++i) {
4693 
4694             const InstrumentId id = armedInstruments[i];
4695 
4696             m_recordingInstruments.insert(id);
4697             if (audioCount >= (unsigned int)audioFileNames.size())
4698                 continue;
4699 
4700             const QString fileName = audioFileNames[audioCount];
4701 
4702             if (id >= AudioInstrumentBase &&
4703                 id < MidiInstrumentBase) {
4704 
4705                 bool good = false;
4706 
4707 #ifdef DEBUG_ALSA
4708                 RG_DEBUG << "record(): Requesting new record file \"" << fileName << "\" for instrument " << id;
4709 #endif
4710 
4711 #ifdef HAVE_LIBJACK
4712                 if (m_jackDriver &&
4713                     m_jackDriver->openRecordFile(id, fileName)) {
4714                     good = true;
4715                 }
4716 #endif
4717 
4718                 if (!good) {
4719                     m_recordStatus = RECORD_OFF;
4720                     RG_WARNING << "record(): No JACK driver, or JACK driver failed to prepare for recording audio";
4721                     return false;
4722                 }
4723 
4724                 ++audioCount;
4725             }
4726         }
4727     } else
4728         if (recordStatus == RECORD_OFF) {
4729             m_recordStatus = RECORD_OFF;
4730         }
4731 #ifdef DEBUG_ALSA
4732         else {
4733             RG_DEBUG << "record(): unsupported recording mode";
4734         }
4735 #endif
4736 
4737     return true;
4738 }
4739 
4740 ClientPortPair
getFirstDestination(bool duplex)4741 AlsaDriver::getFirstDestination(bool duplex)
4742 {
4743     ClientPortPair destPair( -1, -1);
4744     AlsaPortVector::iterator it;
4745 
4746     for (it = m_alsaPorts.begin(); it != m_alsaPorts.end(); ++it) {
4747         destPair.client = (*it)->m_client;
4748         destPair.port = (*it)->m_port;
4749 
4750         // If duplex port is required then choose first one
4751         //
4752         if (duplex) {
4753             if ((*it)->m_direction == Duplex)
4754                 return destPair;
4755         } else {
4756             // If duplex port isn't required then choose first
4757             // specifically non-duplex port (should be a synth)
4758             //
4759             if ((*it)->m_direction != Duplex)
4760                 return destPair;
4761         }
4762     }
4763 
4764     return destPair;
4765 }
4766 
4767 
4768 // Sort through the ALSA client/port pairs for the range that
4769 // matches the one we're querying.  If none matches then send
4770 // back -1 for each.
4771 //
4772 ClientPortPair
getPairForMappedInstrument(InstrumentId id)4773 AlsaDriver::getPairForMappedInstrument(InstrumentId id)
4774 {
4775     MappedInstrument *instrument = getMappedInstrument(id);
4776     if (instrument) {
4777         DeviceId device = instrument->getDevice();
4778         DevicePortMap::iterator i = m_devicePortMap.find(device);
4779         if (i != m_devicePortMap.end()) {
4780             return i->second;
4781         }
4782     }
4783 #ifdef DEBUG_ALSA
4784     /*
4785       else
4786       {
4787       RG_DEBUG << "getPairForMappedInstrument(): WARNING: couldn't find instrument for id " << id << ", falling through";
4788       }
4789     */
4790 #endif
4791 
4792     return ClientPortPair( -1, -1);
4793 }
4794 
4795 int
getOutputPortForMappedInstrument(InstrumentId id)4796 AlsaDriver::getOutputPortForMappedInstrument(InstrumentId id)
4797 {
4798     MappedInstrument *instrument = getMappedInstrument(id);
4799     if (instrument) {
4800         DeviceId device = instrument->getDevice();
4801         DeviceIntMap::iterator i = m_outputPorts.find(device);
4802         if (i != m_outputPorts.end()) {
4803             return i->second;
4804         }
4805 #ifdef DEBUG_ALSA
4806         else {
4807             RG_DEBUG << "getOutputPortForMappedInstrument(): WARNING: couldn't find output port for device for instrument " << id << ", falling through";
4808         }
4809 #endif
4810 
4811     }
4812 
4813     return -1;
4814 }
4815 
4816 // Send a direct controller to the specified port/client
4817 //
4818 void
sendDeviceController(DeviceId device,MidiByte controller,MidiByte value)4819 AlsaDriver::sendDeviceController(DeviceId device,
4820                                  MidiByte controller,
4821                                  MidiByte value)
4822 {
4823     snd_seq_event_t event;
4824 
4825     snd_seq_ev_clear(&event);
4826 
4827     snd_seq_ev_set_subs(&event);
4828 
4829     DeviceIntMap::iterator dimi = m_outputPorts.find(device);
4830     if (dimi == m_outputPorts.end())
4831         return ;
4832 
4833     snd_seq_ev_set_source(&event, dimi->second);
4834     snd_seq_ev_set_direct(&event);
4835 
4836     for (int i = 0; i < 16; i++) {
4837         snd_seq_ev_set_controller(&event,
4838                                   i,
4839                                   controller,
4840                                   value);
4841         snd_seq_event_output_direct(m_midiHandle, &event);
4842     }
4843 
4844     // we probably don't need this:
4845     checkAlsaError(snd_seq_drain_output(m_midiHandle), "sendDeviceController(): draining");
4846 }
4847 
4848 void
processPending()4849 AlsaDriver::processPending()
4850 {
4851     if (!m_playing) {
4852         processNotesOff(getAlsaTime(), true);
4853         checkAlsaError(snd_seq_drain_output(m_midiHandle), "processPending(): draining");
4854     }
4855 
4856 #ifdef HAVE_LIBJACK
4857     if (m_jackDriver) {
4858         m_jackDriver->updateAudioData();
4859     }
4860 #endif
4861 
4862     scavengePlugins();
4863     m_audioQueueScavenger.scavenge();
4864 }
4865 
4866 void
insertMappedEventForReturn(MappedEvent * mE)4867 AlsaDriver::insertMappedEventForReturn(MappedEvent *mE)
4868 {
4869     // Insert the event ready for return at the next opportunity.
4870     //
4871     m_returnComposition.insert(mE);
4872 }
4873 
4874 #if 0
4875 bool
4876 AlsaDriver::isRecording(AlsaPortDescription *port)
4877 {
4878     RG_DEBUG << "isRecording() begin...";
4879 
4880     if (port->isReadable()) {
4881 
4882         snd_seq_query_subscribe_t *qSubs;
4883         snd_seq_addr_t rg_addr, sender_addr;
4884         snd_seq_query_subscribe_alloca(&qSubs);
4885 
4886         rg_addr.client = m_client;
4887         rg_addr.port = m_inputPort;
4888 
4889         snd_seq_query_subscribe_set_type(qSubs, SND_SEQ_QUERY_SUBS_WRITE);
4890         snd_seq_query_subscribe_set_index(qSubs, 0);
4891         snd_seq_query_subscribe_set_root(qSubs, &rg_addr);
4892 
4893         while (snd_seq_query_port_subscribers(m_midiHandle, qSubs) >= 0) {
4894             sender_addr = *snd_seq_query_subscribe_get_addr(qSubs);
4895             if (sender_addr.client == port->m_client &&
4896                 sender_addr.port == port->m_port) {
4897                 RG_DEBUG << "isRecording(): returning true";
4898                 return true;
4899             }
4900             snd_seq_query_subscribe_set_index(qSubs,
4901                                               snd_seq_query_subscribe_get_index(qSubs) + 1);
4902         }
4903     }
4904     RG_DEBUG << "isRecording(): returning false";
4905     return false;
4906 }
4907 #endif
4908 
4909 void
checkForNewClients()4910 AlsaDriver::checkForNewClients()
4911 {
4912     //RG_DEBUG << "checkForNewClients() begin...";
4913 
4914     // If no ALSA client or port events have come in, bail.
4915     if (!m_portCheckNeeded)
4916         return;
4917 
4918     //RG_DEBUG << "checkForNewClients(): port check needed";
4919 
4920     // Update m_alsaPorts.
4921     // ??? Rename: updateALSAPorts()?
4922     generatePortList();
4923 
4924     // Update Connections (m_devicePortMap)
4925 
4926     // From this point on, this routine checks the connections (ALSA
4927     // port subscribers) that are out there and makes sure our list of
4928     // connections (m_devicePortMap) is in sync.
4929 
4930     // For each MappedDevice (Rosegarden MIDI output port) in the
4931     // Studio/Composition...
4932     // ??? The naming here gets confusing.  Perhaps "MappedDevice" should
4933     //     be "MIDIPort" and contain a description of the device that it is
4934     //     expected to be connected to?  That might be a more realistic
4935     //     and easier to understand model.
4936     //       for (MIDIPort *midiPort : m_midiPorts)
4937     for (MappedDevice *device : m_devices) {
4938 
4939         //RG_DEBUG << "  Device:" << device->getName();
4940 
4941         DevicePortMap::iterator connectionIter =
4942                 m_devicePortMap.find(device->getId());
4943 
4944         // Assemble the ALSA address (client and port numbers) for
4945         // this MappedDevice.
4946 
4947         snd_seq_addr_t addr;
4948 
4949         // Rosegarden's ALSA client number.
4950         addr.client = m_client;
4951 
4952         // Get the current MappedDevice's ALSA port number.
4953         DeviceIntMap::iterator portIter =
4954                 m_outputPorts.find(device->getId());
4955         // Not found?  Try the next.
4956         if (portIter == m_outputPorts.end())
4957             continue;
4958 
4959         addr.port = portIter->second;
4960 
4961         // Prepare to query subscribers (connected ports).
4962 
4963         // ??? Rename: midiSynthIter
4964         snd_seq_query_subscribe_t *subs;
4965         // On stack, so no need to free.
4966         // ??? Really?  Then why do we have snd_seq_query_subscribe_free()?
4967         //     Note that aconnect never calls snd_seq_*_free() either.
4968         snd_seq_query_subscribe_alloca(&subs);
4969         // Search only for readers (MIDI synths).
4970         snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_READ);
4971         // Connected to the current "device" (MIDI output port).
4972         snd_seq_query_subscribe_set_root(subs, &addr);
4973         // Start at subscriber number 0.
4974         snd_seq_query_subscribe_set_index(subs, 0);
4975 
4976         bool haveOurs = false;
4977         int others = 0;
4978         ClientPortPair firstOther;
4979 
4980         // For each MIDI output port subscriber (connected MIDI synth)
4981         while (!snd_seq_query_port_subscribers(m_midiHandle, subs)) {
4982 
4983             // Get the subscriber's client:port address.
4984             const snd_seq_addr_t *otherEnd =
4985                     snd_seq_query_subscribe_get_addr(subs);
4986 
4987             if (!otherEnd)
4988                 continue;
4989 
4990             //RG_DEBUG << "    " << otherEnd->client << ":" << otherEnd->port;
4991 
4992             // If this MidiDevice is connected to something, and it matches
4993             // the subscriber that ALSA has, try the next MidiDevice.
4994             if (connectionIter != m_devicePortMap.end()  &&
4995                 otherEnd->client == connectionIter->second.client  &&
4996                 otherEnd->port == connectionIter->second.port) {
4997                 haveOurs = true;
4998                 break;
4999             } else {  // We are not aware of a connection to this MidiDevice.
5000                 // Keep a count of the subscribers per ALSA.
5001                 ++others;
5002                 // ??? Doesn't this end up being last other since it gets
5003                 //     clobbered every time?
5004                 firstOther = ClientPortPair(otherEnd->client, otherEnd->port);
5005             }
5006 
5007             // Move to the next subscriber.
5008             snd_seq_query_subscribe_set_index(
5009                     subs, snd_seq_query_subscribe_get_index(subs) + 1);
5010         }
5011 
5012         // leave our own connection alone, and stop worrying
5013         if (haveOurs)
5014             continue;
5015 
5016         // No subscribers?
5017         if (others == 0) {
5018             // If there is a connection in m_devicePortMap, disconnect it.
5019             if (connectionIter != m_devicePortMap.end()) {
5020                 connectionIter->second = ClientPortPair( -1, -1);
5021                 // ??? This also redundantly disconnects the "connection"
5022                 //     via ALSA.  Need to separate the maintenance of
5023                 //     data structures from the maintenance of actual
5024                 //     connections.
5025                 setConnectionToDevice(*device, "");
5026             }
5027         } else {  // ALSA indicates unexpected subscribers.
5028             // For each ALSA port
5029             for (QSharedPointer<const AlsaPortDescription> port : m_alsaPorts) {
5030                 // If this one matches the "first" subscriber.
5031                 if (port->m_client == firstOther.client  &&
5032                     port->m_port == firstOther.port) {
5033                     // Make the connection.
5034                     m_devicePortMap[device->getId()] = firstOther;
5035                     // ??? This also redundantly reconnects the connection
5036                     //     via ALSA.  Need to separate the maintenance of
5037                     //     data structures from the maintenance of actual
5038                     //     connections.
5039                     setConnectionToDevice(
5040                             *device, port->m_name.c_str(), firstOther);
5041                     break;
5042                 }
5043             }
5044         }
5045     }
5046 
5047     // Port check is complete.
5048     m_portCheckNeeded = false;
5049 
5050 #if 0
5051     // ??? At this point, we should check to see if we can connect any
5052     //     devices that aren't connected to whatever is in their
5053     //     m_userConnection/getUserConnection().  It might be worth
5054     //     pulling out a function to do this and reusing as the main
5055     //     function for making connections after file load.
5056     // For each device in the Studio/Composition
5057     for (MappedDevice *device : m_devices) {
5058 
5059         // If this MappedDevice is connected, try the next.
5060         if (isConnected(device->getId()))
5061             continue;
5062 
5063         // If this device does not want a connection, try the next.
5064         if (device->getUserconnection() == "")
5065             continue;
5066 
5067         // ??? We need the "user connection" from MidiDevice.
5068         //
5069         //     How do we get the MidiDevice to get the user connection?
5070         //     I think the MidiDevice's live in Studio, which we are not
5071         //     privy to at this point.  So, MidiDevice is out of the
5072         //     question.
5073         //
5074         //     Can we maintain our own MappedDevice::m_userConnection?
5075         //
5076         //     RoseXmlHandler calls addDevice() to add devices to m_devices.
5077         //     At that point we might be able to take in a "user connection"
5078         //     and add it to MappedDevice.
5079         //
5080         //     But it wouldn't be kept in sync with the user's wishes and
5081         //     connections might get made that shouldn't.  E.g. if the user
5082         //     disconnects a device, then introduces a new synth, the old
5083         //     user connection from the .rg file will still be in here and
5084         //     might cause a connection.
5085         //
5086         //     We would need to track the user changing the connection
5087         //     (setConnection()) and update the user connection in
5088         //     MappedDevice.  Problem here is that setConnection() is used
5089         //     for automatic *and* user connections.  We would need a way
5090         //     to differentiate.
5091 
5092         // Try to make a connection.
5093         setPlausibleConnection(
5094                 device->getId(),
5095                 device->getUserConnection(),  // idealConnection
5096                 device->getDirection() == MidiDevice::Record)  // recordDevice
5097 
5098     }
5099 #endif
5100 }
5101 
5102 
5103 // From a DeviceId get a client/port pair for connecting as the
5104 // MIDI record device.
5105 //
5106 void
setRecordDevice(DeviceId id,bool connectAction)5107 AlsaDriver::setRecordDevice(DeviceId id, bool connectAction)
5108 {
5109     RG_DEBUG << "setRecordDevice(): device " << id << ", action " << connectAction;
5110 
5111     // Locate a suitable port
5112     //
5113     if (m_devicePortMap.find(id) == m_devicePortMap.end()) {
5114 #ifdef DEBUG_ALSA
5115         RG_DEBUG << "setRecordDevice() - couldn't match device id (" << id << ") to ALSA port";
5116 #endif
5117 
5118         return ;
5119     }
5120 
5121     ClientPortPair pair = m_devicePortMap[id];
5122 
5123     RG_DEBUG << "setRecordDevice(): port is " << pair.client << ":" << pair.port;
5124 
5125     snd_seq_addr_t sender, dest;
5126     sender.client = pair.client;
5127     sender.port = pair.port;
5128 
5129     MappedDevice *device = findDevice(id);
5130     if (!device)
5131         return;
5132 
5133     if (device->getDirection() == MidiDevice::Record) {
5134         if (device->isRecording() && connectAction) {
5135 #ifdef DEBUG_ALSA
5136             RG_DEBUG << "setRecordDevice() - attempting to subscribe (" << id << ") already subscribed";
5137 #endif
5138             return ;
5139         }
5140         if (!device->isRecording() && !connectAction) {
5141 #ifdef DEBUG_ALSA
5142             RG_DEBUG << "setRecordDevice() - attempting to unsubscribe (" << id << ") already unsubscribed";
5143 #endif
5144             return ;
5145         }
5146     } else {
5147 #ifdef DEBUG_ALSA
5148         RG_DEBUG << "setRecordDevice() - attempting to set play device (" << id << ") to record device";
5149 #endif
5150         return ;
5151     }
5152 
5153     snd_seq_port_subscribe_t *subs;
5154     snd_seq_port_subscribe_alloca(&subs);
5155 
5156     dest.client = m_client;
5157     dest.port = m_inputPort;
5158 
5159     // Set destinations and senders
5160     //
5161     snd_seq_port_subscribe_set_sender(subs, &sender);
5162     snd_seq_port_subscribe_set_dest(subs, &dest);
5163 
5164     // subscribe or unsubscribe the port
5165     //
5166     if (connectAction) {
5167         if (checkAlsaError(snd_seq_subscribe_port(m_midiHandle, subs),
5168                            "setRecordDevice - failed subscription of input port") < 0) {
5169             // Not the end of the world if this fails but we
5170             // have to flag it internally.
5171             //
5172             AUDIT << "AlsaDriver::setRecordDevice() - "
5173                   << int(sender.client) << ":" << int(sender.port)
5174                   << " failed to subscribe device "
5175                   << id << " as record port\n";
5176             RG_DEBUG << "setRecordDevice() - "
5177                   << int(sender.client) << ":" << int(sender.port)
5178                   << " failed to subscribe device "
5179                   << id << " as record port";
5180         } else {
5181             m_midiInputPortConnected = true;
5182             AUDIT << "AlsaDriver::setRecordDevice() - successfully subscribed device " << id << " as record port\n";
5183             RG_DEBUG << "setRecordDevice() - successfully subscribed device " << id << " as record port";
5184             device->setRecording(true);
5185         }
5186     } else {
5187         if (checkAlsaError(snd_seq_unsubscribe_port(m_midiHandle, subs),
5188                            "setRecordDevice - failed to unsubscribe a device") == 0) {
5189             AUDIT << "AlsaDriver::setRecordDevice() - "
5190                   << "successfully unsubscribed device "
5191                   << id << " as record port\n";
5192             RG_DEBUG << "setRecordDevice() - "
5193                   << "successfully unsubscribed device "
5194                   << id << " as record port";
5195             device->setRecording(false);
5196         }
5197     }
5198 }
5199 
5200 #if 0
5201 void
5202 AlsaDriver::unsetRecordDevices()
5203 {
5204     snd_seq_addr_t dest;
5205     dest.client = m_client;
5206     dest.port = m_inputPort;
5207 
5208     snd_seq_query_subscribe_t *qSubs;
5209     snd_seq_addr_t tmp_addr;
5210     snd_seq_query_subscribe_alloca(&qSubs);
5211 
5212     tmp_addr.client = m_client;
5213     tmp_addr.port = m_inputPort;
5214 
5215     // Unsubscribe any existing connections
5216     //
5217     snd_seq_query_subscribe_set_type(qSubs, SND_SEQ_QUERY_SUBS_WRITE);
5218     snd_seq_query_subscribe_set_index(qSubs, 0);
5219     snd_seq_query_subscribe_set_root(qSubs, &tmp_addr);
5220 
5221     while (snd_seq_query_port_subscribers(m_midiHandle, qSubs) >= 0) {
5222         tmp_addr = *snd_seq_query_subscribe_get_addr(qSubs);
5223 
5224         snd_seq_port_subscribe_t *dSubs;
5225         snd_seq_port_subscribe_alloca(&dSubs);
5226 
5227         snd_seq_addr_t dSender;
5228         dSender.client = tmp_addr.client;
5229         dSender.port = tmp_addr.port;
5230 
5231         snd_seq_port_subscribe_set_sender(dSubs, &dSender);
5232         snd_seq_port_subscribe_set_dest(dSubs, &dest);
5233 
5234         int error = snd_seq_unsubscribe_port(m_midiHandle, dSubs);
5235 
5236         if (error < 0) {
5237 #ifdef DEBUG_ALSA
5238             RG_DEBUG << "unsetRecordDevices() - can't unsubscribe record port";
5239 #endif
5240 
5241         }
5242 
5243         snd_seq_query_subscribe_set_index(qSubs,
5244                                           snd_seq_query_subscribe_get_index(qSubs) + 1);
5245     }
5246 }
5247 #endif
5248 
5249 void
sendMMC(MidiByte deviceArg,MidiByte instruction,bool isCommand,const std::string & data)5250 AlsaDriver::sendMMC(MidiByte deviceArg,
5251                     MidiByte instruction,
5252                     bool isCommand,
5253                     const std::string &data)
5254 {
5255     snd_seq_event_t event;
5256 
5257     snd_seq_ev_clear(&event);
5258     snd_seq_ev_set_source(&event, m_syncOutputPort);
5259     snd_seq_ev_set_subs(&event);
5260 
5261     unsigned char dataArr[10] =
5262         { MIDI_SYSTEM_EXCLUSIVE,
5263           MIDI_SYSEX_RT, deviceArg,
5264           (isCommand ? MIDI_SYSEX_RT_COMMAND : MIDI_SYSEX_RT_RESPONSE),
5265           instruction };
5266 
5267     std::string dataString = std::string((const char *)dataArr) +
5268         data + (char)MIDI_END_OF_EXCLUSIVE;
5269 
5270     snd_seq_ev_set_sysex(&event, dataString.length(),
5271                          (char *)dataString.c_str());
5272 
5273     event.queue = SND_SEQ_QUEUE_DIRECT;
5274 
5275     checkAlsaError(snd_seq_event_output_direct(m_midiHandle, &event),
5276                    "sendMMC event send");
5277 
5278     if (m_queueRunning) {
5279         checkAlsaError(snd_seq_drain_output(m_midiHandle), "sendMMC drain");
5280     }
5281 }
5282 
5283 // Send a system real-time message from the sync output port
5284 //
5285 void
sendSystemDirect(MidiByte command,int * args)5286 AlsaDriver::sendSystemDirect(MidiByte command, int *args)
5287 {
5288     snd_seq_event_t event;
5289 
5290     snd_seq_ev_clear(&event);
5291     snd_seq_ev_set_source(&event, m_syncOutputPort);
5292     snd_seq_ev_set_subs(&event);
5293 
5294     event.queue = SND_SEQ_QUEUE_DIRECT;
5295 
5296     // set the command
5297     event.type = command;
5298 
5299     // set args if we have them
5300     if (args) {
5301         event.data.control.value = *args;
5302     }
5303 
5304     int error = snd_seq_event_output_direct(m_midiHandle, &event);
5305 
5306     if (error < 0) {
5307 #ifdef DEBUG_ALSA
5308         RG_DEBUG << "sendSystemDirect() - can't send event (" << int(command) << ")";
5309 #endif
5310 
5311     }
5312 
5313     //    checkAlsaError(snd_seq_drain_output(m_midiHandle),
5314     //           "sendSystemDirect(): draining");
5315 }
5316 
5317 
5318 void
sendSystemQueued(MidiByte command,const std::string & args,const RealTime & time)5319 AlsaDriver::sendSystemQueued(MidiByte command,
5320                              const std::string &args,
5321                              const RealTime &time)
5322 {
5323     snd_seq_event_t event;
5324 
5325     snd_seq_ev_clear(&event);
5326     snd_seq_ev_set_source(&event, m_syncOutputPort);
5327     snd_seq_ev_set_subs(&event);
5328 
5329     snd_seq_real_time_t sendTime =
5330         { (unsigned int)time.sec, (unsigned int)time.nsec };
5331 
5332     // Schedule the command
5333     //
5334     event.type = command;
5335 
5336     snd_seq_ev_schedule_real(&event, m_queue, 0, &sendTime);
5337 
5338     // set args if we have them
5339     switch (args.length()) {
5340     case 1:
5341         event.data.control.value = args[0];
5342         break;
5343 
5344     case 2:
5345         event.data.control.value = int(args[0]) | (int(args[1]) << 7);
5346         break;
5347 
5348     default:  // do nothing
5349         break;
5350     }
5351 
5352     int error = snd_seq_event_output(m_midiHandle, &event);
5353 
5354     if (error < 0) {
5355 #ifdef DEBUG_ALSA
5356         RG_DEBUG << "sendSystemQueued() - "
5357                  << "can't send event (" << int(command) << ")"
5358                  << " - error = (" << error << ")";
5359 #endif
5360 
5361     }
5362 
5363     //    if (m_queueRunning) {
5364     //    checkAlsaError(snd_seq_drain_output(m_midiHandle), "sendSystemQueued(): draining");
5365     //    }
5366 }
5367 
5368 
5369 void
claimUnwantedPlugin(void * plugin)5370 AlsaDriver::claimUnwantedPlugin(void *plugin)
5371 {
5372     m_pluginScavenger.claim((RunnablePluginInstance *)plugin);
5373 }
5374 
5375 
5376 void
scavengePlugins()5377 AlsaDriver::scavengePlugins()
5378 {
5379     m_pluginScavenger.scavenge();
5380 }
5381 
5382 QString
getStatusLog()5383 AlsaDriver::getStatusLog()
5384 {
5385     return strtoqstr(AUDIT.str());
5386 }
5387 
5388 void
sleep(const RealTime & rt)5389 AlsaDriver::sleep(const RealTime &rt)
5390 {
5391     int npfd = snd_seq_poll_descriptors_count(m_midiHandle, POLLIN);
5392     struct pollfd *pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
5393     snd_seq_poll_descriptors(m_midiHandle, pfd, npfd, POLLIN);
5394     poll(pfd, npfd, rt.sec * 1000 + rt.msec());
5395 }
5396 
5397 void
runTasks()5398 AlsaDriver::runTasks()
5399 {
5400 #ifdef HAVE_LIBJACK
5401     if (m_jackDriver) {
5402         if (!m_jackDriver->isOK()) {
5403             m_jackDriver->restoreIfRestorable();
5404         }
5405     }
5406 
5407     if (m_doTimerChecks && m_timerRatioCalculated) {
5408 
5409         double ratio = m_timerRatio;
5410         m_timerRatioCalculated = false;
5411 
5412         snd_seq_queue_tempo_t *q_ptr;
5413         snd_seq_queue_tempo_alloca(&q_ptr);
5414 
5415         snd_seq_get_queue_tempo(m_midiHandle, m_queue, q_ptr);
5416 
5417         unsigned int t_skew = snd_seq_queue_tempo_get_skew(q_ptr);
5418 #ifdef DEBUG_ALSA
5419 
5420         unsigned int t_base = snd_seq_queue_tempo_get_skew_base(q_ptr);
5421         if (!m_playing) {
5422             RG_DEBUG << "runTasks(): Skew: " << t_skew << "/" << t_base;
5423         }
5424 #endif
5425 
5426         unsigned int newSkew = t_skew + (unsigned int)(t_skew * ratio);
5427 
5428         if (newSkew != t_skew) {
5429 #ifdef DEBUG_ALSA
5430             if (!m_playing) {
5431                 RG_DEBUG << "runTasks():     changed to " << newSkew;
5432             }
5433 #endif
5434             snd_seq_queue_tempo_set_skew(q_ptr, newSkew);
5435             snd_seq_set_queue_tempo( m_midiHandle, m_queue, q_ptr);
5436         }
5437 
5438         m_firstTimerCheck = true;
5439     }
5440 
5441 #endif
5442 }
5443 
5444 void
reportFailure(MappedEvent::FailureCode code)5445 AlsaDriver::reportFailure(MappedEvent::FailureCode code)
5446 {
5447     //#define REPORT_XRUNS 1
5448 #ifndef REPORT_XRUNS
5449     if (code == MappedEvent::FailureXRuns ||
5450         code == MappedEvent::FailureDiscUnderrun ||
5451         code == MappedEvent::FailureBussMixUnderrun ||
5452         code == MappedEvent::FailureMixUnderrun) {
5453         return ;
5454     }
5455 #endif
5456 
5457     // Ignore consecutive duplicates
5458     if (failureReportWriteIndex > 0 &&
5459         failureReportWriteIndex != failureReportReadIndex) {
5460         if (code == failureReports[failureReportWriteIndex - 1])
5461             return ;
5462     }
5463 
5464     failureReports[failureReportWriteIndex] = code;
5465     failureReportWriteIndex =
5466         (failureReportWriteIndex + 1) % FAILURE_REPORT_COUNT;
5467 }
5468 
5469 std::string
getAlsaVersion()5470 AlsaDriver::getAlsaVersion()
5471 {
5472     FILE *versionFile = fopen("/proc/asound/version", "r");
5473 
5474     if (!versionFile)
5475         return "(unknown)";
5476 
5477     // Examples:
5478     // Advanced Linux Sound Architecture Driver Version 1.0.14rc3.
5479     //   "1.0.14rc3"
5480     // Advanced Linux Sound Architecture Driver Version 1.0.14 (Thu May 31 09:03:25 2008 UTC).
5481     //   "1.0.14 (Thu May 31 09:03:25 2008 UTC)"
5482     // Advanced Linux Sound Architecture Driver Version k5.4.0-51-lowlatency.
5483     //   "5.4.0-52-lowlatency"
5484 
5485     const int bufSize = 256;
5486     char buf[bufSize];
5487     // Get the version line.  If it fails...
5488     if (fgets(buf, bufSize, versionFile) == nullptr) {
5489         fclose(versionFile);
5490         return "(unknown)";
5491     }
5492 
5493     fclose(versionFile);
5494 
5495     std::string versionString(buf);
5496 
5497     // Find the decimal.
5498     std::string::size_type startPos = versionString.find_first_of('.');
5499 
5500     if (startPos > 0  &&  startPos != std::string::npos) {
5501         // Scan for digits backwards to find the beginning of the version
5502         // number.  We scan for digits because extractVersion() requires
5503         // that the version string starts with the major version number.
5504         while (startPos > 0  &&  isdigit(versionString[startPos-1]))
5505             --startPos;
5506 
5507         versionString = versionString.substr(startPos);
5508 
5509         // Remove trailing LF
5510         if (versionString.length() > 0  &&  versionString[versionString.length()-1] == '\n')
5511             versionString = versionString.substr(0, versionString.length()-1);
5512 
5513         // Remove trailing "."
5514         if (versionString.length() > 0  &&  versionString[versionString.length()-1] == '.')
5515             versionString = versionString.substr(0, versionString.length()-1);
5516 
5517         return versionString;
5518     }
5519 
5520     return "(unknown)";
5521 
5522 }
5523 
5524 std::string
getKernelVersionString()5525 AlsaDriver::getKernelVersionString()
5526 {
5527     FILE *v = fopen("/proc/version", "r");
5528 
5529     if (v) {
5530         char buf[256];
5531         if (fgets(buf, 256, v) == nullptr) {
5532             fclose(v);
5533             return "(unknown)"; /* check fgets result */
5534         }
5535         fclose(v);
5536 
5537         std::string vs(buf);
5538         std::string key(" version ");
5539         std::string::size_type sp = vs.find(key);
5540         if (sp != std::string::npos) {
5541             vs = vs.substr(sp + key.length());
5542             sp = vs.find(' ');
5543             if (sp != std::string::npos) {
5544                 vs = vs.substr(0, sp);
5545             }
5546             if (vs.length() > 0 && vs[vs.length()-1] == '\n') {
5547                 vs = vs.substr(0, vs.length()-1);
5548             }
5549             return vs;
5550         }
5551     }
5552 
5553     return "(unknown)";
5554 }
5555 
5556 void
extractVersion(std::string v,int & major,int & minor,int & subminor,std::string & suffix)5557 AlsaDriver::extractVersion(std::string v, int &major, int &minor, int &subminor, std::string &suffix)
5558 {
5559     major = minor = subminor = 0;
5560     suffix = "";
5561     if (v == "(unknown)") return;
5562 
5563     std::string::size_type sp, pp;
5564 
5565     sp = v.find('.');
5566     if (sp == std::string::npos) goto done;
5567     major = atoi(v.substr(0, sp).c_str());
5568     pp = sp + 1;
5569 
5570     sp = v.find('.', pp);
5571     if (sp == std::string::npos) goto done;
5572     minor = atoi(v.substr(pp, sp - pp).c_str());
5573     pp = sp + 1;
5574 
5575     while (++sp < v.length() && (::isdigit(v[sp]) || v[sp] == '-')) { }
5576     subminor = atoi(v.substr(pp, sp - pp).c_str());
5577 
5578     if (sp >= v.length()) goto done;
5579     suffix = v.substr(sp);
5580 
5581 done:
5582     RG_DEBUG << "extractVersion(): major = " << major << ", minor = " << minor << ", subminor = " << subminor << ", suffix = \"" << suffix << "\"";
5583 }
5584 
5585 bool
versionIsAtLeast(std::string v,int major,int minor,int subminor)5586 AlsaDriver::versionIsAtLeast(std::string v, int major, int minor, int subminor)
5587 {
5588     int actualMajor, actualMinor, actualSubminor;
5589     std::string actualSuffix;
5590 
5591     extractVersion(v, actualMajor, actualMinor, actualSubminor, actualSuffix);
5592 
5593     bool ok = false;
5594 
5595     if (actualMajor > major) {
5596         ok = true;
5597     } else if (actualMajor == major) {
5598         if (actualMinor > minor) {
5599             ok = true;
5600         } else if (actualMinor == minor) {
5601             if (actualSubminor > subminor) {
5602                 ok = true;
5603             } else if (actualSubminor == subminor) {
5604                 // If the ALSA driver's version does not include "rc" or "pre",
5605                 // then we are ok.
5606                 // ??? So this is "versionIsAtLeastAndNotPreOrRC()".  I'm
5607                 //     guessing we can remove this.
5608                 if (strncmp(actualSuffix.c_str(), "rc", 2) &&
5609                     strncmp(actualSuffix.c_str(), "pre", 3)) {
5610                     ok = true;
5611                 }
5612             }
5613         }
5614     }
5615 
5616     RG_DEBUG << "versionIsAtLeast(): is version " << v << " at least " << major << "." << minor << "." << subminor << "? " << (ok ? "yes" : "no");
5617     return ok;
5618 }
5619 
5620 bool
throttledDebug() const5621 AlsaDriver::throttledDebug() const
5622 {
5623     if (!m_debug)
5624         return false;
5625 
5626     static bool active = true;
5627     static int count = 0;
5628     static QTime timeout;
5629 
5630     // if we are active
5631     if (active) {
5632         ++count;
5633         // if we've done too many
5634         if (count > 5) {
5635             active = false;
5636             timeout = QTime::currentTime().addSecs(5);
5637             return false;
5638         }
5639         return true;
5640     } else {
5641         // if current time > timeout
5642         if (QTime::currentTime() > timeout) {
5643             active = true;
5644             count = 1;
5645             return true;
5646         }
5647         return false;
5648     }
5649 
5650     return false;
5651 }
5652 
5653 bool
portInUse(int client,int port) const5654 AlsaDriver::portInUse(int client, int port) const
5655 {
5656     // If the client/port is in m_devicePortMap, then it
5657     // is in use.  See setConnectionToDevice().
5658 
5659     for (DevicePortMap::const_iterator dpmi =
5660              m_devicePortMap.begin();
5661          dpmi != m_devicePortMap.end();
5662          ++dpmi) {
5663         if (dpmi->second.client == client  &&
5664             dpmi->second.port == port) {
5665             return true;
5666         }
5667     }
5668 
5669     // Not found, so not in use.
5670     return false;
5671 }
5672 
5673 bool
isConnected(DeviceId deviceId) const5674 AlsaDriver::isConnected(DeviceId deviceId) const
5675 {
5676     DevicePortMap::const_iterator deviceIter = m_devicePortMap.find(deviceId);
5677 
5678     // Device not found?  Bail.
5679     if (deviceIter == m_devicePortMap.end())
5680         return false;
5681 
5682     // Return true if the client/port are valid.
5683     return (deviceIter->second != ClientPortPair()  &&
5684             deviceIter->second != ClientPortPair(-1,-1));
5685 }
5686 
handleTransportCCs(unsigned controlNumber,int value)5687 bool AlsaDriver::handleTransportCCs(unsigned controlNumber, int value)
5688 {
5689     // If transport CCs are not enabled, bail.
5690     if (!m_acceptTransportCCs)
5691         return false;
5692 
5693     // Play
5694     if (controlNumber == 117) {
5695         // Press
5696         if (value == 127) {
5697             if (!isPlaying()) {
5698                 RosegardenSequencer::getInstance()->transportChange(
5699                         RosegardenSequencer::TransportPlay);
5700             }
5701         }
5702 
5703         // We've recognized and handled this.  Do not process it further.
5704         return true;
5705     }
5706 
5707     // Record
5708     if (controlNumber == 118) {
5709         // Press
5710         if (value == 127) {
5711             if (!isPlaying()) {
5712                 RosegardenSequencer::getInstance()->transportChange(
5713                         RosegardenSequencer::TransportRecord);
5714             }
5715         }
5716 
5717         // We've recognized and handled this.  Do not process it further.
5718         return true;
5719     }
5720 
5721     // Stop
5722     if (controlNumber == 116) {
5723         // Press
5724         if (value == 127) {
5725             // This approach works, but you don't get the double-press
5726             // stop behavior (return to where playback started).
5727             //if (isPlaying()) {
5728             //    RosegardenSequencer::getInstance()->transportChange(
5729             //            RosegardenSequencer::TransportStop);
5730             //}
5731 
5732             // This gives the double-stop behavior.
5733             QEvent *event = new QEvent(Stop);
5734             QCoreApplication::postEvent(
5735                     RosegardenMainWindow::self(), event);
5736         }
5737 
5738         // We've recognized and handled this.  Do not process it further.
5739         return true;
5740     }
5741 
5742     // Previous track
5743     if (controlNumber == 110) {
5744         // Press
5745         if (value == 127) {
5746             QEvent *event = new QEvent(PreviousTrack);
5747             QCoreApplication::postEvent(
5748                     RosegardenMainWindow::self(), event);
5749         }
5750 
5751         // We've recognized and handled this.  Do not process it further.
5752         return true;
5753     }
5754 
5755     // Next track
5756     if (controlNumber == 111) {
5757         if (value == 127) {
5758             QEvent *event = new QEvent(NextTrack);
5759             QCoreApplication::postEvent(
5760                     RosegardenMainWindow::self(), event);
5761         }
5762 
5763         // We've recognized and handled this.  Do not process it further.
5764         return true;
5765     }
5766 
5767     // Loop
5768     if (controlNumber == 113) {
5769         if (value == 127) {
5770             QEvent *event = new QEvent(Loop);
5771             QCoreApplication::postEvent(
5772                     RosegardenMainWindow::self(), event);
5773         }
5774 
5775         // We've recognized and handled this.  Do not process it further.
5776         return true;
5777     }
5778 
5779     // Rewind
5780     if (controlNumber == 114) {
5781         QEvent *event = new ButtonEvent(Rewind, (value == 127));
5782         QCoreApplication::postEvent(
5783                 RosegardenMainWindow::self(), event);
5784 
5785         // We've recognized and handled this.  Do not process it further.
5786         return true;
5787     }
5788 
5789     // Fast Forward
5790     if (controlNumber == 115) {
5791         QEvent *event = new ButtonEvent(FastForward, (value == 127));
5792         QCoreApplication::postEvent(
5793                 RosegardenMainWindow::self(), event);
5794 
5795         // We've recognized and handled this.  Do not process it further.
5796         return true;
5797     }
5798 
5799     // Don't know what this is.  Continue processing.
5800     return false;
5801 }
5802 
5803 MappedDevice *
findDevice(DeviceId deviceId)5804 AlsaDriver::findDevice(DeviceId deviceId)
5805 {
5806     for (size_t i = 0; i < m_devices.size(); ++i) {
5807         if (m_devices[i]->getId() == deviceId)
5808             return m_devices[i];
5809     }
5810 
5811     return nullptr;
5812 }
5813 
5814 MappedInstrument*
getMappedInstrument(InstrumentId id)5815 AlsaDriver::getMappedInstrument(InstrumentId id)
5816 {
5817     std::vector<MappedInstrument*>::const_iterator it;
5818 
5819     for (it = m_instruments.begin(); it != m_instruments.end(); ++it) {
5820         if ((*it)->getId() == id)
5821             return (*it);
5822     }
5823 
5824     return nullptr;
5825 }
5826 
5827 void
cancelAudioFile(const MappedEvent * mE)5828 AlsaDriver::cancelAudioFile(const MappedEvent *mE)
5829 {
5830     RG_DEBUG << "cancelAudioFile()";
5831 
5832     if (!m_audioQueue)
5833         return ;
5834 
5835     // For now we only permit cancelling unscheduled files.
5836 
5837     const AudioPlayQueue::FileList &files = m_audioQueue->getAllUnscheduledFiles();
5838     for (AudioPlayQueue::FileList::const_iterator fi = files.begin();
5839             fi != files.end(); ++fi) {
5840         PlayableAudioFile *file = *fi;
5841         if (mE->getRuntimeSegmentId() == -1) {
5842 
5843             // ERROR? The comparison between file->getAudioFile()->getId() of type unsigned int
5844             //        and mE->getAudioID() of type int.
5845             if (file->getInstrument() == mE->getInstrument() &&
5846                     int(file->getAudioFile()->getId()) == mE->getAudioID()) {
5847                 file->cancel();
5848             }
5849         } else {
5850             if (file->getRuntimeSegmentId() == mE->getRuntimeSegmentId() &&
5851                     file->getStartTime() == mE->getEventTime()) {
5852                 file->cancel();
5853             }
5854         }
5855     }
5856 }
5857 
5858 void
clearAudioQueue()5859 AlsaDriver::clearAudioQueue()
5860 {
5861     RG_DEBUG << "clearAudioQueue()";
5862 
5863     if (m_audioQueue->empty())
5864         return ;
5865 
5866     AudioPlayQueue *newQueue = new AudioPlayQueue();
5867     AudioPlayQueue *oldQueue = m_audioQueue;
5868     m_audioQueue = newQueue;
5869     if (oldQueue)
5870         m_audioQueueScavenger.claim(oldQueue);
5871 }
5872 
5873 
5874 }
5875 
5876 
5877 #endif // HAVE_ALSA
5878