// cppcheck-suppress missingIncludeSystem #include "channel.h" #include #include #include #include /* 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); } }