Files
looper/engine/src/channel.c

134 lines
4.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// cppcheck-suppress missingIncludeSystem
#include "channel.h"
#include <jack/jack.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
/* Helper: zero a scene and set its state to IDLE */
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) {
char in_name[64], out_name[64];
pid_t pid = getpid();
snprintf(in_name, sizeof(in_name), "ch%din", next_channel_id);
snprintf(out_name, sizeof(out_name), "ch%dout", next_channel_id);
/* Always register audio ports (needed for pass-through even for MIDI
* channels?) */
channels[idx].audio_in = jack_port_register(
client, in_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
channels[idx].audio_out = jack_port_register(
client, out_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if (!channels[idx].audio_in || !channels[idx].audio_out) {
fprintf(stderr, "Failed to register ports for channel %d\n",
next_channel_id);
/* Do NOT mark channel active process loop will skip it */
atomic_store(&channels[idx].active, 0);
return;
}
/* If this is a MIDI channel, register MIDI ports */
if (channels[idx].type == CHANNEL_MIDI) {
char midi_in_name[64], midi_out_name[64];
snprintf(midi_in_name, sizeof(midi_in_name), "ch%dmidiin",
next_channel_id);
snprintf(midi_out_name, sizeof(midi_out_name), "ch%dmidiout",
next_channel_id);
channels[idx].midi_in = jack_port_register(
client, midi_in_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
channels[idx].midi_out = jack_port_register(
client, midi_out_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
if (!channels[idx].midi_in || !channels[idx].midi_out) {
fprintf(stderr, "Failed to register MIDI ports for channel %d\n",
next_channel_id);
atomic_store(&channels[idx].active, 0);
jack_port_unregister(client, channels[idx].audio_in);
jack_port_unregister(client, channels[idx].audio_out);
return;
}
} else {
channels[idx].midi_in = NULL;
channels[idx].midi_out = NULL;
}
atomic_store(&channels[idx].active, 1);
/* Initialise first scene */
channels[idx].scene_count = 1;
channels[idx].current_scene = 0;
init_scene(&channels[idx].scenes[0]);
channels[idx].save_ring = NULL;
atomic_store(&channels[idx].save_complete, 0);
next_channel_id++;
channel_count++;
}
void channel_remove(jack_client_t *client, int idx) {
(void)client;
atomic_store_explicit(&channels[idx].active, 0, memory_order_release);
atomic_fetch_sub_explicit(&channel_count, 1, memory_order_release);
}
void channel_add_scene(jack_client_t *client, int idx) {
(void)client;
if (atomic_load(&channels[idx].scene_count) >= MAX_SCENES)
return;
int ns = atomic_load(&channels[idx].scene_count);
init_scene(&channels[idx].scenes[ns]);
atomic_fetch_add(&channels[idx].scene_count, 1);
}
void channel_remove_scene(jack_client_t *client, int idx) {
(void)client;
int sc = atomic_load(&channels[idx].scene_count);
if (sc <= 1)
return;
int cs = atomic_load(&channels[idx].current_scene);
/* shift remaining scenes down (atomic copy of fields) */
for (int i = cs; i < sc - 1; i++) {
atomic_store(&channels[idx].scenes[i].loop_count,
atomic_load(&channels[idx].scenes[i + 1].loop_count));
atomic_store(&channels[idx].scenes[i].record_pos,
atomic_load(&channels[idx].scenes[i + 1].record_pos));
atomic_store(&channels[idx].scenes[i].playback_pos,
atomic_load(&channels[idx].scenes[i + 1].playback_pos));
atomic_store(&channels[idx].scenes[i].state,
atomic_load(&channels[idx].scenes[i + 1].state));
atomic_store(&channels[idx].scenes[i].prev_state,
atomic_load(&channels[idx].scenes[i + 1].prev_state));
/* copy loop data (may race with RT thread; acceptable for this release) */
memcpy(channels[idx].scenes[i].loop.audio_buffer,
channels[idx].scenes[i + 1].loop.audio_buffer,
LOOP_BUF_SIZE * sizeof(float));
}
atomic_fetch_sub(&channels[idx].scene_count, 1);
int new_sc = atomic_load(&channels[idx].scene_count);
if (cs >= new_sc)
atomic_store(&channels[idx].current_scene, new_sc - 1);
}
void channel_next_scene(jack_client_t *client, int idx) {
(void)client;
int sc = atomic_load(&channels[idx].scene_count);
if (sc > 1) {
int cs = atomic_load(&channels[idx].current_scene);
atomic_store(&channels[idx].current_scene, (cs + 1) % sc);
}
}
void channel_prev_scene(jack_client_t *client, int idx) {
(void)client;
int sc = atomic_load(&channels[idx].scene_count);
if (sc > 1) {
int cs = atomic_load(&channels[idx].current_scene);
atomic_store(&channels[idx].current_scene, (cs - 1 + sc) % sc);
}
}