start gui with proper values
This commit is contained in:
17
TODO
17
TODO
@@ -6,21 +6,4 @@
|
||||
-effects level
|
||||
-handling presets (loading, saving, exporting to xml patches)
|
||||
-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)
|
||||
|
||||
140
gdigi.c
140
gdigi.c
@@ -22,6 +22,10 @@
|
||||
#include "gdigi.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 *input = NULL;
|
||||
static char *device = "hw:1,0,0";
|
||||
@@ -47,6 +51,18 @@ char calculate_checksum(gchar *array, int length, int check)
|
||||
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
|
||||
Returns TRUE on error
|
||||
@@ -91,6 +107,7 @@ GString* read_data()
|
||||
by Clemens Ladisch <clemens@ladisch.de> */
|
||||
int err;
|
||||
int npfds;
|
||||
gboolean stop = FALSE;
|
||||
struct pollfd *pfds;
|
||||
GString *string = NULL;
|
||||
|
||||
@@ -118,6 +135,7 @@ GString* read_data()
|
||||
break;
|
||||
if (!(revents & POLLIN))
|
||||
continue;
|
||||
|
||||
err = snd_rawmidi_read(input, buf, sizeof(buf));
|
||||
if (err == -EAGAIN)
|
||||
continue;
|
||||
@@ -125,11 +143,15 @@ GString* read_data()
|
||||
g_error("cannot read: %s", snd_strerror(err));
|
||||
break;
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for (i = 0; i < err; ++i)
|
||||
if (buf[i] != 0xFE) // ignore active sensing
|
||||
buf[length++] = buf[i];
|
||||
|
||||
if ((u_char)buf[length-1] == 0xF7)
|
||||
stop = TRUE;
|
||||
|
||||
if (length != 0) {
|
||||
if (string == NULL) {
|
||||
string = g_string_new_len(buf, length);
|
||||
@@ -137,11 +159,42 @@ GString* read_data()
|
||||
string = g_string_append_len(string, buf, length);
|
||||
}
|
||||
}
|
||||
} while (err != 0);
|
||||
} while ((err != 0) && (stop == FALSE));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
id - ID as found in preset file
|
||||
position - Position as found in preset file
|
||||
@@ -310,9 +363,7 @@ GStrv query_preset_names(guint bank)
|
||||
gchar **str_array = NULL;
|
||||
|
||||
/* clear MIDI IN buffer */
|
||||
data = read_data();
|
||||
if (data != NULL)
|
||||
g_string_free(data, TRUE);
|
||||
clear_midi_in_buffer();
|
||||
|
||||
/* query user preset names */
|
||||
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;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
|
||||
{NULL}
|
||||
@@ -390,17 +510,15 @@ int main(int argc, char *argv[]) {
|
||||
g_option_context_free(context);
|
||||
|
||||
if (open_device() == TRUE) {
|
||||
GtkWidget *msg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_OK,
|
||||
"Failed to open MIDI device");
|
||||
|
||||
gtk_dialog_run(GTK_DIALOG(msg));
|
||||
gtk_widget_destroy(msg);
|
||||
show_error_message(NULL, "Failed to open MIDI device");
|
||||
} else {
|
||||
if (request_who_am_i(&device_id, &family_id, &product_id) == FALSE) {
|
||||
show_error_message(NULL, "No suitable reply from device - is it connected?");
|
||||
} else {
|
||||
create_window();
|
||||
gtk_main();
|
||||
}
|
||||
}
|
||||
|
||||
if (output != NULL)
|
||||
snd_rawmidi_close(output);
|
||||
|
||||
44
gdigi.h
44
gdigi.h
@@ -489,15 +489,51 @@ enum {
|
||||
#define USB_AUDIO_PLAYBACK_MIX 12297
|
||||
#define USB_AUDIO_LEVEL 12307
|
||||
|
||||
typedef enum {
|
||||
enum {
|
||||
PRESETS_SYSTEM = 0,
|
||||
PRESETS_USER = 1
|
||||
} PresetBank;
|
||||
PRESETS_USER = 1,
|
||||
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 switch_preset(guint bank, guint x);
|
||||
void store_preset_name(int x, const gchar *name);
|
||||
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 */
|
||||
|
||||
39
gui.c
39
gui.c
@@ -23,6 +23,21 @@
|
||||
extern EffectList 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 {
|
||||
GtkWidget *widget;
|
||||
gint id;
|
||||
@@ -37,17 +52,21 @@ void value_changed_option_cb(GtkSpinButton *spinbutton, EffectSettings *setting)
|
||||
{
|
||||
g_return_if_fail(setting != NULL);
|
||||
|
||||
int val = gtk_spin_button_get_value_as_int(spinbutton);
|
||||
if (allow_send) {
|
||||
gint val = gtk_spin_button_get_value_as_int(spinbutton);
|
||||
set_option(setting->option, setting->position, val);
|
||||
}
|
||||
}
|
||||
|
||||
void toggled_cb(GtkToggleButton *button, Effect *effect)
|
||||
{
|
||||
g_return_if_fail(effect != NULL);
|
||||
|
||||
if (allow_send) {
|
||||
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)
|
||||
{
|
||||
@@ -73,7 +92,7 @@ GtkWidget *create_table(GList **list, EffectSettings *settings, gint amt)
|
||||
|
||||
for (x = 0; x<amt; x++) {
|
||||
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);
|
||||
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);
|
||||
@@ -126,7 +145,7 @@ void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
|
||||
settings = g_object_get_data(G_OBJECT(widget), name);
|
||||
g_free(name);
|
||||
|
||||
if (settings != NULL)
|
||||
if (settings != NULL && allow_send)
|
||||
set_option(settings->option, settings->position, settings->id);
|
||||
|
||||
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)
|
||||
{
|
||||
allow_send = FALSE;
|
||||
|
||||
GList *iter = preset->params;
|
||||
while (iter) {
|
||||
SettingParam *param = iter->data;
|
||||
@@ -357,6 +378,8 @@ static void apply_preset_to_gui(GList *list, Preset *preset)
|
||||
if (param != NULL)
|
||||
g_list_foreach(list, (GFunc)apply_widget_setting, param);
|
||||
}
|
||||
|
||||
allow_send = TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
GtkWidget *window;
|
||||
@@ -587,6 +619,7 @@ void create_window()
|
||||
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
|
||||
}
|
||||
|
||||
apply_current_preset(list);
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);
|
||||
|
||||
1
gui.h
1
gui.h
@@ -17,6 +17,7 @@
|
||||
#ifndef GDIGI_GUI_H
|
||||
#define GDIGI_GUI_H
|
||||
|
||||
void show_error_message(GtkWidget *parent, gchar *message);
|
||||
void create_window();
|
||||
|
||||
#endif /* GDIGI_GUI_H */
|
||||
|
||||
48
preset.c
48
preset.c
@@ -165,6 +165,54 @@ Preset *create_preset_from_xml_file(gchar *filename)
|
||||
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)
|
||||
{
|
||||
g_return_if_fail(preset != NULL);
|
||||
|
||||
Reference in New Issue
Block a user