f66f4fd2c83b5c1a0ce3f2c5609424ef9ffb1801
[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) {
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             get_button(InputMonitor).set_led_state (_output_port, true);
54             break;
55           case MonitorInput:
56             _current_stripable->monitoring_control()->set_value (MonitorDisk, PBD::Controllable::NoGroup);
57             get_button(InputMonitor).set_led_state (_output_port, false);
58             break;
59           case MonitorDisk:
60             _current_stripable->monitoring_control()->set_value (MonitorCue, PBD::Controllable::NoGroup);
61             get_button(InputMonitor).set_led_state (_output_port, false);
62             break;
63           case MonitorCue:
64             _current_stripable->monitoring_control()->set_value (MonitorInput, PBD::Controllable::NoGroup);
65             get_button(InputMonitor).set_led_state (_output_port, true);
66             break;
67           default:
68             break;
69           }
70         }
71 }
72
73 void
74 CC121::left ()
75 {
76         access_action ("Editor/select-prev-route");
77
78         //ToDo:  bank by 8?
79         //if ( (button_state & ShiftDown) == ShiftDown )
80
81 }
82
83 void
84 CC121::right ()
85 {
86         access_action ("Editor/select-next-route");
87
88         //ToDo:  bank by 8?
89         //if ( (button_state & ShiftDown) == ShiftDown )
90 }
91
92
93 void
94 CC121::read ()
95 {
96         if (_current_stripable) {
97                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
98                 if (gain) {
99                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Play );
100                 }
101         }
102 }
103
104 void
105 CC121::write ()
106 {
107         if (_current_stripable) {
108                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
109                 if (gain) {
110                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Write );
111                 }
112         }
113 }
114
115 void
116 CC121::touch ()
117 {
118         if (_current_stripable) {
119                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
120                 if (gain) {
121                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Touch );
122                 }
123         }
124 }
125
126 void
127 CC121::off ()
128 {
129         if (_current_stripable) {
130                 boost::shared_ptr<AutomationControl> gain = _current_stripable->gain_control ();
131                 if (gain) {
132                         gain->set_automation_state( (ARDOUR::AutoState) ARDOUR::Off );
133                 }
134         }
135 }
136
137
138
139
140 void
141 CC121::undo ()
142 {
143         ControlProtocol::Undo (); /* EMIT SIGNAL */
144 }
145
146 void
147 CC121::redo ()
148 {
149         ControlProtocol::Redo (); /* EMIT SIGNAL */
150 }
151
152 void
153 CC121::jog()
154 {
155         if (_jogmode == scroll) {
156              _jogmode = zoom;
157         }
158         else {
159              _jogmode = scroll;
160         }
161         get_button (Jog).set_led_state (_output_port, _jogmode == scroll);
162 }
163
164 void
165 CC121::mute ()
166 {
167         if (!_current_stripable) {
168                 return;
169         }
170
171         if (_current_stripable == session->monitor_out()) {
172                 boost::shared_ptr<MonitorProcessor> mp = _current_stripable->monitor_control();
173                 mp->set_cut_all (!mp->cut_all());
174                 return;
175         }
176
177         _current_stripable->mute_control()->set_value (!_current_stripable->mute_control()->muted(), PBD::Controllable::UseGroup);
178 }
179
180 void
181 CC121::solo ()
182 {
183         if (!_current_stripable) {
184                 return;
185         }
186         _current_stripable->solo_control()->set_value (!_current_stripable->solo_control()->soloed(), PBD::Controllable::UseGroup);
187 }
188
189 void
190 CC121::rec_enable ()
191 {
192         if (!_current_stripable) {
193                 return;
194         }
195
196         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_current_stripable);
197
198         if (!t) {
199                 return;
200         }
201
202         t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
203 }
204
205 void
206 CC121::use_master ()
207 {
208         boost::shared_ptr<Stripable> r = session->master_out();
209         if (r) {
210                 if (_current_stripable == r) {
211                         r = pre_master_stripable.lock();
212                         set_current_stripable (r);
213                         get_button(Output).set_led_state (_output_port, false);
214                         blinkers.remove (Output);
215                 } else {
216                         if (_current_stripable != session->master_out() && _current_stripable != session->monitor_out()) {
217                                 pre_master_stripable = boost::weak_ptr<Stripable> (_current_stripable);
218                         }
219                         set_current_stripable (r);
220                         get_button(Output).set_led_state (_output_port, true);
221                         blinkers.remove (Output);
222                 }
223         }
224 }
225
226 void
227 CC121::use_monitor ()
228 {
229         boost::shared_ptr<Stripable> r = session->monitor_out();
230
231         if (r) {
232                 if (_current_stripable == r) {
233                         r = pre_monitor_stripable.lock();
234                         set_current_stripable (r);
235                         get_button(Output).set_led_state (_output_port, false);
236                         blinkers.remove (Output);
237                 } else {
238                         if (_current_stripable != session->master_out() && _current_stripable != session->monitor_out()) {
239                                 pre_monitor_stripable = boost::weak_ptr<Stripable> (_current_stripable);
240                         }
241                         set_current_stripable (r);
242                         get_button(Output).set_led_state (_output_port, true);
243                         blinkers.push_back (Output);
244                 }
245         }
246 }
247
248 void
249 CC121::set_controllable (boost::shared_ptr<AutomationControl> ac, float delta)
250 {
251         if (!ac || delta == 0) {
252                 return;
253         }
254         ac->start_touch (ac->session().transport_sample());
255         double v = ac->internal_to_interface (ac->get_value());
256         v = std::max (0.0, std::min (1.0, v + delta));
257         ac->set_value (ac->interface_to_internal(v), PBD::Controllable::NoGroup);
258 }
259
260
261 void
262 CC121::punch ()
263 {
264         access_action ("Transport/TogglePunch");
265 }