2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <pbd/error.h>
21 #include <sigc++/retype.h>
22 #include <sigc++/retype_return.h>
23 #include <sigc++/bind.h>
25 #include <ardour/audio_track.h>
26 #include <ardour/diskstream.h>
27 #include <ardour/session.h>
28 #include <ardour/redirect.h>
29 #include <ardour/audioregion.h>
30 #include <ardour/route_group_specialized.h>
31 #include <ardour/insert.h>
32 #include <ardour/audioplaylist.h>
33 #include <ardour/panner.h>
34 #include <ardour/utils.h>
41 //using namespace sigc;
42 using namespace ARDOUR;
44 AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag)
45 : Route (sess, name, 1, -1, -1, -1, flag),
47 _midi_rec_enable_control (*this, _session.midi_port())
49 DiskStream::Flag dflags = DiskStream::Flag (0);
51 if (_flags & Hidden) {
52 dflags = DiskStream::Flag (dflags | DiskStream::Hidden);
54 dflags = DiskStream::Flag (dflags | DiskStream::Recordable);
57 DiskStream* ds = new DiskStream (_session, name, dflags);
59 set_diskstream (*ds, this);
62 _freeze_record.state = NoFreeze;
63 _saved_meter_point = _meter_point;
65 // we do this even though Route already did it in it's init
66 reset_midi_control (_session.midi_port(), _session.get_midi_control());
70 AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
71 : Route (sess, "to be renamed", 0, 0, -1, -1),
73 _midi_rec_enable_control (*this, _session.midi_port())
75 _freeze_record.state = NoFreeze;
78 _saved_meter_point = _meter_point;
80 // we do this even though Route already did it in it's init
81 reset_midi_control (_session.midi_port(), _session.get_midi_control());
84 AudioTrack::~AudioTrack ()
92 AudioTrack::deprecated_use_diskstream_connections ()
94 if (diskstream->deprecated_io_node == 0) {
98 const XMLProperty* prop;
99 XMLNode& node (*diskstream->deprecated_io_node);
101 /* don't do this more than once. */
103 diskstream->deprecated_io_node = 0;
105 set_input_minimum (-1);
106 set_input_maximum (-1);
107 set_output_minimum (-1);
108 set_output_maximum (-1);
110 if ((prop = node.property ("gain")) != 0) {
111 set_gain (atof (prop->value().c_str()), this);
112 _gain = _desired_gain;
115 if ((prop = node.property ("input-connection")) != 0) {
116 Connection* c = _session.connection_by_name (prop->value());
119 error << string_compose(_("Unknown connection \"%1\" listed for input of %2"), prop->value(), _name) << endmsg;
121 if ((c = _session.connection_by_name (_("in 1"))) == 0) {
122 error << _("No input connections available as a replacement")
126 info << string_compose (_("Connection %1 was not available - \"in 1\" used instead"), prop->value())
131 use_input_connection (*c, this);
133 } else if ((prop = node.property ("inputs")) != 0) {
134 if (set_inputs (prop->value())) {
135 error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
144 AudioTrack::set_diskstream (DiskStream& ds, void *src)
150 diskstream = &ds.ref();
151 diskstream->set_io (*this);
153 if (diskstream->deprecated_io_node) {
155 if (!connecting_legal) {
156 ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
158 deprecated_use_diskstream_connections ();
162 diskstream->set_record_enabled (false, this);
163 diskstream->monitor_input (false);
165 ic_connection.disconnect();
166 ic_connection = input_changed.connect (mem_fun (*diskstream, &DiskStream::handle_input_change));
168 diskstream_changed (src); /* EMIT SIGNAL */
174 AudioTrack::use_diskstream (string name)
178 if ((dstream = _session.diskstream_by_name (name)) == 0) {
179 error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), name) << endmsg;
183 return set_diskstream (*dstream, this);
187 AudioTrack::use_diskstream (id_t id)
191 if ((dstream = _session.diskstream_by_id (id)) == 0) {
192 error << string_compose(_("AudioTrack: diskstream \"%1\" not known by session"), id) << endmsg;
196 return set_diskstream (*dstream, this);
200 AudioTrack::record_enabled () const
202 return diskstream->record_enabled ();
206 AudioTrack::set_record_enable (bool yn, void *src)
208 if (_freeze_record.state == Frozen) {
212 if (_mix_group && src != _mix_group && _mix_group->is_active()) {
213 _mix_group->apply (&AudioTrack::set_record_enable, yn, _mix_group);
217 /* keep track of the meter point as it was before we rec-enabled */
219 if (!diskstream->record_enabled()) {
220 _saved_meter_point = _meter_point;
223 diskstream->set_record_enabled (yn, src);
225 if (diskstream->record_enabled()) {
226 set_meter_point (MeterInput, this);
228 set_meter_point (_saved_meter_point, this);
231 if (_session.get_midi_feedback()) {
232 _midi_rec_enable_control.send_feedback (record_enabled());
238 AudioTrack::set_meter_point (MeterPoint p, void *src)
240 Route::set_meter_point (p, src);
244 AudioTrack::state(bool full_state)
246 XMLNode& track_state (Route::state (full_state));
249 /* we don't return diskstream state because we don't
250 own the diskstream exclusively. control of the diskstream
251 state is ceded to the Session, even if we create the
255 snprintf (buf, sizeof (buf), "%" PRIu64, diskstream->id());
256 track_state.add_property ("diskstream-id", buf);
262 AudioTrack::set_state (const XMLNode& node)
264 const XMLProperty *prop;
265 XMLNodeConstIterator iter;
266 XMLNodeList midi_kids;
268 if (Route::set_state (node)) {
272 midi_kids = node.children ("MIDI");
274 for (iter = midi_kids.begin(); iter != midi_kids.end(); ++iter) {
277 XMLNodeConstIterator miter;
280 kids = (*iter)->children ();
282 for (miter = kids.begin(); miter != kids.end(); ++miter) {
286 if (child->name() == "rec_enable") {
288 MIDI::eventType ev = MIDI::on; /* initialize to keep gcc happy */
289 MIDI::byte additional = 0; /* ditto */
290 MIDI::channel_t chn = 0; /* ditto */
292 if (get_midi_node_info (child, ev, chn, additional)) {
293 _midi_rec_enable_control.set_control_type (chn, ev, additional);
295 error << string_compose(_("MIDI rec_enable control specification for %1 is incomplete, so it has been ignored"), _name) << endmsg;
302 if ((prop = node.property ("diskstream-id")) == 0) {
304 /* some old sessions use the diskstream name rather than the ID */
306 if ((prop = node.property ("diskstream")) == 0) {
307 fatal << _("programming error: AudioTrack given state without diskstream!") << endmsg;
312 if (use_diskstream (prop->value())) {
318 id_t id = strtoull (prop->value().c_str(), 0, 10);
320 if (use_diskstream (id)) {
325 pending_state = const_cast<XMLNode*> (&node);
327 _session.StateReady.connect (mem_fun (*this, &AudioTrack::set_state_part_two));
333 AudioTrack::get_state()
335 XMLNode& root (Route::get_state());
336 XMLNode* freeze_node;
339 if (_freeze_record.playlist) {
342 freeze_node = new XMLNode (X_("freeze-info"));
343 freeze_node->add_property ("playlist", _freeze_record.playlist->name());
344 snprintf (buf, sizeof (buf), "%d", (int) _freeze_record.state);
345 freeze_node->add_property ("state", buf);
347 for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
348 inode = new XMLNode (X_("insert"));
349 snprintf (buf, sizeof (buf), "%" PRIu64, (*i)->id);
350 inode->add_property (X_("id"), buf);
351 inode->add_child_copy ((*i)->state);
353 freeze_node->add_child_nocopy (*inode);
356 root.add_child_nocopy (*freeze_node);
359 /* Alignment: act as a proxy for the diskstream */
361 XMLNode* align_node = new XMLNode (X_("alignment"));
362 switch (diskstream->alignment_style()) {
363 case ExistingMaterial:
364 snprintf (buf, sizeof (buf), X_("existing"));
367 snprintf (buf, sizeof (buf), X_("capture"));
370 align_node->add_property (X_("style"), buf);
371 root.add_child_nocopy (*align_node);
377 MIDI::byte additional;
378 XMLNode* midi_node = 0;
380 XMLNodeList midikids;
382 midikids = root.children ("MIDI");
383 if (!midikids.empty()) {
384 midi_node = midikids.front();
387 midi_node = root.add_child ("MIDI");
390 if (_midi_rec_enable_control.get_control_info (chn, ev, additional) && midi_node) {
392 child = midi_node->add_child ("rec_enable");
393 set_midi_node_info (child, ev, chn, additional);
401 AudioTrack::set_state_part_two ()
405 LocaleGuard lg (X_("POSIX"));
407 /* This is called after all session state has been restored but before
408 have been made ports and connections are established.
411 if (pending_state == 0) {
415 if ((fnode = find_named_node (*pending_state, X_("freeze-info"))) != 0) {
418 _freeze_record.have_mementos = false;
419 _freeze_record.state = Frozen;
421 for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
424 _freeze_record.insert_info.clear ();
426 if ((prop = fnode->property (X_("playlist"))) != 0) {
427 Playlist* pl = _session.playlist_by_name (prop->value());
429 _freeze_record.playlist = dynamic_cast<AudioPlaylist*> (pl);
431 _freeze_record.playlist = 0;
432 _freeze_record.state = NoFreeze;
437 if ((prop = fnode->property (X_("state"))) != 0) {
438 _freeze_record.state = (FreezeState) atoi (prop->value().c_str());
441 XMLNodeConstIterator citer;
442 XMLNodeList clist = fnode->children();
444 for (citer = clist.begin(); citer != clist.end(); ++citer) {
445 if ((*citer)->name() != X_("insert")) {
449 if ((prop = (*citer)->property (X_("id"))) == 0) {
453 FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo (*((*citer)->children().front()));
455 sscanf (prop->value().c_str(), "%" PRIu64, &frii->id);
456 _freeze_record.insert_info.push_back (frii);
460 /* Alignment: act as a proxy for the diskstream */
462 if ((fnode = find_named_node (*pending_state, X_("alignment"))) != 0) {
464 if ((prop = fnode->property (X_("style"))) != 0) {
465 if (prop->value() == "existing") {
466 diskstream->set_persistent_align_style (ExistingMaterial);
467 } else if (prop->value() == "capture") {
468 diskstream->set_persistent_align_style (CaptureTime);
476 AudioTrack::n_process_buffers ()
478 return max ((uint32_t) diskstream->n_channels(), redirect_max_outs);
482 AudioTrack::passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter)
484 uint32_t nbufs = n_process_buffers ();
485 process_output_buffers (_session.get_silent_buffers (nbufs), nbufs, start_frame, end_frame, nframes, offset, true, declick, meter);
489 AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset,
490 bool session_state_changing, bool can_record, bool rec_monitors_input)
492 if (n_outputs() == 0) {
497 silence (nframes, offset);
501 if (session_state_changing) {
503 /* XXX is this safe to do against transport state changes? */
505 passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
509 diskstream->check_record_status (start_frame, nframes, can_record);
513 if (_have_internal_generator) {
514 /* since the instrument has no input streams,
515 there is no reason to send any signal
521 if (_session.get_auto_input()) {
522 if (Config->get_no_sw_monitoring()) {
525 send_silence = false;
528 if (diskstream->record_enabled()) {
529 if (Config->get_no_sw_monitoring()) {
532 send_silence = false;
540 apply_gain_automation = false;
544 /* if we're sending silence, but we want the meters to show levels for the signal,
548 if (_have_internal_generator) {
549 passthru_silence (start_frame, end_frame, nframes, offset, 0, true);
551 if (_meter_point == MeterInput) {
552 just_meter_input (start_frame, end_frame, nframes, offset);
554 passthru_silence (start_frame, end_frame, nframes, offset, 0, false);
559 /* we're sending signal, but we may still want to meter the input.
562 passthru (start_frame, end_frame, nframes, offset, 0, (_meter_point == MeterInput));
569 AudioTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, int declick,
570 bool can_record, bool rec_monitors_input)
575 jack_nframes_t transport_frame;
577 automation_snapshot (start_frame);
579 if (n_outputs() == 0 && _redirects.empty()) {
584 silence (nframes, offset);
588 transport_frame = _session.transport_frame();
590 if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) {
591 /* need to do this so that the diskstream sets its
592 playback distance to zero, thus causing diskstream::commit
595 return diskstream->process (transport_frame, 0, 0, can_record, rec_monitors_input);
599 apply_gain_automation = false;
601 if ((dret = diskstream->process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) {
603 silence (nframes, offset);
608 /* special condition applies */
610 if (_meter_point == MeterInput) {
611 just_meter_input (start_frame, end_frame, nframes, offset);
614 if (diskstream->record_enabled() && !can_record && !_session.get_auto_input()) {
616 /* not actually recording, but we want to hear the input material anyway,
617 at least potentially (depending on monitoring options)
620 passthru (start_frame, end_frame, nframes, offset, 0, true);
622 } else if ((b = diskstream->playback_buffer(0)) != 0) {
625 XXX is it true that the earlier test on n_outputs()
626 means that we can avoid checking it again here? i think
627 so, because changing the i/o configuration of an IO
628 requires holding the AudioEngine lock, which we hold
629 while in the process() tree.
633 /* copy the diskstream data to all output buffers */
635 vector<Sample*>& bufs = _session.get_passthru_buffers ();
636 uint32_t limit = n_process_buffers ();
642 for (i = 0, n = 1; i < limit; ++i, ++n) {
643 memcpy (bufs[i], b, sizeof (Sample) * nframes);
644 if (n < diskstream->n_channels()) {
645 tmpb = diskstream->playback_buffer(n);
652 /* don't waste time with automation if we're recording */
654 if (!diskstream->record_enabled()) {
656 if (gain_automation_playback()) {
657 apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
661 process_output_buffers (bufs, limit, start_frame, end_frame, nframes, offset, (!_session.get_record_enabled() || _session.get_recording_plugins()), declick, (_meter_point != MeterInput));
664 /* problem with the diskstream; just be quiet for a bit */
665 silence (nframes, offset);
672 AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset,
673 bool can_record, bool rec_monitors_input)
675 if (n_outputs() == 0 && _redirects.empty()) {
680 silence (nframes, offset);
685 apply_gain_automation = false;
687 silence (nframes, offset);
689 return diskstream->process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input);
693 AudioTrack::toggle_monitor_input ()
695 for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
696 (*i)->request_monitor_input(!(*i)->monitoring_input());
701 AudioTrack::set_name (string str, void *src)
703 if (record_enabled() && _session.actively_recording()) {
704 /* this messes things up if done while recording */
708 diskstream->set_name (str, src);
709 return IO::set_name (str, src);
713 AudioTrack::export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
715 gain_t gain_automation[nframes];
716 gain_t gain_buffer[nframes];
717 float mix_buffer[nframes];
718 RedirectList::iterator i;
719 bool post_fader_work = false;
720 gain_t this_gain = _gain;
721 vector<Sample*>::iterator bi;
724 LockMonitor rlock (redirect_lock, __LINE__, __FILE__);
726 if (diskstream->playlist()->read (buffers[0], mix_buffer, gain_buffer, start, nframes) != nframes) {
731 bi = buffers.begin();
734 for (; bi != buffers.end(); ++bi, ++n) {
735 if (n < diskstream->n_channels()) {
736 if (diskstream->playlist()->read ((*bi), mix_buffer, gain_buffer, start, nframes, n) != nframes) {
742 /* duplicate last across remaining buffers */
743 memcpy ((*bi), b, sizeof (Sample) * nframes);
748 /* note: only run inserts during export. other layers in the machinery
749 will already have checked that there are no external port inserts.
752 for (i = _redirects.begin(); i != _redirects.end(); ++i) {
755 if ((insert = dynamic_cast<Insert*>(*i)) != 0) {
756 switch (insert->placement()) {
758 insert->run (buffers, nbufs, nframes, 0);
761 post_fader_work = true;
767 if (_gain_automation_curve.automation_state() == Play) {
769 _gain_automation_curve.get_vector (start, start + nframes, gain_automation, nframes);
771 for (bi = buffers.begin(); bi != buffers.end(); ++bi) {
773 for (jack_nframes_t n = 0; n < nframes; ++n) {
774 b[n] *= gain_automation[n];
780 for (bi = buffers.begin(); bi != buffers.end(); ++bi) {
782 for (jack_nframes_t n = 0; n < nframes; ++n) {
788 if (post_fader_work) {
790 for (i = _redirects.begin(); i != _redirects.end(); ++i) {
791 PluginInsert *insert;
793 if ((insert = dynamic_cast<PluginInsert*>(*i)) != 0) {
794 switch ((*i)->placement()) {
798 insert->run (buffers, nbufs, nframes, 0);
809 AudioTrack::set_latency_delay (jack_nframes_t longest_session_latency)
811 Route::set_latency_delay (longest_session_latency);
812 diskstream->set_roll_delay (_roll_delay);
816 AudioTrack::update_total_latency ()
820 for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
821 if ((*i)->active ()) {
822 _own_latency += (*i)->latency ();
826 set_port_latency (_own_latency);
832 AudioTrack::bounce (InterThreadInfo& itt)
834 vector<Source*> srcs;
835 _session.write_one_track (*this, 0, _session.current_end_frame(), false, srcs, itt);
840 AudioTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo& itt)
842 vector<Source*> srcs;
843 _session.write_one_track (*this, start, end, false, srcs, itt);
847 AudioTrack::freeze (InterThreadInfo& itt)
850 vector<Source*> srcs;
851 string new_playlist_name;
852 Playlist* new_playlist;
857 if ((_freeze_record.playlist = diskstream->playlist()) == 0) {
863 while (n < (UINT_MAX-1)) {
867 candidate = string_compose ("<F%2>%1", _freeze_record.playlist->name(), n);
869 if (_session.playlist_by_name (candidate) == 0) {
870 new_playlist_name = candidate;
878 if (n == (UINT_MAX-1)) {
879 error << string_compose (X_("There Are too many frozen versions of playlist \"%1\""
880 " to create another one"), _freeze_record.playlist->name())
885 if (_session.write_one_track (*this, 0, _session.current_end_frame(), true, srcs, itt)) {
889 _freeze_record.insert_info.clear ();
890 _freeze_record.have_mementos = true;
893 LockMonitor lm (redirect_lock, __LINE__, __FILE__);
895 for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
897 if ((insert = dynamic_cast<Insert*>(*r)) != 0) {
899 FreezeRecordInsertInfo* frii = new FreezeRecordInsertInfo ((*r)->get_state());
901 frii->insert = insert;
902 frii->id = insert->id();
903 frii->memento = (*r)->get_memento();
905 _freeze_record.insert_info.push_back (frii);
907 /* now deactivate the insert */
909 insert->set_active (false, this);
914 new_playlist = new AudioPlaylist (_session, new_playlist_name, false);
915 region_name = new_playlist_name;
917 /* create a new region from all filesources, keep it private */
919 region = new AudioRegion (srcs, 0, srcs[0]->length(),
921 (AudioRegion::Flag) (AudioRegion::WholeFile|AudioRegion::DefaultFlags),
924 new_playlist->set_orig_diskstream_id (diskstream->id());
925 new_playlist->add_region (*region, 0);
926 new_playlist->set_frozen (true);
927 region->set_locked (true);
929 diskstream->use_playlist (dynamic_cast<AudioPlaylist*>(new_playlist));
930 diskstream->set_record_enabled (false, this);
932 _freeze_record.state = Frozen;
933 FreezeChange(); /* EMIT SIGNAL */
937 AudioTrack::unfreeze ()
939 if (_freeze_record.playlist) {
940 diskstream->use_playlist (_freeze_record.playlist);
942 if (_freeze_record.have_mementos) {
944 for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
950 LockMonitor lm (redirect_lock, __LINE__, __FILE__);
951 for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
952 for (vector<FreezeRecordInsertInfo*>::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) {
953 if ((*ii)->id == (*i)->id()) {
954 (*i)->set_state (((*ii)->state));
961 _freeze_record.playlist = 0;
964 _freeze_record.state = UnFrozen;
965 FreezeChange (); /* EMIT SIGNAL */
968 AudioTrack::FreezeRecord::~FreezeRecord ()
970 for (vector<FreezeRecordInsertInfo*>::iterator i = insert_info.begin(); i != insert_info.end(); ++i) {
975 AudioTrack::FreezeState
976 AudioTrack::freeze_state() const
978 return _freeze_record.state;
983 AudioTrack::reset_midi_control (MIDI::Port* port, bool on)
989 Route::reset_midi_control (port, on);
991 _midi_rec_enable_control.get_control_info (chn, ev, extra);
995 _midi_rec_enable_control.midi_rebind (port, chn);
999 AudioTrack::send_all_midi_feedback ()
1001 if (_session.get_midi_feedback()) {
1003 Route::send_all_midi_feedback();
1005 _midi_rec_enable_control.send_feedback (record_enabled());
1010 AudioTrack::MIDIRecEnableControl::MIDIRecEnableControl (AudioTrack& s, MIDI::Port* port)
1011 : MIDI::Controllable (port, 0), track (s), setting(false)
1013 last_written = false; /* XXX need a good out of bound value */
1017 AudioTrack::MIDIRecEnableControl::set_value (float val)
1019 bool bval = ((val >= 0.5f) ? true: false);
1022 track.set_record_enable (bval, this);
1027 AudioTrack::MIDIRecEnableControl::send_feedback (bool value)
1030 if (!setting && get_midi_feedback()) {
1031 MIDI::byte val = (MIDI::byte) (value ? 127: 0);
1032 MIDI::channel_t ch = 0;
1033 MIDI::eventType ev = MIDI::none;
1034 MIDI::byte additional = 0;
1035 MIDI::EventTwoBytes data;
1037 if (get_control_info (ch, ev, additional)) {
1038 data.controller_number = additional;
1041 track._session.send_midi_message (get_port(), ev, ch, data);
1048 AudioTrack::MIDIRecEnableControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool val, bool force)
1050 if (get_midi_feedback()) {
1052 MIDI::channel_t ch = 0;
1053 MIDI::eventType ev = MIDI::none;
1054 MIDI::byte additional = 0;
1056 if (get_control_info (ch, ev, additional)) {
1057 if (val != last_written || force) {
1059 *buf++ = additional; /* controller number */
1060 *buf++ = (MIDI::byte) (val ? 127: 0);