Add Auto Stop Recording
parent
d3be43a44f
commit
335571ad17
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
12
src/jack.cxx
12
src/jack.cxx
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue