1 /*
2 * Author: Harry van Haaren 2013
3 * harryhaaren@gmail.com
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "looperclip.hxx"
20
21 #include <stdio.h>
22 #include "config.hxx"
23 #include "jack.hxx"
24 #include "event.hxx"
25 #include "eventhandler.hxx"
26 #include "audiobuffer.hxx"
27
28 #include "controllerupdater.hxx"
29 #include "timemanager.hxx"
30 #include <math.h>
31
32
33 extern Jack* jack;
34
LooperClip(int t,int s)35 LooperClip::LooperClip(int t, int s) :
36 Stately(),
37 track(t),
38 scene(s)
39 {
40 _buffer = new AudioBuffer();
41 _buffer->nonRtResize( 4410 );
42 init();
43 }
44
init()45 void LooperClip::init()
46 {
47 _loaded = false;
48 _playing = false;
49 _recording = false;
50
51 _queuePlay = false;
52 _queueStop = false;
53 _queueRecord= false;
54
55 if ( _buffer ) {
56 _buffer->init();
57 }
58 _newBufferInTransit = false;
59
60 _playhead = 0;
61 _recordhead = 0;
62
63 _barsPlayed = 0;
64
65 }
66
save()67 void LooperClip::save()
68 {
69 // ensure the buffer exists, and is saveable (not recording)
70 if ( _loaded && !_recording && !_queueRecord ) {
71 char buffer [50];
72 sprintf (buffer, "LC::save() track %i, scene %i", track,scene);
73 EventGuiPrint e( buffer );
74 writeToGuiRingbuffer( &e );
75
76 int frames = _buffer->getAudioFrames();
77 EventRequestSaveBuffer e2( track, scene, frames );
78 writeToGuiRingbuffer( &e2 );
79 } else {
80 // notify of "success" of save if there *is* no state to save
81 Stately::success();
82 }
83 }
84
reset()85 void LooperClip::reset()
86 {
87 // TODO make the LooperClip reset to initial state
88 if ( _loaded ) {
89 char buffer [50];
90 sprintf (buffer, "LC::reset() track %i, scene %i", track,scene);
91 EventGuiPrint e( buffer );
92 writeToGuiRingbuffer( &e );
93
94 // set "progress" to zero as there's no clip anymore
95 jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0 );
96 } else {
97 //SaveAble::done();
98 }
99
100 init();
101 }
102
103 /// loads a sample: eg from disk, unloading current sample if necessary
load(AudioBuffer * ab)104 void LooperClip::load( AudioBuffer* ab )
105 {
106 _loaded = true;
107 _recording = false;
108 _playing = false;
109
110 _queuePlay = false;
111 _queueStop = false;
112 _queueRecord= false;
113
114 if ( _buffer ) {
115 EventDeallocateBuffer e( _buffer );
116 writeToGuiRingbuffer( &e );
117 }
118
119 _buffer = ab;
120
121 _playhead = 0;
122 _barsPlayed = 0;
123 jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0);
124
125 // set the endpoint to the buffer's size
126 _recordhead = _buffer->getSize();
127
128 #ifdef DEBUG_BUFFER
129 char buffer [50];
130 sprintf (buffer, "LC::load() t %i, s %i, aF %i",track, scene, int(_buffer->getAudioFrames()) );
131 EventGuiPrint e( buffer );
132 writeToGuiRingbuffer( &e );
133 #endif
134 }
135
setRequestedBuffer(AudioBuffer * ab)136 void LooperClip::setRequestedBuffer( AudioBuffer* ab )
137 {
138 if ( _buffer ) {
139 size_t size = _buffer->getSize();
140 memcpy( &ab->getDataL().at(0), &_buffer->getDataL().at(0), sizeof(float)*size);
141 memcpy( &ab->getDataR().at(0), &_buffer->getDataR().at(0), sizeof(float)*size);
142
143 ab->setID ( _buffer->getID() );
144 ab->setBeats( _buffer->getBeats() );
145
146 EventDeallocateBuffer e( _buffer );
147 writeToGuiRingbuffer( &e );
148 }
149
150 _buffer = ab;
151
152 _newBufferInTransit = false;
153 }
154
155
156
recieveSaveBuffer(AudioBuffer * saveBuffer)157 void LooperClip::recieveSaveBuffer( AudioBuffer* saveBuffer )
158 {
159 if ( saveBuffer->getSize() >= _buffer->getDataL().at(0) ||
160 saveBuffer->getSize() >= _buffer->getDataR().at(0) ) {
161 // copy current contents into save buffer,
162 // getData() contains L and R buffer, so twice the size is needed
163 size_t framesBySize = _buffer->getAudioFrames();
164 memcpy( &saveBuffer->getDataL().at(0), &_buffer->getDataL().at(0), sizeof(float)*framesBySize);
165 memcpy( &saveBuffer->getDataR().at(0), &_buffer->getDataR().at(0), sizeof(float)*framesBySize);
166
167 saveBuffer->setID ( _buffer->getID() );
168 saveBuffer->setBeats( _buffer->getBeats() );
169 saveBuffer->setAudioFrames( _buffer->getAudioFrames() );
170
171 EventStateSaveBuffer e ( track, scene, saveBuffer );
172 writeToGuiRingbuffer( &e );
173
174 Stately::success();
175 } else {
176 char buffer [50];
177 sprintf (buffer, "LC:: %i, %i: can't save, buf too small",track, scene );
178 EventGuiPrint e( buffer );
179 writeToGuiRingbuffer( &e );
180 Stately::error("");
181 }
182 }
183
setPlayHead(float ph)184 void LooperClip::setPlayHead(float ph)
185 {
186 if(!_recording&&_playing) {
187 _playhead = ph;
188 jack->getControllerUpdater()->setTrackSceneProgress(track, scene, getProgress() );
189 }
190 }
191
192
193
record(int count,float * L,float * R)194 void LooperClip::record(int count, float* L, float* R)
195 {
196 // write "count" samples into current buffer.
197 if ( _buffer ) {
198 size_t size = _buffer->getSize();
199
200 for(int i = 0; i < count; i++) {
201 if ( _recordhead < size ) {
202 _buffer->getDataL().at( _recordhead ) = *L++;
203 _buffer->getDataR().at( _recordhead ) = *R++;
204 _recordhead++;
205 } else {
206 // break: this is *BAD*, audio data is lost but the buffer isn't here
207 // yet to hold new audio data so there's no option. This has not been
208 // encountered in actual usage, only during the development process.
209 char buffer [50];
210 sprintf (buffer, "LooperClip t %i, s %i, Error: out of mem!",track, scene );
211 EventGuiPrint e( buffer );
212 writeToGuiRingbuffer( &e );
213 #ifdef BUILD_TESTS
214 LUPPP_WARN("%s","buffer has no space");
215 #endif
216
217 break;
218 }
219 }
220 }
221
222 _loaded = true;
223 }
224
recordSpaceAvailable()225 unsigned long LooperClip::recordSpaceAvailable()
226 {
227 if ( _buffer )
228 // getData() contains L and R buffer, so it is twice the size
229 return _buffer->getSize() - _recordhead;
230
231 return 0;
232 }
233
audioBufferSize()234 size_t LooperClip::audioBufferSize()
235 {
236 if ( _buffer ) {
237 return _buffer->getSize();
238 }
239 return 0;
240 }
241
setBeats(int beats)242 void LooperClip::setBeats(int beats)
243 {
244 if ( _buffer ) {
245 _buffer->setBeats( beats );
246 }
247 }
248
getBeats()249 int LooperClip::getBeats()
250 {
251 if ( _buffer )
252 return _buffer->getBeats();
253
254 return 0;
255 }
256
getBufferLenght()257 long LooperClip::getBufferLenght()
258 {
259 return _recordhead;
260 }
261
getActualAudioLength()262 long LooperClip::getActualAudioLength()
263 {
264 char cbuffer [50];
265 // sprintf (cbuffer, "LooperClip recordhead %f,audioFrames %d \n",_recordhead,(int)_buffer->getAudioFrames());
266 // EventGuiPrint e( cbuffer );
267 // writeToGuiRingbuffer( &e );
268 // printf(cbuffer);
269 return _buffer->getAudioFrames();
270 }
271
bar()272 void LooperClip::bar()
273 {
274 bool change = false;
275 GridLogic::State s = GridLogic::STATE_EMPTY;
276
277 // first update the buffer, as time has passed
278 if ( _recording ) {
279 // FIXME: assumes 4 beats in a bar
280 _buffer->setBeats( _buffer->getBeats() + 4 );
281 _buffer->setAudioFrames( jack->getTimeManager()->getFpb() * _buffer->getBeats() );
282 }
283
284 if ( _playing ) {
285 _barsPlayed++;
286 }
287
288 if ( _playing && _barsPlayed >= getBeats() / 4) {
289 #ifdef DEBUG_TIME
290 cout << "reset: " << _playhead << " - " << _barsPlayed << "\n";
291 #endif
292 _barsPlayed = 0;
293 _playhead = 0;
294 }
295
296 if ( _playhead >= _recordhead ) {
297 _playhead = 0.f;
298 _barsPlayed = 0;
299 }
300
301 if ( _queuePlay && _loaded ) {
302 //LUPPP_NOTE("QPLay + loaded" );
303 _playing = true;
304 s = GridLogic::STATE_PLAYING;
305 _recording = false;
306 _queuePlay = false;
307 change = true;
308
309 _playhead = 0;
310 _barsPlayed = 0;
311 }
312 else if (_queueStop && _loaded)
313 {
314 _playing = false;
315 s = GridLogic::STATE_STOPPED;
316 _recording = false;
317 _queueStop = false;
318 change = true;
319 // set "progress" to zero, as we're stopped!
320 jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0 );
321 } else if ( _queueRecord ) {
322 _recording = true;
323 s = GridLogic::STATE_RECORDING;
324 _playing = false;
325 _queueRecord = false;
326 change = true;
327
328 if ( _buffer ) {
329 _buffer->setBeats( 0 );
330 }
331
332 _recordhead = 0;
333 } else if ( _queuePlay ) {
334 // clip was queued, but there's nothing loaded
335 _queuePlay = false;
336 change = true;
337 }
338
339 if ( change ) {
340 jack->getControllerUpdater()->setSceneState(track, scene, s );
341 }
342 }
343
neutralize()344 void LooperClip::neutralize()
345 {
346 _queuePlay = false;
347 _queueRecord = false;
348 _queueStop = false;
349 }
350
somethingQueued()351 bool LooperClip::somethingQueued()
352 {
353 if ( _queuePlay || _queueStop || _queueRecord ) {
354 return true;
355 }
356 return false;
357 }
358
queuePlay(bool qP)359 void LooperClip::queuePlay(bool qP)
360 {
361 _queuePlay = true;
362 _queueStop = false;
363 _queueRecord = false;
364 }
365
queueStop()366 void LooperClip::queueStop()
367 {
368 // comment
369 if ( _loaded ) {
370 _queueStop = true;
371 _queuePlay = false;
372 }
373 }
374
queueRecord()375 void LooperClip::queueRecord()
376 {
377 _queueRecord = true;
378 _queuePlay = false;
379 _queueStop = false;
380 }
381
getState()382 GridLogic::State LooperClip::getState()
383 {
384 GridLogic::State s = GridLogic::STATE_EMPTY;
385
386 if ( _loaded )
387 s = GridLogic::STATE_STOPPED;
388 if ( _playing )
389 s = GridLogic::STATE_PLAYING;
390 if ( _recording )
391 s = GridLogic::STATE_RECORDING;
392 if ( _queuePlay )
393 s = GridLogic::STATE_PLAY_QUEUED;
394 if ( _queueStop )
395 s = GridLogic::STATE_STOP_QUEUED;
396 if ( _queueRecord )
397 s = GridLogic::STATE_RECORD_QUEUED;
398
399 return s;
400 }
401
playing()402 bool LooperClip::playing()
403 {
404 return _playing;
405 }
406
getQueueStop()407 bool LooperClip::getQueueStop()
408 {
409 return _queueStop;
410 }
411
getQueuePlay()412 bool LooperClip::getQueuePlay()
413 {
414 return _queuePlay;
415 }
416
getLoaded()417 bool LooperClip::getLoaded()
418 {
419 return _loaded;
420 }
421
recording()422 bool LooperClip::recording()
423 {
424 return _recording;
425 }
426
newBufferInTransit(bool n)427 void LooperClip::newBufferInTransit(bool n)
428 {
429 _newBufferInTransit = n;
430 }
431
newBufferInTransit()432 bool LooperClip::newBufferInTransit()
433 {
434 return _newBufferInTransit;
435 }
436
getSample(long double playSpeed,float * L,float * R)437 void LooperClip::getSample(long double playSpeed, float* L, float* R)
438 {
439 if ( _buffer && (_buffer->getSize() > 0)) {
440 if ( _playhead >= _recordhead ||
441 _playhead >= _buffer->getSize() ||
442 _playhead < 0 ) {
443 _playhead = 0;
444 _barsPlayed = 0;
445
446 EventGuiPrint e( "LooperClip resetting _playhead" );
447 //writeToGuiRingbuffer( &e );
448 }
449
450 std::vector<float>& vL = _buffer->getDataL();
451 std::vector<float>& vR = _buffer->getDataR();
452 *L = vL[_playhead+0.5];
453 *R = vR[_playhead+0.5];
454 _playhead += playSpeed;
455 } else {
456 *L = 0.f;
457 *R = 0.f;
458 }
459 }
460
getProgress()461 float LooperClip::getProgress()
462 {
463 if ( _buffer && _playing ) {
464 float p = float(_playhead) / _recordhead;
465 //printf("LooperClip progress %f\n", p );
466 return p;
467 }
468 return 0.f;
469 }
470
getPlayhead()471 float LooperClip::getPlayhead()
472 {
473 return _playhead;
474 }
475
476 #ifdef BUILD_TESTS
setState(bool load,bool play,bool rec,bool qPlay,bool qStop,bool qRec)477 void LooperClip::setState( bool load, bool play, bool rec, bool qPlay, bool qStop, bool qRec )
478 {
479 _loaded = load;
480 _playing = play;
481 _recording = rec;
482
483 _queuePlay = qPlay;
484 _queueStop = qStop;
485 _queueRecord = qRec;
486 }
487 #endif
488