diff options
author | Andrej Shadura <andrew.shadura@collabora.co.uk> | 2021-10-07 16:12:10 +0200 |
---|---|---|
committer | Andrej Shadura <andrew.shadura@collabora.co.uk> | 2021-10-07 16:12:10 +0200 |
commit | 45ee5d246b838240fce51e3735188ea8f88acf27 (patch) | |
tree | d3b48fd7eb44ee6d59551e5312aae7f797bc2900 /gdigi.c | |
parent | 314596035337348abbc934d96e4d83d4398f64f1 (diff) |
Import Upstream version 0.4.0
Diffstat (limited to 'gdigi.c')
-rw-r--r-- | gdigi.c | 417 |
1 files changed, 377 insertions, 40 deletions
@@ -21,6 +21,7 @@ #include <alsa/asoundlib.h> #include <alloca.h> #include "gdigi.h" +#include "gdigi_xml.h" #include "gui.h" static unsigned char device_id = 0x7F; @@ -35,6 +36,173 @@ static GQueue *message_queue = NULL; static GMutex *message_queue_mutex = NULL; static GCond *message_queue_cond = NULL; +static guint DebugFlags; + +gboolean +debug_flag_is_set (debug_flags_t flags) +{ + if (DebugFlags & flags) { + return TRUE; + } + return FALSE; +} + +gboolean set_debug_flags (const gchar *option_name, const gchar *value, + gpointer data, GError **error) +{ + if (strchr(value, 'd')) { + DebugFlags |= DEBUG_MSG2DEV; + } + if (strchr(value, 'h')) { + DebugFlags |= DEBUG_MSG2HOST; + } + if (strchr(value, 'm')) { + DebugFlags |= DEBUG_MSG2DEV|DEBUG_MSG2HOST|DEBUG_GROUP; + } + if (strchr(value, 's')) { + DebugFlags |= DEBUG_STARTUP; + } + if (strchr(value, 'H')) { + DebugFlags |= DEBUG_HEX; + } + if (strchr(value, 'g')) { + DebugFlags |= DEBUG_GROUP; + } + if (strchr(value, 'x')) { + DebugFlags |= DEBUG_XML; + } + if (strchr(value, 'v')) { + DebugFlags |= DEBUG_VERBOSE; + } + if (strchr(value, 'a')) { + DebugFlags = -1; + } + + return TRUE; +} + +void +debug_msg (debug_flags_t flags, char *fmt, ...) +{ + char buf[1024]; + if (flags & DebugFlags) { + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, 1024, fmt, ap); + va_end(ap); + + fprintf(stderr, "%s\n", buf); + } +} + +/* + * Format a value according to the xml setting. + * Returns an allocated buffer that must be freed by the caller. + */ +GString * +format_value (XmlSettings *xml, guint value) +{ + GString *buf = g_string_sized_new(1); + EffectValues *values = NULL; + ValueType vtype; + gchar *suffix = ""; + gdouble step = 1.0; + gint offset = 0; + gboolean decimal = FALSE; + + values = xml->values; + vtype = values->type; + while ((vtype & VALUE_TYPE_EXTRA) && value_is_extra(values, value)) { + values = values->extra; + vtype = values->type; + } + vtype &= ~VALUE_TYPE_EXTRA; + + if (vtype & VALUE_TYPE_OFFSET) { + offset = values->offset; + vtype &= ~VALUE_TYPE_OFFSET; + } + + if (vtype & VALUE_TYPE_STEP) { + step = values->step; + vtype &= ~VALUE_TYPE_STEP; + } + + if (vtype & VALUE_TYPE_SUFFIX) { + suffix = values->suffix; + vtype &= ~VALUE_TYPE_SUFFIX; + } + + if (vtype & VALUE_TYPE_DECIMAL) { + decimal = TRUE; + vtype &= ~VALUE_TYPE_DECIMAL; + } + + switch (vtype) { + case VALUE_TYPE_LABEL: + { + char *textp = map_xml_value(xml, values, value); + if (!textp) { + g_warning("%s: Unable to map %s value %d for id %d position %d", + __FUNCTION__, xml->label, value, xml->id, xml->position); + textp = ""; + } + g_string_printf(buf, "%s", textp); + break; + } + case VALUE_TYPE_PLAIN: + { + if (decimal) { + double dvalue = ((gint)value + offset) * step; + g_string_printf(buf, "%0.2f%s", dvalue, suffix); + } else { + gint ivalue = ((gint)value + offset) * step; + g_string_printf(buf, "%d%s", ivalue, suffix); + } + break; + } + case VALUE_TYPE_NONE: + g_string_printf(buf, "%s", ""); + break; + + case VALUE_TYPE_POSID: + g_string_printf(buf, "%d", value); + break; + + default: + g_warning("Unhandled value type %d", vtype); + break; + } + + return buf; +} + +GString * +format_ipv (guint id, guint pos, guint val) +{ + GString *buf = g_string_sized_new(1); + GString *vec_buf = g_string_sized_new(1); + XmlSettings *xml = get_xml_settings(id, pos); + GString *val_buf; + + if (!xml) { + g_warning("Failed to find xml settings for position %d id %d.", + id, pos); + g_string_printf(buf, "%s", "error"); + return buf; + } + val_buf = format_value(xml, val); + + g_string_printf(vec_buf, "(%d, %d, %d)", pos, id, val); + g_string_printf(buf, "%-16s %s: %s: %s", + vec_buf->str, + get_position(pos), xml->label, val_buf->str); + g_string_free(vec_buf, TRUE); + g_string_free(val_buf, TRUE); + return buf; +} + /** * Registers an error quark for gdigi if necessary. * @@ -218,33 +386,57 @@ MessageID get_message_id(GString *msg) return -1; } +#define HEX_WIDTH 26 + +static gboolean modifier_linkable_list_request_pending = FALSE; + void push_message(GString *msg) { - if (((unsigned char)msg->str[0] == 0xF0) && ((unsigned char)msg->str[msg->len-1] == 0xF7)) - g_message("Pushing correct message!"); - else + MessageID msgid = get_message_id(msg); + if (((unsigned char)msg->str[0] == 0xF0) && + ((unsigned char)msg->str[msg->len-1] == 0xF7)) { + debug_msg(DEBUG_VERBOSE, "Pushing correct message!"); + } else { g_warning("Pushing incorrect message!"); + } int x; - for (x = 0; x<msg->len; x++) - printf("%02x ", (unsigned char)msg->str[x]); - printf("\n"); + if (debug_flag_is_set(DEBUG_HEX)) { + for (x = 0; x<msg->len; x++) { + if (x && (x % HEX_WIDTH) == 0) { + printf("\n"); + } + printf("%02x ", (unsigned char)msg->str[x]); + } + if (x % HEX_WIDTH) { + printf("\n"); + } + } + debug_msg(DEBUG_VERBOSE, "Received %s", get_message_name(msgid)); - switch (get_message_id(msg)) { + SettingParam *param; + switch (msgid) { case ACK: - g_message("Received ACK"); g_string_free(msg, TRUE); return; case NACK: - g_message("Received NACK"); + g_warning("Received NACK!"); g_string_free(msg, TRUE); return; case RECEIVE_PARAMETER_VALUE: + { unpack_message(msg); - SettingParam *param = setting_param_new_from_data(&msg->str[8], NULL); - g_message("Received parameter change ID: %d Position: %d Value: %d", param->id, param->position, param->value); + param = setting_param_new_from_data(&msg->str[8], NULL); + if (debug_flag_is_set(DEBUG_MSG2HOST)) { + GString *ipv = format_ipv(param->id, + param->position, + param->value); + debug_msg(DEBUG_MSG2HOST, "RECEIVE_PARAMETER_VALUE\n%s", + ipv->str); + g_string_free(ipv, TRUE); + } GDK_THREADS_ENTER(); apply_setting_param_to_gui(param); @@ -253,32 +445,127 @@ void push_message(GString *msg) setting_param_free(param); g_string_free(msg, TRUE); return; + } case RECEIVE_DEVICE_NOTIFICATION: unpack_message(msg); unsigned char *str = (unsigned char*)msg->str; switch (str[8]) { - case NOTIFY_PRESET_MOVED: - if (str[11] == PRESETS_EDIT_BUFFER && str[12] == 0) { - g_message("Loaded preset %d from bank %d", str[10], str[9]); - - GDK_THREADS_ENTER(); - g_timeout_add(0, apply_current_preset_to_gui, NULL); - GDK_THREADS_LEAVE(); - } else { - g_message("%d %d moved to %d %d", str[9], str[10], str[11], str[12]); + case NOTIFY_PRESET_MOVED: + if (str[11] == PRESETS_EDIT_BUFFER && str[12] == 0) { + + GDK_THREADS_ENTER(); + g_timeout_add(0, apply_current_preset_to_gui, NULL); + GDK_THREADS_LEAVE(); + debug_msg(DEBUG_MSG2HOST, + "RECEIVE_DEVICE_NOTIFICATION: Loaded preset " + "%d from bank %d", + str[10], str[9]); + } else { + debug_msg(DEBUG_MSG2HOST, + "RECEIVE_DEVICE_NOTIFICATION: %d %d moved to " + "%d %d", + str[9], str[10], + str[11], str[12]); + } + break; + + case NOTIFY_MODIFIER_GROUP_CHANGED: + { + int i; + if (debug_flag_is_set(DEBUG_HEX)) { + printf("\n"); + for (i = 0; i < msg->len; i++) { + printf(" %02x", (unsigned char) str[i]); } - break; - default: - g_message("Received unhandled device notification 0x%x", str[11]); + printf("\n"); + } + + debug_msg(DEBUG_MSG2HOST, + "NOTIFY_MODIFIER_GROUP_CHANGED: Modifier group " + "id %d changed", + (str[9] << 8) | (str[10])); + + if (!modifier_linkable_list_request_pending) { + send_message(REQUEST_MODIFIER_LINKABLE_LIST, "\x00\x01", 2); + modifier_linkable_list_request_pending = TRUE; + } + + break; + } + default: + g_warning("Received unhandled device notification 0x%x", + str[11]); } g_string_free(msg, TRUE); return; + case RECEIVE_GLOBAL_PARAMETERS: + unpack_message(msg); + gint tot, n, x; + tot = (unsigned char)msg->str[9]; + if (debug_flag_is_set(DEBUG_HEX)) { + for (n = 0; n < msg->len; n++) { + printf("%02x ",(unsigned char) msg->str[n]); + } + printf("\n"); + } + + n = 0; + x = 10; + do { + param = setting_param_new_from_data(&msg->str[x], &x); + debug_msg(DEBUG_MSG2HOST, + "RECEIVE_GLOBAL_PARAMETERS ID: %5d " + "Position: %2.1d Value: %6.1d: %s", + param->id, + param->position, param->value, "XXX"); + + GDK_THREADS_ENTER(); + apply_setting_param_to_gui(param); + GDK_THREADS_LEAVE(); + + setting_param_free(param); + } while ( (x < msg->len) && n < tot); + + g_string_free(msg, TRUE); + return; + + + case RECEIVE_MODIFIER_LINKABLE_LIST: + + modifier_linkable_list_request_pending = FALSE; + unpack_message(msg); + tot = (unsigned char)msg->str[9]; + + if (debug_flag_is_set(DEBUG_HEX)) { + for (n = 0; n < msg->len; n++) { + printf("%02x ",(unsigned char) msg->str[n]); + } + printf("\n"); + } + + + update_modifier_linkable_list(msg); + + g_string_free(msg, TRUE); + + GDK_THREADS_ENTER(); + + create_modifier_group(EXP_POSITION, EXP_ASSIGN1); + create_modifier_group(LFO1_POSITION, LFO_TYPE); + create_modifier_group(LFO2_POSITION, LFO_TYPE); + + GDK_THREADS_LEAVE(); + + return; + + default: g_mutex_lock(message_queue_mutex); g_queue_push_tail(message_queue, msg); g_cond_signal(message_queue_cond); g_mutex_unlock(message_queue_mutex); + break; } } @@ -301,7 +588,8 @@ gpointer read_data_thread(gboolean *stop) unsigned short revents; /* SysEx messages can't contain bytes with 8th bit set. - memset our buffer to 0xFF, so if for some reason we'll get out of reply bounds, we'll catch it */ + memset our buffer to 0xFF, so if for some reason we'll + get out of reply bounds, we'll catch it */ memset(buf, '\0', sizeof(buf)); err = poll(pfds, npfds, 200); @@ -400,6 +688,9 @@ void send_message(gint procedure, gchar *data, gint len) g_string_append_printf(msg, "%c\xF7", calculate_checksum(&msg->str[1], msg->len - 1)); + debug_msg(DEBUG_VERBOSE, "Sending %s len %d", + get_message_name(procedure), len); + send_data(msg->str, msg->len); g_string_free(msg, TRUE); @@ -620,7 +911,7 @@ SectionID get_genetx_section_id(gint version, gint type) } } - g_message("This version of gdigi don't know what to do with this " + g_warning("This version of gdigi don't know what to do with this " "GeNetX version (%d) and type (%d)", version, type); return -1; @@ -631,6 +922,24 @@ SectionID get_genetx_section_id(gint version, gint type) * \param position Parameter position * \param value Parameter value * + * Forms SysEx message to request parameter then sends it to device. + **/ +void get_option(guint id, guint position) +{ + GString *msg = g_string_sized_new(9); + debug_msg(DEBUG_MSG2DEV, "REQUEST_PARAMETER_VALUE: id %d position %d", + id, position); + g_string_append_printf(msg, "%c%c%c", + ((id & 0xFF00) >> 8), (id & 0xFF), + position); + send_message(REQUEST_PARAMETER_VALUE, msg->str, msg->len); + g_string_free(msg, TRUE); +} +/** + * \param id Parameter ID + * \param position Parameter position + * \param value Parameter value + * * Forms SysEx message to set parameter then sends it to device. **/ void set_option(guint id, guint position, guint value) @@ -640,6 +949,11 @@ void set_option(guint id, guint position, guint value) ((id & 0xFF00) >> 8), (id & 0xFF), position); append_value(msg, value); + if (debug_flag_is_set(DEBUG_MSG2DEV)) { + GString *ipv = format_ipv(id, position, value); + debug_msg(DEBUG_MSG2DEV, "RECEIVE_PARAMETER_VALUE\n%s", ipv->str); + g_string_free(ipv, TRUE); + } send_message(RECEIVE_PARAMETER_VALUE, msg->str, msg->len); g_string_free(msg, TRUE); } @@ -846,11 +1160,12 @@ GList *get_message_list(MessageID id) g_error("get_message_list() doesn't support followning id: %d", id); g_string_free(data, TRUE); g_list_free(list); + g_assert(!"BUG"); return NULL; } while (amt) { - g_message("%d messages left", amt); + debug_msg(DEBUG_VERBOSE, "%d messages left", amt); data = g_queue_pop_nth(message_queue, x); if (data == NULL) { g_cond_wait(message_queue_cond, message_queue_mutex); @@ -1058,9 +1373,11 @@ static gboolean request_who_am_i(unsigned char *device_id, unsigned char *family *device_id = data->str[8]; *family_id = data->str[9]; *product_id = data->str[10]; - g_message("I am device id %d family %d product id %d.", - *device_id, *family_id, *product_id); g_string_free(data, TRUE); + debug_msg(DEBUG_STARTUP, "Found device id %d family %d product id %d.", + *device_id, + *family_id, + *product_id); return TRUE; } return FALSE; @@ -1107,6 +1424,25 @@ static void request_device_configuration() static GOptionEntry options[] = { {"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device_port, "MIDI device port to use", NULL}, + {"debug-flags <flags>", 'D', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, set_debug_flags, + "<flags> any of a, d, g, h, m, s, x, v:\n" + " " + "a: Everything.\n" + " " + "d: Messages to the device.\n" + " " + "g: Group messages.\n" + " " + "h: Dump message contents in hex.\n" + " " + "m: All messages.\n" + " " + "s: Startup.\n" + " " + "x: Debug xml parsing/writing.\n" + " " + "v: Additional verbosity.\n" , + NULL}, {NULL} }; @@ -1132,6 +1468,7 @@ static gint get_digitech_devices(GList **devices) number++; *devices = g_list_append(*devices, GINT_TO_POINTER(card_num)); } + free(name); } return number; @@ -1151,7 +1488,7 @@ int main(int argc, char *argv[]) { g_option_context_add_group(context, gtk_get_option_group(TRUE)); if (!g_option_context_parse(context, &argc, &argv, &error)) { - g_message("option parsing failed: %s\n", error->message); + g_warning("option parsing failed: %s\n", error->message); g_error_free(error); g_option_context_free(context); exit(EXIT_FAILURE); @@ -1159,12 +1496,12 @@ int main(int argc, char *argv[]) { if (device_port == NULL) { /* port not given explicitly in commandline - search for devices */ - GList *devices = NULL; - GList *device = NULL; - int num_devices = 0; - int chosen_device = 0; + GList *devices = NULL; + GList *device = NULL; + int num_devices = 0; + int chosen_device = 0; if ((num_devices = get_digitech_devices(&devices)) <= 0) { - g_message("Couldn't find any DigiTech devices!"); + g_warning("Couldn't find DigiTech devices!"); exit(EXIT_FAILURE); } if (num_devices > 1) { @@ -1178,9 +1515,9 @@ int main(int argc, char *argv[]) { device_port = g_strdup_printf("hw:%d,0,0", GPOINTER_TO_INT(device->data)); g_list_free(devices); - g_message("Found device %s", device_port); + debug_msg(DEBUG_STARTUP, "Found device %s.", device_port); } else { - g_message("Using device %s", device_port); + debug_msg(DEBUG_STARTUP, "Using device %s.", device_port); } g_option_context_free(context); @@ -1208,14 +1545,14 @@ int main(int argc, char *argv[]) { if (device != NULL) { /* enable GUI mode */ - set_option(GUI_MODE_ON_OFF, USB_POSITION, 1); + set_option(GUI_MODE_ON_OFF, GLOBAL_POSITION, 1); gui_create(device); gtk_main(); gui_free(); /* disable GUI mode */ - set_option(GUI_MODE_ON_OFF, USB_POSITION, 0); + set_option(GUI_MODE_ON_OFF, GLOBAL_POSITION, 0); } } } @@ -1229,8 +1566,8 @@ int main(int argc, char *argv[]) { g_mutex_free(message_queue_mutex); } - if (message_queue != NULL) { - g_message("%d unread messages in queue", + if (message_queue != NULL && g_queue_get_length(message_queue)) { + g_warning("%d unread messages in queue", g_queue_get_length(message_queue)); g_queue_foreach(message_queue, (GFunc) message_free_func, NULL); g_queue_free(message_queue); |