4-implement-scene-switching-engine #4
@@ -5,6 +5,13 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Helper: zero a scene and set its state to IDLE */
|
||||||
|
static void init_scene(scene_t *sc) {
|
||||||
|
memset(sc, 0, sizeof(scene_t));
|
||||||
|
atomic_store(&sc->state, STATE_IDLE);
|
||||||
|
sc->prev_state = -1;
|
||||||
|
}
|
||||||
|
|
||||||
void channel_add(jack_client_t *client, int idx) {
|
void channel_add(jack_client_t *client, int idx) {
|
||||||
struct channel_t *cur = get_channels_array();
|
struct channel_t *cur = get_channels_array();
|
||||||
|
|
||||||
@@ -24,12 +31,10 @@ void channel_add(jack_client_t *client, int idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_store(&cur[idx].active, 1);
|
atomic_store(&cur[idx].active, 1);
|
||||||
atomic_store(&cur[idx].state, STATE_IDLE);
|
|
||||||
cur[idx].prev_state = -1;
|
|
||||||
cur[idx].loop_count = 0;
|
|
||||||
cur[idx].record_pos = 0;
|
|
||||||
cur[idx].playback_pos = 0;
|
|
||||||
cur[idx].type = CHANNEL_AUDIO;
|
cur[idx].type = CHANNEL_AUDIO;
|
||||||
|
cur[idx].scene_count = 1;
|
||||||
|
cur[idx].current_scene = 0;
|
||||||
|
init_scene(&cur[idx].scenes[0]);
|
||||||
|
|
||||||
next_channel_id++;
|
next_channel_id++;
|
||||||
atomic_fetch_add(&channel_count, 1);
|
atomic_fetch_add(&channel_count, 1);
|
||||||
@@ -54,12 +59,10 @@ void channel_add_midi(jack_client_t *client, int idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
atomic_store(&cur[idx].active, 1);
|
atomic_store(&cur[idx].active, 1);
|
||||||
atomic_store(&cur[idx].state, STATE_IDLE);
|
|
||||||
cur[idx].prev_state = -1;
|
|
||||||
cur[idx].loop_count = 0;
|
|
||||||
cur[idx].record_pos = 0;
|
|
||||||
cur[idx].playback_pos = 0;
|
|
||||||
cur[idx].type = CHANNEL_MIDI;
|
cur[idx].type = CHANNEL_MIDI;
|
||||||
|
cur[idx].scene_count = 1;
|
||||||
|
cur[idx].current_scene = 0;
|
||||||
|
init_scene(&cur[idx].scenes[0]);
|
||||||
|
|
||||||
next_channel_id++;
|
next_channel_id++;
|
||||||
atomic_fetch_add(&channel_count, 1);
|
atomic_fetch_add(&channel_count, 1);
|
||||||
@@ -71,3 +74,47 @@ void channel_remove(jack_client_t *client, int idx) {
|
|||||||
atomic_store(&cur[idx].active, 0);
|
atomic_store(&cur[idx].active, 0);
|
||||||
atomic_fetch_sub(&channel_count, 1);
|
atomic_fetch_sub(&channel_count, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void channel_add_scene(jack_client_t *client, int idx) {
|
||||||
|
(void)client;
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
if (cur[idx].scene_count >= MAX_SCENES)
|
||||||
|
return;
|
||||||
|
int ns = cur[idx].scene_count;
|
||||||
|
init_scene(&cur[idx].scenes[ns]);
|
||||||
|
cur[idx].scene_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void channel_remove_scene(jack_client_t *client, int idx) {
|
||||||
|
(void)client;
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
if (cur[idx].scene_count <= 1)
|
||||||
|
return;
|
||||||
|
int cs = cur[idx].current_scene;
|
||||||
|
/* shift remaining scenes down */
|
||||||
|
for (int i = cs; i < cur[idx].scene_count - 1; i++) {
|
||||||
|
cur[idx].scenes[i] = cur[idx].scenes[i + 1];
|
||||||
|
}
|
||||||
|
cur[idx].scene_count--;
|
||||||
|
if (cur[idx].current_scene >= cur[idx].scene_count)
|
||||||
|
cur[idx].current_scene = cur[idx].scene_count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void channel_next_scene(jack_client_t *client, int idx) {
|
||||||
|
(void)client;
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
if (cur[idx].scene_count > 1) {
|
||||||
|
cur[idx].current_scene =
|
||||||
|
(cur[idx].current_scene + 1) % cur[idx].scene_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void channel_prev_scene(jack_client_t *client, int idx) {
|
||||||
|
(void)client;
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
if (cur[idx].scene_count > 1) {
|
||||||
|
cur[idx].current_scene =
|
||||||
|
(cur[idx].current_scene - 1 + cur[idx].scene_count) %
|
||||||
|
cur[idx].scene_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#define MAX_MIDI_EVENTS 1024
|
#define MAX_MIDI_EVENTS 1024
|
||||||
|
|
||||||
|
#define MAX_SCENES 16
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CHANNEL_AUDIO,
|
CHANNEL_AUDIO,
|
||||||
CHANNEL_MIDI
|
CHANNEL_MIDI
|
||||||
@@ -28,23 +30,28 @@ typedef enum {
|
|||||||
STATE_PAUSED
|
STATE_PAUSED
|
||||||
} looper_state;
|
} looper_state;
|
||||||
|
|
||||||
struct channel_t {
|
typedef struct {
|
||||||
channel_type_t type; /* CHANNEL_AUDIO or CHANNEL_MIDI */
|
|
||||||
|
|
||||||
atomic_int state;
|
|
||||||
int prev_state;
|
|
||||||
union {
|
union {
|
||||||
float audio_buffer[LOOP_BUF_SIZE];
|
float audio_buffer[LOOP_BUF_SIZE];
|
||||||
midi_event_t midi_events[MAX_MIDI_EVENTS];
|
midi_event_t midi_events[MAX_MIDI_EVENTS];
|
||||||
} loop;
|
} loop;
|
||||||
int loop_count; /* for audio: length in samples; for MIDI: number of recorded events */
|
int loop_count;
|
||||||
int record_pos; /* for audio: sample index; for MIDI: next event index for recording */
|
int record_pos;
|
||||||
int playback_pos; /* for audio: sample index; for MIDI: next event index for playback */
|
int playback_pos;
|
||||||
|
atomic_int state;
|
||||||
|
int prev_state;
|
||||||
|
} scene_t;
|
||||||
|
|
||||||
|
struct channel_t {
|
||||||
|
channel_type_t type;
|
||||||
atomic_int active;
|
atomic_int active;
|
||||||
jack_port_t *audio_in;
|
jack_port_t *audio_in;
|
||||||
jack_port_t *audio_out;
|
jack_port_t *audio_out;
|
||||||
jack_port_t *midi_in;
|
jack_port_t *midi_in;
|
||||||
jack_port_t *midi_out;
|
jack_port_t *midi_out;
|
||||||
|
scene_t scenes[MAX_SCENES];
|
||||||
|
int scene_count;
|
||||||
|
int current_scene;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Globals declared in looper.c */
|
/* Globals declared in looper.c */
|
||||||
@@ -62,4 +69,10 @@ void channel_add(jack_client_t *client, int idx);
|
|||||||
void channel_remove(jack_client_t *client, int idx);
|
void channel_remove(jack_client_t *client, int idx);
|
||||||
void channel_add_midi(jack_client_t *client, int idx);
|
void channel_add_midi(jack_client_t *client, int idx);
|
||||||
|
|
||||||
|
/* Scene management (called from main loop) */
|
||||||
|
void channel_add_scene(jack_client_t *client, int idx);
|
||||||
|
void channel_remove_scene(jack_client_t *client, int idx);
|
||||||
|
void channel_next_scene(jack_client_t *client, int idx);
|
||||||
|
void channel_prev_scene(jack_client_t *client, int idx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,13 +2,17 @@
|
|||||||
#define COMMAND_H
|
#define COMMAND_H
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CMD_CYCLE, // toggle record/stop for a channel
|
CMD_CYCLE, // toggle record/stop for the current scene of a channel
|
||||||
CMD_STOP, // force to idle
|
CMD_STOP, // force to idle for all scenes
|
||||||
CMD_BIND_CHANNEL, // bind a channel index (data = channel)
|
CMD_BIND_CHANNEL, // bind a channel index (data = channel)
|
||||||
CMD_UNBIND, // reset bind to channel 0
|
CMD_UNBIND, // reset bind to channel 0
|
||||||
CMD_ADD_CHANNEL, // add a new dynamic channel
|
CMD_ADD_CHANNEL, // add a new dynamic channel
|
||||||
CMD_REMOVE_CHANNEL, // remove last dynamic channel
|
CMD_REMOVE_CHANNEL, // remove last dynamic channel
|
||||||
CMD_ADD_MIDI_CHANNEL, // add a new dynamic MIDI channel
|
CMD_ADD_MIDI_CHANNEL, // add a new dynamic MIDI channel
|
||||||
|
CMD_NEXT_SCENE,
|
||||||
|
CMD_PREV_SCENE,
|
||||||
|
CMD_ADD_SCENE,
|
||||||
|
CMD_REMOVE_SCENE,
|
||||||
} cmd_type_t;
|
} cmd_type_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
196
src/looper.c
196
src/looper.c
@@ -66,7 +66,9 @@ static void apply_command(command_t cmd) {
|
|||||||
switch (cmd.type) {
|
switch (cmd.type) {
|
||||||
case CMD_CYCLE:
|
case CMD_CYCLE:
|
||||||
if (cmd.channel >= 0 && cmd.channel < cap) {
|
if (cmd.channel >= 0 && cmd.channel < cap) {
|
||||||
int cst = atomic_load(&cur[cmd.channel].state);
|
int sc_idx = cur[cmd.channel].current_scene;
|
||||||
|
scene_t *sc = &cur[cmd.channel].scenes[sc_idx];
|
||||||
|
int cst = atomic_load(&sc->state);
|
||||||
int next;
|
int next;
|
||||||
switch (cst) {
|
switch (cst) {
|
||||||
case STATE_IDLE:
|
case STATE_IDLE:
|
||||||
@@ -85,23 +87,29 @@ static void apply_command(command_t cmd) {
|
|||||||
next = STATE_IDLE;
|
next = STATE_IDLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
atomic_store(&cur[cmd.channel].state, next);
|
atomic_store(&sc->state, next);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_STOP:
|
case CMD_STOP:
|
||||||
if (cmd.channel >= 0 && cmd.channel < cap) {
|
if (cmd.channel >= 0 && cmd.channel < cap) {
|
||||||
atomic_store(&cur[cmd.channel].state, STATE_IDLE);
|
struct channel_t *ch = &cur[cmd.channel];
|
||||||
cur[cmd.channel].loop_count = 0;
|
for (int s = 0; s < ch->scene_count; s++) {
|
||||||
cur[cmd.channel].record_pos = 0;
|
atomic_store(&ch->scenes[s].state, STATE_IDLE);
|
||||||
cur[cmd.channel].playback_pos = 0;
|
ch->scenes[s].loop_count = 0;
|
||||||
cur[cmd.channel].prev_state = -1;
|
ch->scenes[s].record_pos = 0;
|
||||||
|
ch->scenes[s].playback_pos = 0;
|
||||||
|
ch->scenes[s].prev_state = -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < cap; i++) {
|
for (int i = 0; i < cap; i++) {
|
||||||
atomic_store(&cur[i].state, STATE_IDLE);
|
struct channel_t *ch = &cur[i];
|
||||||
cur[i].loop_count = 0;
|
for (int s = 0; s < ch->scene_count; s++) {
|
||||||
cur[i].record_pos = 0;
|
atomic_store(&ch->scenes[s].state, STATE_IDLE);
|
||||||
cur[i].playback_pos = 0;
|
ch->scenes[s].loop_count = 0;
|
||||||
cur[i].prev_state = -1;
|
ch->scenes[s].record_pos = 0;
|
||||||
|
ch->scenes[s].playback_pos = 0;
|
||||||
|
ch->scenes[s].prev_state = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -158,6 +166,10 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Obtain current scene pointer */
|
||||||
|
int sc_idx = active_channels[c].current_scene;
|
||||||
|
scene_t *sc = &active_channels[c].scenes[sc_idx];
|
||||||
|
|
||||||
const jack_default_audio_sample_t *in =
|
const jack_default_audio_sample_t *in =
|
||||||
(const jack_default_audio_sample_t *)jack_port_get_buffer(
|
(const jack_default_audio_sample_t *)jack_port_get_buffer(
|
||||||
active_channels[c].audio_in, nframes);
|
active_channels[c].audio_in, nframes);
|
||||||
@@ -167,18 +179,18 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
if (!out)
|
if (!out)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int state = atomic_load(&active_channels[c].state);
|
int state = atomic_load(&sc->state);
|
||||||
|
|
||||||
if (state != active_channels[c].prev_state) {
|
if (state != sc->prev_state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_RECORD:
|
case STATE_RECORD:
|
||||||
active_channels[c].record_pos = 0;
|
sc->record_pos = 0;
|
||||||
active_channels[c].loop_count = 0;
|
sc->loop_count = 0;
|
||||||
break;
|
break;
|
||||||
case STATE_LOOPING:
|
case STATE_LOOPING:
|
||||||
if (active_channels[c].record_pos > 0)
|
if (sc->record_pos > 0)
|
||||||
active_channels[c].loop_count = active_channels[c].record_pos;
|
sc->loop_count = sc->record_pos;
|
||||||
active_channels[c].playback_pos = 0;
|
sc->playback_pos = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -197,20 +209,14 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
for (jack_nframes_t j = 0; j < nevents; j++) {
|
for (jack_nframes_t j = 0; j < nevents; j++) {
|
||||||
if (jack_midi_event_get(&ev, midi_in_buf, j) != 0)
|
if (jack_midi_event_get(&ev, midi_in_buf, j) != 0)
|
||||||
continue;
|
continue;
|
||||||
if (active_channels[c].record_pos < MAX_MIDI_EVENTS) {
|
if (sc->record_pos < MAX_MIDI_EVENTS) {
|
||||||
active_channels[c]
|
sc->loop.midi_events[sc->record_pos].timestamp = ev.time;
|
||||||
.loop.midi_events[active_channels[c].record_pos]
|
sc->loop.midi_events[sc->record_pos].status = ev.buffer[0];
|
||||||
.timestamp = ev.time;
|
sc->loop.midi_events[sc->record_pos].note =
|
||||||
active_channels[c]
|
(ev.size > 1) ? ev.buffer[1] : 0;
|
||||||
.loop.midi_events[active_channels[c].record_pos]
|
sc->loop.midi_events[sc->record_pos].velocity =
|
||||||
.status = ev.buffer[0];
|
(ev.size > 2) ? ev.buffer[2] : 0;
|
||||||
active_channels[c]
|
sc->record_pos++;
|
||||||
.loop.midi_events[active_channels[c].record_pos]
|
|
||||||
.note = (ev.size > 1) ? ev.buffer[1] : 0;
|
|
||||||
active_channels[c]
|
|
||||||
.loop.midi_events[active_channels[c].record_pos]
|
|
||||||
.velocity = (ev.size > 2) ? ev.buffer[2] : 0;
|
|
||||||
active_channels[c].record_pos++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* forward incoming MIDI to output during record */
|
/* forward incoming MIDI to output during record */
|
||||||
@@ -232,15 +238,13 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
jack_port_get_buffer(active_channels[c].midi_out, nframes);
|
jack_port_get_buffer(active_channels[c].midi_out, nframes);
|
||||||
if (midi_out_buf) {
|
if (midi_out_buf) {
|
||||||
jack_midi_clear_buffer(midi_out_buf);
|
jack_midi_clear_buffer(midi_out_buf);
|
||||||
int cnt =
|
int cnt = sc->loop_count;
|
||||||
active_channels[c].loop_count; /* number of recorded events */
|
|
||||||
if (cnt > 0) {
|
if (cnt > 0) {
|
||||||
/* simple: output all recorded events at frame 0 of each cycle */
|
|
||||||
for (int e = 0; e < cnt; e++) {
|
for (int e = 0; e < cnt; e++) {
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
msg[0] = active_channels[c].loop.midi_events[e].status;
|
msg[0] = sc->loop.midi_events[e].status;
|
||||||
msg[1] = active_channels[c].loop.midi_events[e].note;
|
msg[1] = sc->loop.midi_events[e].note;
|
||||||
msg[2] = active_channels[c].loop.midi_events[e].velocity;
|
msg[2] = sc->loop.midi_events[e].velocity;
|
||||||
jack_midi_event_write(midi_out_buf, 0, msg, 3);
|
jack_midi_event_write(midi_out_buf, 0, msg, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +255,6 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
/* no output */
|
/* no output */
|
||||||
break;
|
break;
|
||||||
default: /* IDLE */
|
default: /* IDLE */
|
||||||
/* pass through MIDI input to output */
|
|
||||||
{
|
{
|
||||||
void *midi_in_buf =
|
void *midi_in_buf =
|
||||||
jack_port_get_buffer(active_channels[c].midi_in, nframes);
|
jack_port_get_buffer(active_channels[c].midi_in, nframes);
|
||||||
@@ -270,9 +273,8 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* for MIDI channels, the loop_count holds number of recorded events */
|
|
||||||
if (state == STATE_LOOPING) {
|
if (state == STATE_LOOPING) {
|
||||||
active_channels[c].loop_count = active_channels[c].record_pos;
|
sc->loop_count = sc->record_pos;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* audio channel handling */
|
/* audio channel handling */
|
||||||
@@ -283,9 +285,8 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
float *f_out = (float *)out;
|
float *f_out = (float *)out;
|
||||||
const float *f_in = (const float *)in;
|
const float *f_in = (const float *)in;
|
||||||
for (i = 0; i < nframes; i++) {
|
for (i = 0; i < nframes; i++) {
|
||||||
if (active_channels[c].record_pos < LOOP_BUF_SIZE)
|
if (sc->record_pos < LOOP_BUF_SIZE)
|
||||||
active_channels[c]
|
sc->loop.audio_buffer[sc->record_pos++] = f_in[i];
|
||||||
.loop.audio_buffer[active_channels[c].record_pos++] = f_in[i];
|
|
||||||
f_out[i] = f_in[i];
|
f_out[i] = f_in[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -294,14 +295,11 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case STATE_LOOPING:
|
case STATE_LOOPING:
|
||||||
if (active_channels[c].loop_count > 0) {
|
if (sc->loop_count > 0) {
|
||||||
float *outf = (float *)out;
|
float *outf = (float *)out;
|
||||||
for (i = 0; i < nframes; i++) {
|
for (i = 0; i < nframes; i++) {
|
||||||
outf[i] = active_channels[c]
|
outf[i] = sc->loop.audio_buffer[sc->playback_pos];
|
||||||
.loop.audio_buffer[active_channels[c].playback_pos];
|
sc->playback_pos = (sc->playback_pos + 1) % sc->loop_count;
|
||||||
active_channels[c].playback_pos =
|
|
||||||
(active_channels[c].playback_pos + 1) %
|
|
||||||
active_channels[c].loop_count;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
memset(out, 0, sizeof(jack_default_audio_sample_t) * nframes);
|
||||||
@@ -322,7 +320,7 @@ int process_callback(jack_nframes_t nframes, void *arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
active_channels[c].prev_state = state;
|
sc->prev_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI clock events – affect channel 0 only */
|
/* MIDI clock events – affect channel 0 only */
|
||||||
@@ -392,12 +390,14 @@ int looper_init(jack_client_t *client) {
|
|||||||
}
|
}
|
||||||
struct channel_t *init = atomic_load(&channels);
|
struct channel_t *init = atomic_load(&channels);
|
||||||
/* channel 0 */
|
/* channel 0 */
|
||||||
init[0].active = 1;
|
atomic_store(&init[0].active, 1);
|
||||||
atomic_store(&init[0].state, STATE_IDLE);
|
init[0].scene_count = 1;
|
||||||
init[0].prev_state = -1;
|
init[0].current_scene = 0;
|
||||||
init[0].loop_count = 0;
|
init[0].scenes[0].loop_count = 0;
|
||||||
init[0].record_pos = 0;
|
init[0].scenes[0].record_pos = 0;
|
||||||
init[0].playback_pos = 0;
|
init[0].scenes[0].playback_pos = 0;
|
||||||
|
atomic_store(&init[0].scenes[0].state, STATE_IDLE);
|
||||||
|
init[0].scenes[0].prev_state = -1;
|
||||||
|
|
||||||
init[0].audio_in = jack_port_register(
|
init[0].audio_in = jack_port_register(
|
||||||
client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
||||||
@@ -471,6 +471,46 @@ void looper_process_commands(jack_client_t *client) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_ADD_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_add_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_REMOVE_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_remove_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_NEXT_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_next_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_PREV_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_prev_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -519,6 +559,46 @@ void looper_process_commands(jack_client_t *client) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CMD_ADD_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_add_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_REMOVE_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_remove_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_NEXT_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_next_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CMD_PREV_SCENE: {
|
||||||
|
int cap = atomic_load(&channel_capacity);
|
||||||
|
struct channel_t *cur = get_channels_array();
|
||||||
|
int bind = atomic_load(&bind_channel);
|
||||||
|
int ch = bind;
|
||||||
|
if (ch < cap) {
|
||||||
|
channel_prev_scene(client, ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/midi.c
20
src/midi.c
@@ -71,6 +71,26 @@ void midi_handle_events(void *port_buffer, jack_nframes_t nframes) {
|
|||||||
.type = CMD_ADD_MIDI_CHANNEL, .channel = -1, .data = 0};
|
.type = CMD_ADD_MIDI_CHANNEL, .channel = -1, .data = 0};
|
||||||
queue_push(&cmd_queue_main_midi, cmd);
|
queue_push(&cmd_queue_main_midi, cmd);
|
||||||
} break;
|
} break;
|
||||||
|
case 67: {
|
||||||
|
command_t cmd = {
|
||||||
|
.type = CMD_NEXT_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_midi, cmd);
|
||||||
|
} break;
|
||||||
|
case 68: {
|
||||||
|
command_t cmd = {
|
||||||
|
.type = CMD_PREV_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_midi, cmd);
|
||||||
|
} break;
|
||||||
|
case 69: {
|
||||||
|
command_t cmd = {
|
||||||
|
.type = CMD_ADD_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_midi, cmd);
|
||||||
|
} break;
|
||||||
|
case 70: {
|
||||||
|
command_t cmd = {
|
||||||
|
.type = CMD_REMOVE_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_midi, cmd);
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/pipe.c
12
src/pipe.c
@@ -54,6 +54,18 @@ static void *pipe_thread_func(void *arg) {
|
|||||||
} else if (strcmp(line, "unbind") == 0) {
|
} else if (strcmp(line, "unbind") == 0) {
|
||||||
command_t cmd = {.type = CMD_UNBIND, .channel = -1, .data = 0};
|
command_t cmd = {.type = CMD_UNBIND, .channel = -1, .data = 0};
|
||||||
queue_push(&cmd_queue, cmd);
|
queue_push(&cmd_queue, cmd);
|
||||||
|
} else if (strcmp(line, "scene_add") == 0) {
|
||||||
|
command_t cmd = {.type = CMD_ADD_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_fifo, cmd);
|
||||||
|
} else if (strcmp(line, "scene_remove") == 0) {
|
||||||
|
command_t cmd = {.type = CMD_REMOVE_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_fifo, cmd);
|
||||||
|
} else if (strcmp(line, "scene_next") == 0) {
|
||||||
|
command_t cmd = {.type = CMD_NEXT_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_fifo, cmd);
|
||||||
|
} else if (strcmp(line, "scene_prev") == 0) {
|
||||||
|
command_t cmd = {.type = CMD_PREV_SCENE, .channel = -1, .data = 0};
|
||||||
|
queue_push(&cmd_queue_main_fifo, cmd);
|
||||||
}
|
}
|
||||||
/* ignore unknown lines */
|
/* ignore unknown lines */
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user