diff --git a/gdigi.c b/gdigi.c index 39d956b..e14fb2d 100644 --- a/gdigi.c +++ b/gdigi.c @@ -564,6 +564,68 @@ void setting_param_free(SettingParam *param) g_slice_free(SettingParam, param); } +/** + * Allocates memory for SettingGenetx. + * + * \return SettingGenetx which must be freed using setting_genetx_free. + **/ +SettingGenetx *setting_genetx_new() +{ + SettingGenetx *genetx = g_slice_new(SettingGenetx); + /* Older patches don't specify GeNetX version */ + genetx->version = GENETX_VERSION_1; + genetx->type = GENETX_TYPE_NOT_SET; + genetx->channel = -1; + genetx->name = NULL; + genetx->data = NULL; + + return genetx; +} + +/** + * \param genetx SettingGenetx to be freed + * + * Frees all memory used by SettingGenetx. + **/ +void setting_genetx_free(SettingGenetx *genetx) +{ + g_free(genetx->name); + if (genetx->data != NULL) { + g_string_free(genetx->data, TRUE); + } + g_slice_free(SettingGenetx, genetx); +} + +/** + * \param version GeNetX version + * \param type GeNetX type + * + * Retrieves SectionID for specified GeNetX version and type. + * + * \return SectionID specified by version and type, or -1 on error. + **/ +SectionID get_genetx_section_id(gint version, gint type) +{ + if (version == GENETX_VERSION_1) { + if (type == GENETX_TYPE_AMP) { + return SECTION_GENETX_AMP; + } else if (type == GENETX_TYPE_CABINET) { + return SECTION_GENETX_CABINET; + } + } else if (version == GENETX_VERSION_2) { + if (type == GENETX_TYPE_AMP) { + return SECTION_GENETX2_AMP; + } else if (type == GENETX_TYPE_CABINET) { + return SECTION_GENETX2_CABINET; + } + } + + g_message("This version of gdigi don't know what to do with this " + "GeNetX version (%d) and type (%d)", version, type); + + return -1; +} + /** * \param id Parameter ID * \param position Parameter position @@ -582,6 +644,68 @@ void set_option(guint id, guint position, guint value) g_string_free(msg, TRUE); } +/** + * \param section data section ID + * \param bank section-specific bank number + * \param index index of the desired object within the bank + * \param name object name + * \param data GString containing object data + * + * Forms RECEIVE_OBJECT SysEx message then sends it to device. + **/ +void send_object(SectionID section, guint bank, guint index, + gchar *name, GString *data) +{ + GString *msg = g_string_new(NULL); + + gint len = data->len; + + g_string_append_printf(msg, + "%c%c%c%c%s%c%c%c", + section, bank, + ((index & 0xFF00) >> 8), (index & 0xFF), + name, 0 /* NULL terminated string */, + ((len & 0xFF00) >> 8), (len & 0xFF)); + + g_string_append_len(msg, data->str, data->len); + + send_message(RECEIVE_OBJECT, msg->str, msg->len); + + g_string_free(msg, TRUE); +} + +/** + * \param params GList containing SettingParam + * + * Forms RECEIVE_PRESET_PARAMETERS SysEx message then sends it to device. + **/ +void send_preset_parameters(GList *params) +{ + GString *msg = g_string_sized_new(500); + GList *iter = params; + gint len = g_list_length(iter); + + g_string_append_printf(msg, "%c%c", + ((len & 0xFF00) >> 8), + (len & 0xFF)); + + while (iter) { + SettingParam *param = (SettingParam *) iter->data; + iter = iter->next; + + g_string_append_printf(msg, "%c%c%c", + ((param->id & 0xFF00) >> 8), + (param->id & 0xFF), + param->position); + + append_value(msg, param->value); + }; + + send_message(RECEIVE_PRESET_PARAMETERS, msg->str, msg->len); + + g_string_free(msg, TRUE); +} + /** * \param bank preset bank * \param x preset index diff --git a/gdigi.h b/gdigi.h index 590453c..0fc0ace 100644 --- a/gdigi.h +++ b/gdigi.h @@ -936,20 +936,67 @@ typedef enum { NACK = 0x7F } MessageID; +typedef enum { + SECTION_GENETX_AMP = 0, + SECTION_GENETX_CABINET = 1, + SECTION_DRUM_PATTERN = 2, + SECTION_DRUM_KIT = 3, + SECTION_DRUM_SAMPLES = 4, + SECTION_SONG = 5, + SECTION_FOOTSWITCH = 6, + SECTION_GENETX2_AMP = 7, + SECTION_GENETX2_CABINET = 8, + SECTION_DEVICE_GUID = 9, + SECTION_DEVICE_NAME = 10, +} SectionID; + typedef struct { int id; int position; int value; } SettingParam; +enum { + GENETX_VERSION_1, + GENETX_VERSION_2 +}; + +enum { + GENETX_TYPE_NOT_SET = -1, + GENETX_TYPE_AMP, + GENETX_TYPE_CABINET +}; + +enum { + GENETX_CHANNEL1 = 0, + GENETX_CHANNEL2 = 1, + GENETX_CHANNEL1_CUSTOM = 2, + GENETX_CHANNEL2_CUSTOM = 3, + GENETX_CHANNEL_CURRENT = 4 +} ChannelBankIndex; + +typedef struct { + int version; + int type; + int channel; + gchar *name; + GString *data; +} SettingGenetx; + void send_message(gint procedure, gchar *data, gint len); MessageID get_message_id(GString *msg); void append_value(GString *msg, guint value); GString *get_message_by_id(MessageID id); SettingParam *setting_param_new(); SettingParam *setting_param_new_from_data(gchar *str, gint *len); +SettingGenetx *setting_genetx_new(); +void setting_genetx_free(SettingGenetx *genetx); void setting_param_free(SettingParam *param); +SectionID get_genetx_section_id(gint version, gint type); void set_option(guint id, guint position, guint value); +void send_object(SectionID section, guint bank, guint index, + gchar *name, GString *data); +void send_preset_parameters(GList *params); void switch_preset(guint bank, guint x); void store_preset_name(int x, const gchar *name); void set_preset_level(int level); diff --git a/gui.c b/gui.c index f0641da..aaef7e5 100644 --- a/gui.c +++ b/gui.c @@ -862,6 +862,8 @@ static SupportedFileTypes file_types[] = { {"RP355Preset", "*.rp355p"}, {"RP500Preset", "*.rp500p"}, {"RP1000Preset", "*.rp1000p"}, + {"GNX4 Preset", "*.g4p"}, + {"GNX3kPreset", "*.g3kp"}, }; static guint n_file_types = G_N_ELEMENTS(file_types); @@ -919,41 +921,77 @@ static void action_open_preset_cb(GtkAction *action) gtk_widget_hide(dialog); - GString *msg = g_string_sized_new(500); - GList *iter = preset->params; - gint len = g_list_length(iter); - - g_string_append_printf(msg, "%c%c", - ((len & 0xFF00) >> 8), - (len & 0xFF)); - - while (iter) { - SettingParam *param = iter->data; - iter = iter->next; - - g_string_append_printf(msg, "%c%c%c", - ((param->id & 0xFF00) >> 8), - (param->id & 0xFF), - param->position); - - append_value(msg, param->value); - }; - GString *start = g_string_new(NULL); g_string_append_printf(start, "%c%c%s%c%c%c", PRESETS_EDIT_BUFFER, 0, preset->name, 0 /* NULL terminated string */, - 0 /* modified */, 2 /* messages to follow */); + 0 /* modified */, + /* messages to follow */ + preset->genetxs ? 10 : 2); send_message(RECEIVE_PRESET_START, start->str, start->len); - send_message(RECEIVE_PRESET_PARAMETERS, msg->str, msg->len); + send_preset_parameters(preset->params); + if (preset->genetxs != NULL) { + gint i; + + /* GNX4 sends messages in following order: + * Section Bank Index + * 0x00 0x04 0x0000 + * 0x00 0x04 0x0001 + * 0x01 0x04 0x0000 + * 0x01 0x04 0x0001 + * 0x00 0x04 0x0002 + * 0x00 0x04 0x0003 + * 0x01 0x04 0x0002 + * 0x01 0x04 0x0003 + */ + + /* GNX3000 sends messages in following order: + * Section Bank Index + * 0x07 0x04 0x0000 + * 0x07 0x04 0x0001 + * 0x08 0x04 0x0000 + * 0x08 0x04 0x0001 + * 0x07 0x04 0x0002 + * 0x07 0x04 0x0003 + * 0x08 0x04 0x0002 + * 0x08 0x04 0x0003 + */ + for (i = 0; i < 2; i++) { + GList *iter = preset->genetxs; + + while (iter) { + SectionID section; + guint bank, index; + + SettingGenetx *genetx = (SettingGenetx *) iter->data; + iter = iter->next; + + section = get_genetx_section_id(genetx->version, + genetx->type); + bank = 0x04; + + if (i == 0) { + index = genetx->channel; + } else { + if (genetx->channel == GENETX_CHANNEL1) { + index = GENETX_CHANNEL1_CUSTOM; + } else if (genetx->channel == GENETX_CHANNEL2) { + index = GENETX_CHANNEL2_CUSTOM; + } + } + + send_object(section, bank, index, + genetx->name, genetx->data); + } + } + } send_message(RECEIVE_PRESET_END, NULL, 0); show_store_preset_window(window, preset->name); g_string_free(start, TRUE); - g_string_free(msg, TRUE); preset_free(preset); loaded = TRUE; } diff --git a/preset.c b/preset.c index 8604172..839f635 100644 --- a/preset.c +++ b/preset.c @@ -29,12 +29,24 @@ enum { PARSER_TYPE_PARAM_POSITION, PARSER_TYPE_PARAM_VALUE, PARSER_TYPE_PARAM_NAME, - PARSER_TYPE_PARAM_TEXT + PARSER_TYPE_PARAM_TEXT, + PARSER_TYPE_GENETX_VERSION, + PARSER_TYPE_GENETX_TYPE, + PARSER_TYPE_GENETX_CHANNEL, + PARSER_TYPE_GENETX_NAME, + PARSER_TYPE_GENETX_DATA +}; + +enum { + SECTION_NOT_SET = -1, + SECTION_PARAMS, + SECTION_GENETX }; typedef struct { int depth; int id; + int section; Preset *preset; } AppData; @@ -46,11 +58,16 @@ static void XMLCALL start(void *data, const char *el, const char **attr) { if (ad->depth == 1) { ad->id = PARSER_TYPE_PRESET_NAME; } else if (ad->depth == 3) { - ad->id = PARSER_TYPE_PARAM_NAME; + if (ad->section == SECTION_PARAMS) { + ad->id = PARSER_TYPE_PARAM_NAME; + } else if (ad->section == SECTION_GENETX) { + ad->id = PARSER_TYPE_GENETX_NAME; + } } } if (g_strcmp0(el, "Params") == 0) { + ad->section = SECTION_PARAMS; if (ad->preset->params != NULL) g_message("Params aleady exists!"); } else if (g_strcmp0(el, "Param") == 0) { @@ -64,6 +81,21 @@ static void XMLCALL start(void *data, const char *el, const char **attr) { ad->id = PARSER_TYPE_PARAM_VALUE; } else if (g_strcmp0(el, "Text") == 0) { ad->id = PARSER_TYPE_PARAM_TEXT; + } else if (g_strcmp0(el, "Genetx") == 0) { + ad->section = SECTION_GENETX; + if (ad->preset->genetxs != NULL) + g_message("Genetx already exists!"); + } else if (g_strcmp0(el, "GenetxModel") == 0) { + SettingGenetx *genetx = setting_genetx_new(); + ad->preset->genetxs = g_list_prepend(ad->preset->genetxs, genetx); + } else if (g_strcmp0(el, "Version") == 0) { + ad->id = PARSER_TYPE_GENETX_VERSION; + } else if (g_strcmp0(el, "Type") == 0) { + ad->id = PARSER_TYPE_GENETX_TYPE; + } else if (g_strcmp0(el, "Channel") == 0) { + ad->id = PARSER_TYPE_GENETX_CHANNEL; + } else if (g_strcmp0(el, "Data") == 0) { + ad->id = PARSER_TYPE_GENETX_DATA; } ad->depth++; @@ -88,28 +120,87 @@ static void XMLCALL text_cb(void *data, const char* text, int len) ad->preset->name = g_strndup(text, len); } - if (ad->preset->params == NULL) - return; + if (ad->section == SECTION_PARAMS) { + if (ad->preset->params == NULL) + return; - SettingParam *param = (SettingParam *) ad->preset->params->data; - if (param == NULL) - return; + SettingParam *param = (SettingParam *) ad->preset->params->data; + if (param == NULL) + return; - gchar *value = g_strndup(text, len); + gchar *value = g_strndup(text, len); - switch (ad->id) { - case PARSER_TYPE_PARAM_ID: - param->id = atoi(value); - break; - case PARSER_TYPE_PARAM_POSITION: - param->position = atoi(value); - break; - case PARSER_TYPE_PARAM_VALUE: - param->value = atoi(value); - break; + switch (ad->id) { + case PARSER_TYPE_PARAM_ID: + param->id = atoi(value); + break; + case PARSER_TYPE_PARAM_POSITION: + param->position = atoi(value); + break; + case PARSER_TYPE_PARAM_VALUE: + param->value = atoi(value); + break; + } + + g_free(value); + } else if (ad->section == SECTION_GENETX) { + if (ad->preset->genetxs == NULL) + return; + + SettingGenetx *genetx = (SettingGenetx *) ad->preset->genetxs->data; + if (genetx == NULL) + return; + + gchar *value = g_strndup(text, len); + + switch (ad->id) { + case PARSER_TYPE_GENETX_VERSION: + if (g_strcmp0(value, "Version1") == 0) { + genetx->version = GENETX_VERSION_1; + } else if (g_strcmp0(value, "Version2") == 0) { + genetx->version = GENETX_VERSION_2; + } else { + g_message("Unknown GeNetX version: %s", value); + } + break; + case PARSER_TYPE_GENETX_TYPE: + if (g_strcmp0(value, "Amp") == 0) { + genetx->type = GENETX_TYPE_AMP; + } else if (g_strcmp0(value, "Cabinet") == 0) { + genetx->type = GENETX_TYPE_CABINET; + } else { + g_message("Unknown GeNetX type: %s", value); + } + break; + case PARSER_TYPE_GENETX_CHANNEL: + if (g_strcmp0(value, "Channel1") == 0) { + genetx->channel = GENETX_CHANNEL1; + } else if (g_strcmp0(value, "Channel2") == 0) { + genetx->channel = GENETX_CHANNEL2; + } else { + g_message("Unknown GeNetX channel: %s", value); + } + break; + case PARSER_TYPE_GENETX_NAME: + /* reassign pointer */ + genetx->name = value; + value = NULL; + break; + case PARSER_TYPE_GENETX_DATA: + { + guchar *data = NULL; + gsize length = 0; + + data = g_base64_decode(value, &length); + genetx->data = g_string_new_len((gchar *) data, length); + + g_free(data); + break; + } + } + + g_free(value); } - - g_free(value); } #endif /* DOXYGEN_SHOULD_SKIP_THIS */ @@ -139,6 +230,7 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error) ad->preset = g_slice_new(Preset); ad->preset->name = NULL; ad->preset->params = NULL; + ad->preset->genetxs = NULL; ad->id = PARSER_TYPE_NOT_SET; XML_Parser p; @@ -159,6 +251,7 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error) Preset *preset = ad->preset; preset->params = g_list_reverse(preset->params); + preset->genetxs = g_list_reverse(preset->genetxs); XML_ParserFree(p); g_slice_free(AppData, ad); @@ -187,6 +280,7 @@ Preset *create_preset_from_data(GList *list) Preset *preset = g_slice_new(Preset); preset->name = NULL; preset->params = NULL; + preset->genetxs = NULL; iter = list; for (iter = list; iter; iter = g_list_next(iter)) { @@ -249,8 +343,15 @@ void preset_free(Preset *preset) g_list_free(preset->params); } - if (preset->name != NULL) - g_free(preset->name); + if (preset->genetxs != NULL) { + GList *iter; + for (iter = preset->genetxs; iter; iter = iter->next) { + setting_genetx_free((SettingGenetx*)iter->data); + } + g_list_free(preset->genetxs); + } + + g_free(preset->name); g_slice_free(Preset, preset); } diff --git a/preset.h b/preset.h index 8f6d9c2..95d92d7 100644 --- a/preset.h +++ b/preset.h @@ -22,6 +22,7 @@ typedef struct { gchar *name; GList *params; + GList *genetxs; } Preset; Preset *create_preset_from_xml_file(gchar *filename, GError **error);