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