24 Commits
0.1.8 ... 0.2.0

Author SHA1 Message Date
Tomasz Moń
0bb0f6db71 update manpage 2010-10-07 11:08:59 +02:00
Tomasz Moń
dcf66adfa9 fix RP1000 support 2010-08-25 11:15:29 +02:00
Tomasz Moń
0886ba00c1 add support for GNX4 and GNX3k patches 2010-06-17 19:20:58 +02:00
Jonathan A. Tice
e12de97fab add RP1000 support 2010-04-24 15:07:18 +02:00
Miklos Aubert
59753a61dc add RP255 support 2010-03-04 18:54:58 +01:00
Tomasz Moń
ff0be8230e fix some rp500 values 2010-02-05 09:43:21 +01:00
Tomasz Moń
07cfd70941 display values correctly (offsets, correct steps, suffixes, labels) 2010-01-03 14:18:53 +01:00
Rafael Moreno
2523b27205 add rp355p to SupportedFileTypes 2009-09-20 20:06:27 +02:00
Tomasz Moń
530dd397c5 remove USB settings from effect list as they're not part of Preset 2009-09-20 19:57:39 +02:00
Rafael Moreno
158fd081a5 fix RP355 amp B settings 2009-09-04 17:49:11 +02:00
Tomasz Moń
a8bac07f68 correct manpage 2009-08-11 12:18:03 +02:00
Andreas Karajannis
87bb59f43a don't use uninitialized value 2009-08-11 12:17:28 +02:00
Andrew O. Shadoura
cdeb821deb added manpage 2009-08-10 19:56:56 +01:00
Andrew O. Shadoura
ce463b29d8 added simple .desktop file 2009-08-08 21:04:40 +01:00
Andrew O. Shadoura
159bca158e use LDADD instead of LDFLAGS and -Wl,--as-needed; added install target 2009-08-08 20:53:07 +01:00
Tomasz Moń
6ae750c4fb GFile requires gio.h 2009-07-31 14:10:21 +02:00
Rafael Moreno
5f21c62a2f fix RP355 support 2009-07-28 11:38:24 +02:00
Tomasz Moń
08b20b398f remove redundant GFile 2009-07-19 18:52:57 +02:00
Tomasz Moń
1be664e82f rename Pickup to Pickup/USB as this frame contains both pickup and USB settings 2009-07-19 18:32:48 +02:00
Tomasz Moń
3ab55054c1 add restore_backup_file() 2009-07-19 16:15:23 +02:00
Tomasz Moń
97b8c9fd6d add create_backup_file() 2009-07-19 14:03:55 +02:00
Tomasz Moń
211df27cf8 fix typos in comments 2009-06-29 20:03:54 +02:00
Rafael Moreno
dfe28ac81d add RP355 support 2009-06-29 20:02:50 +02:00
Tomasz Moń
3da458d370 Added tag 0.1.8 for changeset 5e6d6124b5f2 2009-06-22 16:36:52 +02:00
10 changed files with 1843 additions and 168 deletions

View File

@@ -2,7 +2,8 @@ CC = gcc
EXTRA_CFLAGS ?= EXTRA_CFLAGS ?=
EXTRA_LDFLAGS ?= EXTRA_LDFLAGS ?=
CFLAGS := $(shell pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0) -Wall -g -ansi -std=c99 $(EXTRA_CFLAGS) CFLAGS := $(shell pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0) -Wall -g -ansi -std=c99 $(EXTRA_CFLAGS)
LDFLAGS := $(shell pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 gthread-2.0 alsa) -lexpat $(EXTRA_LDFLAGS) LDFLAGS = $(EXTRA_LDFLAGS) -Wl,--as-needed
LDADD := $(shell pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 gthread-2.0 alsa) -lexpat
OBJECTS = gdigi.o gui.o effects.o preset.o gtkknob.o OBJECTS = gdigi.o gui.o effects.o preset.o gtkknob.o
DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m) DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m)
@@ -16,7 +17,7 @@ DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m)
all: gdigi all: gdigi
gdigi: $(OBJECTS) gdigi: $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $+ $(CC) $(LDFLAGS) -o $@ $+ $(LDADD)
knob.h: knob.png knob.h: knob.png
gdk-pixbuf-csource --name=knob_pixbuf knob.png > $@ gdk-pixbuf-csource --name=knob_pixbuf knob.png > $@
@@ -29,6 +30,9 @@ distclean : clean
rm -f .*.m rm -f .*.m
rm -f gdigi rm -f gdigi
install: gdigi
install gdigi $(DESTDIR)/usr/bin
NODEP_TARGETS := clean distclean NODEP_TARGETS := clean distclean
depinc := 1 depinc := 1
ifneq (,$(filter $(NODEP_TARGETS),$(MAKECMDGOALS))) ifneq (,$(filter $(NODEP_TARGETS),$(MAKECMDGOALS)))

990
effects.c

File diff suppressed because it is too large Load Diff

View File

@@ -19,10 +19,30 @@
#include <glib.h> #include <glib.h>
typedef struct { enum {
VALUE_TYPE_PLAIN = 0, /**< value displayed directly */
VALUE_TYPE_SUFFIX = 1 << 0, /**< use suffix for displaying */
VALUE_TYPE_OFFSET = 1 << 1, /**< use value offset */
VALUE_TYPE_STEP = 1 << 2, /**< use value step different than 1 */
VALUE_TYPE_LABEL = 1 << 3, /**< use value labels (overrides any other option) */
VALUE_TYPE_EXTRA = 1 << 4, /**< use extra values */
VALUE_TYPE_DECIMAL= 1 << 5, /**< display decimal places */
} ValueType;
typedef struct _EffectValues {
gdouble min; /**< Minumum value */ gdouble min; /**< Minumum value */
gdouble max; /**< Maximum value */ gdouble max; /**< Maximum value */
gint type; /**< value type bitmask (ValueType) */
GStrv labels; /**< value labels */ GStrv labels; /**< value labels */
gint offset; /**< value offset */
gdouble step; /**< value step */
gchar *suffix; /**< value suffix */
struct _EffectValues *extra;
/**< additional value range,
use it when there're different range types */
gint decimal; /**< amount of decimal places to display */
} EffectValues; } EffectValues;
typedef struct { typedef struct {
@@ -85,6 +105,8 @@ typedef struct {
ModifierGroup *modifier_linkable_list(); ModifierGroup *modifier_linkable_list();
void modifier_group_free(ModifierGroup *modifier_group); void modifier_group_free(ModifierGroup *modifier_group);
void get_values_info(EffectValues *values,
gdouble *min, gdouble *max, gboolean *custom);
gboolean get_device_info(unsigned char device_id, unsigned char family_id, gboolean get_device_info(unsigned char device_id, unsigned char family_id,
unsigned char product_id, unsigned char product_id,
Device **device); Device **device);

74
gdigi.1 Normal file
View File

@@ -0,0 +1,74 @@
.\" Hey, EMACS: -*- nroff -*-
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH GDIGI 1 "October 07, 2010"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
.\" .nh disable hyphenation
.\" .hy enable hyphenation
.\" .ad l left justify
.\" .ad b justify to both left and right margins
.\" .nf disable filling
.\" .fi enable filling
.\" .br insert line break
.\" .sp <n> insert n+1 empty lines
.\" for manpage-specific macros, see man(7)
.SH NAME
gdigi \- utility to control DigiTech effect pedals
.SH SYNOPSIS
.B gdigi
.RI [OPTION...]
.SH DESCRIPTION
gdigi is a tool aimed to provide X-Edit functionality to Linux users
.PP
Supported devices:
.IP \(bu
RP250
.IP \(bu
RP255
.IP \(bu
RP355
.IP \(bu
RP500
.IP \(bu
RP1000
.IP \(bu
GNX3000
.IP \(bu
GNX4K
.PP
.SH OPTIONS
These programs follow the usual GNU command line syntax, with long
options starting with two dashes (`\-').
A summary of options is included below.
For a complete description, see the Info files.
.TP
.B \-?, \-\-help
Show summary of options.
.TP
.B \-\-help\-all
Show all help options.
.TP
.B \-\-help\-gtk
Show GTK+ options.
.TP
.B \-\-display=\fIDISPLAY\fR
X display to use.
.TP
.B \-d, \-\-device
MIDI device port to use.
.SH AUTHOR
gdigi was written by Tomasz Moń <desowin@gmail.com>.
.PP
Send comments, bug reports and patches to gdigi
mailinglist at Google Groups.
.PP
This manual page was written by Andrew O. Shadoura <bugzilla@tut.by>,
for the Debian project (but may be used by others).
.PP
Permission is granted to copy, distribute and/or modify this document under the
terms of the GNU General Public License as published by the Free Software
Foundation, under version 3 of the License.

345
gdigi.c
View File

@@ -16,6 +16,7 @@
#include <stdio.h> #include <stdio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gio/gio.h>
#include <getopt.h> #include <getopt.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include <alloca.h> #include <alloca.h>
@@ -34,6 +35,22 @@ static GQueue *message_queue = NULL;
static GMutex *message_queue_mutex = NULL; static GMutex *message_queue_mutex = NULL;
static GCond *message_queue_cond = NULL; static GCond *message_queue_cond = NULL;
/**
* Registers an error quark for gdigi if necessary.
*
* \return error quark used for gdigi errors
**/
static GQuark gdigi_error_quark()
{
static GQuark quark = 0;
if (quark == 0) {
quark = g_quark_from_static_string("gdigi-error");
}
return quark;
}
/** /**
* \param array data to calculate checksum * \param array data to calculate checksum
* \param length data length * \param length data length
@@ -159,20 +176,27 @@ static void unpack_message(GString *msg)
do { do {
offset += 8; offset += 8;
status = str[offset-1]; status = str[offset-1];
for (x=0; x<7; x++) { for (x=0; x<7 && !stop; x++) {
if (offset+x >= msg->len) { if (offset+x >= msg->len) {
i++;
stop = TRUE; stop = TRUE;
break; break;
} }
if (str[offset+x] == 0xF7) { if (str[offset+x] == 0xF7) {
if (x == 0) {
str[i] = status;
i++;
}
str[i] = 0xF7; str[i] = 0xF7;
i++;
stop = TRUE; stop = TRUE;
break;
} }
str[i] = (((status << (x+1)) & 0x80) | str[x+offset]); str[i] = (((status << (x+1)) & 0x80) | str[x+offset]);
i++; i++;
} }
} while (!stop && (offset+x < msg->len)); } while (!stop);
g_string_truncate(msg, i); g_string_truncate(msg, i);
} }
@@ -540,6 +564,68 @@ void setting_param_free(SettingParam *param)
g_slice_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 id Parameter ID
* \param position Parameter position * \param position Parameter position
@@ -558,6 +644,68 @@ void set_option(guint id, guint position, guint value)
g_string_free(msg, TRUE); 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 bank preset bank
* \param x preset index * \param x preset index
@@ -653,11 +801,13 @@ GStrv query_preset_names(gchar bank)
} }
/** /**
* Queries current edit buffer. * Reads multiple messages and puts them into GList.
* *
* \return GList with preset SysEx messages, which must be freed using preset_list_free. * \param id MessageID starting message sequence
*
* \return GList with SysEx messages, which must be freed using message_list_free.
**/ **/
GList *get_current_preset() GList *get_message_list(MessageID id)
{ {
GString *data = NULL; GString *data = NULL;
GList *list = NULL; GList *list = NULL;
@@ -665,15 +815,13 @@ GList *get_current_preset()
gboolean found = FALSE; gboolean found = FALSE;
gboolean done = FALSE; gboolean done = FALSE;
send_message(REQUEST_PRESET, "\x04\x00", 2);
g_mutex_lock(message_queue_mutex); g_mutex_lock(message_queue_mutex);
do { do {
len = g_queue_get_length(message_queue); len = g_queue_get_length(message_queue);
for (x = 0; x<len && (found == FALSE); x++) { for (x = 0; x<len && (found == FALSE); x++) {
data = g_queue_peek_nth(message_queue, x); data = g_queue_peek_nth(message_queue, x);
if (get_message_id(data) == RECEIVE_PRESET_START) { if (get_message_id(data) == id) {
found = TRUE; found = TRUE;
g_queue_pop_nth(message_queue, x); g_queue_pop_nth(message_queue, x);
unpack_message(data); unpack_message(data);
@@ -686,11 +834,23 @@ GList *get_current_preset()
int i; int i;
int amt; int amt;
for (i = 10; (i < data->len) && data->str[i]; i++); switch (id) {
case RECEIVE_PRESET_START:
amt = (unsigned char)data->str[i+2]; for (i = 10; (i < data->len) && data->str[i]; i++);
amt = (unsigned char)data->str[i+2];
break;
case RECEIVE_BULK_DUMP_START:
amt = ((unsigned char)data->str[8] << 8) | (unsigned char)data->str[9];
break;
default:
g_error("get_message_list() doesn't support followning id: %d", id);
g_string_free(data, TRUE);
g_list_free(list);
return NULL;
}
while (amt) { while (amt) {
g_message("%d messages left", amt);
data = g_queue_pop_nth(message_queue, x); data = g_queue_pop_nth(message_queue, x);
if (data == NULL) { if (data == NULL) {
g_cond_wait(message_queue_cond, message_queue_mutex); g_cond_wait(message_queue_cond, message_queue_mutex);
@@ -703,7 +863,7 @@ GList *get_current_preset()
done = TRUE; done = TRUE;
} else { } else {
/* Receive Preset Start not found in message queue */ /* id not found in message queue */
g_cond_wait(message_queue_cond, message_queue_mutex); g_cond_wait(message_queue_cond, message_queue_mutex);
} }
} while (done == FALSE); } while (done == FALSE);
@@ -712,7 +872,12 @@ GList *get_current_preset()
return list; return list;
} }
void preset_list_free(GList *list) /**
* \param list list to be freed
*
* Frees all memory used by message list.
**/
void message_list_free(GList *list)
{ {
g_return_if_fail(list != NULL); g_return_if_fail(list != NULL);
@@ -720,6 +885,160 @@ void preset_list_free(GList *list)
g_list_free(list); g_list_free(list);
} }
/**
* Queries current edit buffer.
*
* \return GList with preset SysEx messages, which must be freed using message_list_free.
**/
GList *get_current_preset()
{
send_message(REQUEST_PRESET, "\x04\x00", 2);
return get_message_list(RECEIVE_PRESET_START);
}
/**
* Creates backup file.
*
* \param file backup file handle
* \param error a GError
*
* \return FALSE on success, TRUE on error.
**/
static gboolean create_backup_file(GFile *file, GError **error)
{
GFileOutputStream *output = NULL;
GList *list = NULL, *iter = NULL;
const gchar header[] = {'\x01', '\x00'};
gsize written;
gboolean val;
if (error)
*error = NULL;
output = g_file_create(file, G_FILE_CREATE_NONE, NULL, error);
if (output == NULL)
return TRUE;
if (error)
*error = NULL;
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), header,
sizeof(header), &written, NULL, error);
if (val == FALSE) {
g_object_unref(output);
return TRUE;
}
send_message(REQUEST_BULK_DUMP, "\x00", 1);
list = get_message_list(RECEIVE_BULK_DUMP_START);
for (iter = list; iter; iter = g_list_next(iter)) {
GString *str;
guchar id; /* message id */
guint32 len; /* message length */
str = (GString*) iter->data;
id = get_message_id(str);
if (error)
*error = NULL;
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &id,
sizeof(id), &written, NULL, error);
if (val == FALSE) {
message_list_free(list);
g_object_unref(output);
return TRUE;
}
len = GUINT32_TO_LE(str->len - 10);
if (error)
*error = NULL;
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &len,
sizeof(len), &written, NULL, error);
if (val == FALSE) {
message_list_free(list);
g_object_unref(output);
return TRUE;
}
if (error)
*error = NULL;
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &str->str[8],
str->len - 10, &written, NULL, error);
if (val == FALSE) {
message_list_free(list);
g_object_unref(output);
return TRUE;
}
}
message_list_free(list);
if (error)
*error = NULL;
val = g_output_stream_close(G_OUTPUT_STREAM(output), NULL, error);
g_object_unref(output);
return !val;
}
/**
* Restores backup file.
*
* \param filename backup filename
* \param error a GError
*
* \return FALSE on success, TRUE on error.
**/
static gboolean restore_backup_file(const gchar *filename, GError **error)
{
gchar *data;
gsize length;
gsize x;
if (g_file_get_contents(filename, &data, &length, error) == FALSE)
return TRUE;
if (error)
*error = NULL;
if (!(data[0] == 0x01 && data[1] == 0x00)) {
g_free(data);
g_set_error_literal(error, gdigi_error_quark(), 0,
"Magic byte doesn't match");
return TRUE;
}
x = 0x02;
while (x < length) {
gchar id;
guint32 len;
id = data[x];
x++;
if (x+4 <= length) {
len = GUINT32_FROM_LE(*((guint32*) &data[x]));
x += 4;
} else {
g_free(data);
g_set_error_literal(error, gdigi_error_quark(), 0,
"Unexpected end of data");
return TRUE;
}
if (x+len <= length) {
send_message(id, &data[x], len);
x += len;
} else {
g_free(data);
g_set_error_literal(error, gdigi_error_quark(), 0,
"Unexpected end of data");
return TRUE;
}
}
g_free(data);
return FALSE;
}
/** /**
* \param device_id Variable to hold device ID * \param device_id Variable to hold device ID
* \param family_id Variable to hold family ID * \param family_id Variable to hold family ID

6
gdigi.desktop Normal file
View File

@@ -0,0 +1,6 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=gdigi
Exec=gdigi

120
gdigi.h
View File

@@ -104,10 +104,15 @@ enum {
enum { enum {
DIST_TYPE_SCREAMER = 1280, DIST_TYPE_SCREAMER = 1280,
DIST_TYPE_808 = 1292, DIST_TYPE_808 = 1292,
DIST_TYPE_TS_MOD = 1301,
DIST_TYPE_SD_ODRV = 1302,
DIST_TYPE_OD_ODRV = 1299,
DIST_TYPE_SPARKDRIVE = 1286, DIST_TYPE_SPARKDRIVE = 1286,
DIST_TYPE_GUYOD = 1285, DIST_TYPE_GUYOD = 1285,
DIST_TYPE_DOD250 = 1283, DIST_TYPE_DOD250 = 1283,
DIST_TYPE_REDLINE = 1297, DIST_TYPE_REDLINE = 1297,
DIST_TYPE_AMPDRIVR = 1298,
DIST_TYPE_OC_DRIVE = 1300,
DIST_TYPE_RODENT = 1281, DIST_TYPE_RODENT = 1281,
DIST_TYPE_MX = 1291, DIST_TYPE_MX = 1291,
DIST_TYPE_DS = 1282, DIST_TYPE_DS = 1282,
@@ -134,6 +139,17 @@ enum {
#define DIST_808_TONE 2474 #define DIST_808_TONE 2474
#define DIST_808_LVL 2475 #define DIST_808_LVL 2475
#define DIST_TS_MOD_DRIVE 2562
#define DIST_TS_MOD_TONE 2564
#define DIST_TS_MOD_LVL 2563
#define DIST_SD_ODRV_DRIVE 2565
#define DIST_SD_ODRV_TONE 2566
#define DIST_SD_ODRV_LVL 2567
#define DIST_OD_ODRV_OVERDRIVE 2568
#define DIST_OD_ODRV_LVL 2569
#define DIST_SPARKDRIVE_GAIN 2450 #define DIST_SPARKDRIVE_GAIN 2450
#define DIST_SPARKDRIVE_TONE 2451 #define DIST_SPARKDRIVE_TONE 2451
#define DIST_SPARKDRIVE_CLEAN 2452 #define DIST_SPARKDRIVE_CLEAN 2452
@@ -150,12 +166,22 @@ enum {
#define DIST_REDLINE_HIGH 2490 #define DIST_REDLINE_HIGH 2490
#define DIST_REDLINE_LEVEL 2491 #define DIST_REDLINE_LEVEL 2491
#define DIST_AMPDRIVR_GAIN 2570
#define DIST_AMPDRIVR_MIDBOOST 2571
#define DIST_AMPDRIVR_LVL 2572
#define DIST_OC_DRIVE_DRIVE 2492
#define DIST_OC_DRIVE_TONE 2494
#define DIST_OC_DRIVE_HP_LP 2493
#define DIST_OC_DRIVE_LVL 2495
#define DIST_RODENT_DIST 2437 #define DIST_RODENT_DIST 2437
#define DIST_RODENT_FILTER 2438 #define DIST_RODENT_FILTER 2438
#define DIST_RODENT_LVL 2439 #define DIST_RODENT_LVL 2439
#define DIST_MX_DIST 2468 #define DIST_MX_DIST 2468
#define DIST_MX_OUTPUT 2469 #define DIST_MX_OUTPUT 2469
#define DIST_DS_GAIN 2440 #define DIST_DS_GAIN 2440
#define DIST_DS_TONE 2441 #define DIST_DS_TONE 2441
#define DIST_DS_LVL 2442 #define DIST_DS_LVL 2442
@@ -225,8 +251,10 @@ enum {
AMP_TYPE_BOOGIE_MARK_IV = 371, AMP_TYPE_BOOGIE_MARK_IV = 371,
AMP_TYPE_DUAL_RECTIFIER = 321, AMP_TYPE_DUAL_RECTIFIER = 321,
AMP_TYPE_TRIPLE_RECTIFIER = 370, AMP_TYPE_TRIPLE_RECTIFIER = 370,
AMP_TYPE_22_CALIBR = 386,
AMP_TYPE_LEGACY_VL100 = 327, AMP_TYPE_LEGACY_VL100 = 327,
AMP_TYPE_MATCHLESS_HC30 = 326, AMP_TYPE_MATCHLESS_HC30 = 326,
AMP_TYPE_CHIEF = 385,
AMP_TYPE_SOLDANO_100 = 325, AMP_TYPE_SOLDANO_100 = 325,
AMP_TYPE_SUPERGROUP = 381, AMP_TYPE_SUPERGROUP = 381,
AMP_TYPE_GA40 = 380, AMP_TYPE_GA40 = 380,
@@ -282,6 +310,18 @@ enum {
#define AMP_POSITION 8 #define AMP_POSITION 8
#define CH2_AMP_POSITION 10 #define CH2_AMP_POSITION 10
#define AMP_LOOP_ON_OFF 3649
#define AMP_LOOP_POSITION 33
#define AMP_BYPASS_ON_OFF 12361
#define AMP_BYPASS_POSITION 0
#define AMP_SELECT 256
#define AMP_SELECT_POSITION 7
#define AMP_CHANNEL_A 0
#define AMP_CHANNEL_B 1
#define AMP_GAIN 2497 #define AMP_GAIN 2497
#define AMP_LEVEL 2498 #define AMP_LEVEL 2498
#define AMP_BASS_FREQ 2499 #define AMP_BASS_FREQ 2499
@@ -312,6 +352,7 @@ enum {
AMP_CAB_TWIN = 576, AMP_CAB_TWIN = 576,
AMP_CAB_BRITISH2_12 = 613, AMP_CAB_BRITISH2_12 = 613,
AMP_CAB_JAZZ2_12 = 626, AMP_CAB_JAZZ2_12 = 626,
AMP_CAB_JBL_215 = 627,
AMP_CAB_BASSMAN = 579, AMP_CAB_BASSMAN = 579,
AMP_CAB_BRITISH4_12 = 614, AMP_CAB_BRITISH4_12 = 614,
AMP_CAB_BRITISH_GREEN = 616, AMP_CAB_BRITISH_GREEN = 616,
@@ -368,11 +409,13 @@ enum {
#define EQ_TYPE 3202 #define EQ_TYPE 3202
#define EQ_ON_OFF 3212 #define EQ_ON_OFF 3212
#define EQ_POSITION 24 #define EQ_POSITION 24
#define EQ_POSITION_B 25
#define EQ_BASS 3203 #define EQ_BASS 3203
#define EQ_MID 3204 #define EQ_MID 3204
#define EQ_MID_HZ 3206 #define EQ_MID_HZ 3206
#define EQ_TREBLE 3205 #define EQ_TREBLE 3205
#define EQ_PRESENCE 3207
#define EQ_TREBLE_HZ 3211 #define EQ_TREBLE_HZ 3211
#define EQ_LOW_LEVEL 3203 #define EQ_LOW_LEVEL 3203
#define EQ_MID_LEVEL 3204 #define EQ_MID_LEVEL 3204
@@ -429,8 +472,11 @@ enum {
CHORUS_TYPE_DUAL = 0x379, CHORUS_TYPE_DUAL = 0x379,
CHORUS_TYPE_GLISTEN = 0x392, CHORUS_TYPE_GLISTEN = 0x392,
CHORUS_TYPE_MULTI = 0x37a, CHORUS_TYPE_MULTI = 0x37a,
CHORUS_TYPE_VOO_DOO = 0x396,
CHORUS_TYPE_CLONE = 0x397,
CHORUS_TYPE_FLANGER = 0x37d, CHORUS_TYPE_FLANGER = 0x37d,
CHORUS_TYPE_TRIGGERED_FLANGER = 0x37e, CHORUS_TYPE_TRIGGERED_FLANGER = 0x37e,
CHORUS_TYPE_FLTFLANGER = 0x398,
CHORUS_TYPE_MXR_FLANGER = 0x37f, CHORUS_TYPE_MXR_FLANGER = 0x37f,
CHORUS_TYPE_EH_FLANGER = 0x380, CHORUS_TYPE_EH_FLANGER = 0x380,
CHORUS_TYPE_AD_FLANGER = 0x393, CHORUS_TYPE_AD_FLANGER = 0x393,
@@ -463,7 +509,10 @@ enum {
#define CHORUSFX_TYPE 768 #define CHORUSFX_TYPE 768
#define CHORUSFX_ON_OFF 769 #define CHORUSFX_ON_OFF 769
#define CHORUSFX_PRE_POST 770
#define CHORUSFX_POSITION 14 #define CHORUSFX_POSITION 14
#define CHORUSFX_PRE 1543
#define CHORUSFX_POST 1544
#define CHORUS_SPEED 837 #define CHORUS_SPEED 837
#define CHORUS_DEPTH 838 #define CHORUS_DEPTH 838
@@ -476,6 +525,8 @@ enum {
#define CHORUS_WAVE 840 #define CHORUS_WAVE 840
#define CHORUS_BALANCE 841 #define CHORUS_BALANCE 841
#define CHORUS_RATE 850
#define FLANGER_SPEED 902 #define FLANGER_SPEED 902
#define FLANGER_DEPTH 903 #define FLANGER_DEPTH 903
#define FLANGER_REGEN 904 #define FLANGER_REGEN 904
@@ -489,6 +540,8 @@ enum {
#define TRIG_FLANGER_MIX 1029 #define TRIG_FLANGER_MIX 1029
#define TRIG_FLANGER_LEVEL 1032 #define TRIG_FLANGER_LEVEL 1032
#define FLTFLANGER_FREQ 922
#define MXR_FLANGER_WIDTH 914 #define MXR_FLANGER_WIDTH 914
#define MXR_FLANGER_MANUAL 917 #define MXR_FLANGER_MANUAL 917
@@ -608,6 +661,8 @@ enum {
DELAY_TYPE_MODULATED = 1047, DELAY_TYPE_MODULATED = 1047,
DELAY_TYPE_PONG = 1048, DELAY_TYPE_PONG = 1048,
DELAY_TYPE_TAPE = 1049, DELAY_TYPE_TAPE = 1049,
DELAY_TYPE_ECHOPLEX = 1050,
DELAY_TYPE_DM = 1051,
DELAY_RP500_TYPE_DIGITAL = 1052, DELAY_RP500_TYPE_DIGITAL = 1052,
DELAY_RP500_TYPE_ANALOG = 1053, DELAY_RP500_TYPE_ANALOG = 1053,
@@ -618,6 +673,9 @@ enum {
DELAY_RP500_TYPE_REVERSE = 1064, DELAY_RP500_TYPE_REVERSE = 1064,
DELAY_RP500_TYPE_TAPE = 1056, DELAY_RP500_TYPE_TAPE = 1056,
DELAY_RP1000_TYPE_LO_FI = 1065,
DELAY_RP1000_TYPE_2_TAP = 1066,
DELAY_GNX3K_TYPE_MONO = 1027, DELAY_GNX3K_TYPE_MONO = 1027,
DELAY_GNX3K_TYPE_PINGPONG = 1028, DELAY_GNX3K_TYPE_PINGPONG = 1028,
DELAY_GNX3K_TYPE_ANALOG = 1029, DELAY_GNX3K_TYPE_ANALOG = 1029,
@@ -631,6 +689,13 @@ enum {
#define DELAY_TIME 1888 #define DELAY_TIME 1888
#define DELAY_MULTIPLIER 1904
#define DELAY_3_QUARTR 2180
#define DELAY_EIGHT 2179
#define DELAY_DOTEIGHT 2178
#define DELAY_QUARTER 2177
#define DELAY_HALF 2176
#define DELAY_TAPE_WOW 1891 #define DELAY_TAPE_WOW 1891
#define DELAY_TAPE_FLUTTER 1892 #define DELAY_TAPE_FLUTTER 1892
@@ -640,8 +705,10 @@ enum {
#define DELAY_DUCK_THRESH 1889 #define DELAY_DUCK_THRESH 1889
#define DELAY_DUCK_LEVEL 1890 #define DELAY_DUCK_LEVEL 1890
#define DELAY_REPEAT_RATE 1898 #define DELAY_REPEAT_RATE 1898
#define DELAY_REPEAT_RATE_DM 1894
#define DELAY_ECHO 1895 #define DELAY_ECHO 1895
#define DELAY_INTENSITY 1896 #define DELAY_INTENSITY 1896
#define DELAY_ECHOPLEX_TIME 1897
#define DELAY_TIME_0_760 1899 #define DELAY_TIME_0_760 1899
#define DELAY_VOLUME 1893 #define DELAY_VOLUME 1893
#define DELAY_REPEATS_0_99 1874 #define DELAY_REPEATS_0_99 1874
@@ -649,6 +716,7 @@ enum {
#define DELAY_TAP_TIME_0_4990 1900 #define DELAY_TAP_TIME_0_4990 1900
#define DELAY_MIX 1902 #define DELAY_MIX 1902
#define DELAY_TIME_0_4650 1901 #define DELAY_TIME_0_4650 1901
#define DELAY_TAP_RATIO 1905
#define GNX3K_DELAY_TIME 1862 #define GNX3K_DELAY_TIME 1862
#define GNX3K_DELAY_FEEDBACK 1863 #define GNX3K_DELAY_FEEDBACK 1863
@@ -693,6 +761,9 @@ enum {
#define EXP_MIN 8195 #define EXP_MIN 8195
#define EXP_MAX 8196 #define EXP_MAX 8196
#define LFO_TYPE 8258
#define LFO1_POSITION 22
#define LFO2_POSITION 23
#define LIBRARY_TONE 8704 #define LIBRARY_TONE 8704
#define LIBRARY_EFFECTS 8705 #define LIBRARY_EFFECTS 8705
@@ -865,25 +936,72 @@ typedef enum {
NACK = 0x7F NACK = 0x7F
} MessageID; } 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 { typedef struct {
int id; int id;
int position; int position;
int value; int value;
} SettingParam; } 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); void send_message(gint procedure, gchar *data, gint len);
MessageID get_message_id(GString *msg); MessageID get_message_id(GString *msg);
void append_value(GString *msg, guint value); void append_value(GString *msg, guint value);
GString *get_message_by_id(MessageID id); GString *get_message_by_id(MessageID id);
SettingParam *setting_param_new(); SettingParam *setting_param_new();
SettingParam *setting_param_new_from_data(gchar *str, gint *len); 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); 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 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 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(gchar bank); GStrv query_preset_names(gchar bank);
void message_list_free(GList *list);
GList *get_current_preset(); GList *get_current_preset();
void preset_list_free(GList *list);
#endif /* GDIGI_H */ #endif /* GDIGI_H */

293
gui.c
View File

@@ -15,6 +15,7 @@
*/ */
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <string.h>
#include "gdigi.h" #include "gdigi.h"
#include "gui.h" #include "gui.h"
#include "effects.h" #include "effects.h"
@@ -56,6 +57,169 @@ void show_error_message(GtkWidget *parent, gchar *message)
gtk_widget_destroy(msg); gtk_widget_destroy(msg);
} }
/**
* \param value value to examine
* \param values EffectValues to check value against
*
* Examines whether value fits inside values range for given EffectValues.
*
* \return TRUE is value fits inside range, otherwise FALSE.
**/
static gboolean check_value_range(gint value, EffectValues *values)
{
if (((gint) values->min <= value) && (value <= (gint) values->max))
return TRUE;
else
return FALSE;
}
/**
* \param spin a GtkSpinButton
* \param new_val return value for valid input
* \param values signal user data, EffectValues for this parameter
*
* Custom GtkSpinButton "input" handler for EffectValues with non plain type.
*
* \return TRUE if new_val was set, otherwise FALSE.
**/
static gboolean custom_value_input_cb(GtkSpinButton *spin, gdouble *new_val, EffectValues *values)
{
gchar *text = g_strdup(gtk_entry_get_text(GTK_ENTRY(spin)));
gchar *err = NULL;
gdouble value;
for (;;) {
if (values->type & VALUE_TYPE_LABEL) {
/** search labels for value */
gint n;
for (n = 0; values->labels[n] != NULL; n++) {
if (g_strcmp0(values->labels[n], text) == 0) {
/* Value found */
*new_val = values->min + (gdouble)n;
g_free(text);
return TRUE;
}
}
/* Value not found */
if (values->type & VALUE_TYPE_EXTRA) {
values = values->extra;
continue;
} else {
g_free(text);
return FALSE;
}
}
if (values->type & VALUE_TYPE_SUFFIX) {
/* remove suffix from entry text */
gchar *tmp;
tmp = strstr(text, values->suffix);
if (tmp != NULL) {
gchar *temp = g_strndup(text, tmp - text);
g_free(text);
text = temp;
}
}
g_strstrip(text);
value = g_strtod(text, &err);
if (*err) {
if (values->type & VALUE_TYPE_EXTRA) {
values = values->extra;
continue;
} else {
g_free(text);
return FALSE;
}
}
if (values->type & VALUE_TYPE_STEP) {
value /= values->step;
}
if (values->type & VALUE_TYPE_OFFSET) {
value -= values->offset;
}
if (check_value_range((gint) value, values) == FALSE) {
if (values->type & VALUE_TYPE_EXTRA) {
values = values->extra;
continue;
} else {
g_free(text);
return FALSE;
}
}
*new_val = value;
g_free(text);
return TRUE;
}
}
/**
* \param spin a GtkSpinButton
* \param values signal user data, EffectValues for this parameter
*
* Custom GtkSpinButton "output" handler for EffectValues with non plain type.
*
* \return TRUE if text was set, otherwise FALSE.
**/
static gboolean custom_value_output_cb(GtkSpinButton *spin, EffectValues *values)
{
GtkAdjustment *adj;
gchar *text;
gdouble value;
adj = gtk_spin_button_get_adjustment(spin);
value = gtk_adjustment_get_value(adj);
while (check_value_range(value, values) == FALSE) {
if (values->type & VALUE_TYPE_EXTRA) {
values = values->extra;
} else {
g_message("custom_value_output_cb called with out of bounds value");
return FALSE;
}
}
if (values->type & VALUE_TYPE_LABEL) {
gtk_entry_set_text(GTK_ENTRY(spin), values->labels[(gint) value - (gint) values->min]);
return TRUE;
}
if (values->type & VALUE_TYPE_OFFSET) {
value += (gdouble) values->offset;
}
if (values->type & VALUE_TYPE_STEP) {
value *= values->step;
}
if (values->type & VALUE_TYPE_DECIMAL) {
text = g_strdup_printf("%.*f", values->decimal, value);
} else {
text = g_strdup_printf("%d", (gint) value);
}
if (values->type & VALUE_TYPE_SUFFIX) {
gchar *tmp;
tmp = g_strdup_printf("%s %s", text, values->suffix);
g_free(text);
text = tmp;
}
gtk_entry_set_text(GTK_ENTRY(spin), text);
g_free(text);
return TRUE;
}
/** /**
* \param adj the object which emitted the signal * \param adj the object which emitted the signal
* \param setting setting controlled by adj * \param setting setting controlled by adj
@@ -71,20 +235,6 @@ void value_changed_option_cb(GtkAdjustment *adj, EffectSettings *setting)
g_object_get(G_OBJECT(adj), "value", &val, NULL); g_object_get(G_OBJECT(adj), "value", &val, NULL);
set_option(setting->id, setting->position, (gint)val); set_option(setting->id, setting->position, (gint)val);
} }
if (setting->values != NULL && setting->values->labels != NULL) {
GtkWidget *label;
gint x;
gdouble val = -1.0;
g_object_get(G_OBJECT(adj), "value", &val, NULL);
x = (gint)val;
if ((x >= setting->values->min) && (x <= setting->values->max)) {
label = g_object_get_data(G_OBJECT(adj), "label");
gtk_label_set_text(GTK_LABEL(label), setting->values->labels[x]);
}
}
} }
/** /**
@@ -213,7 +363,7 @@ static void apply_current_preset()
{ {
GList *list = get_current_preset(); GList *list = get_current_preset();
Preset *preset = create_preset_from_data(list); Preset *preset = create_preset_from_data(list);
preset_list_free(list); message_list_free(list);
apply_preset_to_gui(preset); apply_preset_to_gui(preset);
preset_free(preset); preset_free(preset);
} }
@@ -248,20 +398,24 @@ GtkWidget *create_table(EffectSettings *settings, gint amt, GHashTable *widget_t
table = gtk_table_new(3, amt, FALSE); table = gtk_table_new(3, amt, FALSE);
for (x = 0; x<amt; x++) { for (x = 0; x<amt; x++) {
gdouble min, max;
gboolean custom;
get_values_info(settings[x].values, &min, &max, &custom);
label = gtk_label_new(settings[x].label); label = gtk_label_new(settings[x].label);
adj = gtk_adjustment_new(0.0, settings[x].values->min, settings[x].values->max, adj = gtk_adjustment_new(0.0, min, max,
1.0, /* step increment */ 1.0, /* step increment */
MAX((settings[x].values->max / 100), 5.0), /* page increment */ MAX((max / 100), 5.0), /* page increment */
0.0); 0.0);
knob = gtk_knob_new(GTK_ADJUSTMENT(adj), knob_anim); knob = gtk_knob_new(GTK_ADJUSTMENT(adj), knob_anim);
if (settings[x].values->labels == NULL) { widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0); gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), FALSE);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID);
gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID); if (custom == TRUE) {
} else { g_signal_connect(G_OBJECT(widget), "input", G_CALLBACK(custom_value_input_cb), settings[x].values);
widget = gtk_label_new(settings[x].values->labels[0]); g_signal_connect(G_OBJECT(widget), "output", G_CALLBACK(custom_value_output_cb), settings[x].values);
g_object_set_data(G_OBJECT(adj), "label", widget);
} }
widget_tree_add(adj, settings[x].id, settings[x].position, -1, -1); widget_tree_add(adj, settings[x].id, settings[x].position, -1, -1);
@@ -472,6 +626,10 @@ GtkWidget *create_vbox(Effect *widgets, gint amt, gchar *label)
widget = gtk_label_new(widgets[x].label); widget = gtk_label_new(widgets[x].label);
gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1); gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1);
y = 0; y = 0;
} else {
/* Default to 1 */
if (x == 0)
y = 1;
} }
container = create_widget_container(widgets[x].group, widgets[x].group_amt, widgets[x].type, widgets[x].position); container = create_widget_container(widgets[x].group, widgets[x].group_amt, widgets[x].type, widgets[x].position);
@@ -700,7 +858,12 @@ typedef struct {
static SupportedFileTypes file_types[] = { static SupportedFileTypes file_types[] = {
{"RP250Preset", "*.rp250p"}, {"RP250Preset", "*.rp250p"},
{"RP255Preset", "*.rp255p"},
{"RP355Preset", "*.rp355p"},
{"RP500Preset", "*.rp500p"}, {"RP500Preset", "*.rp500p"},
{"RP1000Preset", "*.rp1000p"},
{"GNX4 Preset", "*.g4p"},
{"GNX3kPreset", "*.g3kp"},
}; };
static guint n_file_types = G_N_ELEMENTS(file_types); static guint n_file_types = G_N_ELEMENTS(file_types);
@@ -758,41 +921,77 @@ static void action_open_preset_cb(GtkAction *action)
gtk_widget_hide(dialog); 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); GString *start = g_string_new(NULL);
g_string_append_printf(start, g_string_append_printf(start,
"%c%c%s%c%c%c", "%c%c%s%c%c%c",
PRESETS_EDIT_BUFFER, 0, PRESETS_EDIT_BUFFER, 0,
preset->name, 0 /* NULL terminated string */, 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_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); send_message(RECEIVE_PRESET_END, NULL, 0);
show_store_preset_window(window, preset->name); show_store_preset_window(window, preset->name);
g_string_free(start, TRUE); g_string_free(start, TRUE);
g_string_free(msg, TRUE);
preset_free(preset); preset_free(preset);
loaded = TRUE; loaded = TRUE;
} }

150
preset.c
View File

@@ -29,12 +29,24 @@ enum {
PARSER_TYPE_PARAM_POSITION, PARSER_TYPE_PARAM_POSITION,
PARSER_TYPE_PARAM_VALUE, PARSER_TYPE_PARAM_VALUE,
PARSER_TYPE_PARAM_NAME, 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 { typedef struct {
int depth; int depth;
int id; int id;
int section;
Preset *preset; Preset *preset;
} AppData; } AppData;
@@ -46,11 +58,16 @@ static void XMLCALL start(void *data, const char *el, const char **attr) {
if (ad->depth == 1) { if (ad->depth == 1) {
ad->id = PARSER_TYPE_PRESET_NAME; ad->id = PARSER_TYPE_PRESET_NAME;
} else if (ad->depth == 3) { } 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) { if (g_strcmp0(el, "Params") == 0) {
ad->section = SECTION_PARAMS;
if (ad->preset->params != NULL) if (ad->preset->params != NULL)
g_message("Params aleady exists!"); g_message("Params aleady exists!");
} else if (g_strcmp0(el, "Param") == 0) { } 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; ad->id = PARSER_TYPE_PARAM_VALUE;
} else if (g_strcmp0(el, "Text") == 0) { } else if (g_strcmp0(el, "Text") == 0) {
ad->id = PARSER_TYPE_PARAM_TEXT; 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++; 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); ad->preset->name = g_strndup(text, len);
} }
if (ad->preset->params == NULL) if (ad->section == SECTION_PARAMS) {
return; if (ad->preset->params == NULL)
return;
SettingParam *param = (SettingParam *) ad->preset->params->data; SettingParam *param = (SettingParam *) ad->preset->params->data;
if (param == NULL) if (param == NULL)
return; return;
gchar *value = g_strndup(text, len); gchar *value = g_strndup(text, len);
switch (ad->id) { switch (ad->id) {
case PARSER_TYPE_PARAM_ID: case PARSER_TYPE_PARAM_ID:
param->id = atoi(value); param->id = atoi(value);
break; break;
case PARSER_TYPE_PARAM_POSITION: case PARSER_TYPE_PARAM_POSITION:
param->position = atoi(value); param->position = atoi(value);
break; break;
case PARSER_TYPE_PARAM_VALUE: case PARSER_TYPE_PARAM_VALUE:
param->value = atoi(value); param->value = atoi(value);
break; 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 */ #endif /* DOXYGEN_SHOULD_SKIP_THIS */
@@ -124,16 +215,13 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
**/ **/
Preset *create_preset_from_xml_file(gchar *filename, GError **error) Preset *create_preset_from_xml_file(gchar *filename, GError **error)
{ {
GFile *file;
GError *err = NULL; GError *err = NULL;
gchar *contents; gchar *contents;
file = g_file_new_for_path(filename);
if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) { if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) {
g_message("Failed to get %s contents: %s", filename, err->message); g_message("Failed to get %s contents: %s", filename, err->message);
*error = g_error_copy(err); *error = g_error_copy(err);
g_error_free(err); g_error_free(err);
g_object_unref(file);
return NULL; return NULL;
} }
@@ -142,6 +230,7 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error)
ad->preset = g_slice_new(Preset); ad->preset = g_slice_new(Preset);
ad->preset->name = NULL; ad->preset->name = NULL;
ad->preset->params = NULL; ad->preset->params = NULL;
ad->preset->genetxs = NULL;
ad->id = PARSER_TYPE_NOT_SET; ad->id = PARSER_TYPE_NOT_SET;
XML_Parser p; XML_Parser p;
@@ -157,18 +246,17 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error)
preset_free(ad->preset); preset_free(ad->preset);
g_slice_free(AppData, ad); g_slice_free(AppData, ad);
g_free(contents); g_free(contents);
g_object_unref(file);
return NULL; return NULL;
} }
Preset *preset = ad->preset; Preset *preset = ad->preset;
preset->params = g_list_reverse(preset->params); preset->params = g_list_reverse(preset->params);
preset->genetxs = g_list_reverse(preset->genetxs);
XML_ParserFree(p); XML_ParserFree(p);
g_slice_free(AppData, ad); g_slice_free(AppData, ad);
g_free(contents); g_free(contents);
g_object_unref(file);
return preset; return preset;
} }
@@ -192,6 +280,7 @@ Preset *create_preset_from_data(GList *list)
Preset *preset = g_slice_new(Preset); Preset *preset = g_slice_new(Preset);
preset->name = NULL; preset->name = NULL;
preset->params = NULL; preset->params = NULL;
preset->genetxs = NULL;
iter = list; iter = list;
for (iter = list; iter; iter = g_list_next(iter)) { for (iter = list; iter; iter = g_list_next(iter)) {
@@ -254,8 +343,15 @@ void preset_free(Preset *preset)
g_list_free(preset->params); g_list_free(preset->params);
} }
if (preset->name != NULL) if (preset->genetxs != NULL) {
g_free(preset->name); 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); g_slice_free(Preset, preset);
} }

View File

@@ -22,6 +22,7 @@
typedef struct { typedef struct {
gchar *name; gchar *name;
GList *params; GList *params;
GList *genetxs;
} Preset; } Preset;
Preset *create_preset_from_xml_file(gchar *filename, GError **error); Preset *create_preset_from_xml_file(gchar *filename, GError **error);