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