diff --git a/sysmisc.c b/sysmisc.c index b91efc3..11a15a9 100644 --- a/sysmisc.c +++ b/sysmisc.c @@ -1,5 +1,6 @@ #include "sysmisc.h" #include "gbuffer.h" +#include "oso.h" #include ORCA_FORCE_NO_INLINE @@ -168,3 +169,44 @@ ok: *out_rightsize = b1 - b0; return Conf_read_left_and_right; } + +typedef enum { + Conf_dir_ok = 0, + Conf_dir_no_home, +} Conf_dir_error; + +static char const* const xdg_config_home_env = "XDG_CONFIG_HOME"; +static char const* const home_env = "HOME"; +static char const* const conf_file_name = "/orca.conf"; + +static Conf_dir_error try_get_conf_dir(oso** out) { + char const* xdgcfgdir = getenv(xdg_config_home_env); + if (xdgcfgdir) { + Usz xdgcfgdirlen = strlen(xdgcfgdir); + if (xdgcfgdirlen > 0) { + osoputlen(out, xdgcfgdir, xdgcfgdirlen); + return Conf_dir_ok; + } + } + char const* homedir = getenv(home_env); + if (homedir) { + Usz homedirlen = strlen(homedir); + if (homedirlen > 0) { + osoputprintf(out, "%s/.config", homedir); + return Conf_dir_ok; + } + } + return Conf_dir_no_home; +} + +FILE* conf_file_open_for_reading(void) { + oso* path = NULL; + if (try_get_conf_dir(&path)) + return NULL; + osocat(&path, conf_file_name); + if (!path) + return NULL; + FILE* file = fopen(osoc(path), "r"); + osofree(path); + return file; +} diff --git a/sysmisc.h b/sysmisc.h index 5a4e72d..50d28f9 100644 --- a/sysmisc.h +++ b/sysmisc.h @@ -27,3 +27,6 @@ typedef enum { Conf_read_result conf_read_line(FILE* file, char* buf, Usz bufsize, char** out_left, Usz* out_leftlen, char** out_right, Usz* out_rightlen); + + +FILE* conf_file_open_for_reading(void); diff --git a/tui_main.c b/tui_main.c index 0cd39e0..b088d8e 100644 --- a/tui_main.c +++ b/tui_main.c @@ -10,6 +10,8 @@ #include #include +#include + #define SOKOL_IMPL #include "sokol_time.h" #undef SOKOL_IMPL @@ -786,13 +788,40 @@ PmError portmidi_init_if_necessary(void) { PmError midi_mode_init_portmidi(Midi_mode* mm, PmDeviceID dev_id) { PmError e = portmidi_init_if_necessary(); if (e) - return e; + goto fail; e = Pm_OpenOutput(&mm->portmidi.stream, dev_id, NULL, 0, NULL, NULL, 0); if (e) - return e; + goto fail; mm->portmidi.type = Midi_mode_type_portmidi; mm->portmidi.device_id = dev_id; return pmNoError; + +fail: + midi_mode_init_null(mm); + return e; +} +// Returns true on success. todo currently output only +bool portmidi_find_device_id_by_name(char const* name, Usz namelen, + PmError* out_pmerror, PmDeviceID* out_id) { + fprintf(stderr, "hi there\n"); + *out_pmerror = portmidi_init_if_necessary(); + if (*out_pmerror) + return false; + int num = Pm_CountDevices(); + for (int i = 0; i < num; ++i) { + PmDeviceInfo const* info = Pm_GetDeviceInfo(i); + if (!info || !info->output) + continue; + Usz len = strlen(info->name); + fprintf(stderr, "trying: %s\n", info->name); + if (len != namelen) + continue; + if (strncmp(name, info->name, namelen) == 0) { + *out_id = i; + return true; + } + } + return false; } #endif void midi_mode_deinit(Midi_mode* mm) { @@ -2340,6 +2369,64 @@ char const* field_load_error_string(Field_load_error fle) { return errstr; } +typedef struct { + oso* portmidi_output_device; +} Prefs; + +void prefs_init(Prefs* p) { memset(p, 0, sizeof(Prefs)); } +void prefs_deinit(Prefs* p) { osofree(p->portmidi_output_device); } + +typedef enum { + Prefs_load_ok = 0, +} Prefs_load_error; + +ORCA_FORCE_NO_INLINE +Prefs_load_error prefs_load_from_conf_file(Prefs* p) { + (void)p; + FILE* conffile = conf_file_open_for_reading(); + if (!conffile) { + return Prefs_load_ok; + } + char linebuff[512]; + for (;;) { + char *left, *right; + Usz leftsz, rightsz; + Conf_read_result res = conf_read_line(conffile, linebuff, sizeof linebuff, + &left, &leftsz, &right, &rightsz); + switch (res) { + case Conf_read_left_and_right: { + if (strcmp("portmidi_output_device", left) == 0) { + osoput(&p->portmidi_output_device, right); + } + continue; + } + case Conf_read_irrelevant: + continue; + case Conf_read_buffer_too_small: + case Conf_read_eof: + case Conf_read_io_error: + break; + } + break; + } + fclose(conffile); + return Prefs_load_ok; +} + +void print_loading_message(char const* s) { + Usz len = strlen(s); + if (len > INT_MAX) + return; + int h, w; + getmaxyx(stdscr, h, w); + int y = h / 2; + int x = (int)len < w ? (w - (int)len) / 2 : 0; + werase(stdscr); + wmove(stdscr, y, x); + waddstr(stdscr, s); + refresh(); +} + // // main // @@ -2582,6 +2669,8 @@ int main(int argc, char** argv) { osofree(file_name); exit(1); } + mbuf_reusable_ensure_size(&ged_state.mbuf_r, ged_state.field.height, + ged_state.field.width); } else { // Temp hacky stuff: we've crammed two code paths into the KEY_RESIZE event // case. One of them is for the initial setup for an automatic grid size. @@ -2595,6 +2684,8 @@ int main(int argc, char** argv) { if (!should_autosize_grid) { field_init_fill(&ged_state.field, (Usz)init_grid_dim_y, (Usz)init_grid_dim_x, '.'); + mbuf_reusable_ensure_size(&ged_state.mbuf_r, ged_state.field.height, + ged_state.field.width); } } ged_state.filename = osolen(file_name) ? osoc(file_name) : "unnamed"; @@ -2641,6 +2732,34 @@ int main(int argc, char** argv) { printf("\033[?2004h\n"); // Ask terminal to use bracketed paste. + Prefs prefs; + prefs_init(&prefs); + Prefs_load_error prefserr = prefs_load_from_conf_file(&prefs); + if (prefserr == Prefs_load_ok) { +#ifdef FEAT_PORTMIDI + if (osolen(prefs.portmidi_output_device)) { + // PortMidi can be hilariously slow to initialize. Since it will be + // initialized automatically if the user has a prefs entry for PortMidi + // devices, we should show a message to the user letting them know why + // orca is locked up/frozen. (When it's done via menu action, that's + // fine, since they can figure out why.) + print_loading_message("Waiting on PortMidi..."); + PmError pmerr; + PmDeviceID devid; + if (portmidi_find_device_id_by_name(osoc(prefs.portmidi_output_device), + osolen(prefs.portmidi_output_device), + &pmerr, &devid)) { + midi_mode_deinit(&midi_mode); + pmerr = midi_mode_init_portmidi(&midi_mode, devid); + if (pmerr) { + // todo stuff + } + } + } +#endif + } + prefs_deinit(&prefs); + WINDOW* cont_window = NULL; int key = KEY_RESIZE; @@ -2995,6 +3114,7 @@ int main(int argc, char** argv) { } break; #ifdef FEAT_PORTMIDI case Portmidi_output_device_menu_id: { + ged_stop_all_sustained_notes(&ged_state); midi_mode_deinit(&midi_mode); PmError pme = midi_mode_init_portmidi(&midi_mode, act.picked.id); qnav_stack_pop();