Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bb0f6db71 | ||
|
|
dcf66adfa9 | ||
|
|
0886ba00c1 | ||
|
|
e12de97fab | ||
|
|
59753a61dc | ||
|
|
ff0be8230e | ||
|
|
07cfd70941 | ||
|
|
2523b27205 | ||
|
|
530dd397c5 | ||
|
|
158fd081a5 | ||
|
|
a8bac07f68 | ||
|
|
87bb59f43a | ||
|
|
cdeb821deb | ||
|
|
ce463b29d8 | ||
|
|
159bca158e | ||
|
|
6ae750c4fb | ||
|
|
5f21c62a2f | ||
|
|
08b20b398f | ||
|
|
1be664e82f | ||
|
|
3ab55054c1 | ||
|
|
97b8c9fd6d | ||
|
|
211df27cf8 | ||
|
|
dfe28ac81d | ||
|
|
3da458d370 |
8
Makefile
8
Makefile
@@ -2,7 +2,8 @@ CC = gcc
|
||||
EXTRA_CFLAGS ?=
|
||||
EXTRA_LDFLAGS ?=
|
||||
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
|
||||
DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m)
|
||||
|
||||
@@ -16,7 +17,7 @@ DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m)
|
||||
all: gdigi
|
||||
|
||||
gdigi: $(OBJECTS)
|
||||
$(CC) $(LDFLAGS) -o $@ $+
|
||||
$(CC) $(LDFLAGS) -o $@ $+ $(LDADD)
|
||||
|
||||
knob.h: knob.png
|
||||
gdk-pixbuf-csource --name=knob_pixbuf knob.png > $@
|
||||
@@ -29,6 +30,9 @@ distclean : clean
|
||||
rm -f .*.m
|
||||
rm -f gdigi
|
||||
|
||||
install: gdigi
|
||||
install gdigi $(DESTDIR)/usr/bin
|
||||
|
||||
NODEP_TARGETS := clean distclean
|
||||
depinc := 1
|
||||
ifneq (,$(filter $(NODEP_TARGETS),$(MAKECMDGOALS)))
|
||||
|
||||
24
effects.h
24
effects.h
@@ -19,10 +19,30 @@
|
||||
|
||||
#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 max; /**< Maximum value */
|
||||
gint type; /**< value type bitmask (ValueType) */
|
||||
|
||||
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;
|
||||
|
||||
typedef struct {
|
||||
@@ -85,6 +105,8 @@ typedef struct {
|
||||
|
||||
ModifierGroup *modifier_linkable_list();
|
||||
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,
|
||||
unsigned char product_id,
|
||||
Device **device);
|
||||
|
||||
74
gdigi.1
Normal file
74
gdigi.1
Normal 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.
|
||||
|
||||
341
gdigi.c
341
gdigi.c
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/gio.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alloca.h>
|
||||
@@ -34,6 +35,22 @@ static GQueue *message_queue = NULL;
|
||||
static GMutex *message_queue_mutex = 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 length data length
|
||||
@@ -159,20 +176,27 @@ static void unpack_message(GString *msg)
|
||||
do {
|
||||
offset += 8;
|
||||
status = str[offset-1];
|
||||
for (x=0; x<7; x++) {
|
||||
for (x=0; x<7 && !stop; x++) {
|
||||
if (offset+x >= msg->len) {
|
||||
i++;
|
||||
stop = TRUE;
|
||||
break;
|
||||
}
|
||||
if (str[offset+x] == 0xF7) {
|
||||
if (x == 0) {
|
||||
str[i] = status;
|
||||
i++;
|
||||
}
|
||||
str[i] = 0xF7;
|
||||
i++;
|
||||
stop = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
str[i] = (((status << (x+1)) & 0x80) | str[x+offset]);
|
||||
i++;
|
||||
}
|
||||
} while (!stop && (offset+x < msg->len));
|
||||
} while (!stop);
|
||||
|
||||
g_string_truncate(msg, i);
|
||||
}
|
||||
@@ -540,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
|
||||
@@ -558,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
|
||||
@@ -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;
|
||||
GList *list = NULL;
|
||||
@@ -665,15 +815,13 @@ GList *get_current_preset()
|
||||
gboolean found = FALSE;
|
||||
gboolean done = FALSE;
|
||||
|
||||
send_message(REQUEST_PRESET, "\x04\x00", 2);
|
||||
|
||||
g_mutex_lock(message_queue_mutex);
|
||||
do {
|
||||
len = g_queue_get_length(message_queue);
|
||||
|
||||
for (x = 0; x<len && (found == FALSE); 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;
|
||||
g_queue_pop_nth(message_queue, x);
|
||||
unpack_message(data);
|
||||
@@ -686,11 +834,23 @@ GList *get_current_preset()
|
||||
int i;
|
||||
int amt;
|
||||
|
||||
switch (id) {
|
||||
case RECEIVE_PRESET_START:
|
||||
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) {
|
||||
g_message("%d messages left", amt);
|
||||
data = g_queue_pop_nth(message_queue, x);
|
||||
if (data == NULL) {
|
||||
g_cond_wait(message_queue_cond, message_queue_mutex);
|
||||
@@ -703,7 +863,7 @@ GList *get_current_preset()
|
||||
|
||||
done = TRUE;
|
||||
} else {
|
||||
/* Receive Preset Start not found in message queue */
|
||||
/* id not found in message queue */
|
||||
g_cond_wait(message_queue_cond, message_queue_mutex);
|
||||
}
|
||||
} while (done == FALSE);
|
||||
@@ -712,7 +872,12 @@ GList *get_current_preset()
|
||||
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);
|
||||
|
||||
@@ -720,6 +885,160 @@ void preset_list_free(GList *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 family_id Variable to hold family ID
|
||||
|
||||
6
gdigi.desktop
Normal file
6
gdigi.desktop
Normal file
@@ -0,0 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=gdigi
|
||||
Exec=gdigi
|
||||
|
||||
120
gdigi.h
120
gdigi.h
@@ -104,10 +104,15 @@ enum {
|
||||
enum {
|
||||
DIST_TYPE_SCREAMER = 1280,
|
||||
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_GUYOD = 1285,
|
||||
DIST_TYPE_DOD250 = 1283,
|
||||
DIST_TYPE_REDLINE = 1297,
|
||||
DIST_TYPE_AMPDRIVR = 1298,
|
||||
DIST_TYPE_OC_DRIVE = 1300,
|
||||
DIST_TYPE_RODENT = 1281,
|
||||
DIST_TYPE_MX = 1291,
|
||||
DIST_TYPE_DS = 1282,
|
||||
@@ -134,6 +139,17 @@ enum {
|
||||
#define DIST_808_TONE 2474
|
||||
#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_TONE 2451
|
||||
#define DIST_SPARKDRIVE_CLEAN 2452
|
||||
@@ -150,12 +166,22 @@ enum {
|
||||
#define DIST_REDLINE_HIGH 2490
|
||||
#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_FILTER 2438
|
||||
#define DIST_RODENT_LVL 2439
|
||||
|
||||
#define DIST_MX_DIST 2468
|
||||
#define DIST_MX_OUTPUT 2469
|
||||
|
||||
#define DIST_DS_GAIN 2440
|
||||
#define DIST_DS_TONE 2441
|
||||
#define DIST_DS_LVL 2442
|
||||
@@ -225,8 +251,10 @@ enum {
|
||||
AMP_TYPE_BOOGIE_MARK_IV = 371,
|
||||
AMP_TYPE_DUAL_RECTIFIER = 321,
|
||||
AMP_TYPE_TRIPLE_RECTIFIER = 370,
|
||||
AMP_TYPE_22_CALIBR = 386,
|
||||
AMP_TYPE_LEGACY_VL100 = 327,
|
||||
AMP_TYPE_MATCHLESS_HC30 = 326,
|
||||
AMP_TYPE_CHIEF = 385,
|
||||
AMP_TYPE_SOLDANO_100 = 325,
|
||||
AMP_TYPE_SUPERGROUP = 381,
|
||||
AMP_TYPE_GA40 = 380,
|
||||
@@ -282,6 +310,18 @@ enum {
|
||||
#define AMP_POSITION 8
|
||||
#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_LEVEL 2498
|
||||
#define AMP_BASS_FREQ 2499
|
||||
@@ -312,6 +352,7 @@ enum {
|
||||
AMP_CAB_TWIN = 576,
|
||||
AMP_CAB_BRITISH2_12 = 613,
|
||||
AMP_CAB_JAZZ2_12 = 626,
|
||||
AMP_CAB_JBL_215 = 627,
|
||||
AMP_CAB_BASSMAN = 579,
|
||||
AMP_CAB_BRITISH4_12 = 614,
|
||||
AMP_CAB_BRITISH_GREEN = 616,
|
||||
@@ -368,11 +409,13 @@ enum {
|
||||
#define EQ_TYPE 3202
|
||||
#define EQ_ON_OFF 3212
|
||||
#define EQ_POSITION 24
|
||||
#define EQ_POSITION_B 25
|
||||
|
||||
#define EQ_BASS 3203
|
||||
#define EQ_MID 3204
|
||||
#define EQ_MID_HZ 3206
|
||||
#define EQ_TREBLE 3205
|
||||
#define EQ_PRESENCE 3207
|
||||
#define EQ_TREBLE_HZ 3211
|
||||
#define EQ_LOW_LEVEL 3203
|
||||
#define EQ_MID_LEVEL 3204
|
||||
@@ -429,8 +472,11 @@ enum {
|
||||
CHORUS_TYPE_DUAL = 0x379,
|
||||
CHORUS_TYPE_GLISTEN = 0x392,
|
||||
CHORUS_TYPE_MULTI = 0x37a,
|
||||
CHORUS_TYPE_VOO_DOO = 0x396,
|
||||
CHORUS_TYPE_CLONE = 0x397,
|
||||
CHORUS_TYPE_FLANGER = 0x37d,
|
||||
CHORUS_TYPE_TRIGGERED_FLANGER = 0x37e,
|
||||
CHORUS_TYPE_FLTFLANGER = 0x398,
|
||||
CHORUS_TYPE_MXR_FLANGER = 0x37f,
|
||||
CHORUS_TYPE_EH_FLANGER = 0x380,
|
||||
CHORUS_TYPE_AD_FLANGER = 0x393,
|
||||
@@ -463,7 +509,10 @@ enum {
|
||||
|
||||
#define CHORUSFX_TYPE 768
|
||||
#define CHORUSFX_ON_OFF 769
|
||||
#define CHORUSFX_PRE_POST 770
|
||||
#define CHORUSFX_POSITION 14
|
||||
#define CHORUSFX_PRE 1543
|
||||
#define CHORUSFX_POST 1544
|
||||
|
||||
#define CHORUS_SPEED 837
|
||||
#define CHORUS_DEPTH 838
|
||||
@@ -476,6 +525,8 @@ enum {
|
||||
#define CHORUS_WAVE 840
|
||||
#define CHORUS_BALANCE 841
|
||||
|
||||
#define CHORUS_RATE 850
|
||||
|
||||
#define FLANGER_SPEED 902
|
||||
#define FLANGER_DEPTH 903
|
||||
#define FLANGER_REGEN 904
|
||||
@@ -489,6 +540,8 @@ enum {
|
||||
#define TRIG_FLANGER_MIX 1029
|
||||
#define TRIG_FLANGER_LEVEL 1032
|
||||
|
||||
#define FLTFLANGER_FREQ 922
|
||||
|
||||
#define MXR_FLANGER_WIDTH 914
|
||||
#define MXR_FLANGER_MANUAL 917
|
||||
|
||||
@@ -608,6 +661,8 @@ enum {
|
||||
DELAY_TYPE_MODULATED = 1047,
|
||||
DELAY_TYPE_PONG = 1048,
|
||||
DELAY_TYPE_TAPE = 1049,
|
||||
DELAY_TYPE_ECHOPLEX = 1050,
|
||||
DELAY_TYPE_DM = 1051,
|
||||
|
||||
DELAY_RP500_TYPE_DIGITAL = 1052,
|
||||
DELAY_RP500_TYPE_ANALOG = 1053,
|
||||
@@ -618,6 +673,9 @@ enum {
|
||||
DELAY_RP500_TYPE_REVERSE = 1064,
|
||||
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_PINGPONG = 1028,
|
||||
DELAY_GNX3K_TYPE_ANALOG = 1029,
|
||||
@@ -631,6 +689,13 @@ enum {
|
||||
|
||||
#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_FLUTTER 1892
|
||||
|
||||
@@ -640,8 +705,10 @@ enum {
|
||||
#define DELAY_DUCK_THRESH 1889
|
||||
#define DELAY_DUCK_LEVEL 1890
|
||||
#define DELAY_REPEAT_RATE 1898
|
||||
#define DELAY_REPEAT_RATE_DM 1894
|
||||
#define DELAY_ECHO 1895
|
||||
#define DELAY_INTENSITY 1896
|
||||
#define DELAY_ECHOPLEX_TIME 1897
|
||||
#define DELAY_TIME_0_760 1899
|
||||
#define DELAY_VOLUME 1893
|
||||
#define DELAY_REPEATS_0_99 1874
|
||||
@@ -649,6 +716,7 @@ enum {
|
||||
#define DELAY_TAP_TIME_0_4990 1900
|
||||
#define DELAY_MIX 1902
|
||||
#define DELAY_TIME_0_4650 1901
|
||||
#define DELAY_TAP_RATIO 1905
|
||||
|
||||
#define GNX3K_DELAY_TIME 1862
|
||||
#define GNX3K_DELAY_FEEDBACK 1863
|
||||
@@ -693,6 +761,9 @@ enum {
|
||||
|
||||
#define EXP_MIN 8195
|
||||
#define EXP_MAX 8196
|
||||
#define LFO_TYPE 8258
|
||||
#define LFO1_POSITION 22
|
||||
#define LFO2_POSITION 23
|
||||
|
||||
#define LIBRARY_TONE 8704
|
||||
#define LIBRARY_EFFECTS 8705
|
||||
@@ -865,25 +936,72 @@ 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);
|
||||
GStrv query_preset_names(gchar bank);
|
||||
void message_list_free(GList *list);
|
||||
GList *get_current_preset();
|
||||
void preset_list_free(GList *list);
|
||||
|
||||
#endif /* GDIGI_H */
|
||||
|
||||
289
gui.c
289
gui.c
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
#include "effects.h"
|
||||
@@ -56,6 +57,169 @@ void show_error_message(GtkWidget *parent, gchar *message)
|
||||
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 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);
|
||||
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();
|
||||
Preset *preset = create_preset_from_data(list);
|
||||
preset_list_free(list);
|
||||
message_list_free(list);
|
||||
apply_preset_to_gui(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);
|
||||
|
||||
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);
|
||||
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 */
|
||||
MAX((settings[x].values->max / 100), 5.0), /* page increment */
|
||||
MAX((max / 100), 5.0), /* page increment */
|
||||
0.0);
|
||||
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);
|
||||
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), TRUE);
|
||||
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(widget), FALSE);
|
||||
gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(widget), GTK_UPDATE_IF_VALID);
|
||||
} else {
|
||||
widget = gtk_label_new(settings[x].values->labels[0]);
|
||||
g_object_set_data(G_OBJECT(adj), "label", widget);
|
||||
if (custom == TRUE) {
|
||||
g_signal_connect(G_OBJECT(widget), "input", G_CALLBACK(custom_value_input_cb), settings[x].values);
|
||||
g_signal_connect(G_OBJECT(widget), "output", G_CALLBACK(custom_value_output_cb), settings[x].values);
|
||||
}
|
||||
|
||||
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);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1);
|
||||
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);
|
||||
@@ -700,7 +858,12 @@ typedef struct {
|
||||
|
||||
static SupportedFileTypes file_types[] = {
|
||||
{"RP250Preset", "*.rp250p"},
|
||||
{"RP255Preset", "*.rp255p"},
|
||||
{"RP355Preset", "*.rp355p"},
|
||||
{"RP500Preset", "*.rp500p"},
|
||||
{"RP1000Preset", "*.rp1000p"},
|
||||
{"GNX4 Preset", "*.g4p"},
|
||||
{"GNX3kPreset", "*.g3kp"},
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
110
preset.c
110
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) {
|
||||
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,6 +120,7 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
ad->preset->name = g_strndup(text, len);
|
||||
}
|
||||
|
||||
if (ad->section == SECTION_PARAMS) {
|
||||
if (ad->preset->params == NULL)
|
||||
return;
|
||||
|
||||
@@ -110,6 +143,64 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
GFile *file;
|
||||
GError *err = NULL;
|
||||
gchar *contents;
|
||||
|
||||
file = g_file_new_for_path(filename);
|
||||
if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) {
|
||||
g_message("Failed to get %s contents: %s", filename, err->message);
|
||||
*error = g_error_copy(err);
|
||||
g_error_free(err);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -142,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;
|
||||
@@ -157,18 +246,17 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error)
|
||||
preset_free(ad->preset);
|
||||
g_slice_free(AppData, ad);
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return preset;
|
||||
}
|
||||
|
||||
@@ -192,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)) {
|
||||
@@ -254,7 +343,14 @@ void preset_free(Preset *preset)
|
||||
g_list_free(preset->params);
|
||||
}
|
||||
|
||||
if (preset->name != NULL)
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user