summaryrefslogtreecommitdiff
path: root/gdigi.c
diff options
context:
space:
mode:
authorAndrej Shadura <andrew.shadura@collabora.co.uk>2021-10-07 16:12:10 +0200
committerAndrej Shadura <andrew.shadura@collabora.co.uk>2021-10-07 16:12:10 +0200
commit45ee5d246b838240fce51e3735188ea8f88acf27 (patch)
treed3b48fd7eb44ee6d59551e5312aae7f797bc2900 /gdigi.c
parent314596035337348abbc934d96e4d83d4398f64f1 (diff)
Import Upstream version 0.4.0
Diffstat (limited to 'gdigi.c')
-rw-r--r--gdigi.c417
1 files changed, 377 insertions, 40 deletions
diff --git a/gdigi.c b/gdigi.c
index 0275adc..1ca93ae 100644
--- a/gdigi.c
+++ b/gdigi.c
@@ -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);