Add Auto Stop Recording

main
Georg Krause 2019-05-31 20:59:48 +02:00
parent d3be43a44f
commit 335571ad17
14 changed files with 266 additions and 37 deletions

View File

@ -1,5 +1,9 @@
# recent changes
## Features:
* Auto Stop Record of Clips after a defined number of bars
## Improvements
* Improve BPM Dial to avoid jitter

View File

@ -329,6 +329,15 @@ void GenericMIDI::midi(unsigned char* midi)
case Event::MASTER_VOL:
jack->getLogic()->trackVolume( -1 , value );
break;
case Event::AUTO_STOP_REC_CLIP_LENGTH:
jack->getLogic()->setClipLength(value);
break;
case Event::AUTO_STOP_REC_CLIP_LENGTH_UP:
jack->getLogic()->setClipLengthUp();
break;
case Event::AUTO_STOP_REC_CLIP_LENGTH_DOWN:
jack->getLogic()->setClipLengthDown();
break;
}
}

View File

@ -41,6 +41,13 @@ const char* EventMetronomeVolume::prettyName = "metronome:volume";
const char* EventGridEvent::prettyName = "grid:event";
const char* EventGridLaunchScene::prettyName = "grid:launch_scene";
const char *EventAutoStopRecClipLength::prettyName =
"auto_stop_rec:clip_length";
const char *EventAutoStopRecClipLengthUp::prettyName =
"auto_stop_rec:clip_length_up";
const char *EventAutoStopRecClipLengthDown::prettyName =
"auto_stop_rec:clip_length_down";
EVENT_TYPE Event::getTypeFromName(const char* name)
{
for(int i = 0; i < EVENT_TYPE_FINAL; i++) {
@ -116,6 +123,15 @@ const char* Event::getPrettyName( int type )
case METRONOME_VOLUME: {
return EventMetronomeVolume::prettyName;
}
case AUTO_STOP_REC_CLIP_LENGTH: {
return EventAutoStopRecClipLength::prettyName;
}
case AUTO_STOP_REC_CLIP_LENGTH_UP: {
return EventAutoStopRecClipLengthUp::prettyName;
}
case AUTO_STOP_REC_CLIP_LENGTH_DOWN: {
return EventAutoStopRecClipLengthDown::prettyName;
}
default:
return 0;

View File

@ -99,6 +99,11 @@ enum EVENT_TYPE {
LOOPER_LOOP_LENGTH,
LOOPER_LOOP_USE_AS_TEMPO,
// Set the clip length for auto stop recording
AUTO_STOP_REC_CLIP_LENGTH,
AUTO_STOP_REC_CLIP_LENGTH_UP,
AUTO_STOP_REC_CLIP_LENGTH_DOWN,
/// Transport etc
METRONOME_ACTIVE,
METRONOME_VOLUME,
@ -864,6 +869,65 @@ public:
EventLooperUseAsTempo(int t, int s) : track(t), scene(s) {}
};
class EventAutoStopRecClipLength : public EventBase {
public:
static const char *prettyName;
int clipLength;
const char *name() {
return prettyName;
}
int type() {
return int(AUTO_STOP_REC_CLIP_LENGTH);
}
uint32_t size() {
return sizeof(EventAutoStopRecClipLength);
}
EventAutoStopRecClipLength() {}
EventAutoStopRecClipLength(int l) : clipLength(l) {}
};
class EventAutoStopRecClipLengthUp : public EventBase {
public:
static const char *prettyName;
const char *name() {
return prettyName;
}
int type() {
return int(AUTO_STOP_REC_CLIP_LENGTH_UP);
}
uint32_t size() {
return sizeof(EventAutoStopRecClipLengthUp);
}
EventAutoStopRecClipLengthUp() {}
};
class EventAutoStopRecClipLengthDown : public EventBase {
public:
static const char *prettyName;
const char *name() {
return prettyName;
}
int type() {
return int(AUTO_STOP_REC_CLIP_LENGTH_DOWN);
}
uint32_t size() {
return sizeof(EventAutoStopRecClipLengthDown);
}
EventAutoStopRecClipLengthDown() {}
};
class EventLooperLoad : public EventBase
{
public:

View File

@ -272,7 +272,17 @@ void handleDspEvents()
break;
}
// Set Clip Length for Auto Stop Record
case Event::AUTO_STOP_REC_CLIP_LENGTH: {
if(availableRead >=
sizeof(EventAutoStopRecClipLength)) {
EventAutoStopRecClipLength e;
jack_ringbuffer_read(rbToDsp, (char*)&e,
sizeof(EventAutoStopRecClipLength));
jack->setClipLength(e.clipLength);
}
break;
}
case Event::TIME_BPM: {
if ( availableRead >= sizeof(EventTimeBPM) ) {

View File

@ -124,6 +124,17 @@ void handleGuiEvents()
}
break;
}
case Event::AUTO_STOP_REC_CLIP_LENGTH: {
if(availableRead >= sizeof(EventAutoStopRecClipLength)) {
EventAutoStopRecClipLength e;
jack_ringbuffer_read(rbToGui,
(char *)&e,
sizeof(EventAutoStopRecClipLength));
gui->getMasterTrack()->setClipLength(e.clipLength);
}
break;
}
case Event::LOOPER_STATE: {
if ( availableRead >= sizeof(EventLooperState) ) {
EventLooperState ev;

View File

@ -19,6 +19,7 @@
#include "gmastertrack.hxx"
#include <FL/Fl_Menu_Item.H>
#include <stdlib.h>
static void gmastertrack_tempoDial_callback(Fl_Widget *w, void *data)
{
@ -188,37 +189,81 @@ static void gmastertrack_button_callback(Fl_Widget *w, void *data)
}
}
#define OFST 33
GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) :
Fl_Group(x, y, w, h),
title( strdup(l) ),
bg( x, y , w, h, title ),
static void gmastertrack_autoStopRec_callback(Fl_Widget *w, void *data) {
int clipLength = -1;
// with "true" master flag: launches scenes instead of clips on tracks
clipSel(x + 5, y + 26 + 102, 140, 294,"", true),
if(Fl::event_button() == FL_LEFT_MOUSE) {
Fl_Menu_Item rclick_menu[] = { { "1" }, { "2" }, { "4" },
{ "8" }, { "16" }, { "" }, { "Custom" }, { 0 } };
source(x+5, y+26, 140, 100, ""),
volBox(x+5, y+422, 140, 232, ""),
Fl_Menu_Item *m = (Fl_Menu_Item *)rclick_menu->popup(
Fl::event_x(), Fl::event_y(), 0, 0, 0);
transport ( x + w * 2/4.f - 18, y + 436 + OFST * 0, 44,28, "Stop" ),
tapTempo ( x + w * 2/4.f - 18, y + 436 + OFST * 1, 44,28, "Tap" ),
metronomeButton( x + w * 2/4.f - 18, y + 436 + OFST * 2, 44,28,"Metro"),
if(!m) {
return;
} else if(strcmp(m->label(), "Custom") == 0) {
const char *answer = fl_input(
// TODO magic number
"Enter Clip Length (range 1 and 64):", 0);
tempoDial ( x + w * 2/4.f - 18, y + 436 + OFST * 3.5, 45, 38,"BPM"),
returnVol ( x + w * 2/4.f - 18, y + 436 + OFST * 5, 45, 38,"Return"),
if(answer) {
clipLength = atoi(answer);
inputVolume(x + 9,y + 26 + 4, w - 18, 30,""),
// TODO magic number
if(clipLength < 1 || clipLength > 64) {
// do not accept invalid input
clipLength = -1;
}
}
} else if(strcmp(m->label(), "") == 0) {
clipLength = 0;
} else {
clipLength = atoi(m->label());
}
inputToSend (x + 10,y + 28 + 68, 40, 26,"Snd"),
inputToSendVol(x + w*0.2-15,y + 28 + 36, 30, 30,""),
} else {
clipLength = 0;
}
inputToSidechainKey (x + w*0.5-20,y + 28 + 68, 40, 26,"Key"),
inputToSidechainSignalVol(x + w*0.5-15,y + 28 + 36, 30, 30,""),
if(clipLength >= 0) {
EventAutoStopRecClipLength e = EventAutoStopRecClipLength(clipLength);
writeToDspRingbuffer(&e);
}
}
inputToMix (x + w*0.8-20,y + 28 + 68, 40, 26,"Mix"),
inputToMixVol(x + w*0.8-15,y + 28 + 36, 30, 30,""),
#define OFST 30
GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char *l)
: Fl_Group(x, y, w, h), title(strdup(l)), bg(x, y, w, h, title),
volume(x+106, y +425, 36, 216, "")
// with "true" master flag: launches scenes instead of clips on tracks
clipSel(x + 5, y + 26 + 102, 140, 294, "", true),
source(x + 5, y + 26, 140, 100, ""),
volBox(x + 5, y + 422, 140, 232, ""),
transport(x + w * 2 / 4.f - 18, y + 436 + OFST * 0, 44, 22, "Stop"),
tapTempo(x + w * 2 / 4.f - 18, y + 436 + OFST * 1, 44, 22, "Tap"),
metronomeButton(
x + w * 2 / 4.f - 18, y + 436 + OFST * 2, 44, 22, "Metro"),
autoStopRecButton(
x + w * 2 / 4.f - 18, y + 436 + OFST * 3, 44, 22, ""),
tempoDial(x + w * 2 / 4.f - 18, y + 436 + OFST * 4, 45, 38, "BPM"),
returnVol(
x + w * 2 / 4.f - 18, y + 436 + OFST * 5.5, 45, 38, "Return"),
inputVolume(x + 9, y + 26 + 4, w - 18, 30, ""),
inputToSend(x + 10, y + 28 + 68, 40, 26, "Snd"),
inputToSendVol(x + w * 0.2 - 15, y + 28 + 36, 30, 30, ""),
inputToSidechainKey(x + w * 0.5 - 20, y + 28 + 68, 40, 26, "Key"),
inputToSidechainSignalVol(x + w * 0.5 - 15, y + 28 + 36, 30, 30, ""),
inputToMix(x + w * 0.8 - 20, y + 28 + 68, 40, 26, "Mix"),
inputToMixVol(x + w * 0.8 - 15, y + 28 + 36, 30, 30, ""),
volume(x + 106, y + 425, 36, 216, "")
{
ID = privateID++;
@ -235,6 +280,8 @@ GMasterTrack::GMasterTrack(int x, int y, int w, int h, const char* l ) :
metronomeButton.callback( gmastertrack_button_callback, 0 );
autoStopRecButton.callback(gmastertrack_autoStopRec_callback, &ID);
tempoDial.callback( gmastertrack_tempoDial_callback, 0 );
inputToSend.setColor( 0, 1.0, 0 );
@ -321,6 +368,19 @@ void GMasterTrack::metronomeEnable( bool b )
metronomeButton.value( b );
}
void
GMasterTrack::setClipLength(int l)
{
const char *str;
if(l == 0) {
str = "";
} else {
std::string tmp = std::to_string(l);
str = tmp.c_str();
}
autoStopRecButton.copy_label(str);
}
int GMasterTrack::getBpm()
{
return bpm;

View File

@ -59,6 +59,8 @@ public:
void setInputToActive(int to, bool f);
void metronomeEnable( bool b );
void
setClipLength(int l);
Avtk::Volume* getInputVolume();
Avtk::Volume* getVolume();
@ -91,7 +93,8 @@ private:
Avtk::Button transport;
Avtk::Button tapTempo;
Avtk::LightButton metronomeButton;
Avtk::Dial tempoDial;
Avtk::LightButton autoStopRecButton;
Avtk::Dial tempoDial;
Avtk::Dial returnVol;

View File

@ -771,3 +771,15 @@ int Jack::static_timebase(jack_transport_state_t state,
{
return static_cast<Jack*>(instance)->timebase(state,nframes, pos, newPos );
}
void
Jack::setClipLength(int l)
{
// TODO magic numbers
if(l >= 0 && l <= 16) {
clipLength = l;
}
EventAutoStopRecClipLength e = EventAutoStopRecClipLength(clipLength);
writeToGuiRingbuffer(&e);
}

View File

@ -89,6 +89,10 @@ public:
{
return metronome;
}
int getClipLength()
{
return clipLength;
}
GridLogic* getGridLogic()
{
return gridLogic;
@ -120,6 +124,9 @@ public:
void inputTo(INPUT_TO to, float v);
void inputToActive(INPUT_TO to, bool a);
void
setClipLength(int l);
jack_client_t* getJackClientPointer()
{
return client;
@ -150,6 +157,7 @@ private:
GridLogic* gridLogic;
ControllerUpdater* controllerUpdater;
int clipLength;
vector<Looper*> loopers;
vector<JackSendReturn*> tracksendreturns;
vector<TrackOutput*> trackOutputs;

View File

@ -168,3 +168,15 @@ void Logic::looperUseAsTempo(int t, int s)
}
}
void Logic::setClipLength(float l) {
jack->setClipLength((int)(l * 16));
}
void Logic::setClipLengthUp() {
jack->setClipLength(jack->getClipLength() * 2);
}
void Logic::setClipLengthDown() {
jack->setClipLength(jack->getClipLength() / 2);
}

View File

@ -63,6 +63,10 @@ public:
void trackJackSend(int t, float vol);
void looperUseAsTempo(int track, int scene);
void looperClipLenght(int track, int scene, int lenght);
void setClipLength(float f);
void setClipLengthUp();
void setClipLengthDown();
};
#endif // LUPPP_LOGIC_H

View File

@ -68,6 +68,8 @@ void LooperClip::init()
_playbackSpeedChange = false;
_beatsPlayed = 0;
_barsPlayed = 0;
_barsRecorded = 0;
updateController();
}
@ -172,6 +174,13 @@ void LooperClip::resetPlayHead()
{
_playhead = 0;
_beatsPlayed = 0;
_barsPlayed = 0;
if(_playbackSpeedChange) {
_playbackSpeed = _nextPlaybackSpeed;
_playbackSpeedChange = false;
}
updateController();
}
}
@ -254,25 +263,28 @@ long LooperClip::getActualAudioLength()
return _buffer->getAudioFrames();
}
void LooperClip::bar()
void
LooperClip::bar()
{
if(_playbackSpeedChange) {
_playbackSpeed = _nextPlaybackSpeed;
_playbackSpeedChange = false;
if(_playing) {
_barsPlayed++;
}
if(_recording) {
_barsRecorded++;
}
if ( _queuePlay ) {
if(_queuePlay) {
setPlaying();
}
else if (_queueStop && _loaded)
{
} else if(_queueStop && _loaded) {
setStopped();
}
else if ( _queueRecord )
{
} else if(_queueRecord) {
setRecording();
}
if(jack->getClipLength() > 0 &&
_barsRecorded == jack->getClipLength() - 1) {
queuePlay();
}
if(_recording) {
// FIXME: assumes 4 beats in a bar
_buffer->setBeats(_buffer->getBeats() + 4);
@ -281,7 +293,9 @@ void LooperClip::bar()
}
}
void LooperClip::beat() {
void
LooperClip::beat()
{
if(_playing) {
_beatsPlayed++;
}

View File

@ -154,7 +154,9 @@ private:
bool _playbackSpeedChange;
unsigned int _beatsPlayed;
AudioBuffer* _buffer;
unsigned int _barsPlayed;
unsigned int _barsRecorded;
AudioBuffer *_buffer;
/// Request new internal Buffer
void requestNewBuffer();