feat(midi): add device routing and bounded external note output (phase 101)

This commit is contained in:
Johannes Findeisen 2026-11-06 02:23:37 +01:00
commit 75dee16b6a
9 changed files with 251 additions and 15 deletions

View file

@ -20,7 +20,8 @@ static JackXRunCallback xrun_cb;
static JackShutdownCallback shutdown_cb;
static void *context;
static float input[128], output[128], output_right[128];
static int client_token, input_token, output_token, right_token, midi_token;
static int client_token, input_token, output_token, right_token, midi_token, midi_output_token;
static unsigned char sent[512][3];static unsigned int sent_time[512],sent_count;
static unsigned int midi_count;
static jack_midi_event_t midi_events[256];
static int open_fail, register_fail, callback_fail, activate_fail, deactivate_fail, close_fail;
@ -46,6 +47,7 @@ jack_port_t *jack_port_register(jack_client_t *client, const char *name, const c
++port_calls;
if (register_fail == port_calls) return NULL;
if (!strcmp(name, "output_right")) return (jack_port_t *)&right_token;
if(!strcmp(name,"midi_out"))return (jack_port_t *)&midi_output_token;
if (!strcmp(type, JACK_DEFAULT_MIDI_TYPE)) return (jack_port_t *)&midi_token;
return (jack_port_t *)(flags == JackPortIsInput ? &input_token : &output_token);
}
@ -68,12 +70,15 @@ int jack_activate(jack_client_t *client)
int jack_deactivate(jack_client_t *client)
{ (void)client; if (deactivate_fail) return -1; active = 0; return 0; }
void *jack_port_get_buffer(jack_port_t *port, jack_nframes_t frames)
{ (void)frames; if (null_buffer) return NULL; if (port == (jack_port_t *)&midi_token) return &midi_token; if (port == (jack_port_t *)&right_token) return output_right; return port == (jack_port_t *)&input_token ? input : output; }
{ (void)frames; if (null_buffer) return NULL; if(port==(jack_port_t *)&midi_output_token)return &midi_output_token; if (port == (jack_port_t *)&midi_token) return &midi_token; if (port == (jack_port_t *)&right_token) return output_right; return port == (jack_port_t *)&input_token ? input : output; }
void jack_midi_clear_buffer(void *buffer){(void)buffer;sent_count=0;}
int jack_midi_event_write(void *buffer,jack_nframes_t time,const jack_midi_data_t *data,size_t size)
{(void)buffer;if(size!=3 || sent_count>=512)return -1;memcpy(sent[sent_count],data,3);sent_time[sent_count++]=time;return 0;}
uint32_t jack_midi_get_event_count(void *buffer) { (void)buffer; return midi_count; }
int jack_midi_event_get(jack_midi_event_t *event, void *buffer, uint32_t index)
{ (void)buffer; if (index >= midi_count || index >= 256) return -1; *event = midi_events[index]; return 0; }
const char *jack_port_name(const jack_port_t *port)
{ if (port == (jack_port_t *)&right_token) return "test:output_right"; if (port == (jack_port_t *)&midi_token) return "test:midi_in"; return port == (jack_port_t *)&input_token ? "test:input" : "test:output"; }
{ if(port==(jack_port_t *)&midi_output_token)return "test:midi_out"; if (port == (jack_port_t *)&right_token) return "test:output_right"; if (port == (jack_port_t *)&midi_token) return "test:midi_in"; return port == (jack_port_t *)&input_token ? "test:input" : "test:output"; }
const char **jack_get_ports(jack_client_t *client, const char *pattern, const char *type, unsigned long flags)
{
const char **list = malloc(2U * sizeof(*list));
@ -402,6 +407,23 @@ int main(void)
xtc_project_destroy(p);
}
CHECK(closed >= 104);
{
xtc_project *p=NULL;uint64_t t,c,n;const char *midi_name=NULL;unsigned char on[]={0x92,64,100};
CHECK(xtc_project_create(&p)==XTC_OK && xtc_project_add_track(p,"Out",&t)==XTC_OK);
CHECK(xtc_project_add_midi_clip(p,t,0,3840,&c)==XTC_OK && xtc_project_add_note(p,c,0,960,60,90,1,&n)==XTC_OK);
CHECK(xtc_backend_open(&config,&backend)==XTC_OK && xtc_backend_prepare_project(backend,p)==XTC_OK);
CHECK(xtc_backend_midi_name(backend,XTC_PORT_OUTPUT,&midi_name)==XTC_OK && !strcmp(midi_name,"test:midi_out"));
CHECK(xtc_backend_set_midi_options(backend,2,4,1)==XTC_OK && xtc_backend_start(backend)==XTC_OK);
CHECK(xtc_backend_route_midi(backend,XTC_PORT_OUTPUT,"device:in",0)==XTC_OK);
CHECK(xtc_backend_set_midi_options(backend,-1,-1,0)==XTC_ERR_INVALID_STATE);
midi_count=1;midi_events[0]=(jack_midi_event_t){8,3,on};CHECK(process_cb(32,context)==0);
CHECK(sent_count==18 && sent[16][0]==0x94 && sent[16][1]==60 && sent_time[17]==8 && sent[17][1]==64);
on[0]=0x93;CHECK(process_cb(32,context)==0 && sent_count==0);
midi_count=0;CHECK(xtc_backend_panic(backend)==XTC_OK && process_cb(32,context)==0 && sent_count==16);
CHECK(xtc_backend_stop(backend)==XTC_OK && xtc_backend_seek(backend,23984)==XTC_OK && xtc_backend_start(backend)==XTC_OK);
CHECK(process_cb(32,context)==0 && sent_count==18 && sent[16][0]==0x94 && sent_time[16]==0 && sent[17][0]==0x84 && sent_time[17]==16);
CHECK(xtc_backend_stop(backend)==XTC_OK && xtc_backend_close(backend)==XTC_OK);xtc_project_destroy(p);
}
CHECK(xtc_backend_close(NULL) == XTC_OK);
xtc_graph_destroy(invalid_graph);
xtc_graph_destroy(graph);