1 /* -----------------------------------------------------------------------------
2 *
3 * Giada - Your Hardcore Loopmachine
4 *
5 * -----------------------------------------------------------------------------
6 *
7 * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
8 *
9 * This file is part of Giada - Your Hardcore Loopmachine.
10 *
11 * Giada - Your Hardcore Loopmachine is free software: you can
12 * redistribute it and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation, either
14 * version 3 of the License, or (at your option) any later version.
15 *
16 * Giada - Your Hardcore Loopmachine is distributed in the hope that it
17 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
18 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Giada - Your Hardcore Loopmachine. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 * -------------------------------------------------------------------------- */
26
27
28 #include "gui/dispatcher.h"
29 #include "core/model/model.h"
30 #include "core/types.h"
31 #include "core/clock.h"
32 #include "core/kernelAudio.h"
33 #include "core/conf.h"
34 #include "core/mixer.h"
35 #include "core/sequencer.h"
36 #include "core/mixerHandler.h"
37 #include "core/midiDispatcher.h"
38 #include "core/recorder.h"
39 #include "core/recorderHandler.h"
40 #include "core/recManager.h"
41
42
43 namespace giada {
44 namespace m {
45 namespace recManager
46 {
47 namespace
48 {
setRecordingAction_(bool v)49 void setRecordingAction_(bool v)
50 {
51 model::onSwap(model::recorder, [&](model::Recorder& r)
52 {
53 r.isRecordingAction = v;
54 });
55 }
56
57
setRecordingInput_(bool v)58 void setRecordingInput_(bool v)
59 {
60 model::onSwap(model::recorder, [&](model::Recorder& r)
61 {
62 r.isRecordingInput = v;
63 });
64 }
65
66
67 /* -------------------------------------------------------------------------- */
68
69
startActionRec_()70 bool startActionRec_()
71 {
72 if (!kernelAudio::isReady())
73 return false;
74 clock::setStatus(ClockStatus::RUNNING);
75 sequencer::start();
76 m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
77 return true;
78 }
79
80
81 /* -------------------------------------------------------------------------- */
82
83
startInputRec_()84 bool startInputRec_()
85 {
86 if (!kernelAudio::isReady() || !mh::hasInputRecordableChannels())
87 return false;
88 mixer::startInputRec();
89 sequencer::start();
90 m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
91 return true;
92 }
93 } // {anonymous}
94
95
96 /* -------------------------------------------------------------------------- */
97 /* -------------------------------------------------------------------------- */
98 /* -------------------------------------------------------------------------- */
99
100
isRecording()101 bool isRecording()
102 {
103 return isRecordingAction() || isRecordingInput();
104 }
105
106
isRecordingAction()107 bool isRecordingAction()
108 {
109 model::RecorderLock lock(model::recorder);
110 return model::recorder.get()->isRecordingAction;
111 }
112
113
isRecordingInput()114 bool isRecordingInput()
115 {
116 model::RecorderLock lock(model::recorder);
117 return model::recorder.get()->isRecordingInput;
118 }
119
120
121 /* -------------------------------------------------------------------------- */
122
123
startActionRec(RecTriggerMode mode)124 void startActionRec(RecTriggerMode mode)
125 {
126 if (mode == RecTriggerMode::NORMAL) {
127 if (startActionRec_())
128 setRecordingAction_(true);
129 }
130 else { // RecTriggerMode::SIGNAL
131 clock::setStatus(ClockStatus::WAITING);
132 clock::rewind();
133 m::midiDispatcher::setSignalCallback(startActionRec_);
134 v::dispatcher::setSignalCallback(startActionRec_);
135 setRecordingAction_(true);
136 }
137 }
138
139
140 /* -------------------------------------------------------------------------- */
141
142
stopActionRec()143 void stopActionRec()
144 {
145 setRecordingAction_(false);
146
147 /* If you stop the Action Recorder in SIGNAL mode before any actual
148 recording: just clean up everything and return. */
149
150 if (clock::getStatus() == ClockStatus::WAITING) {
151 clock::setStatus(ClockStatus::STOPPED);
152 midiDispatcher::setSignalCallback(nullptr);
153 v::dispatcher::setSignalCallback(nullptr);
154 return;
155 }
156
157 std::unordered_set<ID> channels = recorderHandler::consolidate();
158
159 /* Enable reading actions for Channels that have just been filled with
160 actions. Start reading right away, without checking whether
161 conf::treatRecsAsLoops is enabled or not. Same thing for MIDI channels. */
162
163 for (ID id : channels) {
164 model::onGet(model::channels, id, [](Channel& c)
165 {
166 c.state->readActions.store(true);
167 if (c.getType() == ChannelType::MIDI)
168 c.state->playStatus.store(ChannelStatus::PLAY);
169 });
170 }
171 }
172
173
174 /* -------------------------------------------------------------------------- */
175
176
toggleActionRec(RecTriggerMode m)177 void toggleActionRec(RecTriggerMode m)
178 {
179 isRecordingAction() ? stopActionRec() : startActionRec(m);
180 }
181
182
183 /* -------------------------------------------------------------------------- */
184
185
startInputRec(RecTriggerMode mode)186 bool startInputRec(RecTriggerMode mode)
187 {
188 if (mode == RecTriggerMode::NORMAL) {
189 G_DEBUG("Start input rec, NORMAL mode");
190 if (!startInputRec_())
191 return false;
192 setRecordingInput_(true);
193 return true;
194 }
195 else {
196 G_DEBUG("Start input rec, SIGNAL mode");
197 if (!mh::hasInputRecordableChannels())
198 return false;
199 clock::setStatus(ClockStatus::WAITING);
200 clock::rewind();
201 mixer::setSignalCallback(startInputRec_);
202 setRecordingInput_(true);
203 return true;
204 }
205 }
206
207
208 /* -------------------------------------------------------------------------- */
209
210
stopInputRec()211 void stopInputRec()
212 {
213 setRecordingInput_(false);
214
215 mixer::stopInputRec();
216
217 /* If you stop the Input Recorder in SIGNAL mode before any actual
218 recording: just clean up everything and return. */
219
220 if (clock::getStatus() == ClockStatus::WAITING) {
221 clock::setStatus(ClockStatus::STOPPED);
222 mixer::setSignalCallback(nullptr);
223 }
224 else
225 mh::finalizeInputRec();
226 }
227
228
229 /* -------------------------------------------------------------------------- */
230
231
toggleInputRec(RecTriggerMode m)232 bool toggleInputRec(RecTriggerMode m)
233 {
234 if (isRecordingInput()) {
235 stopInputRec();
236 return true;
237 }
238 return startInputRec(m);
239 }
240 }}} // giada::m::recManager
241