137 lines
4.8 KiB
C
137 lines
4.8 KiB
C
// cppcheck-suppress missingIncludeSystem
|
|
#include "channel.h"
|
|
#include <jack/jack.h>
|
|
#include <stdatomic.h>
|
|
#include <stdio.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);
|
|
atomic_store(&sc->prev_state, -1);
|
|
}
|
|
|
|
void channel_add(jack_client_t *client, int idx) {
|
|
struct channel_t *cur = get_channels_array();
|
|
|
|
char in_name[64], out_name[64];
|
|
snprintf(in_name, sizeof(in_name), "channel%d_input", next_channel_id);
|
|
snprintf(out_name, sizeof(out_name), "channel%d_output", next_channel_id);
|
|
|
|
cur[idx].audio_in = jack_port_register(
|
|
client, in_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
|
cur[idx].audio_out = jack_port_register(
|
|
client, out_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
|
if (!cur[idx].audio_in || !cur[idx].audio_out) {
|
|
fprintf(stderr, "Failed to register ports for channel %d\n",
|
|
next_channel_id);
|
|
atomic_store(&cur[idx].active, 0);
|
|
return;
|
|
}
|
|
|
|
atomic_store(&cur[idx].active, 1);
|
|
cur[idx].type = CHANNEL_AUDIO;
|
|
atomic_store(&cur[idx].scene_count, 1);
|
|
atomic_store(&cur[idx].current_scene, 0);
|
|
init_scene(&cur[idx].scenes[0]);
|
|
|
|
next_channel_id++;
|
|
atomic_fetch_add(&channel_count, 1);
|
|
}
|
|
|
|
void channel_add_midi(jack_client_t *client, int idx) {
|
|
struct channel_t *cur = get_channels_array();
|
|
|
|
char in_name[64], out_name[64];
|
|
snprintf(in_name, sizeof(in_name), "channel%d_midi_in", next_channel_id);
|
|
snprintf(out_name, sizeof(out_name), "channel%d_midi_out", next_channel_id);
|
|
|
|
cur[idx].midi_in = jack_port_register(client, in_name, JACK_DEFAULT_MIDI_TYPE,
|
|
JackPortIsInput, 0);
|
|
cur[idx].midi_out = jack_port_register(
|
|
client, out_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
|
|
if (!cur[idx].midi_in || !cur[idx].midi_out) {
|
|
fprintf(stderr, "Failed to register MIDI ports for channel %d\n",
|
|
next_channel_id);
|
|
atomic_store(&cur[idx].active, 0);
|
|
return;
|
|
}
|
|
|
|
atomic_store(&cur[idx].active, 1);
|
|
cur[idx].type = CHANNEL_MIDI;
|
|
atomic_store(&cur[idx].scene_count, 1);
|
|
atomic_store(&cur[idx].current_scene, 0);
|
|
init_scene(&cur[idx].scenes[0]);
|
|
|
|
next_channel_id++;
|
|
atomic_fetch_add(&channel_count, 1);
|
|
}
|
|
|
|
void channel_remove(jack_client_t *client, int idx) {
|
|
(void)client;
|
|
struct channel_t *cur = get_channels_array();
|
|
atomic_store(&cur[idx].active, 0);
|
|
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 (atomic_load(&cur[idx].scene_count) >= MAX_SCENES)
|
|
return;
|
|
int ns = atomic_load(&cur[idx].scene_count);
|
|
init_scene(&cur[idx].scenes[ns]);
|
|
atomic_fetch_add(&cur[idx].scene_count, 1);
|
|
}
|
|
|
|
void channel_remove_scene(jack_client_t *client, int idx) {
|
|
(void)client;
|
|
struct channel_t *cur = get_channels_array();
|
|
int sc = atomic_load(&cur[idx].scene_count);
|
|
if (sc <= 1)
|
|
return;
|
|
int cs = atomic_load(&cur[idx].current_scene);
|
|
/* shift remaining scenes down (atomic copy of fields) */
|
|
for (int i = cs; i < sc - 1; i++) {
|
|
atomic_store(&cur[idx].scenes[i].loop_count,
|
|
atomic_load(&cur[idx].scenes[i+1].loop_count));
|
|
atomic_store(&cur[idx].scenes[i].record_pos,
|
|
atomic_load(&cur[idx].scenes[i+1].record_pos));
|
|
atomic_store(&cur[idx].scenes[i].playback_pos,
|
|
atomic_load(&cur[idx].scenes[i+1].playback_pos));
|
|
atomic_store(&cur[idx].scenes[i].state,
|
|
atomic_load(&cur[idx].scenes[i+1].state));
|
|
atomic_store(&cur[idx].scenes[i].prev_state,
|
|
atomic_load(&cur[idx].scenes[i+1].prev_state));
|
|
/* copy loop data (may race with RT thread; acceptable for this release) */
|
|
memcpy(cur[idx].scenes[i].loop.audio_buffer,
|
|
cur[idx].scenes[i+1].loop.audio_buffer,
|
|
LOOP_BUF_SIZE * sizeof(float));
|
|
}
|
|
atomic_fetch_sub(&cur[idx].scene_count, 1);
|
|
int new_sc = atomic_load(&cur[idx].scene_count);
|
|
if (cs >= new_sc)
|
|
atomic_store(&cur[idx].current_scene, new_sc - 1);
|
|
}
|
|
|
|
void channel_next_scene(jack_client_t *client, int idx) {
|
|
(void)client;
|
|
struct channel_t *cur = get_channels_array();
|
|
int sc = atomic_load(&cur[idx].scene_count);
|
|
if (sc > 1) {
|
|
int cs = atomic_load(&cur[idx].current_scene);
|
|
atomic_store(&cur[idx].current_scene, (cs + 1) % sc);
|
|
}
|
|
}
|
|
|
|
void channel_prev_scene(jack_client_t *client, int idx) {
|
|
(void)client;
|
|
struct channel_t *cur = get_channels_array();
|
|
int sc = atomic_load(&cur[idx].scene_count);
|
|
if (sc > 1) {
|
|
int cs = atomic_load(&cur[idx].current_scene);
|
|
atomic_store(&cur[idx].current_scene, (cs - 1 + sc) % sc);
|
|
}
|
|
}
|