CC121: cycle track monitoring states
[ardour.git] / libs / surfaces / cc121 / operations.cc
1 /*
2     Copyright (C) 2015 Paul Davis
3     Copyright (C) 2016 W.P. van Paassen
4
5     Thanks to Rolf Meyerhoff for reverse engineering the CC121 protocol.
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22
23 #include "ardour/async_midi_port.h"
24 #include "ardour/monitor_processor.h"
25 #include "ardour/monitor_control.h"
26 #include "ardour/pannable.h"
27 #include "ardour/plugin_insert.h"
28 #include "ardour/rc_configuration.h"
29 #include "ardour/record_enable_control.h"
30 #include "ardour/session.h"
31 #include "ardour/track.h"
32 #include "ardour/types.h"
33
34 #include "cc121.h"
35
36 using namespace ARDOUR;
37 using namespace ArdourSurface;
38 using namespace PBD;
39
40 /* this value is chosen to given smooth motion from 0..1.0 in about 270 degrees
41  * of encoder rotation.
42  */
43 static const double encoder_divider = 24.0;
44
45 void
46 CC121::input_monitor ()
47 {
48         if (_current_stripable && _current_stripable->monitoring_control()) {
49           MonitorChoice choice = _current_stripable->monitoring_control()->monitoring_choice ();
50           switch(choice) {
51           case MonitorAuto:
52             _current_stripable->monitoring_control()->set_value (MonitorInput, PBD::Controllable::NoGroup);
53             break;
54           case MonitorInput:
55             _current_stripable->monitoring_control()->set_value (MonitorDisk, PBD::Controllable::NoGroup);
56             break;
57           case MonitorDisk:
58             _current_stripable->monitoring_control()->set_value (MonitorCue, PBD::Controllable::NoGroup);
59             break;
60           case MonitorCue:
61             _current_stripable->monitoring_control()->set_value (MonitorAuto, PBD::Controllable::NoGroup);
62             break;
63           default:
64             break;
65           }
66         }
67 }
68
69 void
70 CC121::left ()
71 {
72         access_action ("Editor/select-prev-route");
73
74         //ToDo:  bank by 8?
75         //if ( (button_state & ShiftDown) == ShiftDown )
76
77 }
78
79 void
80 CC121::right ()
81 {
82         access_action ("Editor/select-next-route");
83
84         //ToDo:  bank by 8?
85         //if ( (button_state & ShiftDown) == ShiftDown )
86 }
87
88
89 void
90 CC121::read ()
91 {
92         if (_current_stripable) {
93                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
94                 if (gain) {
95                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Play );
96                 }
97         }
98 }
99
100 void
101 CC121::write ()
102 {
103         if (_current_stripable) {
104                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
105                 if (gain) {
106                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Write );
107                 }
108         }
109 }
110
111 void
112 CC121::touch ()
113 {
114         if (_current_stripable) {
115                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
116                 if (gain) {
117                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Touch );
118                 }
119         }
120 }
121
122 void
123 CC121::off ()
124 {
125         if (_current_stripable) {
126                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
127                 if (gain) {
128                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Off );
129                 }
130         }
131 }
132
133
134
135
136 void
137 CC121::undo ()
138 {
139         ControlProtocol::Undo (); /* EMIT SIGNAL */
140 }
141
142 void
143 CC121::redo ()
144 {
145         ControlProtocol::Redo (); /* EMIT SIGNAL */
146 }
147
148 void
149 CC121::jog()
150 {
151         if (_jogmode == scroll) {
152              _jogmode = zoom;
153         }
154         else {
155              _jogmode = scroll;
156         }
157         get_button (Jog).set_led_state (_output_port, _jogmode == scroll);
158 }
159
160 void
161 CC121::mute ()
162 {
163         if (!_current_stripable) {
164                 return;
165         }
166
167         if (_current_stripable == session->monitor_out()) {
168                 boost::shared_ptr<MonitorProcessor> mp = _current_stripable->monitor_control();
169                 mp->set_cut_all (!mp->cut_all());
170                 return;
171         }
172
173         _current_stripable->mute_control()->set_value (!_current_stripable->mute_control()->muted(), PBD::Controllable::UseGroup);
174 }
175
176 void
177 CC121::solo ()
178 {
179         if (!_current_stripable) {
180                 return;
181         }
182         _current_stripable->solo_control()->set_value (!_current_stripable->solo_control()->soloed(), PBD::Controllable::UseGroup);
183 }
184
185 void
186 CC121::rec_enable ()
187 {
188         if (!_current_stripable) {
189                 return;
190         }
191
192         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_current_stripable);
193
194         if (!t) {
195                 return;
196         }
197
198         t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
199 }
200
201 void
202 CC121::use_master ()
203 {
204         boost::shared_ptr<Stripable> r = session->master_out();
205         if (r) {
206                 if (_current_stripable == r) {
207                         r = pre_master_stripable.lock();
208                         set_current_stripable (r);
209                         get_button(Output).set_led_state (_output_port, false);
210                         blinkers.remove (Output);
211                 } else {
212                         if (_current_stripable != session->master_out() && _current_stripable != session->monitor_out()) {
213                                 pre_master_stripable = boost::weak_ptr<Stripable> (_current_stripable);
214                         }
215                         set_current_stripable (r);
216                         get_button(Output).set_led_state (_output_port, true);
217                         blinkers.remove (Output);
218                 }
219         }
220 }
221
222 void
223 CC121::use_monitor ()
224 {
225         boost::shared_ptr<Stripable> r = session->monitor_out();
226
227         if (r) {
228                 if (_current_stripable == r) {
229                         r = pre_monitor_stripable.lock();
230                         set_current_stripable (r);
231                         get_button(Output).set_led_state (_output_port, false);
232                         blinkers.remove (Output);
233                 } else {
234                         if (_current_stripable != session->master_out() && _current_stripable != session->monitor_out()) {
235                                 pre_monitor_stripable = boost::weak_ptr<Stripable> (_current_stripable);
236                         }
237                         set_current_stripable (r);
238                         get_button(Output).set_led_state (_output_port, true);
239                         blinkers.push_back (Output);
240                 }
241         }
242 }
243
244 void
245 CC121::set_controllable (boost::shared_ptr<AutomationControl> ac, float delta)
246 {
247         if (!ac || delta == 0) {
248                 return;
249         }
250         ac->start_touch (ac->session().transport_sample());
251         double v = ac->internal_to_interface (ac->get_value());
252         v = std::max (0.0, std::min (1.0, v + delta));
253         ac->set_value (ac->interface_to_internal(v), PBD::Controllable::NoGroup);
254 }
255
256
257 void
258 CC121::punch ()
259 {
260         access_action ("Transport/TogglePunch");
261 }