start gui with proper values

This commit is contained in:
Tomasz Moń
2009-03-03 11:39:25 +01:00
parent 79554a99ce
commit baa3829263
7 changed files with 262 additions and 42 deletions

17
TODO
View File

@@ -6,21 +6,4 @@
-effects level -effects level
-handling presets (loading, saving, exporting to xml patches) -handling presets (loading, saving, exporting to xml patches)
-buildsystem -buildsystem
-start gui with proper values
To do so we need to figure out reply formatting of command querying preset.
amidi --port=hw:1,0,0 --send-hex F0 00 00 10 00 5E 02 2a 00 04 00 62 F7 --receive=preset
will create file named preset (give a while for it, and then hit ctrl+c)
this file should have around 440 bytes (depends on actual preset)
0x21 byte holds amount of options
from 0x22 byte starts effects configuration which is:
-2 bytes for ID
-1 byte for position
-1 to 3 bytes for value
Each 8th byte (beginning from 0x27) seems to be status byte which describes
whether or not we shall add 0x80 to ID or value and whether or not value
will be multibyte. So far I couldn't figure the exact meaning of those bytes.
To check you can download some patch from DigiTech Sound Community, apply
it to your device, and then do this amidi command.
Open resulting file in hex editor, and open patch file in text editor.
Every ID, position and value found in patch will appear in the binary file.
-fix expression pedal settings (possible types depend on active effects) -fix expression pedal settings (possible types depend on active effects)

146
gdigi.c
View File

@@ -22,6 +22,10 @@
#include "gdigi.h" #include "gdigi.h"
#include "gui.h" #include "gui.h"
static u_char device_id = 0x7F;
static u_char family_id = 0x7F;
static u_char product_id = 0x7F;
static snd_rawmidi_t *output = NULL; static snd_rawmidi_t *output = NULL;
static snd_rawmidi_t *input = NULL; static snd_rawmidi_t *input = NULL;
static char *device = "hw:1,0,0"; static char *device = "hw:1,0,0";
@@ -47,6 +51,18 @@ char calculate_checksum(gchar *array, int length, int check)
return checksum; return checksum;
} }
static char calc_checksum(gchar *array, gint length)
{
int x;
int checksum = 0;
for (x = 0; x<length; x++) {
checksum ^= array[x];
}
return checksum;
}
/* /*
opens MIDI device opens MIDI device
Returns TRUE on error Returns TRUE on error
@@ -91,6 +107,7 @@ GString* read_data()
by Clemens Ladisch <clemens@ladisch.de> */ by Clemens Ladisch <clemens@ladisch.de> */
int err; int err;
int npfds; int npfds;
gboolean stop = FALSE;
struct pollfd *pfds; struct pollfd *pfds;
GString *string = NULL; GString *string = NULL;
@@ -118,6 +135,7 @@ GString* read_data()
break; break;
if (!(revents & POLLIN)) if (!(revents & POLLIN))
continue; continue;
err = snd_rawmidi_read(input, buf, sizeof(buf)); err = snd_rawmidi_read(input, buf, sizeof(buf));
if (err == -EAGAIN) if (err == -EAGAIN)
continue; continue;
@@ -125,11 +143,15 @@ GString* read_data()
g_error("cannot read: %s", snd_strerror(err)); g_error("cannot read: %s", snd_strerror(err));
break; break;
} }
length = 0; length = 0;
for (i = 0; i < err; ++i) for (i = 0; i < err; ++i)
if (buf[i] != 0xFE) // ignore active sensing if (buf[i] != 0xFE) // ignore active sensing
buf[length++] = buf[i]; buf[length++] = buf[i];
if ((u_char)buf[length-1] == 0xF7)
stop = TRUE;
if (length != 0) { if (length != 0) {
if (string == NULL) { if (string == NULL) {
string = g_string_new_len(buf, length); string = g_string_new_len(buf, length);
@@ -137,9 +159,40 @@ GString* read_data()
string = g_string_append_len(string, buf, length); string = g_string_append_len(string, buf, length);
} }
} }
} while (err != 0); } while ((err != 0) && (stop == FALSE));
return string; return string;
}
static void clear_midi_in_buffer()
{
GString *str;
do {
str = read_data();
} while (str != NULL);
}
static void send_message(gint procedure, gchar *data, gint len)
{
GString *msg = g_string_new_len("\xF0" /* SysEx status byte */
"\x00\x00\x10", /* Manufacturer ID */
4);
g_string_append_printf(msg,
"%c%c%c" /* device, family, product ID */
"%c", /* procedure */
device_id, family_id, product_id,
procedure);
if (len > 0)
g_string_append_len(msg, data, len);
g_string_append_printf(msg, "%c\xF7",
calc_checksum(&msg->str[1], msg->len - 1));
send_data(msg->str, msg->len);
g_string_free(msg, TRUE);
} }
/* /*
@@ -310,9 +363,7 @@ GStrv query_preset_names(guint bank)
gchar **str_array = NULL; gchar **str_array = NULL;
/* clear MIDI IN buffer */ /* clear MIDI IN buffer */
data = read_data(); clear_midi_in_buffer();
if (data != NULL)
g_string_free(data, TRUE);
/* query user preset names */ /* query user preset names */
char command[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x21, 0x00, 0x00 /* bank */, 0x00 /* checksum */, 0xF7}; char command[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x21, 0x00, 0x00 /* bank */, 0x00 /* checksum */, 0xF7};
@@ -368,6 +419,75 @@ GStrv query_preset_names(guint bank)
return str_array; return str_array;
} }
static void unpack_message(GString *msg)
{
int offset;
int x;
int i;
u_char status;
gboolean finish = FALSE;
offset = 9;
x = 0;
i = 8;
do {
printf("status byte [%d] 0x%02x\n", offset-1, msg->str[offset-1]);
status = (u_char)msg->str[offset-1];
for (x=0; x<7; x++) {
if ((u_char)msg->str[offset+x] == 0xF7) {
msg->str[i] = 0xF7;
finish = TRUE;
}
msg->str[i] = (((status << (x+1)) & 0x80) | (u_char)msg->str[x+offset]);
printf("merging byte [%d] with byte [%d] MSB is %d\n",
i, x+offset, (((status << (x+1)) & 0x80) >> 7));
i++;
}
offset += 8;
} while (finish == FALSE && offset < msg->len);
}
GString *get_current_preset()
{
GString *data = NULL;
/* clear MIDI IN buffer */
clear_midi_in_buffer();
send_message(REQUEST_PRESET, "\x00\x04\x00", 3);
/* read reply */
data = read_data();
g_string_free(data, TRUE);
data = read_data();
unpack_message(data);
return data;
}
static gboolean request_who_am_i(u_char *device_id, u_char *family_id,
u_char *product_id)
{
send_message(REQUEST_WHO_AM_I, NULL, 0);
GString *data = read_data();
if (data != NULL) {
if ((data->len == 15) && (data->str[7] == RECEIVE_WHO_AM_I)) {
*device_id = data->str[9];
*family_id = data->str[10];
*product_id = data->str[11];
g_string_free(data, TRUE);
return TRUE;
}
g_string_free(data, TRUE);
}
return FALSE;
}
static GOptionEntry options[] = { static GOptionEntry options[] = {
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL}, {"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
{NULL} {NULL}
@@ -390,16 +510,14 @@ int main(int argc, char *argv[]) {
g_option_context_free(context); g_option_context_free(context);
if (open_device() == TRUE) { if (open_device() == TRUE) {
GtkWidget *msg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, show_error_message(NULL, "Failed to open MIDI device");
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"Failed to open MIDI device");
gtk_dialog_run(GTK_DIALOG(msg));
gtk_widget_destroy(msg);
} else { } else {
create_window(); if (request_who_am_i(&device_id, &family_id, &product_id) == FALSE) {
gtk_main(); show_error_message(NULL, "No suitable reply from device - is it connected?");
} else {
create_window();
gtk_main();
}
} }
if (output != NULL) if (output != NULL)

46
gdigi.h
View File

@@ -489,15 +489,51 @@ enum {
#define USB_AUDIO_PLAYBACK_MIX 12297 #define USB_AUDIO_PLAYBACK_MIX 12297
#define USB_AUDIO_LEVEL 12307 #define USB_AUDIO_LEVEL 12307
typedef enum { enum {
PRESETS_SYSTEM = 0, PRESETS_SYSTEM = 0,
PRESETS_USER = 1 PRESETS_USER = 1,
} PresetBank; PRESETS_ARTIST = 2,
/* Version 1 and later */
PRESETS_MEDIA_CARD = 3,
PRESETS_EDIT_BUFFER = 4, /* Current preset edit buffer, index must be 0 */
PRESETS_FACTORY2 = 5,
/* Version 2 and later */
PRESETS_EXTERNAL = 6,
};
enum {
REQUEST_WHO_AM_I = 0x01,
RECEIVE_WHO_AM_I = 0x02,
REQUEST_DEVICE_CONFIGURATION = 0x08,
RECEIVE_DEVICE_CONFIGURATION = 0x09,
REQUEST_GLOBAL_PARAMETERS = 0x10,
RECEIVE_GLOBAL_PARAMETERS = 0x11,
REQUEST_BULK_DUMP = 0x18,
RECEIVE_BULK_DUMP_START = 0x19,
RECEIVE_BULK_DUMP_END = 0x1B,
REQUEST_PRESET_NAMES = 0x21,
RECEIVE_PRESET_NAMES = 0x22,
REQUEST_PRESET_NAME = 0x28,
RECEIVE_PRESET_NAME = 0x29,
REQUEST_PRESET = 0x2A,
RECEIVE_PRESET_START = 0x2B,
RECEIVE_PRESET_END = 0x2C,
RECEIVE_PRESET_PARAMETERS = 0x2D,
};
void set_option(guint id, guint position, guint value); void set_option(guint id, guint position, guint value);
void switch_preset(guint bank, guint x); void switch_preset(guint bank, guint x);
void store_preset_name(int x, const gchar *name); void store_preset_name(int x, const gchar *name);
void set_preset_level(int level); void set_preset_level(int level);
GStrv query_preset_names(PresetBank bank); GStrv query_preset_names(guint bank);
GString *get_current_preset();
#endif /* GDIGI_H */ #endif /* GDIGI_H */

45
gui.c
View File

@@ -23,6 +23,21 @@
extern EffectList effects[]; extern EffectList effects[];
extern int n_effects; extern int n_effects;
static gboolean allow_send = FALSE;
void show_error_message(GtkWidget *parent, gchar *message)
{
g_return_if_fail(message != NULL);
GtkWidget *msg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
message);
gtk_dialog_run(GTK_DIALOG(msg));
gtk_widget_destroy(msg);
}
typedef struct { typedef struct {
GtkWidget *widget; GtkWidget *widget;
gint id; gint id;
@@ -37,16 +52,20 @@ void value_changed_option_cb(GtkSpinButton *spinbutton, EffectSettings *setting)
{ {
g_return_if_fail(setting != NULL); g_return_if_fail(setting != NULL);
int val = gtk_spin_button_get_value_as_int(spinbutton); if (allow_send) {
set_option(setting->option, setting->position, val); gint val = gtk_spin_button_get_value_as_int(spinbutton);
set_option(setting->option, setting->position, val);
}
} }
void toggled_cb(GtkToggleButton *button, Effect *effect) void toggled_cb(GtkToggleButton *button, Effect *effect)
{ {
g_return_if_fail(effect != NULL); g_return_if_fail(effect != NULL);
guint val = gtk_toggle_button_get_active(button); if (allow_send) {
set_option(effect->option, effect->position, val); guint val = gtk_toggle_button_get_active(button);
set_option(effect->option, effect->position, val);
}
} }
static void widget_list_add(GList **list, GtkWidget *widget, gint id, gint position, gint value, gint x) static void widget_list_add(GList **list, GtkWidget *widget, gint id, gint position, gint value, gint x)
@@ -73,7 +92,7 @@ GtkWidget *create_table(GList **list, EffectSettings *settings, gint amt)
for (x = 0; x<amt; x++) { for (x = 0; x<amt; x++) {
label = gtk_label_new(settings[x].label); label = gtk_label_new(settings[x].label);
adj = gtk_adjustment_new(0.0, settings[x].min, settings[x].max, 1.0, 1.0, 1.0); adj = gtk_adjustment_new(0.0, settings[x].min, settings[x].max, 1.0, 1.0, 0.0);
widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0); widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK(value_changed_option_cb), &settings[x]); g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK(value_changed_option_cb), &settings[x]);
widget_list_add(list, widget, settings[x].option, settings[x].position, -1, -1); widget_list_add(list, widget, settings[x].option, settings[x].position, -1, -1);
@@ -126,7 +145,7 @@ void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
settings = g_object_get_data(G_OBJECT(widget), name); settings = g_object_get_data(G_OBJECT(widget), name);
g_free(name); g_free(name);
if (settings != NULL) if (settings != NULL && allow_send)
set_option(settings->option, settings->position, settings->id); set_option(settings->option, settings->position, settings->id);
child = g_object_get_data(G_OBJECT(widget), "active_child"); child = g_object_get_data(G_OBJECT(widget), "active_child");
@@ -349,6 +368,8 @@ static void apply_widget_setting(WidgetListElem *el, SettingParam *param)
static void apply_preset_to_gui(GList *list, Preset *preset) static void apply_preset_to_gui(GList *list, Preset *preset)
{ {
allow_send = FALSE;
GList *iter = preset->params; GList *iter = preset->params;
while (iter) { while (iter) {
SettingParam *param = iter->data; SettingParam *param = iter->data;
@@ -357,6 +378,8 @@ static void apply_preset_to_gui(GList *list, Preset *preset)
if (param != NULL) if (param != NULL)
g_list_foreach(list, (GFunc)apply_widget_setting, param); g_list_foreach(list, (GFunc)apply_widget_setting, param);
} }
allow_send = TRUE;
} }
static void action_store_cb(GtkAction *action) static void action_store_cb(GtkAction *action)
@@ -547,6 +570,15 @@ static void add_menubar(GList **list, GtkWidget *window, GtkWidget *vbox)
g_object_unref(ui); g_object_unref(ui);
} }
static void apply_current_preset(GList *list)
{
GString *msg = get_current_preset();
Preset *preset = create_preset_from_data(msg);
g_string_free(msg, TRUE);
apply_preset_to_gui(list, preset);
preset_free(preset);
}
void create_window() void create_window()
{ {
GtkWidget *window; GtkWidget *window;
@@ -587,6 +619,7 @@ void create_window()
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2); gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
} }
apply_current_preset(list);
gtk_widget_show_all(window); gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);

1
gui.h
View File

@@ -17,6 +17,7 @@
#ifndef GDIGI_GUI_H #ifndef GDIGI_GUI_H
#define GDIGI_GUI_H #define GDIGI_GUI_H
void show_error_message(GtkWidget *parent, gchar *message);
void create_window(); void create_window();
#endif /* GDIGI_GUI_H */ #endif /* GDIGI_GUI_H */

View File

@@ -165,6 +165,54 @@ Preset *create_preset_from_xml_file(gchar *filename)
return preset; return preset;
} }
Preset *create_preset_from_data(GString *data)
{
gint total;
gint n;
gint id;
gint position;
guint value;
gint x;
gint tmp;
x = 0x09;
n = 0;
total = (u_char)data->str[x];
x++;
Preset *preset = g_malloc(sizeof(Preset));
preset->name = NULL; /* TODO */
preset->params = NULL;
do {
id = ((u_char)data->str[x] << 8) | (u_char)data->str[x+1];
position = (u_char)data->str[x+2];
x+=3;
value = data->str[x];
x++;
if (value > 0x80) {
tmp = value & 0x7F;
value = 0;
gint i;
for (i=0; i<tmp; i++) {
value |= ((u_char)data->str[x+i] << (8*(tmp-i-1)));
}
x+=tmp;
}
n++;
SettingParam *param = (SettingParam *)g_malloc(sizeof(SettingParam));
param->id = id;
param->position = position;
param->value = value;
preset->params = g_list_prepend(preset->params, param);
g_message("%d ID %d Position %d Value %d", n, id, position, value);
} while ((x < data->len) && n<total);
g_message("TOTAL %d", total);
preset->params = g_list_reverse(preset->params);
return preset;
}
void preset_free(Preset *preset) void preset_free(Preset *preset)
{ {
g_return_if_fail(preset != NULL); g_return_if_fail(preset != NULL);

View File

@@ -31,6 +31,7 @@ typedef struct {
} Preset; } Preset;
Preset *create_preset_from_xml_file(gchar *filename); Preset *create_preset_from_xml_file(gchar *filename);
Preset *create_preset_from_data(GString *data);
void preset_free(Preset *preset); void preset_free(Preset *preset);
#endif /* GDIGI_PRESET_H */ #endif /* GDIGI_PRESET_H */