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 <cassert>
29 #include "core/action.h"
30 #include "core/clock.h"
31 #include "core/conf.h"
32 #include "core/mixer.h"
33 #include "core/recorderHandler.h"
34 #include "core/recManager.h"
35 #include "core/channels/state.h"
36 #include "sampleActionRecorder.h"
37
38
39 namespace giada {
40 namespace m
41 {
SampleActionRecorder(ChannelState * c,SamplePlayerState * sc)42 SampleActionRecorder::SampleActionRecorder(ChannelState* c, SamplePlayerState* sc)
43 : m_channelState(c)
44 , m_samplePlayerState(sc)
45 {
46 }
47
48
49 /* -------------------------------------------------------------------------- */
50
51
SampleActionRecorder(const SampleActionRecorder &,ChannelState * c,SamplePlayerState * sc)52 SampleActionRecorder::SampleActionRecorder(const SampleActionRecorder& /*o*/,
53 ChannelState* c, SamplePlayerState* sc)
54 : SampleActionRecorder(c, sc)
55 {
56 }
57
58
59 /* -------------------------------------------------------------------------- */
60
61
parse(const mixer::Event & e) const62 void SampleActionRecorder::parse(const mixer::Event& e) const
63 {
64 assert(m_channelState != nullptr);
65
66 switch (e.type) {
67
68 case mixer::EventType::KEY_PRESS:
69 onKeyPress(); break;
70
71 /* Record a stop event only if channel is SINGLE_PRESS. For any other
72 mode the key release event is meaningless. */
73
74 case mixer::EventType::KEY_RELEASE:
75 if (canRecord() && m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS)
76 record(MidiEvent::NOTE_OFF);
77 break;
78
79 case mixer::EventType::KEY_KILL:
80 if (canRecord())
81 record(MidiEvent::NOTE_KILL);
82 break;
83
84 case mixer::EventType::SEQUENCER_FIRST_BEAT:
85 onFirstBeat(); break;
86
87 case mixer::EventType::CHANNEL_TOGGLE_READ_ACTIONS:
88 toggleReadActions(); break;
89
90 case mixer::EventType::CHANNEL_KILL_READ_ACTIONS:
91 killReadActions(); break;
92
93 default: break;
94 }
95 }
96
97
98 /* -------------------------------------------------------------------------- */
99
100
record(int note) const101 void SampleActionRecorder::record(int note) const
102 {
103 recorderHandler::liveRec(m_channelState->id, MidiEvent(note, 0, 0),
104 clock::quantize(clock::getCurrentFrame()));
105
106 m_channelState->hasActions = true;
107 }
108
109
110 /* -------------------------------------------------------------------------- */
111
112
startReadActions() const113 void SampleActionRecorder::startReadActions() const
114 {
115 if (conf::conf.treatRecsAsLoops)
116 m_channelState->recStatus.store(ChannelStatus::WAIT);
117 else {
118 m_channelState->recStatus.store(ChannelStatus::PLAY);
119 m_channelState->readActions.store(true);
120 }
121 }
122
123
124 /* -------------------------------------------------------------------------- */
125
126
stopReadActions(ChannelStatus curRecStatus) const127 void SampleActionRecorder::stopReadActions(ChannelStatus curRecStatus) const
128 {
129 /* First of all, if the clock is not running or treatRecsAsLoops is off,
130 just stop and disable everything. Otherwise make sure a channel with actions
131 behave like a dynamic one. */
132
133 if (!clock::isRunning() || !conf::conf.treatRecsAsLoops) {
134 m_channelState->recStatus.store(ChannelStatus::OFF);
135 m_channelState->readActions.store(false);
136 }
137 else
138 if (curRecStatus == ChannelStatus::WAIT)
139 m_channelState->recStatus.store(ChannelStatus::OFF);
140 else
141 if (curRecStatus == ChannelStatus::ENDING)
142 m_channelState->recStatus.store(ChannelStatus::PLAY);
143 else
144 m_channelState->recStatus.store(ChannelStatus::ENDING);
145 }
146
147
148 /* -------------------------------------------------------------------------- */
149
150
toggleReadActions() const151 void SampleActionRecorder::toggleReadActions() const
152 {
153 /* When you start reading actions while conf::treatRecsAsLoops is true, the
154 value ch.state->readActions actually is not set to true immediately, because
155 the channel is in wait mode (REC_WAITING). readActions will become true on
156 the next first beat. So a 'stop rec' command should occur also when
157 readActions is false but the channel is in wait mode; this check will
158 handle the case of when you press 'R', the channel goes into REC_WAITING and
159 then you press 'R' again to undo the status. */
160
161 if (!m_channelState->hasActions)
162 return;
163
164 bool readActions = m_channelState->readActions.load();
165 ChannelStatus recStatus = m_channelState->recStatus.load();
166
167 if (readActions || (!readActions && recStatus == ChannelStatus::WAIT))
168 stopReadActions(recStatus);
169 else
170 startReadActions();
171 }
172
173
174 /* -------------------------------------------------------------------------- */
175
176
killReadActions() const177 void SampleActionRecorder::killReadActions() const
178 {
179 /* Killing Read Actions, i.e. shift + click on 'R' button is meaninful only
180 when the conf::treatRecsAsLoops is true. */
181
182 if (!conf::conf.treatRecsAsLoops)
183 return;
184 m_channelState->recStatus.store(ChannelStatus::OFF);
185 m_channelState->readActions.store(false);
186 }
187
188
189 /* -------------------------------------------------------------------------- */
190
191
onKeyPress() const192 void SampleActionRecorder::onKeyPress() const
193 {
194 if (!canRecord())
195 return;
196 record(MidiEvent::NOTE_ON);
197
198 /* Skip reading actions when recording on ChannelMode::SINGLE_PRESS to
199 prevent existing actions to interfere with the keypress/keyrel combo. */
200
201 if (m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS)
202 m_channelState->readActions = false;
203 }
204
205
206 /* -------------------------------------------------------------------------- */
207
208
onKeyRelease() const209 void SampleActionRecorder::onKeyRelease() const
210 {
211 if (canRecord() && m_samplePlayerState->mode.load() == SamplePlayerMode::SINGLE_PRESS) {
212 record(MidiEvent::NOTE_OFF);
213 m_channelState->readActions = true;
214 }
215 }
216
217
218 /* -------------------------------------------------------------------------- */
219
220
onFirstBeat() const221 void SampleActionRecorder::onFirstBeat() const
222 {
223 ChannelStatus recStatus = m_channelState->recStatus.load();
224
225 switch (recStatus) {
226
227 case ChannelStatus::ENDING:
228 m_channelState->recStatus.store(ChannelStatus::OFF);
229 m_channelState->readActions = false;
230 break;
231
232 case ChannelStatus::WAIT:
233 m_channelState->recStatus.store(ChannelStatus::PLAY);
234 m_channelState->readActions = true;
235 break;
236
237 default: break;
238 }
239 }
240
241
242 /* -------------------------------------------------------------------------- */
243
244
canRecord() const245 bool SampleActionRecorder::canRecord() const
246 {
247 return recManager::isRecordingAction() &&
248 clock::isRunning() &&
249 !recManager::isRecordingInput() &&
250 !m_samplePlayerState->isAnyLoopMode();
251 }
252 }} // giada::m::
253
254