51 Commits
0.1.3 ... 0.1.7

Author SHA1 Message Date
Tomasz Moń
29124043ba add RP500 distortion settings 2009-04-14 23:23:41 +02:00
Tomasz Moń
e93e6bd16b add compability mode dialog 2009-04-14 21:00:10 +02:00
Tomasz Moń
f7ddd5e0d6 add RP500 chorusfx settings 2009-04-14 18:22:32 +02:00
Tomasz Moń
6a082acc53 add RP500 delay settings 2009-04-13 11:42:15 +02:00
Tomasz Moń
1abcc82829 add RP500 equalizer settings 2009-04-12 20:55:17 +02:00
Tomasz Moń
c964d38c17 add RP500 compressor and amp settings 2009-04-12 18:36:41 +02:00
Tomasz Moń
12c2ccc87f Use single header includes 2009-04-11 22:32:21 +02:00
Tomasz Moń
a6d07fd802 disconnect adjustment signals on gtk_knob_destroy 2009-04-10 14:23:23 +02:00
Tomasz Moń
215683b167 actually g_type_class_peek_parent makes more sense 2009-04-10 13:32:03 +02:00
Tomasz Moń
741482afd4 Added tag 0.1.6 for changeset 80e56807413b 2009-03-26 15:21:18 +01:00
Tomasz Moń
991527418a Don't use deprecated functions in GtkKnob; optipng knob.png 2009-03-24 22:21:01 +01:00
Tomasz Moń
96317d5ac5 actually 'is it connected' doesn't make sense here 2009-03-17 15:36:16 +01:00
Tomasz Moń
d24cc97f5d add error reporting to create_preset_from_xml_file 2009-03-17 12:54:46 +01:00
Tomasz Moń
cac7e74d71 display preset number in preset list 2009-03-15 20:12:58 +01:00
Tomasz Moń
74583e9a7c make GUI more compact 2009-03-15 20:06:18 +01:00
Tomasz Moń
03c3c48ecf remove reduntant text 2009-03-15 18:52:14 +01:00
Tomasz Moń
aa2cc7bbb1 some Doxygen work 2009-03-14 18:51:08 +01:00
Tomasz Moń
ec14a41869 Added tag 0.1.5 for changeset 45f897c02e72 2009-03-14 14:27:12 +01:00
Tomasz Moń
9778dc47c3 add comments 2009-03-14 14:23:18 +01:00
Tomasz Moń
71c3a1e66f use g_slice 2009-03-14 12:58:11 +01:00
Tomasz Moń
bdb35ddf54 finish modifier_linkable_list(), add modifier_group_free() 2009-03-14 12:39:45 +01:00
Tomasz Moń
4ca140ab48 rename get_modifier_label to get_modifier 2009-03-14 10:31:40 +01:00
Tomasz Moń
d2f821eee1 add EffectValues to Modifiers 2009-03-14 10:24:58 +01:00
Tomasz Moń
e607c6cf37 move modifier_linkable_list to effects.c 2009-03-14 10:07:00 +01:00
Tomasz Moń
dc66db841a introduce get_message_by_id 2009-03-14 10:04:56 +01:00
Tomasz Moń
e80683aea2 add cabinet models 2009-03-14 08:38:28 +01:00
Tomasz Moń
b7d2d7d1c5 introduce EffectValues 2009-03-13 22:42:46 +01:00
Tomasz Moń
cd5d7387f3 remove obsolete function 2009-03-13 20:33:24 +01:00
Tomasz Moń
8a39a178c6 add tone library and effects library 2009-03-13 19:46:02 +01:00
Tomasz Moń
40ebcfaf16 make modifiers[] complete 2009-03-13 18:00:41 +01:00
Tomasz Moń
de68d0449f some renames, no functional changes 2009-03-10 20:57:34 +01:00
Tomasz Moń
d280bf1ca6 add some comments 2009-03-10 19:45:16 +01:00
Tomasz Moń
b245e1bac6 add gtk_knob_key_press 2009-03-09 22:51:38 +01:00
Tomasz Moń
8d7fffb6d1 atan2f requires C99 2009-03-09 20:58:03 +01:00
Tomasz Moń
f8e35ff685 let GtkKnob grab focus 2009-03-09 19:57:13 +01:00
Tomasz Moń
3f717a51cd add gui_free 2009-03-09 18:49:29 +01:00
Tomasz Moń
90df427200 add knobs 2009-03-09 18:22:20 +01:00
Tomasz Moń
322c59032e tweak GtkKnob a bit 2009-03-08 13:46:14 +01:00
Tomasz Moń
1b1919649e add GtkKnob from phasex-0.11.1 2009-03-08 13:31:43 +01:00
Tomasz Moń
e7c7efe857 expression pedal settings work-in-progress 2009-03-08 13:25:37 +01:00
Tomasz Moń
17b067f853 don't crash if query preset names fail 2009-03-04 19:00:32 +01:00
Tomasz Moń
8ec3d6579c change query_preset_names 2009-03-04 18:26:22 +01:00
Tomasz Moń
5bd6f8fc2c Added tag 0.1.4 for changeset 78367821f4f4 2009-03-04 08:14:21 +01:00
Tomasz Moń
c61c2372ae cleaning 2009-03-03 23:06:03 +01:00
Tomasz Moń
49b7f42012 compile with -ansi 2009-03-03 22:39:55 +01:00
Tomasz Moń
157fba0380 make set_option wrapper to send_message 2009-03-03 22:31:25 +01:00
Tomasz Moń
904a30bb38 propertly apply xml patch 2009-03-03 21:57:47 +01:00
Tomasz Moń
8e445bb408 update gui on preset switch 2009-03-03 13:42:15 +01:00
Tomasz Moń
eb48d0b9d2 add get_message_id stub 2009-03-03 11:46:28 +01:00
Tomasz Moń
baa3829263 start gui with proper values 2009-03-03 11:39:25 +01:00
Tomasz Moń
79554a99ce Added tag 0.1.3 for changeset 5cc97dba5d41 2009-03-01 20:24:06 +01:00
15 changed files with 3833 additions and 960 deletions

View File

@@ -1,5 +1,5 @@
CC = gcc
CFLAGS = `pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0` -Wall -g
CFLAGS = `pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0` -Wall -g -ansi -std=c99
OFLAG = -o
LIBS = `pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 alsa` -lexpat
@@ -9,8 +9,8 @@ LIBS = `pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 alsa` -lexpat
all: gdigi
gdigi: gdigi.o tests.o gui.o effects.o preset.o
$(CC) $(LIBS) $(OFLAG) gdigi gdigi.o tests.o gui.o effects.o preset.o
gdigi: knob.h gdigi.o tests.o gui.o effects.o preset.o gtkknob.o
$(CC) $(LIBS) $(OFLAG) gdigi gdigi.o tests.o gui.o effects.o preset.o gtkknob.o
gdigi.o: gdigi.c
@@ -22,6 +22,13 @@ effects.o: effects.c
preset.o: preset.c
gtkknob.o: gtkknob.c
gtkknob.o: gtkknob.c
knob.h:
gdk-pixbuf-csource --name=knob_pixbuf knob.png > $@
clean:
rm *.o

29
TODO
View File

@@ -1,26 +1,7 @@
-figure out all magic commands
-make complete gui
-cabinet models
-tone library
-effects library
-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)
-handling presets (saving, exporting to xml patches)
-buildsystem (install knob.png to share dir, don't use inline knob pixbuf)
-add expression pedal settings to gui
-read asynchronously from MIDI IN
-guess device port when user doesn't explicitly provide it (don't use hardcoded "hw:1,0,0")

1678
effects.c

File diff suppressed because it is too large Load Diff

View File

@@ -17,36 +17,59 @@
#ifndef GDIGI_EFFECTS_H
#define GDIGI_EFFECTS_H
#include <glib/gtypes.h>
#include <glib.h>
typedef struct {
char *label; /* Parameter name */
gdouble min; /* Parameter minumum value */
gdouble max; /* Parameter maximum value */
guint option; /* ID (to set parameter) */
guint position; /* position */
gdouble min; /**< Minumum value */
gdouble max; /**< Maximum value */
GStrv labels; /**< value labels */
} EffectValues;
typedef struct {
gchar *label; /**< Parameter name */
guint id; /**< ID (to set parameter) */
guint position; /**< position */
EffectValues *values; /**< valid parameter values */
} EffectSettings;
typedef struct {
guint id; /* value (type) */
gchar *label; /* Effect name */
guint option; /* ID (to set effect type) */
guint position; /* position */
EffectSettings *settings; /* possible parameters */
gint settings_amt; /* possible parameters length */
guint type; /**< value (type) */
gchar *label; /**< Effect name */
guint id; /**< ID (to set effect type) */
guint position; /**< position */
EffectSettings *settings; /**< possible parameters */
gint settings_amt; /**< possible parameters length */
} EffectGroup;
typedef struct {
char *label; /* Base effect name */
guint option; /* ID (to set effect on/off) */
guint position; /* position */
EffectGroup *group; /* possible effect types */
gint group_amt; /* possible effect types length */
gchar *label; /**< Group label */
guint id; /**< ID to set effect on/off, or if it isn't on/off group then -1 */
guint position; /**< position */
EffectGroup *group; /**< possible effect types */
gint group_amt; /**< possible effect types length */
} Effect;
typedef struct {
Effect *effect; /* list of supported effects */
gint amt; /* list of supported effects length */
gchar *label; /**< base effect name */
Effect *effect; /**< list of supported effects */
gint amt; /**< list of supported effects length */
} EffectList;
typedef struct {
EffectGroup *group;
gint group_amt;
} ModifierGroup;
typedef struct {
gchar *name;
EffectList *list;
int n_list;
} SupportedDevices;
ModifierGroup *modifier_linkable_list();
void modifier_group_free(ModifierGroup *modifier_group);
gboolean get_effect_list(unsigned char device_id, unsigned char family_id,
unsigned char product_id,
EffectList **list, int *n_list);
#endif /* GDIGI_EFFECTS_H */

631
gdigi.c
View File

@@ -22,35 +22,39 @@
#include "gdigi.h"
#include "gui.h"
static unsigned char device_id = 0x7F;
static unsigned char family_id = 0x7F;
static unsigned char product_id = 0x7F;
static snd_rawmidi_t *output = NULL;
static snd_rawmidi_t *input = NULL;
static char *device = "hw:1,0,0";
/*
calculate checksum
array - the command to set over usb
length - length of array
check - position of checksum byte in array
*/
char calculate_checksum(gchar *array, int length, int check)
/**
* \param array data to calculate checksum
* \param length data length
*
* Calculates message checksum.
*
* \return calculated checksum.
**/
static char calculate_checksum(gchar *array, gint length)
{
int x;
char checksum;
checksum = 0x07;
int checksum = 0;
for (x = 0; x<length; x++) {
if (x == check) continue;
checksum ^= array[x];
}
return checksum;
}
/*
opens MIDI device
Returns TRUE on error
*/
/**
* Opens MIDI device. This function modifies global input and output variables.
*
* \return FALSE on success, TRUE on error.
**/
gboolean open_device()
{
int err;
@@ -72,25 +76,110 @@ gboolean open_device()
return FALSE;
}
/**
* \param data data to be sent
* \param length data length
*
* Sends data to device. This function uses global output variable.
**/
void send_data(char *data, int length)
{
if (output == NULL)
open_device();
snd_rawmidi_write(output, data, length);
}
/*
reads data from MIDI IN
returns GString containing data
if no data was read it returns NULL
*/
/**
* \param data data to be packed
* \param len data length
*
* Packs data using method used on all newer DigiTech products.
*
* \return GString containing packed data
**/
GString *pack_data(gchar *data, gint len)
{
GString *packed;
gint i;
gint new_len;
unsigned char status;
gint offset;
gint status_byte;
new_len = len + (len/7);
packed = g_string_sized_new(new_len);
status = 0;
offset = -1;
status_byte = 0;
for (i=0; i<len; i++) {
if ((i % 7) == 0) {
packed->str[status_byte] = status;
status = 0;
status_byte = packed->len;
g_string_append_c(packed, '\0');
}
g_string_append_c(packed, (data[i] & 0x7F));
status |= (data[i] & 0x80) >> ((i%7) + 1);
}
packed->str[status_byte] = status;
return packed;
}
/**
* \param msg message to unpack
*
* Unpacks message data. This function modifies given GString.
**/
static void unpack_message(GString *msg)
{
int offset;
int x;
int i;
unsigned char status;
unsigned char *str;
gboolean stop = FALSE;
g_return_if_fail(msg != NULL);
g_return_if_fail(msg->len > 9);
offset = 1;
x = 0;
i = 8;
str = (unsigned char*)msg->str;
do {
offset += 8;
status = str[offset-1];
for (x=0; x<7; x++) {
if (offset+x >= msg->len) {
stop = TRUE;
break;
}
if (str[offset+x] == 0xF7) {
str[i] = 0xF7;
stop = TRUE;
}
str[i] = (((status << (x+1)) & 0x80) | str[x+offset]);
i++;
}
} while (!stop && (offset+x < msg->len));
g_string_truncate(msg, i);
}
/**
* Reads data from MIDI IN. This function uses global input variable.
*
* \return GString containing data, or NULL when no data was read.
**/
GString* read_data()
{
/* This is mostly taken straight from alsa-utils-1.0.19 amidi/amidi.c
by Clemens Ladisch <clemens@ladisch.de> */
int err;
int npfds;
gboolean stop = FALSE;
struct pollfd *pfds;
GString *string = NULL;
@@ -118,6 +207,7 @@ GString* read_data()
break;
if (!(revents & POLLIN))
continue;
err = snd_rawmidi_read(input, buf, sizeof(buf));
if (err == -EAGAIN)
continue;
@@ -125,11 +215,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
if (buf[i] != 0xFE) /* ignore active sensing */
buf[length++] = buf[i];
if ((unsigned char)buf[length-1] == 0xF7)
stop = TRUE;
if (length != 0) {
if (string == NULL) {
string = g_string_new_len(buf, length);
@@ -137,171 +231,195 @@ GString* read_data()
string = g_string_append_len(string, buf, length);
}
}
} while (err != 0);
} while ((err != 0) && (stop == FALSE));
return string;
return string;
}
/*
id - ID as found in preset file
position - Position as found in preset file
value - Value as found in preset file
*/
/**
* \param procedure procedure ID
* \param data unpacked message data
* \param len data length
*
* Creates SysEx message then sends it. This function uses folowing global variables: device_id, family_id and product_id.
**/
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) {
GString *tmp = pack_data(data, len);
g_string_append_len(msg, tmp->str, tmp->len);
g_string_free(tmp, TRUE);
}
g_string_append_printf(msg, "%c\xF7",
calculate_checksum(&msg->str[1], msg->len - 1));
send_data(msg->str, msg->len);
g_string_free(msg, TRUE);
}
/**
* \param msg SysEx message
*
* Checks message ID.
*
* \return MessageID, or -1 on error.
**/
static MessageID get_message_id(GString *msg)
{
/** \todo check if msg is valid SysEx message */
g_return_val_if_fail(msg != NULL, -1);
if (msg->len > 7) {
return (unsigned char)msg->str[7];
}
return -1;
}
/**
* \param id MessageID of requested message
*
* Reads data from MIDI IN until message with matching id is found.
*
* \return GString containing unpacked message.
**/
GString *get_message_by_id(MessageID id)
{
GString *data = NULL;
do {
if (data)
g_string_free(data, TRUE);
data = read_data();
} while (get_message_id(data) != id);
unpack_message(data);
return data;
}
/**
* \param msg message to append value
* \param value value to append
*
* Packs value using scheme used on all newer DigiTech products.
**/
void append_value(GString *msg, guint value)
{
/* check how many bytes long the value is */
guint temp = value;
gint n = 0;
do {
n++;
temp = temp >> 8;
} while (temp);
if (n == 1) {
if (value & 0x80)
n = 2;
else
g_string_append_printf(msg, "%c", value);
}
if (n > 1) {
gint x;
g_string_append_printf(msg, "%c", (n | 0x80));
for (x=0; x<n; x++) {
g_string_append_printf(msg, "%c",
((value >> (8*(n-x-1))) & 0xFF));
}
}
}
/**
* \param id Parameter ID
* \param position Parameter position
* \param value Parameter value
*
* Forms SysEx message to set parameter then sends it to device.
**/
void set_option(guint id, guint position, guint value)
{
static char option[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x41,
0x00, 0x00, 0x00, /* ID */
0x00, /* position */
0x00, /* value length (not necesarry) */
0x00, 0x00, 0x00, /* value (can be either 1, 2 or 3 bytes) */
0x00, /* checksum */ 0xF7};
option[8] = ((id & 0x80) >> 2);
option[9] = ((id & 0xFF00) >> 8);
option[10] = ((id & 0x007F));
option[11] = position;
if (value < 0x80) {
// [12] = value, [13] - checksum, [14] = 0xF7
option[12] = value;
option[14] = 0xF7;
option[13] = calculate_checksum(option, 15, 13);
send_data(option, 15);
} else if (value <= 0xFF) {
option[8] |= 0x08; // there'll be length before value
if (((value & 0x80) >> 7) == 1)
option[8] |= 0x04;
option[12] = 0x01;
// [13] = value, [14] - checksum, [15] = 0xF7
option[13] = (value & 0x007F);
option[15] = 0xF7;
option[14] = calculate_checksum(option, 16, 14);
send_data(option, 16);
} else if (value <= 0xFFFF) {
option[8] |= 0x08; // there'll be length before value
if (((value & 0x80) >> 7) == 1)
option[8] |= 0x02;
option[12] = 0x02;
option[13] = ((value & 0xFF00) >> 8);
option[14] = ((value & 0x007F));
option[16] = 0xF7;
option[15] = calculate_checksum(option, 17, 15);
send_data(option, 17);
} else if (value <= 0xFFFFFF) {
option[8] |= 0x08; // there'll be length before value
if (((value & 0x80) >> 7) == 1)
option[8] |= 0x01;
option[12] = 0x03;
option[13] = ((value & 0xFF0000) >> 16);
option[14] = ((value & 0x00FF00) >> 8);
option[15] = ((value & 0x00007F));
option[17] = 0xF7;
option[16] = calculate_checksum(option, 18, 16);
send_data(option, 18);
}
GString *msg = g_string_sized_new(9);
g_string_append_printf(msg, "%c%c%c",
((id & 0xFF00) >> 8), (id & 0xFF),
position);
append_value(msg, value);
send_message(RECEIVE_PARAMETER_VALUE, msg->str, msg->len);
g_string_free(msg, TRUE);
}
/* x = 0 to 60 */
/**
* \param bank preset bank
* \param x preset index
*
* Switches to selected preset.
**/
void switch_preset(guint bank, guint x)
{
static char switch_preset[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x39, 0x00, 0x00 /* bank */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
switch_preset[10] = bank;
switch_preset[11] = x;
switch_preset[16] = calculate_checksum(switch_preset, sizeof(switch_preset), 16);
send_data(switch_preset, sizeof(switch_preset));
}
/* level = 0 to 99 */
void set_preset_level(int level)
{
set_option(PRESET_LEVEL, PRESET_POSITION, level);
GString *msg = g_string_sized_new(6);
g_string_append_printf(msg, "%c%c%c%c%c%c",
bank, x, /* source */
PRESETS_EDIT_BUFFER, 0, /* destination */
0, /* keep existing name */
1); /* load */
send_message(MOVE_PRESET, msg->str, msg->len);
g_string_free(msg, TRUE);
}
/**
* \param x preset index
* \param name preset name
*
* Stores current edit buffer in user presets bank.
**/
void store_preset_name(int x, const gchar *name)
{
static char set_name[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5e, 0x02, 0x39, 0x00, 0x04, 0x00, 0x01, 0x00 /* preset number */, 0x00 /* name starts here */, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
set_name[12] = x;
int a;
int b;
b = 0;
for (a=0; (name != NULL && a<strlen(name)) && a<10 ; a++) {
if (a == 3) {
set_name[13+a] = 0x00;
b++;
}
set_name[13+a+b] = name[a];
}
if (a == 3) {
set_name[13+a+1+b] = 0x00;
a++;
} else
set_name[13+a+b] = 0x00;
set_name[13+a+1+b] = 0x00;
set_name[13+a+3+b] = 0xF7;
set_name[13+a+2+b] = calculate_checksum(set_name, 13+a+4+b, 13+a+2+b);
send_data(set_name, 14+a+3+b);
switch_preset(PRESETS_USER, x);
GString *msg = g_string_sized_new(6);
g_string_append_printf(msg, "%c%c%c%c%s%c%c",
PRESETS_EDIT_BUFFER, 0, /* source */
PRESETS_USER, x, /* destination */
name, 0, /* name */
1); /* load */
send_message(MOVE_PRESET, msg->str, msg->len);
g_string_free(msg, TRUE);
}
/* x = 0 to 59 (preset number) */
/**
* \param x preset index
* \param name preset name
*
* Sets preset name.
**/
void set_preset_name(int x, gchar *name)
{
static char set_name[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x29, 0x00, 0x01, 0x00 /* preset no */, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
set_name[11] = x;
int a;
int b;
b = 0;
for (a=0; (name != NULL && a<strlen(name)) && a<10 ; a++) {
if (a == 5) {
set_name[12+a] = 0x00;
b++;
}
set_name[12+a+b] = name[a];
}
if (a == 5)
a = 4;
else
set_name[12+a+b] = 0x00;
set_name[12+a+2+b] = 0xF7;
set_name[12+a+1+b] = calculate_checksum(set_name, 12+a+3+b, 12+a+1+b);
send_data(set_name, 13+a+3+b);
GString *msg = g_string_sized_new(12);
g_string_append_printf(msg, "%c%c%s%c",
PRESETS_USER, /* preset bank */
x, /* preset index */
name, 0); /* name */
send_message(RECEIVE_PRESET_NAME, msg->str, msg->len);
g_string_free(msg, TRUE);
}
/*
Queries user preset names
Valid bank values are PRESETS_SYSTEM and PRESETS_USER
Returns GStrv which must be freed with g_strfreev
Returns NULL on error
*/
GStrv query_preset_names(guint bank)
/**
* \param bank preset bank
*
* Queries preset names.
*
* \return GStrv which must be freed with g_strfreev, or NULL on error.
**/
GStrv query_preset_names(gchar bank)
{
GString *data = NULL;
int x; /* used to iterate over whole reply */
@@ -309,70 +427,123 @@ GStrv query_preset_names(guint bank)
int n_total; /* total number of presets */
gchar **str_array = NULL;
/* clear MIDI IN buffer */
data = read_data();
if (data != NULL)
g_string_free(data, TRUE);
/* query user preset names */
char command[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x21, 0x00, 0x00 /* bank */, 0x00 /* checksum */, 0xF7};
command[9] = bank;
command[10] = calculate_checksum(command, sizeof(command), 10);
send_data(command, sizeof(command));
send_message(REQUEST_PRESET_NAMES, &bank, 1);
/* read reply */
data = read_data();
data = get_message_by_id(RECEIVE_PRESET_NAMES);
if (data != NULL) {
char preset_reply_magic[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x22, 0x00, 0x01};
if (strncmp(data->str, preset_reply_magic, sizeof(preset_reply_magic)) == 0) {
char buf[10]; /* temporary, used to read single preset name */
int b = 0; /* used to iterate over buf */
if (data->len >= 10) {
n_total = data->str[9];
str_array = g_new(gchar*, n_total + 1);
str_array[n_total] = NULL;
}
if (data->len >= 10) {
n_total = data->str[10];
str_array = g_new(gchar*, n_total + 1);
str_array[n_total] = NULL;
}
for (x=10; ((x<data->len) && (n<n_total)); x++) {
if (data->str[x] == 0xF7) /* every message ends with 0xF7 */
break;
for (x=11; ((x<data->len) && (n<n_total)); x++) {
if ((x % 8) == 0) // every 8th byte is 0x00
continue;
if (data->str[x] == 0xF7) // every message ends with 0xF7
break;
if (data->str[x] == 0) { // presets are splitted with 0x00
gchar *name;
name = g_new(gchar, b+1);
strncpy(name, buf, b);
name[b] = 0;
if (n < n_total)
str_array[n] = name;
b = 0;
n++;
} else {
if (b < 10) {
buf[b] = data->str[x];
b++;
} else {
g_message("Preset name seems to be longer than 10 chars!");
}
}
}
str_array[n] = g_strdup(&data->str[x]);
x += strlen(str_array[n]);
n++;
}
g_string_free(data, TRUE);
}
return str_array;
}
/**
* Queries current edit buffer.
*
* \return GString containing RECEIVE_PRESET_PARAMETERS SysEx message.
**/
GString *get_current_preset()
{
GString *data = NULL;
send_message(REQUEST_PRESET, "\x04\x00", 3);
/* read reply */
data = get_message_by_id(RECEIVE_PRESET_PARAMETERS);
return data;
}
/**
* \param device_id Variable to hold device ID
* \param family_id Variable to hold family ID
* \param product_id Variable to hold product ID
*
* Requests device information.
*
* \return TRUE on success, FALSE on error.
**/
static gboolean request_who_am_i(unsigned char *device_id, unsigned char *family_id,
unsigned 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 void request_device_configuration()
{
gint os_major, os_minor;
gint cpu_major, cpu_minor;
gint protocol_version;
gint current_bank, current_preset;
gint media_card;
send_message(REQUEST_DEVICE_CONFIGURATION, NULL, 0);
GString *data = get_message_by_id(RECEIVE_DEVICE_CONFIGURATION);
if (data->len > 14) {
os_major = data->str[8];
os_minor = (((data->str[9] & 0xF0) >> 4) * 10) |
(data->str[9] & 0x0F);
g_message("OS version: %d.%d", os_major, os_minor);
cpu_major = data->str[10];
cpu_minor = data->str[11];
g_message("CPU version: %d.%d", cpu_major, cpu_minor);
protocol_version = data->str[12];
g_message("Protocol version: %d", protocol_version);
current_bank = data->str[13];
current_preset = data->str[14];
g_message("Active bank: %d", current_bank);
g_message("Active preset: %d", current_preset);
if (os_major >= 1) {
media_card = data->str[15];
g_message("Media card present: %d", media_card);
}
}
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static GOptionEntry options[] = {
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
{NULL}
};
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
int main(int argc, char *argv[]) {
GError *error = NULL;
GOptionContext *context;
@@ -390,16 +561,26 @@ 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 {
create_window();
gtk_main();
if (request_who_am_i(&device_id, &family_id, &product_id) == FALSE) {
show_error_message(NULL, "No suitable reply from device");
} else {
EffectList *list = NULL;
int n_list = -1;
if (get_effect_list(device_id, family_id, product_id, &list, &n_list) == FALSE) {
if (unsupported_device_dialog(&list, &n_list) == FALSE) {
g_message("Shutting down");
}
}
if (list != NULL && n_list != -1) {
gui_create(list, n_list);
gtk_main();
gui_free();
}
}
}
if (output != NULL)

401
gdigi.h
View File

@@ -20,6 +20,8 @@
#include <glib.h>
#include <glib-object.h>
#ifndef DOXYGEN_SHOULD_SKIP_THIS
enum {
WAH_TYPE_CRY = 132,
WAH_TYPE_FULLRANGE = 133,
@@ -39,7 +41,8 @@ enum {
enum {
COMP_TYPE_DIGI = 195,
COMP_TYPE_CS = 196
COMP_TYPE_CS = 196,
COMP_TYPE_DYNA = 197
};
#define COMP_TYPE 207
@@ -50,6 +53,8 @@ enum {
#define COMP_TONE 209
#define COMP_ATTACK 211
#define COMP_LEVEL 210
#define COMP_SENSITIVITY 213
#define COMP_OUTPUT 212
enum {
PICKUP_TYPE_HB_SC = 66,
@@ -63,8 +68,10 @@ enum {
enum {
DIST_TYPE_SCREAMER = 1280,
DIST_TYPE_808 = 1292,
DIST_TYPE_SPARKDRIVE = 1286,
DIST_TYPE_GUYOD = 1285,
DIST_TYPE_DOD250 = 1283,
DIST_TYPE_REDLINE = 1297,
DIST_TYPE_RODENT = 1281,
DIST_TYPE_MX = 1291,
DIST_TYPE_DS = 1282,
@@ -72,6 +79,9 @@ enum {
DIST_TYPE_ZONE = 1289,
DIST_TYPE_DEATH = 1294,
DIST_TYPE_GONK = 1293,
DIST_TYPE_8TAVIA = 1290,
DIST_TYPE_FUZZLATOR = 1295,
DIST_TYPE_CLASSIC_FUZZ = 1296,
DIST_TYPE_FUZZY = 1288,
DIST_TYPE_MP = 1284
};
@@ -83,41 +93,74 @@ enum {
#define DIST_SCREAMER_DRIVE 2434
#define DIST_SCREAMER_TONE 2435
#define DIST_SCREAMER_LVL 2436
#define DIST_808_OVERDRIVE 2473
#define DIST_808_TONE 2474
#define DIST_808_LVL 2475
#define DIST_SPARKDRIVE_GAIN 2450
#define DIST_SPARKDRIVE_TONE 2451
#define DIST_SPARKDRIVE_CLEAN 2452
#define DIST_SPARKDRIVE_VOLUME 2453
#define DIST_GUYOD_DRIVE 2448
#define DIST_GUYOD_LVL 2449
#define DIST_DOD250_GAIN 2443
#define DIST_DOD250_LVL 2444
#define DIST_REDLINE_GAIN 2488
#define DIST_REDLINE_LOW 2489
#define DIST_REDLINE_HIGH 2490
#define DIST_REDLINE_LEVEL 2491
#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
#define DIST_GRUNGE_GRUNGE 2454
#define DIST_GRUNGE_FACE 2456
#define DIST_GRUNGE_LOUD 2457
#define DIST_GRUNGE_BUTT 2455
#define DIST_ZONE_GAIN 2460
#define DIST_ZONE_LOW 2463
#define DIST_ZONE_MID_LVL 2462
#define DIST_ZONE_MID_FREQ 2461
#define DIST_ZONE_HIGH 2464
#define DIST_ZONE_LEVEL 2465
#define DIST_DEATH_LOW 2477
#define DIST_DEATH_MID 2476
#define DIST_DEATH_HIGH 2479
#define DIST_DEATH_LVL 2478
#define DIST_GONK_GONK 2480
#define DIST_GONK_SMEAR 2471
#define DIST_GONK_SUCK 2470
#define DIST_GONK_HEAVE 2472
#define DIST_8TAVIA_DRIVE 2466
#define DIST_8TAVIA_VOLUME 2467
#define DIST_FUZZLATOR_FUZZ 2481
#define DIST_FUZZLATOR_TONE 2482
#define DIST_FUZZLATOR_LOOSETIGHT 2483
#define DIST_FUZZLATOR_VOLUME 2484
#define DIST_CLASSIC_FUZZ_FUZZ 2485
#define DIST_CLASSIC_FUZZ_TONE 2486
#define DIST_CLASSIC_FUZZ_VOLUME 2487
#define DIST_FUZZY_FUZZ 2458
#define DIST_FUZZY_VOLUME 2459
#define DIST_MP_SUSTAIN 2445
#define DIST_MP_TONE 2446
#define DIST_MP_VOLUME 2447
@@ -129,24 +172,55 @@ enum {
AMP_TYPE_TWEED_CHAMP = 307,
AMP_TYPE_TWEED_DELUXE = 308,
AMP_TYPE_TWEED_BASSMAN = 309,
AMP_TYPE_BROWN_BASSMAN = 310,
AMP_TYPE_BLACKFACE_TWIN = 311,
AMP_TYPE_BLACKFACE_DELUXE = 312,
AMP_TYPE_PLEXI_JTM_45 = 313,
AMP_TYPE_SUPER_LEAD_PLEXI = 314,
AMP_TYPE_PLEXI_JUMP_PANEL = 315,
AMP_TYPE_MASTER_VOLUME = 316,
AMP_TYPE_JCM800 = 317,
AMP_TYPE_JCM900 = 318,
AMP_TYPE_JCM2000 = 319,
AMP_TYPE_AC15 = 322,
AMP_TYPE_AC30TB = 323,
AMP_TYPE_HIWATT_100 = 324,
AMP_TYPE_BOOGIE_MARK_II = 320,
AMP_TYPE_BOOGIE_MARK_IV = 371,
AMP_TYPE_DUAL_RECTIFIER = 321,
AMP_TYPE_TRIPLE_RECTIFIER = 370,
AMP_TYPE_LEGACY_VL100 = 327,
AMP_TYPE_MATCHLESS_HC30 = 326,
AMP_TYPE_SOLDANO_100 = 325,
AMP_TYPE_SUPERGROUP = 381,
AMP_TYPE_GA40 = 380,
AMP_TYPE_OR120 = 372,
AMP_TYPE_PV5150II = 373,
AMP_TYPE_RG100 = 374,
AMP_TYPE_JC120_JAZZ = 375,
AMP_TYPE_SOLAR100 = 376,
AMP_TYPE_SOLO = 331,
AMP_TYPE_METAL = 332,
AMP_TYPE_BRIGHT = 333,
AMP_TYPE_CHUNK = 334,
AMP_TYPE_CLEAN = 335,
AMP_TYPE_HIGH_GAIN = 337,
AMP_TYPE_BLUES = 338,
AMP_TYPE_FUZZ = 339,
AMP_TYPE_SPANK = 330,
AMP_TYPE_GSP2101_CLEAN_TUBE = 328,
AMP_TYPE_GSP2101_SAT_TUBE = 329,
AMP_TYPE_CRUNCH = 336,
AMP_TYPE_MONSTER = 377,
AMP_TYPE_TWEEDFACE = 378,
AMP_TYPE_BLACKBASS = 379,
AMP_TYPE_STONER_ROCK = 368,
AMP_TYPE_DARK_METAL = 369,
AMP_TYPE_TRANSISTOR = 382,
AMP_TYPE_BROWN_SOUND = 383,
AMP_TYPE_MOSH = 384,
AMP_TYPE_ACOUSTIC = 341,
AMP_TYPE_JUMBO_ACOUSTIC = 340,
AMP_TYPE_DIRECT = 306
};
@@ -163,6 +237,40 @@ enum {
#define AMP_GAIN 2497
#define AMP_LEVEL 2498
#define AMP_BASS 2507
#define AMP_MID 2508
#define AMP_TREBLE 2509
#define AMP_CAB_TYPE 2560
#define AMP_CAB_POSITION 9
/* valid AMP_CAB_TYPE values */
#define AMP_CAB_DIRECT 570
#define AMP_CAB_CHAMP 571
#define AMP_CAB_DELUXE 572
#define AMP_CAB_DELUXE_REVERB 573
#define AMP_CAB_BRITISH1_12 623
#define AMP_CAB_GA1_12 624
#define AMP_CAB_BLONDE2_12 577
#define AMP_CAB_TWIN 576
#define AMP_CAB_BRITISH2_12 613
#define AMP_CAB_JAZZ2_12 626
#define AMP_CAB_BASSMAN 579
#define AMP_CAB_BRITISH4_12 614
#define AMP_CAB_BRITISH_GREEN 616
#define AMP_CAB_FANE4_12 584
#define AMP_CAB_BOUTIQUE4_12 583
#define AMP_CAB_VINTAGE 622
#define AMP_CAB_RECTO4_12 625
#define AMP_CAB_DIGI_SOLO 609
#define AMP_CAB_DIGI_BRIGHT 611
#define AMP_CAB_DIGI_METAL 618
#define AMP_CAB_DIGI_ROCK 619
#define AMP_CAB_DIGI_ALT 620
#define AMP_CAB_DIGI_VNTG 621
#define AMP_CAB_DIGI_CHUNK 612
#define AMP_CAB_DIGI_SPANK2_12 608
#define AMP_CAB_DIGI_SPKR_COMP 585
#define EQ_TYPE 3202
#define EQ_ON_OFF 3212
@@ -173,6 +281,15 @@ enum {
#define EQ_MID_HZ 3206
#define EQ_TREBLE 3205
#define EQ_TREBLE_HZ 3211
#define EQ_LOW_LEVEL 3203
#define EQ_MID_LEVEL 3204
#define EQ_HIGH_LEVEL 3205
#define EQ_LOW_FREQ 3213
#define EQ_MID_FREQ 3214
#define EQ_HIGH_FREQ 3215
#define EQ_LOW_BANDWIDTH 3216
#define EQ_MID_BANDWIDTH 3217
#define EQ_HIGH_BANDWIDTH 3218
enum {
NOISEGATE_GATE = 768,
@@ -194,24 +311,40 @@ enum {
enum {
CHORUS_TYPE_CE = 0x37B,
CHORUS_TYPE_TC = 0x37C,
CHORUS_TYPE_DUAL = 0x379,
CHORUS_TYPE_GLISTEN = 0x392,
CHORUS_TYPE_MULTI = 0x37a,
CHORUS_TYPE_FLANGER = 0x37d,
CHORUS_TYPE_TRIGGERED_FLANGER = 0x37e,
CHORUS_TYPE_MXR_FLANGER = 0x37f,
CHORUS_TYPE_EH_FLANGER = 0x380,
CHORUS_TYPE_AD_FLANGER = 0x393,
CHORUS_TYPE_PHASER = 0x381,
CHORUS_TYPE_TRIGGERED_PHASER = 0x382,
CHORUS_TYPE_MX_PHASER = 0x383,
CHORUS_TYPE_EH_PHASER = 0x384,
CHORUS_TYPE_VIBRATO = 0x360,
CHORUS_TYPE_ROTARY = 0x361,
CHORUS_TYPE_VIBROPAN = 0x38f,
CHORUS_TYPE_UNOVIBE = 0x390,
CHORUS_TYPE_TREMOLO = 0x35e,
CHORUS_TYPE_SCATTER_TREM = 0x394,
CHORUS_TYPE_OPTO_TREMOLO = 0x388,
CHORUS_TYPE_BIAS_TREMOLO = 0x389,
CHORUS_TYPE_PANNER = 0x35f,
CHORUS_TYPE_ENVELOPE = 0x38a,
CHORUS_TYPE_FX25 = 0x38e,
CHORUS_TYPE_AUTOYA = 0x38b,
CHORUS_TYPE_YAYA = 0x38c,
CHORUS_TYPE_SYNTH_TALK = 0x391,
CHORUS_TYPE_STEP_FILTER = 0x38d,
CHORUS_TYPE_SAMPLE_HOLD = 0x395,
CHORUS_TYPE_WHAMMY = 0x540,
CHORUS_TYPE_PITCH_SHIFT = 0x543,
CHORUS_TYPE_DETUNE = 0x542,
CHORUS_TYPE_IPS = 0x541
CHORUS_TYPE_IPS = 0x541,
CHORUS_TYPE_OCTAVER = 0x385,
};
#define CHORUSFX_TYPE 768
@@ -221,6 +354,9 @@ enum {
#define CE_CHORUS_SPEED 837
#define CE_CHORUS_DEPTH 838
#define CHORUS_WIDTH 848
#define CHORUS_INTENSITY 849
#define DUAL_CHORUS_SPEED 837
#define DUAL_CHORUS_DEPTH 838
#define DUAL_CHORUS_LEVEL 836
@@ -237,17 +373,39 @@ enum {
#define FLANGER_LEVEL 901
#define FLANGER_WAVE 905
#define TRIG_FLANGER_SPEED 1030
#define TRIG_FLANGER_SENS 1031
#define TRIG_FLANGER_LFO_START 1028
#define TRIG_FLANGER_LEVEL 1032
#define MXR_FLANGER_SPEED 902
#define MXR_FLANGER_WIDTH 914
#define MXR_FLANGER_REGEN 904
#define MXR_FLANGER_MANUAL 917
#define EH_FLANGER_RATE 918
#define EH_FLANGER_RANGE 919
#define EH_FLANGER_COLOR 916
#define AD_FLANGER_ENHANCE 920
#define AD_FLANGER_HARMONICS 921
#define PHASER_SPEED 962
#define PHASER_DEPTH 963
#define PHASER_REGEN 966
#define PHASER_LEVEL 965
#define PHASER_WAVE 967
#define TRIG_PHASER_SPEED 1094
#define TRIG_PHASER_SENS 1095
#define TRIG_PHASER_LFO_START 1092
#define TRIG_PHASER_LEVEL 1096
#define MX_PHASER_INTENSITY 976
#define EH_PHASER_RATE 979
#define EH_PHASER_COLOR 977
#define VIBRATO_SPEED 1284
#define VIBRATO_DEPTH 1285
@@ -261,6 +419,11 @@ enum {
#define VIBROPAN_VIBRA 1316
#define VIBROPAN_WAVE 1317
#define UNOVIBE_PEDAL_SPEED 2884
#define UNOVIBE_INTENSITY 2883
#define UNOVIBE_CHORUS_VIBRATO 2882
#define UNOVIBE_VOLUME 2885
#define TREMOLO_SPEED 1156
#define TREMOLO_DEPTH 1155
#define TREMOLO_WAVE 1157
@@ -271,6 +434,7 @@ enum {
#define ENVELOPE_SENSITIVITY 1606
#define ENVELOPE_RANGE 1605
#define ENVELOPE_BLEND 1608
#define AUTOYA_SPEED 1478
#define AUTOYA_INTENSITY 1482
@@ -280,9 +444,18 @@ enum {
#define YAYA_INTENSITY 1417
#define YAYA_RANGE 1418
#define SYNTH_TALK_ATTACK 1542
#define SYNTH_TALK_RELEASE 1547
#define SYNTH_TALK_SENS 1544
#define SYNTH_TALK_VOX 1540
#define SYNTH_TALK_BALANCE 1545
#define STEP_FILTER_SPEED 3010
#define STEP_FILTER_INTENSITY 3011
#define SAMPLE_HOLD_SPEED 3012
#define SAMPLE_HOLD_INTENSITY 3013
#define WHAMMY_AMOUNT 1797
#define WHAMMY_PEDAL 1795
#define WHAMMY_MIX 1796
@@ -298,6 +471,10 @@ enum {
#define IPS_SCALE 2755
#define IPS_LEVEL 2757
#define OCTAVER_OCTAVE1 1746
#define OCTAVER_OCTAVE2 1747
#define OCTAVER_DRY_LEVEL 1748
/* DUAL_CHORUS_WAVE, MULTI_CHORUS_WAVE, FLANGER_WAVE, PHASER_WAVE,
VIBROPAN_WAVE, TREMOLO_WAVE, PANNER_WAVE valid values */
#define WAVE_TRI 0x00
@@ -348,7 +525,7 @@ enum {
#define IPS_BB 0x06
#define IPS_B 0x07
#define IPS_C 0x08
#define IPS_DD 0x09
#define IPS_DB 0x09
#define IPS_D 0x0A
#define IPS_EB 0x0B
@@ -365,7 +542,16 @@ enum {
DELAY_TYPE_DIGITAL = 1045,
DELAY_TYPE_MODULATED = 1047,
DELAY_TYPE_PONG = 1048,
DELAY_TYPE_TAPE = 1049
DELAY_TYPE_TAPE = 1049,
DELAY_RP500_TYPE_DIGITAL = 1052,
DELAY_RP500_TYPE_ANALOG = 1053,
DELAY_RP500_TYPE_DM = 1058,
DELAY_RP500_TYPE_ECHOPLEX = 1057,
DELAY_RP500_TYPE_MODULATED = 1054,
DELAY_RP500_TYPE_PONG = 1055,
DELAY_RP500_TYPE_REVERSE = 1064,
DELAY_RP500_TYPE_TAPE = 1056,
};
#define DELAY_TYPE 1856
@@ -396,6 +582,22 @@ enum {
#define TAPE_WOW 1891
#define TAPE_FLUTTER 1892
#define DELAY_LEVEL 1860
#define DELAY_REPEATS 1863
#define DELAY_TAP_TIME 1868
#define DELAY_DUCK_THRESH 1889
#define DELAY_DUCK_LEVEL 1890
#define DELAY_REPEAT_RATE 1898
#define DELAY_ECHO 1895
#define DELAY_INTENSITY 1896
#define DELAY_TIME_0_760 1899
#define DELAY_VOLUME 1893
#define DELAY_REPEATS_0_99 1874
#define DELAY_DEPTH 1873
#define DELAY_TAP_TIME_0_4990 1900
#define DELAY_MIX 1902
#define DELAY_TIME_0_4650 1901
enum {
REVERB_TYPE_TWIN = 1146,
REVERB_TYPE_LEX_AMBIENCE = 1150,
@@ -436,68 +638,167 @@ enum {
#define EMT240_PLATE_LIVELINESS 1933
#define EMT240_PLATE_LEVEL 1925
enum {
EXP_TYPE_NONE = 0,
EXP_TYPE_PICKUP_ENABLE = 131137,
EXP_TYPE_PIKCUP_TYPE = 131136,
EXP_TYPE_COMP_ENABLE = 262337,
EXP_TYPE_COMP_SUST = 262352,
EXP_TYPE_COMP_TONE = 262353,
EXP_TYPE_COMP_LEVEL = 262354,
EXP_TYPE_COMP_ATTACK = 262355,
EXP_TYPE_DIST_ENABLE = 395649,
EXP_TYPE_DIST_DISTORTION = 395653,
EXP_TYPE_DIST_FILTER = 395654,
EXP_TYPE_DIST_VOLUME = 395655,
EXP_TYPE_AMP_ENABLE = 524553,
EXP_TYPE_AMP_GAIN = 526785,
EXP_TYPE_AMP_LEVEL = 526786,
EXP_TYPE_EQ_ENABLE = 1576076,
EXP_TYPE_EQ_BASS = 1576067,
EXP_TYPE_EQ_MID = 1576068,
EXP_TYPE_EQ_TREB = 1576069,
EXP_TYPE_GATE_ENABLE = 787137,
EXP_TYPE_GATE_THRESHOLD = 787142,
EXP_TYPE_GATE_ATTACK = 787144,
EXP_TYPE_GATE_RELEASE = 787145,
EXP_TYPE_GATE_ATTN = 787146,
EXP_TYPE_CHORUSFX_ENABLE = 918273,
EXP_TYPE_PHASER_SPEED = 918466,
EXP_TYPE_PHASER_DEPTH = 918467,
EXP_TYPE_PHASER_REGEN = 918470,
EXP_TYPE_PHASER_WAVEFORM = 918471,
EXP_TYPE_PHASER_LEVEL = 918469,
EXP_TYPE_DELAY_ENABLE = 984897,
EXP_TYPE_DELAY_TIME = 984928,
EXP_TYPE_DELAY_REPEATS = 984903,
EXP_TYPE_DELAY_LEVEL = 984900,
EXP_TYPE_DELAY_DUCK_THRESH = 984929,
EXP_TYPE_DELAY_DUCK_LEVEL = 984930,
EXP_TYPE_REVERB_ENABLE = 1050497,
EXP_TYPE_REVERB_LEVEL = 1050501,
EXP_TYPE_VOLUME_PRE_FX = 854594,
EXP_TYPE_VOLUME_POST_FX = 1116738
};
#define EXP_TYPE 8194
#define EXP_POSITION 19
#define EXP_MIN 8195
#define EXP_MAX 8196
#define LIBRARY_TONE 8704
#define LIBRARY_EFFECTS 8705
#define LIBRARY_POSITION 25
/* LIBRARY_TONE valid options */
#define TONE_LIB_OVERDRIVE 1793
#define TONE_LIB_ROCK1 1794
#define TONE_LIB_ROCK2 1795
#define TONE_LIB_BLUES1 1796
#define TONE_LIB_BLUES2 1797
#define TONE_LIB_METAL1 1798
#define TONE_LIB_METAL2 1799
#define TONE_LIB_COUNTRY1 1800
#define TONE_LIB_COUNTRY2 1801
#define TONE_LIB_WARM_DRIVE 1802
#define TONE_LIB_CRUNCH 1803
#define TONE_LIB_TEXAS_TONE 1804
#define TONE_LIB_ROCKABILLY 1805
#define TONE_LIB_SOLO1 1806
#define TONE_LIB_SOLO2 1807
#define TONE_LIB_ROCKWAH 1808
#define TONE_LIB_CHUNKY 1809
#define TONE_LIB_SMOOTH 1810
#define TONE_LIB_HEAVY 1811
#define TONE_LIB_CLEAN1 1812
#define TONE_LIB_CLEAN2 1813
#define TONE_LIB_BRITISH1 1814
#define TONE_LIB_BRITISH2 1815
#define TONE_LIB_AMERICAN1 1816
#define TONE_LIB_AMERICAN2 1817
#define TONE_LIB_TUBE_DRIVE 1818
#define TONE_LIB_DISTORTION 1819
#define TONE_LIB_SCOOPED 1820
#define TONE_LIB_PUNCHY 1821
#define TONE_LIB_BRIGHT_CLEAN 1822
/* setting LIBRARY_TONE to this option seems to crash device */
#define TONE_LIB_CUSTOM 1792
/* LIBRARY_EFFECTS valid options */
#define EFFECTS_LIB_CHORUS 1857
#define EFFECTS_LIB_PHASER 1858
#define EFFECTS_LIB_FLANGER 1859
#define EFFECTS_LIB_PITCH 1860
#define EFFECTS_LIB_TREMOLO 1861
#define EFFECTS_LIB_ROTARY 1862
#define EFFECTS_LIB_ENVELOPE 1863
#define EFFECTS_LIB_DIGITAL 1864
#define EFFECTS_LIB_ANALOG 1865
#define EFFECTS_LIB_PONG 1866
#define EFFECTS_LIB_MOD 1867
#define EFFECTS_LIB_TAPE 1868
#define EFFECTS_LIB_HALL 1869
#define EFFECTS_LIB_PLATE 1870
#define EFFECTS_LIB_SPRING 1871
#define EFFECTS_LIB_CHORUS_DIGITAL 1872
#define EFFECTS_LIB_CHORUS_DELAY_REVERB 1873
#define EFFECTS_LIB_FLANGER_ANALOG 1874
#define EFFECTS_LIB_PHASER_TAPE 1875
#define EFFECTS_LIB_PHASER_MOD 1876
#define EFFECTS_LIB_PHASER_ROOM 1877
#define EFFECTS_LIB_DIGITAL_HALL 1878
#define EFFECTS_LIB_ANALOG_SPRING 1879
#define EFFECTS_LIB_CHORUS_HALL 1880
#define EFFECTS_LIB_PONG_HALL 1881
#define EFFECTS_LIB_TAPE_SPRING 1882
#define EFFECTS_LIB_TREMOLO_TAPE 1883
#define EFFECTS_LIB_PITCH_DIGITAL 1884
#define EFFECTS_LIB_MOD_PLATE 1885
#define EFFECTS_LIB_ROTARY_TAPE 1886
/* setting EFFECTS_LIBRARY to this option seems to crash device */
#define EFFECTS_LIB_CUSTOM 1856
#define USB_POSITION 0
#define USB_AUDIO_PLAYBACK_MIX 12297
#define USB_AUDIO_LEVEL 12307
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
typedef enum {
PRESETS_SYSTEM = 0,
PRESETS_USER = 1
PRESETS_SYSTEM = 0,
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
} PresetBank;
typedef 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,
LOAD_EDIT_BUFFER_PRESET = 0x38, /* version 0 only
use move preset in later versions */
MOVE_PRESET = 0x39,
REQUEST_MODIFIER_LINKABLE_LIST = 0x3A,
RECEIVE_MODIFIER_LINKABLE_LIST = 0x3B,
REQUEST_PARAMETER_VALUE = 0x40,
RECEIVE_PARAMETER_VALUE = 0x41,
/* version 1 and later */
REQUEST_OBJECT_NAMES = 0x50,
RECEIVE_OBJECT_NAMES = 0x51,
REQUEST_OBJECT_NAME = 0x52,
RECEIVE_OBJECT_NAME = 0x53,
REQUEST_OBJECT = 0x54,
RECEIVE_OBJECT = 0x55,
MOVE_OBJECT = 0x56,
DELETE_OBJECT = 0x57,
REQUEST_TABLE = 0x5A,
RECEIVE_TABLE = 0x5B,
RECEIVE_DEVICE_NOTIFICATION = 0x70,
ACK = 0x7E,
NACK = 0x7F
} MessageID;
void send_message(gint procedure, gchar *data, gint len);
void append_value(GString *msg, guint value);
GString *get_message_by_id(MessageID id);
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(gchar bank);
GString *get_current_preset();
#endif /* GDIGI_H */

919
gtkknob.c Normal file
View File

@@ -0,0 +1,919 @@
/*****************************************************************************
*
* Most of this code comes from gAlan 0.2.0, copyright (C) 1999
* Tony Garnock-Jones, with modifications from Sean Bolton,
* copyright (C) 2004, William Weston copyright (C) 2007,
* Pete Shorthose copyright (C) 2007, and Tomasz Moń,
* copyright (C) 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*****************************************************************************/
#include <math.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "gtkknob.h"
#ifndef M_PI
# define M_PI 3.14159265358979323846 /* pi */
#endif
#ifndef M_1_PI
# define M_1_PI 0.31830988618379067154 /* 1/pi */
#endif
#define SCROLL_DELAY_LENGTH 250
#define KNOB_SIZE 32 /* this should really be read from the knob image */
#define STATE_IDLE 0
#define STATE_PRESSED 1
#define STATE_DRAGGING 2
static void gtk_knob_class_init(GtkKnobClass *klass);
static void gtk_knob_init(GtkKnob *knob);
static void gtk_knob_destroy(GtkObject *object);
static void gtk_knob_realize(GtkWidget *widget);
static void gtk_knob_size_request(GtkWidget *widget, GtkRequisition *requisition);
static void gtk_knob_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
static gint gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event);
static gint gtk_knob_scroll(GtkWidget *widget, GdkEventScroll *event);
static gint gtk_knob_button_press(GtkWidget *widget, GdkEventButton *event);
static gint gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event);
static gint gtk_knob_key_press(GtkWidget *widget, GdkEventKey *event);
static gint gtk_knob_motion_notify(GtkWidget *widget, GdkEventMotion *event);
static gint gtk_knob_timer(GtkKnob *knob);
static void gtk_knob_update_mouse_update(GtkKnob *knob);
static void gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step);
static void gtk_knob_update(GtkKnob *knob);
static void gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data);
static void gtk_knob_adjustment_value_changed(GtkAdjustment *adjustment, gpointer data);
/* Local data */
static GtkWidgetClass *parent_class = NULL;
/*****************************************************************************
*
* gtk_knob_get_type()
*
*****************************************************************************/
GType
gtk_knob_get_type(void) {
static GType knob_type = 0;
if (!knob_type) {
static const GTypeInfo knob_info = {
sizeof (GtkKnobClass),
NULL,
NULL,
(GClassInitFunc) gtk_knob_class_init,
NULL,
NULL,
sizeof (GtkKnob),
0,
(GInstanceInitFunc) gtk_knob_init,
};
knob_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkKnob", &knob_info, 0);
}
return knob_type;
}
/*****************************************************************************
*
* gtk_knob_class_init()
*
*****************************************************************************/
static void
gtk_knob_class_init (GtkKnobClass *klass) {
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = (GtkObjectClass*) klass;
widget_class = (GtkWidgetClass*) klass;
parent_class = g_type_class_peek_parent(klass);
object_class->destroy = gtk_knob_destroy;
widget_class->realize = gtk_knob_realize;
widget_class->expose_event = gtk_knob_expose;
widget_class->size_request = gtk_knob_size_request;
widget_class->size_allocate = gtk_knob_size_allocate;
widget_class->scroll_event = gtk_knob_scroll;
widget_class->button_press_event = gtk_knob_button_press;
widget_class->button_release_event = gtk_knob_button_release;
widget_class->key_press_event = gtk_knob_key_press;
widget_class->motion_notify_event = gtk_knob_motion_notify;
}
/*****************************************************************************
*
* gtk_knob_init()
*
*****************************************************************************/
static void
gtk_knob_init (GtkKnob *knob) {
knob->policy = GTK_UPDATE_CONTINUOUS;
knob->state = STATE_IDLE;
knob->saved_x = 0;
knob->saved_y = 0;
knob->timer = 0;
knob->anim = NULL;
knob->mask = NULL;
knob->mask_gc = NULL;
knob->red_gc = NULL;
knob->old_value = 0.0;
knob->old_lower = 0.0;
knob->old_upper = 0.0;
knob->adjustment = NULL;
}
/*****************************************************************************
*
* gtk_knob_new()
*
*****************************************************************************/
GtkWidget *
gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim) {
GtkKnob *knob;
g_return_val_if_fail (anim != NULL, NULL);
g_return_val_if_fail (GDK_IS_PIXBUF (anim->pixbuf), NULL);
knob = g_object_new (gtk_knob_get_type (), NULL);
gtk_knob_set_animation (knob, anim);
if (!adjustment) {
adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0,
0.0, 0.0, 0.0);
}
gtk_knob_set_adjustment (knob, adjustment);
return GTK_WIDGET (knob);
}
/*****************************************************************************
*
* gtk_knob_destroy()
*
*****************************************************************************/
static void
gtk_knob_destroy(GtkObject *object) {
GtkKnob *knob;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_KNOB (object));
knob = GTK_KNOB (object);
gtk_knob_set_adjustment (knob, NULL);
/* FIXME: needs ref counting for automatic GtkKnobAnim cleanup
if (knob->anim) {
gtk_knob_anim_unref (knob->anim);
knob->anim = NULL;
}
*/
if (knob->mask) {
g_object_unref (knob->mask);
knob->mask = NULL;
}
if (knob->mask_gc) {
g_object_unref (knob->mask_gc);
knob->mask_gc = NULL;
}
if (knob->red_gc) {
g_object_unref (knob->red_gc);
knob->red_gc = NULL;
}
if (GTK_OBJECT_CLASS (parent_class)->destroy) {
(*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
}
/*****************************************************************************
*
* gtk_knob_get_adjustment()
*
*****************************************************************************/
GtkAdjustment*
gtk_knob_get_adjustment(GtkKnob *knob) {
g_return_val_if_fail (knob != NULL, NULL);
g_return_val_if_fail (GTK_IS_KNOB (knob), NULL);
return knob->adjustment;
}
/*****************************************************************************
*
* gtk_knob_set_update_policy()
*
*****************************************************************************/
void
gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy) {
g_return_if_fail (knob != NULL);
g_return_if_fail (GTK_IS_KNOB (knob));
knob->policy = policy;
}
/*****************************************************************************
*
* gtk_knob_set_adjustment()
*
*****************************************************************************/
void
gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment) {
g_return_if_fail (knob != NULL);
g_return_if_fail (GTK_IS_KNOB (knob));
if (knob->adjustment) {
g_signal_handlers_disconnect_matched(knob->adjustment,
G_SIGNAL_MATCH_DATA,
0, 0, NULL, NULL,
knob);
g_object_unref (knob->adjustment);
}
knob->adjustment = adjustment;
if (adjustment) {
g_object_ref_sink (adjustment);
g_signal_connect (adjustment, "changed",
G_CALLBACK(gtk_knob_adjustment_changed),
knob);
g_signal_connect (adjustment, "value_changed",
G_CALLBACK(gtk_knob_adjustment_value_changed),
knob);
knob->old_value = adjustment->value;
knob->old_lower = adjustment->lower;
knob->old_upper = adjustment->upper;
gtk_knob_update (knob);
}
}
/*****************************************************************************
*
* gtk_knob_realize()
*
*****************************************************************************/
static void
gtk_knob_realize(GtkWidget *widget) {
GtkKnob *knob;
GdkWindowAttr attributes;
gint attributes_mask;
GdkColor color = { 0, 0xffff, 0, 0 };
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_KNOB (widget));
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
knob = GTK_KNOB (widget);
attributes.x = widget->allocation.x;
attributes.y = widget->allocation.y;
attributes.width = widget->allocation.width;
attributes.height = widget->allocation.height;
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.window_type = GDK_WINDOW_CHILD;
attributes.event_mask =
gtk_widget_get_events (widget) |
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK;
attributes.visual = gtk_widget_get_visual (widget);
attributes.colormap = gtk_widget_get_colormap (widget);
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
widget->window = gdk_window_new (widget->parent->window,
&attributes, attributes_mask);
widget->style = gtk_style_attach (widget->style, widget->window);
gdk_window_set_user_data (widget->window, widget);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
knob->mask_gc = gdk_gc_new (widget->window);
gdk_gc_copy (knob->mask_gc, widget->style->bg_gc[GTK_STATE_NORMAL]);
gdk_gc_set_clip_mask (knob->mask_gc, knob->mask);
knob->red_gc = gdk_gc_new (widget->window);
gdk_gc_copy (knob->red_gc, widget->style->bg_gc[GTK_STATE_NORMAL]);
gdk_colormap_alloc_color (attributes.colormap, &color, FALSE, TRUE);
gdk_gc_set_foreground (knob->red_gc, &color);
}
/*****************************************************************************
*
* gtk_knob_size_request()
*
*****************************************************************************/
static void
gtk_knob_size_request (GtkWidget *widget, GtkRequisition *requisition) {
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_KNOB (widget));
requisition->width = GTK_KNOB (widget)->width;
requisition->height = GTK_KNOB (widget)->height;
}
/*****************************************************************************
*
* gtk_knob_size_allocate()
*
*****************************************************************************/
static void
gtk_knob_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
GtkKnob *knob;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_KNOB (widget));
g_return_if_fail (allocation != NULL);
widget->allocation = *allocation;
knob = GTK_KNOB (widget);
if (GTK_WIDGET_REALIZED (widget)) {
gdk_window_move_resize (widget->window,
allocation->x, allocation->y,
allocation->width, allocation->height);
}
}
/*****************************************************************************
*
* gtk_knob_expose()
*
*****************************************************************************/
static gint
gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event) {
GtkKnob *knob;
gfloat dx, dy;
gint frames;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
if (event->count > 0)
return FALSE;
knob = GTK_KNOB (widget);
frames = ((knob->anim->width / knob->anim->frame_width) - 1);
dx = knob->adjustment->value - knob->adjustment->lower; /* value, from 0 */
dy = knob->adjustment->upper - knob->adjustment->lower; /* range */
dx = (int)(frames * dx / dy) * knob->width; /* check this for height != width */
gdk_draw_pixbuf (widget->window, knob->mask_gc, knob->anim->pixbuf,
dx, 0, 0, 0, knob->width, knob->height,
GDK_RGB_DITHER_NONE, 0, 0);
if (GTK_WIDGET_HAS_FOCUS(widget)) {
gtk_paint_focus (widget->style, widget->window, widget->state,
NULL, widget, NULL, 0, 0,
widget->allocation.width, widget->allocation.height);
}
return FALSE;
}
/*****************************************************************************
*
* gtk_knob_scroll()
*
*****************************************************************************/
static gint
gtk_knob_scroll(GtkWidget *widget, GdkEventScroll *event) {
GtkKnob *knob;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
knob = GTK_KNOB (widget);
switch (event->direction) {
case GDK_SCROLL_UP:
knob->adjustment->value += knob->adjustment->step_increment;
g_signal_emit_by_name (knob->adjustment, "value_changed");
break;
case GDK_SCROLL_DOWN:
knob->adjustment->value -= knob->adjustment->step_increment;
g_signal_emit_by_name (knob->adjustment, "value_changed");
break;
default:
break;
}
return FALSE;
}
/*****************************************************************************
*
* gtk_knob_button_press()
*
*****************************************************************************/
static gint
gtk_knob_button_press(GtkWidget *widget, GdkEventButton *event) {
GtkKnob *knob;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
knob = GTK_KNOB (widget);
switch (knob->state) {
case STATE_IDLE:
switch (event->button) {
case 1:
case 3:
if (!GTK_WIDGET_HAS_FOCUS(widget))
gtk_widget_grab_focus(widget);
knob->state = STATE_PRESSED;
knob->saved_x = event->x;
knob->saved_y = event->y;
break;
case 2:
knob->adjustment->value = floor ((knob->adjustment->lower +
knob->adjustment->upper + 1.0)
* 0.5);
g_signal_emit_by_name (knob->adjustment, "value_changed");
break;
}
break;
}
return FALSE;
}
/*****************************************************************************
*
* gtk_knob_button_release()
*
*****************************************************************************/
static gint
gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event) {
GtkKnob *knob;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
knob = GTK_KNOB (widget);
switch (knob->state) {
case STATE_PRESSED:
knob->state = STATE_IDLE;
break;
case STATE_DRAGGING:
knob->state = STATE_IDLE;
switch (event->button) {
case 1:
case 3:
if (knob->policy != GTK_UPDATE_CONTINUOUS
&& knob->old_value != knob->adjustment->value)
{
g_signal_emit_by_name (knob->adjustment, "value_changed");
}
break;
}
break;
}
return FALSE;
}
static gint gtk_knob_key_press(GtkWidget *widget, GdkEventKey *event)
{
GtkKnob *knob;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
knob = GTK_KNOB (widget);
switch (event->keyval) {
case GDK_Up:
if (GTK_WIDGET_HAS_FOCUS (widget))
{
gtk_adjustment_set_value (knob->adjustment,
knob->old_value + knob->adjustment->step_increment);
return TRUE;
}
return FALSE;
case GDK_Down:
if (GTK_WIDGET_HAS_FOCUS (widget))
{
gtk_adjustment_set_value (knob->adjustment,
knob->old_value - knob->adjustment->step_increment);
return TRUE;
}
return FALSE;
default:
break;
}
return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
}
/*****************************************************************************
*
* gtk_knob_motion_notify()
*
*****************************************************************************/
static gint
gtk_knob_motion_notify(GtkWidget *widget, GdkEventMotion *event) {
GtkKnob *knob;
GdkModifierType mods;
gint x, y;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
knob = GTK_KNOB (widget);
x = event->x;
y = event->y;
if (event->is_hint || (event->window != widget->window)) {
gdk_window_get_pointer (widget->window, &x, &y, &mods);
}
switch (knob->state) {
case STATE_PRESSED:
knob->state = STATE_DRAGGING;
/* fall through */
case STATE_DRAGGING:
if (mods & GDK_BUTTON1_MASK) {
gtk_knob_update_mouse (knob, x, y, TRUE);
return TRUE;
}
else if (mods & GDK_BUTTON3_MASK) {
gtk_knob_update_mouse (knob, x, y, FALSE);
return TRUE;
}
break;
}
return FALSE;
}
/*****************************************************************************
*
* gtk_knob_timer()
*
*****************************************************************************/
static gint
gtk_knob_timer(GtkKnob *knob) {
g_return_val_if_fail (knob != NULL, FALSE);
g_return_val_if_fail (GTK_IS_KNOB (knob), FALSE);
g_return_val_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment), FALSE);
if (knob->policy == GTK_UPDATE_DELAYED) {
g_signal_emit_by_name (knob->adjustment, "value_changed");
}
/* don't keep running this timer */
return FALSE;
}
/*****************************************************************************
*
* gtk_knob_update_mouse_update()
*
*****************************************************************************/
static void
gtk_knob_update_mouse_update(GtkKnob *knob) {
g_return_if_fail(GTK_IS_ADJUSTMENT (knob->adjustment));
if (knob->policy == GTK_UPDATE_CONTINUOUS) {
g_signal_emit_by_name (knob->adjustment, "value_changed");
}
else {
gtk_widget_queue_draw (GTK_WIDGET (knob));
if (knob->policy == GTK_UPDATE_DELAYED) {
if (knob->timer) {
g_source_remove (knob->timer);
}
knob->timer = g_timeout_add (SCROLL_DELAY_LENGTH,
(GSourceFunc) gtk_knob_timer,
(gpointer) knob);
}
}
}
/*****************************************************************************
*
* gtk_knob_update_mouse()
*
*****************************************************************************/
static void
gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step) {
gfloat old_value, new_value, dv, dh;
gfloat angle;
g_return_if_fail (knob != NULL);
g_return_if_fail (GTK_IS_KNOB (knob));
g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment));
old_value = knob->adjustment->value;
angle = atan2f (-y + (knob->height >> 1), x - (knob->width >> 1));
/* inverted cartesian graphics coordinate system */
dv = knob->saved_y - y;
dh = x - knob->saved_x;
knob->saved_x = x;
knob->saved_y = y;
if ((x >= 0) && (x <= knob->width)) {
dh = 0; /* dead zone */
} else {
angle = cosf (angle);
dh *= angle * angle;
}
new_value = knob->adjustment->value +
dv * (step ? knob->adjustment->step_increment : knob->adjustment->page_increment) +
dh * (knob->adjustment->upper -
knob->adjustment->lower) * 0.005; /* 0.005 == (1 / 200) */
new_value = MAX (MIN (new_value, knob->adjustment->upper),
knob->adjustment->lower);
knob->adjustment->value = new_value;
if (knob->adjustment->value != old_value) {
gtk_knob_update_mouse_update (knob);
}
}
/*****************************************************************************
*
* gtk_knob_update()
*
*****************************************************************************/
static void
gtk_knob_update(GtkKnob *knob) {
gfloat new_value;
g_return_if_fail (knob != NULL);
g_return_if_fail (GTK_IS_KNOB (knob));
g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment));
if (knob->adjustment->step_increment == 1) {
new_value = floor (knob->adjustment->value + 0.5);
}
else {
new_value = knob->adjustment->value;
}
if (new_value < knob->adjustment->lower) {
new_value = knob->adjustment->lower;
}
if (new_value > knob->adjustment->upper) {
new_value = knob->adjustment->upper;
}
if (new_value != knob->adjustment->value) {
knob->adjustment->value = new_value;
g_signal_emit_by_name (knob->adjustment, "value_changed");
}
gtk_widget_queue_draw (GTK_WIDGET (knob));
}
/*****************************************************************************
*
* gtk_knob_adjustment_changed()
*
*****************************************************************************/
static void
gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data) {
GtkKnob *knob;
g_return_if_fail (adjustment != NULL);
g_return_if_fail (data != NULL);
knob = GTK_KNOB (data);
if ((knob->old_value != adjustment->value) ||
(knob->old_lower != adjustment->lower) ||
(knob->old_upper != adjustment->upper))
{
gtk_knob_update (knob);
knob->old_value = adjustment->value;
knob->old_lower = adjustment->lower;
knob->old_upper = adjustment->upper;
}
}
/*****************************************************************************
*
* gtk_knob_adjustment_value_changed()
*
*****************************************************************************/
static void
gtk_knob_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) {
GtkKnob *knob;
g_return_if_fail (adjustment != NULL);
g_return_if_fail (data != NULL);
knob = GTK_KNOB (data);
if (knob->old_value != adjustment->value) {
gtk_knob_update (knob);
knob->old_value = adjustment->value;
}
}
/*****************************************************************************
*
* gtk_knob_set_animation()
*
*****************************************************************************/
void
gtk_knob_set_animation (GtkKnob *knob, GtkKnobAnim *anim) {
g_return_if_fail (knob != NULL);
g_return_if_fail (anim != NULL);
g_return_if_fail (GTK_IS_KNOB (knob));
g_return_if_fail (GDK_IS_PIXBUF (anim->pixbuf));
knob->anim = (GtkKnobAnim *)anim;
knob->width = anim->frame_width;
knob->height = anim->height;
if (GTK_WIDGET_REALIZED (knob)) {
gtk_widget_queue_resize (GTK_WIDGET (knob));
}
}
/*****************************************************************************
*
* gtk_knob_animation_new_from_file()
*
*****************************************************************************/
GtkKnobAnim *
gtk_knob_animation_new_from_file(gchar *filename) {
GtkKnobAnim *anim;
anim = gtk_knob_animation_new_from_file_full (filename, -1, -1, KNOB_SIZE);
return anim;
}
/*****************************************************************************
*
* gtk_knob_animation_new_from_inline()
*
*****************************************************************************/
GtkKnobAnim *
gtk_knob_animation_new_from_inline(const guint8 *pixbuf) {
GtkKnobAnim *anim = g_new0 (GtkKnobAnim, 1);
g_return_val_if_fail((pixbuf != NULL), NULL);
anim->pixbuf = gdk_pixbuf_new_from_inline(-1, pixbuf, FALSE, NULL);
if (anim->pixbuf == NULL) {
g_free(anim);
return NULL;
}
anim->height = gdk_pixbuf_get_height (anim->pixbuf);
anim->width = gdk_pixbuf_get_width (anim->pixbuf);
anim->frame_width = anim->height;
return anim;
}
/*****************************************************************************
*
* gtk_knob_new_from_file_full()
*
* frame_width: overrides the frame width (to make rectangular frames)
* but doesn't affect the image size width and height cause optional
* scaling if not set to -1 when they are derived from the native
* image size.
*
* FIXME: account for any problems where (width % frame_width != 0)
*
*****************************************************************************/
GtkKnobAnim *
gtk_knob_animation_new_from_file_full(gchar *filename, gint frame_width,
gint width, gint height) {
GtkKnobAnim *anim = g_new0 (GtkKnobAnim, 1);
g_return_val_if_fail ((filename != NULL), NULL);
GError *gerror = NULL;
#if GTK_MINOR_VERSION < 10
if (!(anim->pixbuf = gdk_pixbuf_new_from_file (filename, &gerror))) {
g_error_free(gerror);
gerror = NULL;
return NULL;
}
#else /* GTK_MINOR_VERSION >= 10 */
if (!(anim->pixbuf = gdk_pixbuf_new_from_file_at_size (filename, width,
height, &gerror))) {
g_error_free(gerror);
gerror = NULL;
return NULL;
}
#endif /* GTK_MINOR_VERSION < 10 */
else {
anim->height = gdk_pixbuf_get_height (anim->pixbuf);
anim->width = gdk_pixbuf_get_width (anim->pixbuf);
anim->frame_width = (frame_width != -1) ? frame_width : anim->height;
}
return anim;
}
/*****************************************************************************
*
* gtk_knob_animation_free()
*
*****************************************************************************/
void
gtk_knob_animation_free(GtkKnobAnim *anim) {
g_return_if_fail (anim != NULL);
if (anim->pixbuf)
g_object_unref (anim->pixbuf);
g_free (anim);
}

102
gtkknob.h Normal file
View File

@@ -0,0 +1,102 @@
/*****************************************************************************
*
* Most of this code comes from gAlan 0.2.0, copyright (C) 1999
* Tony Garnock-Jones, with modifications by Sean Bolton,
* copyright (C) 2004, and minor modifications by William Weston,
* copyright (C) 2007, Tomasz Moń, copyright (C) 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*****************************************************************************/
#ifndef __GTK_KNOB_H__
#define __GTK_KNOB_H__
#include <gtk/gtk.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GTK_KNOB(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_knob_get_type(), GtkKnob)
#define GTK_KNOB_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, gtk_knob_get_type(), GtkKnobClass)
#define GTK_IS_KNOB(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_knob_get_type())
typedef struct _GtkKnob GtkKnob;
typedef struct _GtkKnobClass GtkKnobClass;
typedef struct _GtkKnobAnim GtkKnobAnim;
/* better to make this an object and let widgets ref/deref it perhaps */
struct _GtkKnobAnim {
GdkPixbuf *pixbuf;
gint width; /* derived from image width */
gint height; /* derived from image height. */
gint frame_width; /* derived from pixbuf (width / height) or provided override for rectangular frames */
};
struct _GtkKnob {
GtkWidget widget;
/* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
guint policy : 2;
/* State of widget (to do with user interaction) */
guint8 state;
gint saved_x, saved_y;
/* ID of update timer, or 0 if none */
guint32 timer;
/* knob animation */
GtkKnobAnim *anim;
gint width, height;
GdkBitmap *mask;
GdkGC *mask_gc;
GdkGC *red_gc;
/* Old values from adjustment stored so we know when something changes */
gfloat old_value;
gfloat old_lower;
gfloat old_upper;
/* The adjustment object that stores the data for this knob */
GtkAdjustment *adjustment;
};
struct _GtkKnobClass {
GtkWidgetClass parent_class;
};
extern GtkWidget *gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim);
extern GType gtk_knob_get_type(void);
extern GtkAdjustment *gtk_knob_get_adjustment(GtkKnob *knob);
extern void gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy);
extern void gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment);
GtkKnobAnim *gtk_knob_animation_new_from_inline(const guint8 *pixbuf);
GtkKnobAnim *gtk_knob_animation_new_from_file_full(gchar *filename,
gint frame_width,
gint width,
gint height);
GtkKnobAnim *gtk_knob_animation_new_from_file(gchar *filename);
void gtk_knob_set_animation (GtkKnob *knob, GtkKnobAnim *anim);
void gtk_knob_animation_free(GtkKnobAnim *anim);
#ifdef __cplusplus
}
#endif
#endif

588
gui.c
View File

@@ -19,97 +19,267 @@
#include "gui.h"
#include "effects.h"
#include "preset.h"
extern EffectList effects[];
extern int n_effects;
#include "gtkknob.h"
#include "knob.h"
typedef struct {
GtkWidget *widget;
GtkObject *widget;
gint id;
gint position;
/* used for combo boxes, if widget isn't combo box, then both value and x are -1 */
gint value; /* effect type value */
gint x; /* combo box item number */
gint value; /**< effect type value */
gint x; /**< combo box item number */
} WidgetListElem;
void value_changed_option_cb(GtkSpinButton *spinbutton, EffectSettings *setting)
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static GtkKnobAnim *knob_anim = NULL; /* animation used by knobs */
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
static GList *widget_list = NULL; /**< this list contains WidgetListElem data elements */
static gboolean allow_send = FALSE; /**< if FALSE GUI parameter changes won't be sent to device */
/**
* \param parent transient parent, or NULL for none
* \param message error description
*
* Shows error message dialog.
**/
void show_error_message(GtkWidget *parent, gchar *message)
{
g_return_if_fail(message != NULL);
GtkWidget *msg = gtk_message_dialog_new(GTK_WINDOW(parent),
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
message);
gtk_dialog_run(GTK_DIALOG(msg));
gtk_widget_destroy(msg);
}
/**
* \param adj the object which emitted the signal
* \param setting setting controlled by adj
*
* Sets effect value.
**/
void value_changed_option_cb(GtkAdjustment *adj, EffectSettings *setting)
{
g_return_if_fail(setting != NULL);
int val = gtk_spin_button_get_value_as_int(spinbutton);
set_option(setting->option, setting->position, val);
if (allow_send) {
gdouble val;
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]);
}
}
}
/**
* \param button the object which emitted the signal
* \param effect effect controlled by button
*
* Turns effect on/off basing on state of button.
**/
void toggled_cb(GtkToggleButton *button, Effect *effect)
{
g_return_if_fail(effect != NULL);
guint val = gtk_toggle_button_get_active(button);
set_option(effect->option, effect->position, val);
if (allow_send) {
guint val = gtk_toggle_button_get_active(button);
set_option(effect->id, effect->position, val);
}
}
static void widget_list_add(GList **list, GtkWidget *widget, gint id, gint position, gint value, gint x)
/**
* \param widget GtkObject to add to widget list
* \param id object controlled ID
* \param position object controlled position
* \param value effect value type (if widget is GtkComboBox, otherwise -1)
* \param x combo box item number (if widget is GtkComboBox, otherwise -1)
*
* Adds widget to widget list.
**/
static void widget_list_add(GtkObject *widget, gint id, gint position, gint value, gint x)
{
WidgetListElem *el;
el = g_malloc(sizeof(WidgetListElem));
el = g_slice_new(WidgetListElem);
el->widget = widget;
el->id = id;
el->position = position;
el->value = value;
el->x = x;
*list = g_list_prepend(*list, el);
widget_list = g_list_prepend(widget_list, el);
}
GtkWidget *create_table(GList **list, EffectSettings *settings, gint amt)
/**
* \param el widget list element
* \param param parameter to set
*
* Sets widget list element value to param value.
**/
static void apply_widget_setting(WidgetListElem *el, SettingParam *param)
{
GtkWidget *table, *label, *widget;
if ((el->id == param->id) && (el->position == param->position)) {
if (el->value == -1) {
if (GTK_IS_TOGGLE_BUTTON(el->widget))
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(el->widget), (param->value == 0) ? FALSE : TRUE);
else if (GTK_IS_ADJUSTMENT(el->widget))
gtk_adjustment_set_value(GTK_ADJUSTMENT(el->widget), (gdouble)param->value);
} else { /* combo box */
if (el->value == param->value)
gtk_combo_box_set_active(GTK_COMBO_BOX(el->widget), el->x);
}
}
}
/**
* \param preset preset to sync
*
* Synces GUI with preset.
**/
static void apply_preset_to_gui(Preset *preset)
{
g_return_if_fail(preset != NULL);
g_return_if_fail(widget_list != NULL);
allow_send = FALSE;
GList *iter = preset->params;
while (iter) {
SettingParam *param = iter->data;
iter = iter->next;
if (param != NULL)
g_list_foreach(widget_list, (GFunc)apply_widget_setting, param);
}
allow_send = TRUE;
}
/**
* Synces GUI with device current edit buffer.
**/
static void apply_current_preset()
{
GString *msg = get_current_preset();
Preset *preset = create_preset_from_data(msg);
g_string_free(msg, TRUE);
apply_preset_to_gui(preset);
preset_free(preset);
}
/**
* \param settings effect parameters
* \param amt amount of effect parameters
*
* Creates knobs that allow user to set effect parameters.
*
* \return GtkTable containing necessary widgets to set effect parameters.
**/
GtkWidget *create_table(EffectSettings *settings, gint amt)
{
GtkWidget *table, *label, *widget, *knob;
GtkObject *adj;
int x;
table = gtk_table_new(2, amt, FALSE);
table = gtk_table_new(3, amt, FALSE);
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);
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);
adj = gtk_adjustment_new(0.0, settings[x].values->min, settings[x].values->max,
1.0, /* step increment */
MAX((settings[x].values->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_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);
}
widget_list_add(adj, settings[x].id, settings[x].position, -1, -1);
gtk_table_attach(GTK_TABLE(table), label, 0, 1, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
gtk_table_attach(GTK_TABLE(table), widget, 1, 2, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
gtk_table_attach(GTK_TABLE(table), knob, 1, 2, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
gtk_table_attach(GTK_TABLE(table), widget, 2, 3, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(value_changed_option_cb), &settings[x]);
}
return table;
}
GtkWidget *create_on_off_button(GList **list, Effect *effect)
/**
* \param effect Effect that can be turned on/off
*
* Creates toggle button that allow user to turn effect on/off.
*
* \return GtkToggleButton
**/
GtkWidget *create_on_off_button(Effect *effect)
{
GtkWidget *button = gtk_toggle_button_new_with_label(effect->label);
GtkWidget *button;
if (effect->label == NULL)
button = gtk_check_button_new();
else
button = gtk_check_button_new_with_label(effect->label);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggled_cb), effect);
widget_list_add(list, button, effect->option, effect->position, -1, -1);
widget_list_add(GTK_OBJECT(button), effect->id, effect->position, -1, -1);
return button;
}
typedef struct {
gint id; /* effect group ID (value) */
gint option; /* option ID */
gint position; /* position */
GtkWidget *child; /* child widget */
gint type; /**< effect group type (value) */
gint id; /**< option ID */
gint position; /**< position */
GtkWidget *child; /**< child widget */
} EffectSettingsGroup;
/**
* \param group group to be freed
*
* Frees all memory used by group
**/
void effect_settings_group_free(EffectSettingsGroup *group)
{
/* destroy widget without parent */
if (gtk_widget_get_parent(group->child) == NULL)
gtk_widget_destroy(group->child);
if (group->child != NULL) {
/* destroy widget without parent */
if (gtk_widget_get_parent(group->child) == NULL)
gtk_widget_destroy(group->child);
g_object_unref(group->child);
g_free(group);
g_object_unref(group->child);
}
g_slice_free(EffectSettingsGroup, group);
}
/**
* \param widget the object which emitted the signal
* \param data user data (unused, can be anything)
*
* Switches effect type and shows widgets allowing to set selected effect type parameters.
**/
void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
{
GtkWidget *child;
@@ -126,20 +296,31 @@ void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
settings = g_object_get_data(G_OBJECT(widget), name);
g_free(name);
if (settings != NULL)
set_option(settings->option, settings->position, settings->id);
if (settings != NULL && allow_send)
set_option(settings->id, settings->position, settings->type);
child = g_object_get_data(G_OBJECT(widget), "active_child");
if (child != NULL) {
gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(gtk_widget_get_parent(vbox))), child);
}
gtk_container_add(GTK_CONTAINER(gtk_widget_get_parent(gtk_widget_get_parent(vbox))), settings->child);
gtk_widget_show_all(gtk_widget_get_parent(gtk_widget_get_parent(vbox)));
if (settings->child != NULL) {
gtk_container_add(GTK_CONTAINER(gtk_widget_get_parent(gtk_widget_get_parent(vbox))), settings->child);
gtk_widget_show_all(gtk_widget_get_parent(gtk_widget_get_parent(vbox)));
}
g_object_set_data(G_OBJECT(widget), "active_child", settings->child);
}
}
GtkWidget *create_widget_container(GList **list, EffectGroup *group, gint amt)
/**
* \param group Effect type groups
* \param amt amount of effect groups
*
* Creates widget allowing user to choose effect type.
*
* \return widget that allow user to set effect type.
**/
GtkWidget *create_widget_container(EffectGroup *group, gint amt)
{
GtkWidget *vbox;
GtkWidget *widget;
@@ -162,51 +343,80 @@ GtkWidget *create_widget_container(GList **list, EffectGroup *group, gint amt)
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), group[x].label);
cmbox_no++;
widget = create_table(list, group[x].settings, group[x].settings_amt);
g_object_ref_sink(widget);
if ((group[x].settings != NULL) && (group[x].settings > 0)) {
widget = create_table(group[x].settings, group[x].settings_amt);
g_object_ref_sink(widget);
} else
widget = NULL;
settings = g_malloc(sizeof(EffectSettingsGroup));
settings = g_slice_new(EffectSettingsGroup);
settings->id = group[x].id;
settings->option = group[x].option;
settings->type = group[x].type;
settings->position = group[x].position;
settings->child = widget;
widget_list_add(list, combo_box, group[x].option, group[x].position, group[x].id, x);
widget_list_add(GTK_OBJECT(combo_box), group[x].id, group[x].position, group[x].type, x);
name = g_strdup_printf("SettingsGroup%d", cmbox_no);
g_object_set_data_full(G_OBJECT(combo_box), name, settings, ((GDestroyNotify)effect_settings_group_free));
g_free(name);
} else {
widget = create_table(list, group[x].settings, group[x].settings_amt);
widget = create_table(group[x].settings, group[x].settings_amt);
gtk_container_add(GTK_CONTAINER(vbox), widget);
}
}
return vbox;
};
}
GtkWidget *create_vbox(GList **list, Effect *widgets, gint amt)
/**
* \param widgets Effect descriptions
* \param amt amount of effect descriptions
* \param label frame label (can be NULL)
*
* Creates frame (with optional label) containing widgets allowing user to set effect options.
*
* \return widget that allow user to set effect options.
**/
GtkWidget *create_vbox(Effect *widgets, gint amt, gchar *label)
{
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *widget;
GtkWidget *table;
GtkWidget *container;
GtkWidget *frame;
int x;
int y;
frame = gtk_frame_new(label);
vbox = gtk_vbox_new(FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
table = gtk_table_new(2, amt, FALSE);
gtk_table_set_col_spacings(GTK_TABLE(table), 2);
for (x = 0; x<amt; x++) {
widget = create_on_off_button(list, &widgets[x]);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
if ((widgets[x].id != -1) && (widgets[x].position != -1)) {
widget = create_on_off_button(&widgets[x]);
gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1);
table = create_widget_container(list, widgets[x].group, widgets[x].group_amt);
gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 2);
if (widgets[x].label)
y = 1;
else
y = 0;
} else if (widgets[x].label) {
widget = gtk_label_new(widgets[x].label);
gtk_table_attach_defaults(GTK_TABLE(table), widget, 0, 1, x, x+1);
}
container = create_widget_container(widgets[x].group, widgets[x].group_amt);
gtk_table_attach_defaults(GTK_TABLE(table), container, 1-y, 2-y, x+y, x+y+1);
}
gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 2);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
return vbox;
gtk_container_add(GTK_CONTAINER(frame), vbox);
return frame;
}
enum {
@@ -216,6 +426,14 @@ enum {
NUM_COLUMNS
};
/**
* \param treeview the object which emitted the signal
* \param path the GtkTreePath for the activated row
* \param column the GtkTreeViewColumn in which the activation occurred
* \param model model holding preset names
*
* Sets active device preset to preset selected by user.
**/
void row_activate_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GtkTreeModel *model) {
GtkTreeIter iter;
gint id;
@@ -224,10 +442,19 @@ void row_activate_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, PRESET_NUMBER_COLUMN, &id, PRESET_BANK_COLUMN, &bank, -1);
if ((bank != -1) && (id != -1))
if ((bank != -1) && (id != -1)) {
switch_preset(bank, id);
apply_current_preset();
}
}
/**
* \param model model to fill
* \param bank preset bank
* \param name preset bank description visible to user
*
* Appends to model preset names found in device preset bank.
**/
static void fill_store_with_presets(GtkTreeStore *model, guint bank, gchar *name)
{
GtkTreeIter iter;
@@ -235,6 +462,8 @@ static void fill_store_with_presets(GtkTreeStore *model, guint bank, gchar *name
int x;
GStrv presets = query_preset_names(bank);
g_return_if_fail(presets != NULL);
gtk_tree_store_append(model, &iter, NULL);
gtk_tree_store_set(model, &iter,
PRESET_NAME_COLUMN, name,
@@ -243,22 +472,36 @@ static void fill_store_with_presets(GtkTreeStore *model, guint bank, gchar *name
-1);
for (x=0; x<g_strv_length(presets); x++) {
gchar *tmp = g_strdup_printf("%d - %s", x+1, presets[x]);
gtk_tree_store_append(model, &child_iter, &iter);
gtk_tree_store_set(model, &child_iter,
PRESET_NAME_COLUMN, presets[x],
PRESET_NAME_COLUMN, tmp,
PRESET_NUMBER_COLUMN, x,
PRESET_BANK_COLUMN, bank,
-1);
g_free(tmp);
}
g_strfreev(presets);
}
/**
* \param model model to fill
*
* Fills model with preset names found on device.
**/
static void fill_store(GtkTreeStore *model)
{
fill_store_with_presets(model, PRESETS_USER, "User Presets");
fill_store_with_presets(model, PRESETS_SYSTEM, "System Presets");
}
/**
* Creates treeview showing list of presets available on device.
*
* \return treeview containing all preset names found on device.
**/
GtkWidget *create_preset_tree()
{
GtkWidget *treeview;
@@ -284,6 +527,12 @@ GtkWidget *create_preset_tree()
return treeview;
}
/**
* \param window application toplevel window
* \param default_name default preset name
*
* Shows window allowing user to store current edit buffer.
**/
static void show_store_preset_window(GtkWidget *window, gchar *default_name)
{
GtkWidget *dialog, *cmbox, *entry, *table, *label;
@@ -332,39 +581,22 @@ static void show_store_preset_window(GtkWidget *window, gchar *default_name)
gtk_widget_destroy(dialog);
}
static void apply_widget_setting(WidgetListElem *el, SettingParam *param)
{
if ((el->id == param->id) && (el->position == param->position)) {
if (el->value == -1) {
if (GTK_IS_TOGGLE_BUTTON(el->widget))
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(el->widget), (param->value == 0) ? FALSE : TRUE);
else if (GTK_IS_SPIN_BUTTON(el->widget))
gtk_spin_button_set_value(GTK_SPIN_BUTTON(el->widget), param->value);
} else { /* combo box */
if (el->value == param->value)
gtk_combo_box_set_active(GTK_COMBO_BOX(el->widget), el->x);
}
}
}
static void apply_preset_to_gui(GList *list, Preset *preset)
{
GList *iter = preset->params;
while (iter) {
SettingParam *param = iter->data;
iter = iter->next;
if (param != NULL)
g_list_foreach(list, (GFunc)apply_widget_setting, param);
}
}
/**
* \param action the object which emitted the signal
*
* Shows store preset window.
**/
static void action_store_cb(GtkAction *action)
{
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
show_store_preset_window(window, NULL);
}
/**
* \param action the object which emitted the signal
*
* Shows about dialog.
**/
static void action_show_about_dialog_cb(GtkAction *action)
{
static const gchar * const authors[] = {
@@ -383,6 +615,8 @@ static void action_show_about_dialog_cb(GtkAction *action)
NULL);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
typedef struct {
gchar *name;
gchar *suffix;
@@ -390,9 +624,19 @@ typedef struct {
static SupportedFileTypes file_types[] = {
{"RP250Preset", "*.rp250p"},
{"RP500Preset", "*.rp500p"},
};
static guint n_file_types = G_N_ELEMENTS(file_types);
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/**
* \param action the object which emitted the signal
*
* Shows file chooser dialog.
* If user opens valid preset file, the preset gets applied to edit buffer and store preset window is shown.
**/
static void action_open_preset_cb(GtkAction *action)
{
static GtkWidget *dialog = NULL;
@@ -401,7 +645,6 @@ static void action_open_preset_cb(GtkAction *action)
return;
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
GList **list = g_object_get_data(G_OBJECT(action), "widget-list");
dialog = gtk_file_chooser_dialog_new("Open Preset", GTK_WINDOW(window),
GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -427,27 +670,53 @@ static void action_open_preset_cb(GtkAction *action)
gboolean loaded = FALSE;
while (!loaded && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
GError *error = NULL;
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
Preset *preset = create_preset_from_xml_file(filename);
if (preset != NULL) {
if (list != NULL)
apply_preset_to_gui(*list, preset);
Preset *preset = create_preset_from_xml_file(filename, &error);
if (error) {
show_error_message(window, error->message);
g_error_free(error);
error = NULL;
} else if (preset != NULL) {
apply_preset_to_gui(preset);
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;
/* sending those is likely to freeze/reboot device */
if ((param->id == 8704) || (param->id == 8705))
continue;
g_string_append_printf(msg, "%c%c%c",
((param->id & 0xFF00) >> 8),
(param->id & 0xFF),
param->position);
set_option(param->id, param->position, param->value);
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 */);
send_message(RECEIVE_PRESET_START, start->str, start->len);
send_message(RECEIVE_PRESET_PARAMETERS, msg->str, msg->len);
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;
}
@@ -458,27 +727,35 @@ static void action_open_preset_cb(GtkAction *action)
dialog = NULL;
}
/**
* \param list widget list to be freed
*
* Frees all memory used by widget list.
*/
static void widget_list_free(GList *list)
{
GList *iter;
for (iter = list; iter; iter = iter->next) {
g_free(iter->data);
g_slice_free(WidgetListElem, iter->data);
}
g_list_free(list);
}
/**
* \param action the object which emitted the signal
*
* Destroys action object "window" data, then stops gtk main loop.
**/
static void action_quit_cb(GtkAction *action)
{
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
GList **list = g_object_get_data(G_OBJECT(action), "widget-list");
widget_list_free(*list);
*list = NULL;
gtk_widget_destroy(window);
gtk_main_quit();
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
static GtkActionEntry entries[] = {
{"File", NULL, "_File"},
{"Preset", NULL, "_Preset"},
@@ -507,16 +784,32 @@ static const gchar *menu_info =
" </menubar>"
"</ui>";
static void add_action_data(GtkUIManager *ui, const gchar *path, GtkWidget *window, GList **list)
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/**
* \param ui GtkUIManager to lookup actions
* \param path path to action
* \param window toplevel window
*
* Sets action object "window" data to toplevel window.
**/
static void add_action_data(GtkUIManager *ui, const gchar *path, GtkWidget *window)
{
GtkAction *action;
action = gtk_ui_manager_get_action(ui, path);
g_return_if_fail(action != NULL);
g_object_set_data(G_OBJECT(action), "window", window);
g_object_set_data(G_OBJECT(action), "widget-list", list);
}
static void add_menubar(GList **list, GtkWidget *window, GtkWidget *vbox)
/**
* \param window toplevel window
* \param vbox vbox to hold menubar
*
* Creates menubar (adds accel group to toplevel window as well) and packs it into vbox.
**/
static void add_menubar(GtkWidget *window, GtkWidget *vbox)
{
GtkUIManager *ui;
GtkActionGroup *actions;
@@ -539,22 +832,24 @@ static void add_menubar(GList **list, GtkWidget *window, GtkWidget *vbox)
gtk_ui_manager_get_widget(ui, "/MenuBar"),
FALSE, FALSE, 0);
add_action_data(ui, "/MenuBar/File/Quit", window, list);
add_action_data(ui, "/MenuBar/File/Open", window, list);
add_action_data(ui, "/MenuBar/Preset/Store", window, list);
add_action_data(ui, "/MenuBar/Help/About", window, list);
add_action_data(ui, "/MenuBar/File/Quit", window);
add_action_data(ui, "/MenuBar/File/Open", window);
add_action_data(ui, "/MenuBar/Preset/Store", window);
add_action_data(ui, "/MenuBar/Help/About", window);
g_object_unref(ui);
}
void create_window()
/**
* Creates main window.
**/
void gui_create(EffectList *effects, int n_effects)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *widget;
GtkWidget *sw; /* scrolled window to carry preset treeview */
static GList *list = NULL; /* widget list (every data element is WidgetListElem) */
gint x;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -563,7 +858,7 @@ void create_window()
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
add_menubar(&list, window, vbox);
add_menubar(window, vbox);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(vbox), hbox);
@@ -578,16 +873,85 @@ void create_window()
vbox = gtk_vbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 2);
knob_anim = gtk_knob_animation_new_from_inline(knob_pixbuf);
for (x = 0; x<n_effects; x++) {
if ((x % 3) == 0) {
hbox = gtk_hbox_new(TRUE, 0);
if ((x % ((n_effects+1)/2)) == 0) {
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);
}
widget = create_vbox(&list, effects[x].effect, effects[x].amt);
widget = create_vbox(effects[x].effect, effects[x].amt, effects[x].label);
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
}
apply_current_preset();
gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);
}
/**
* Frees memory allocated by gui_create which is not explicitly freed when main window is destroyed.
**/
void gui_free()
{
widget_list_free(widget_list);
widget_list = NULL;
gtk_knob_animation_free(knob_anim);
knob_anim = NULL;
}
/**
* \param list Variable to hold effect list
* \param n_list Variable to hold length of effect list
*
* Displays dialogbox stating that device is unsupported.
*
* \return TRUE if user selects "compability mode", otherwise FALSE.
**/
gboolean unsupported_device_dialog(EffectList **list, int *n_list)
{
extern SupportedDevices supported_devices[];
extern int n_supported_devices;
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *combo_box;
int x;
dialog = gtk_dialog_new_with_buttons("Unsupported device",
NULL, GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
NULL);
label = gtk_label_new("Your device appears to be unsupported by gdigi.\n"
"As some of the settings may be common between different devices,\n"
"you can now select compability mode with one of the supported devices.\n"
"Please take a look at gdigi's HACKING file.");
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
combo_box = gtk_combo_box_new_text();
for (x=0; x<n_supported_devices; x++) {
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), supported_devices[x].name);
}
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), combo_box);
gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
gint number = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
if (number != -1 && number <n_supported_devices) {
g_message("Starting %s compability mode", supported_devices[number].name);
*list = supported_devices[number].list;
*n_list = supported_devices[number].n_list;
gtk_widget_destroy(dialog);
return TRUE;
}
}
gtk_widget_destroy(dialog);
return FALSE;
}

8
gui.h
View File

@@ -17,6 +17,12 @@
#ifndef GDIGI_GUI_H
#define GDIGI_GUI_H
void create_window();
#include <glib.h>
#include "effects.h"
void show_error_message(GtkWidget *parent, gchar *message);
void gui_create(EffectList *list, int n_list);
void gui_free();
gboolean unsupported_device_dialog(EffectList **list, int *n_list);
#endif /* GDIGI_GUI_H */

BIN
knob.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

112
preset.c
View File

@@ -19,6 +19,8 @@
#include <string.h>
#include "preset.h"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
enum {
PARSER_TYPE_NOT_SET = -1,
PARSER_TYPE_PRESET_NAME = 0,
@@ -51,7 +53,7 @@ static void XMLCALL start(void *data, const char *el, const char **attr) {
if (ad->preset->params != NULL)
g_message("Params aleady exists!");
} else if (g_strcmp0(el, "Param") == 0) {
SettingParam *param = (SettingParam *)g_malloc(sizeof(SettingParam));
SettingParam *param = g_slice_new(SettingParam);
param->id = -1;
param->position = -1;
param->value = -1;
@@ -112,27 +114,34 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
g_free(value);
}
/*
Parses preset file
On success returns Preset which must be freed using preset_free, or NULL on error
*/
Preset *create_preset_from_xml_file(gchar *filename)
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/**
* \param filename valid path to file
* \param error return location for an error
*
* Tries to open file pointed by path, then parses it.
*
* \return Preset which must be freed using preset_free, or NULL on error.
**/
Preset *create_preset_from_xml_file(gchar *filename, GError **error)
{
GFile *file;
GError *error = NULL;
GError *err = NULL;
gchar *contents;
file = g_file_new_for_path(filename);
if (g_file_get_contents(filename, &contents, NULL, &error) == FALSE) {
g_message("Failed to get %s contents: %s", filename, error->message);
g_error_free(error);
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;
}
AppData *ad = (AppData *) g_malloc(sizeof(AppData));
AppData *ad = g_slice_new(AppData);
ad->depth = 0;
ad->preset = g_malloc(sizeof(Preset));
ad->preset = g_slice_new(Preset);
ad->preset->name = NULL;
ad->preset->params = NULL;
ad->id = PARSER_TYPE_NOT_SET;
@@ -144,11 +153,11 @@ Preset *create_preset_from_xml_file(gchar *filename)
XML_SetCharacterDataHandler(p, text_cb);
if (XML_Parse(p, contents, strlen(contents), XML_TRUE) != XML_STATUS_OK) {
g_warning("Parse error at line %d:\n%s",
(int)XML_GetCurrentLineNumber(p),
XML_ErrorString(XML_GetErrorCode(p)));
g_set_error(error, 0, 0, "Parse error at line %d:\n%s",
(int)XML_GetCurrentLineNumber(p),
XML_ErrorString(XML_GetErrorCode(p)));
preset_free(ad->preset);
g_free(ad);
g_slice_free(AppData, ad);
g_free(contents);
g_object_unref(file);
return NULL;
@@ -158,24 +167,89 @@ Preset *create_preset_from_xml_file(gchar *filename)
preset->params = g_list_reverse(preset->params);
XML_ParserFree(p);
g_free(ad);
g_slice_free(AppData, ad);
g_free(contents);
g_object_unref(file);
return preset;
}
/**
* \param data unpacked RECEIVE_PRESET_PARAMETERS message
*
* Parses message
*
* \return Preset which must be freed using preset_free, or NULL on error.
**/
Preset *create_preset_from_data(GString *data)
{
gint total;
gint n;
gint id;
gint position;
guint value;
gint x;
gint tmp;
g_return_val_if_fail(data != NULL, NULL);
x = 0x09;
n = 0;
total = (unsigned char)data->str[x];
x++;
Preset *preset = g_slice_new(Preset);
preset->name = NULL; /* TODO */
preset->params = NULL;
do {
id = ((unsigned char)data->str[x] << 8) | (unsigned char)data->str[x+1];
position = (unsigned 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 |= ((unsigned char)data->str[x+i] << (8*(tmp-i-1)));
}
x+=tmp;
}
n++;
SettingParam *param = g_slice_new(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;
}
/**
* \param preset preset to be freed
*
* Frees all memory used by preset.
**/
void preset_free(Preset *preset)
{
g_return_if_fail(preset != NULL);
if (preset->params != NULL) {
g_list_foreach(preset->params, (GFunc)g_free, NULL);
GList *iter;
for (iter = preset->params; iter; iter = iter->next) {
g_slice_free(SettingParam, iter->data);
}
g_list_free(preset->params);
}
if (preset->name != NULL)
g_free(preset->name);
g_free(preset);
g_slice_free(Preset, preset);
}

View File

@@ -30,7 +30,8 @@ typedef struct {
GList *params;
} Preset;
Preset *create_preset_from_xml_file(gchar *filename);
Preset *create_preset_from_xml_file(gchar *filename, GError **error);
Preset *create_preset_from_data(GString *data);
void preset_free(Preset *preset);
#endif /* GDIGI_PRESET_H */

247
tests.c
View File

@@ -210,9 +210,6 @@ void test_presets()
for (x=0; x<=60; x++)
switch_preset(PRESETS_SYSTEM, x);
for (x=0; x<=99; x++)
set_preset_level(x);
}
void test_pickups()
@@ -480,7 +477,7 @@ void test_chorusfx()
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_BB);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_B);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_C);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_DD);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_DB);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_D);
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_EB);
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_MAJOR);
@@ -620,247 +617,6 @@ void test_reverb()
set_option(REVERB_ON_OFF, REVERB_POSITION, 0);
}
void test_exp()
{
int x;
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_NONE);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PICKUP_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PIKCUP_TYPE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_COMP_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_COMP_SUST);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_COMP_TONE);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_COMP_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_COMP_ATTACK);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DIST_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DIST_DISTORTION);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DIST_FILTER);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DIST_VOLUME);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_AMP_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_AMP_GAIN);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_AMP_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_EQ_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_EQ_BASS);
for (x=0; x<=24; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=24; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_EQ_MID);
for (x=0; x<=24; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=24; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_EQ_TREB);
for (x=0; x<=24; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=24; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_GATE_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_GATE_THRESHOLD);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_GATE_ATTACK);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_GATE_RELEASE);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_GATE_ATTN);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_CHORUSFX_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PHASER_SPEED);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PHASER_DEPTH);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PHASER_REGEN);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PHASER_WAVEFORM);
for (x=0; x<=2; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=2; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_PHASER_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_TIME);
for (x=0; x<=139; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=139; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_REPEATS);
for (x=0; x<=100; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=100; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_DUCK_THRESH);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_DELAY_DUCK_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_REVERB_ENABLE);
for (x=0; x<=1; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=1; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_REVERB_LEVEL);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_VOLUME_PRE_FX);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
set_option(EXP_TYPE, EXP_POSITION, EXP_TYPE_VOLUME_POST_FX);
for (x=0; x<=99; x++)
set_option(EXP_MIN, EXP_POSITION, x);
for (x=0; x<=99; x++)
set_option(EXP_MAX, EXP_POSITION, x);
}
void test_usb()
{
int x;
@@ -884,6 +640,5 @@ void test_all()
test_chorusfx();
test_delay();
test_reverb();
test_exp();
test_usb();
}

View File

@@ -29,7 +29,6 @@ void test_noisegate();
void test_chorusfx();
void test_delay();
void test_reverb();
void test_exp();
void test_usb();
void test_all();