Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9778dc47c3 | ||
|
|
71c3a1e66f | ||
|
|
bdb35ddf54 | ||
|
|
4ca140ab48 | ||
|
|
d2f821eee1 | ||
|
|
e607c6cf37 | ||
|
|
dc66db841a | ||
|
|
e80683aea2 | ||
|
|
b7d2d7d1c5 | ||
|
|
cd5d7387f3 | ||
|
|
8a39a178c6 | ||
|
|
40ebcfaf16 | ||
|
|
de68d0449f | ||
|
|
d280bf1ca6 | ||
|
|
b245e1bac6 | ||
|
|
8d7fffb6d1 | ||
|
|
f8e35ff685 | ||
|
|
3f717a51cd | ||
|
|
90df427200 | ||
|
|
322c59032e | ||
|
|
1b1919649e | ||
|
|
e7c7efe857 | ||
|
|
17b067f853 | ||
|
|
8ec3d6579c | ||
|
|
5bd6f8fc2c | ||
|
|
c61c2372ae | ||
|
|
49b7f42012 | ||
|
|
157fba0380 | ||
|
|
904a30bb38 | ||
|
|
8e445bb408 | ||
|
|
eb48d0b9d2 | ||
|
|
baa3829263 | ||
|
|
79554a99ce | ||
|
|
4740bef10f | ||
|
|
968d2947a7 | ||
|
|
e2cb03ab32 | ||
|
|
ce5fe3fe0c | ||
|
|
966fc748af | ||
|
|
709406f3ef | ||
|
|
ce522227c7 | ||
|
|
7d13b2a7ea | ||
|
|
d4c86b3a60 | ||
|
|
ca23f2c94c | ||
|
|
bfc285ad0f | ||
|
|
4e5f2438d3 | ||
|
|
10aac46dde |
17
Makefile
17
Makefile
@@ -1,7 +1,7 @@
|
||||
CC = gcc
|
||||
CFLAGS = `pkg-config --cflags glib-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 gtk+-2.0 alsa`
|
||||
LIBS = `pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 alsa` -lexpat
|
||||
|
||||
.SUFFIXES : .o .c
|
||||
.c.o :
|
||||
@@ -9,8 +9,8 @@ LIBS = `pkg-config --libs glib-2.0 gtk+-2.0 alsa`
|
||||
|
||||
all: gdigi
|
||||
|
||||
gdigi: gdigi.o tests.o gui.o effects.o
|
||||
$(CC) $(LIBS) $(OFLAG) gdigi gdigi.o tests.o gui.o effects.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
|
||||
|
||||
@@ -20,6 +20,15 @@ gui.o: gui.c
|
||||
|
||||
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
|
||||
|
||||
|
||||
2
README
2
README
@@ -1,4 +1,4 @@
|
||||
Requirments: alsa, gtk+, glib
|
||||
Requirments: alsa, gtk+, glib, expat
|
||||
|
||||
Getting started guide:
|
||||
-to compile: make
|
||||
|
||||
12
TODO
12
TODO
@@ -1,10 +1,6 @@
|
||||
-figure out all magic commands
|
||||
-make complete gui
|
||||
-amp/cabinet models
|
||||
-tone library
|
||||
-effects library
|
||||
-effects level
|
||||
-handling presets (loading, saving, exporting/importing to/from xml patches)
|
||||
-buildsystem
|
||||
-figure out how to get current device settings, start gui with proper values
|
||||
-fix expression pedal settings (possible types depend on active preset)
|
||||
-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
|
||||
|
||||
36
effects.h
36
effects.h
@@ -14,28 +14,36 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_EFFECTS_H
|
||||
#define GDIGI_EFFECTS_H
|
||||
|
||||
#include <glib/gtypes.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) */
|
||||
guint type; /* value (type) */
|
||||
gchar *label; /* Effect name */
|
||||
guint option; /* ID (to set effect type) */
|
||||
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) */
|
||||
gchar *label; /* Base effect name */
|
||||
guint id; /* ID (to set effect on/off) */
|
||||
guint position; /* position */
|
||||
EffectGroup *group; /* possible effect types */
|
||||
gint group_amt; /* possible effect types length */
|
||||
@@ -45,3 +53,13 @@ typedef struct {
|
||||
Effect *effect; /* list of supported effects */
|
||||
gint amt; /* list of supported effects length */
|
||||
} EffectList;
|
||||
|
||||
typedef struct {
|
||||
EffectGroup *group;
|
||||
gint group_amt;
|
||||
} ModifierGroup;
|
||||
|
||||
ModifierGroup *modifier_linkable_list();
|
||||
void modifier_group_free(ModifierGroup *modifier_group);
|
||||
|
||||
#endif /* GDIGI_EFFECTS_H */
|
||||
|
||||
677
gdigi.c
677
gdigi.c
@@ -18,43 +18,51 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <string.h>
|
||||
#include <alloca.h>
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
|
||||
static snd_rawmidi_t *output;
|
||||
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)
|
||||
/**
|
||||
* calculate_checksum:
|
||||
* @array: data to calculate checksum
|
||||
* @length: data length
|
||||
*
|
||||
* Calculates message checksum
|
||||
*
|
||||
* Return value: 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
|
||||
*/
|
||||
/**
|
||||
* open_device:
|
||||
*
|
||||
* Opens MIDI device. This function modifies global input and output variables.
|
||||
*
|
||||
* Return value: FALSE on success, TRUE on error.
|
||||
**/
|
||||
gboolean open_device()
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_open(NULL, &output, device, SND_RAWMIDI_NONBLOCK);
|
||||
err = snd_rawmidi_open(&input, &output, device, SND_RAWMIDI_NONBLOCK);
|
||||
if (err) {
|
||||
fprintf(stderr, "snd_rawmidi_open %s failed: %d\n", device, err);
|
||||
return TRUE;
|
||||
@@ -65,186 +73,525 @@ gboolean open_device()
|
||||
fprintf(stderr, "snd_rawmidi_nonblock failed: %d\n", err);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
snd_rawmidi_read(input, NULL, 0); /* trigger reading */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* send_data:
|
||||
* @data: data to be sent
|
||||
* @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);
|
||||
}
|
||||
|
||||
/*
|
||||
id - ID as found in preset file
|
||||
position - Position as found in preset file
|
||||
value - Value as found in preset file
|
||||
*/
|
||||
/**
|
||||
* pack_data:
|
||||
* @data: data to be packed
|
||||
* @len: data length
|
||||
*
|
||||
* Packs data using method used on all newer DigiTech products.
|
||||
*
|
||||
* Return value: 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* unpack_message:
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* read_data:
|
||||
*
|
||||
* Reads data from MIDI IN. This function uses global input variable.
|
||||
*
|
||||
* Return value: 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;
|
||||
|
||||
npfds = snd_rawmidi_poll_descriptors_count(input);
|
||||
pfds = alloca(npfds * sizeof(struct pollfd));
|
||||
snd_rawmidi_poll_descriptors(input, pfds, npfds);
|
||||
|
||||
do {
|
||||
char buf[20];
|
||||
int i, length;
|
||||
unsigned short revents;
|
||||
|
||||
err = poll(pfds, npfds, 200);
|
||||
if (err < 0 && errno == EINTR)
|
||||
break;
|
||||
if (err < 0) {
|
||||
g_error("poll failed: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
if ((err = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) {
|
||||
g_error("cannot get poll events: %s", snd_strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (revents & (POLLERR | POLLHUP))
|
||||
break;
|
||||
if (!(revents & POLLIN))
|
||||
continue;
|
||||
|
||||
err = snd_rawmidi_read(input, buf, sizeof(buf));
|
||||
if (err == -EAGAIN)
|
||||
continue;
|
||||
if (err < 0) {
|
||||
g_error("cannot read: %s", snd_strerror(err));
|
||||
break;
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for (i = 0; i < err; ++i)
|
||||
if (buf[i] != 0xFE) /* ignore active sensing */
|
||||
buf[length++] = buf[i];
|
||||
|
||||
if ((unsigned char)buf[length-1] == 0xF7)
|
||||
stop = TRUE;
|
||||
|
||||
if (length != 0) {
|
||||
if (string == NULL) {
|
||||
string = g_string_new_len(buf, length);
|
||||
} else {
|
||||
string = g_string_append_len(string, buf, length);
|
||||
}
|
||||
}
|
||||
} while ((err != 0) && (stop == FALSE));
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* send_message:
|
||||
* @procedure: procedure ID
|
||||
* @data: unpacked message data
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_message_id:
|
||||
* @msg: SysEx message
|
||||
*
|
||||
* Checks message ID.
|
||||
*
|
||||
* Return value: MessageID, or -1 on error.
|
||||
**/
|
||||
static MessageID get_message_id(GString *msg)
|
||||
{
|
||||
/* TODO: sanity checks */
|
||||
g_return_val_if_fail(msg != NULL, -1);
|
||||
|
||||
if (msg->len > 7) {
|
||||
return (unsigned char)msg->str[7];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_message_by_id:
|
||||
* @id: MessageID of requested message
|
||||
*
|
||||
* Reads data from MIDI IN until message with matching id is found.
|
||||
*
|
||||
* Return value: 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* append_value:
|
||||
* @msg: message to append value
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set_option:
|
||||
* @id: Parameter ID
|
||||
* @position: Parameter position
|
||||
* @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 */
|
||||
void switch_user_preset(int x)
|
||||
/**
|
||||
* switch_preset:
|
||||
* @bank: preset bank
|
||||
* @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, 0x01 /* bank = user */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
|
||||
|
||||
switch_preset[11] = x;
|
||||
switch_preset[16] = calculate_checksum(switch_preset, sizeof(switch_preset), 16);
|
||||
|
||||
send_data(switch_preset, sizeof(switch_preset));
|
||||
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);
|
||||
}
|
||||
|
||||
/* x = 0 to 60 */
|
||||
void switch_system_preset(int x)
|
||||
/**
|
||||
* store_preset_name:
|
||||
* @x: preset index
|
||||
* @name: preset name
|
||||
*
|
||||
* Stores current edit buffer in user presets bank.
|
||||
**/
|
||||
void store_preset_name(int x, const gchar *name)
|
||||
{
|
||||
static char switch_preset[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x39, 0x00, 0x00 /* bank = system */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
|
||||
|
||||
switch_preset[11] = x;
|
||||
switch_preset[16] = calculate_checksum(switch_preset, sizeof(switch_preset), 16);
|
||||
|
||||
send_data(switch_preset, sizeof(switch_preset));
|
||||
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);
|
||||
}
|
||||
|
||||
/* level = 0 to 99 */
|
||||
void set_preset_level(int level)
|
||||
{
|
||||
set_option(PRESET_LEVEL, PRESET_POSITION, level);
|
||||
}
|
||||
|
||||
/* x = 0 to 59 (preset number) */
|
||||
/**
|
||||
* set_preset_name:
|
||||
* @x: preset index
|
||||
* @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);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
gtk_init(&argc, &argv);
|
||||
/**
|
||||
* query_preset_names:
|
||||
* @bank: preset bank
|
||||
*
|
||||
* Queries preset names.
|
||||
*
|
||||
* Return value: 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 */
|
||||
int n = 0; /* current preset number */
|
||||
int n_total; /* total number of presets */
|
||||
gchar **str_array = NULL;
|
||||
|
||||
int c;
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
{"device", required_argument, 0, 'd'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "d:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
/* query user preset names */
|
||||
send_message(REQUEST_PRESET_NAMES, &bank, 1);
|
||||
|
||||
switch(c) {
|
||||
case 'd':
|
||||
device = optarg;
|
||||
/* read reply */
|
||||
data = get_message_by_id(RECEIVE_PRESET_NAMES);
|
||||
|
||||
if (data != NULL) {
|
||||
if (data->len >= 10) {
|
||||
n_total = data->str[9];
|
||||
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;
|
||||
default:
|
||||
abort();
|
||||
|
||||
str_array[n] = g_strdup(&data->str[x]);
|
||||
x += strlen(str_array[n]);
|
||||
n++;
|
||||
}
|
||||
g_string_free(data, TRUE);
|
||||
}
|
||||
return str_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_current_preset:
|
||||
*
|
||||
* Queries current edit buffer.
|
||||
*
|
||||
* Return value: 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* request_who_am_i:
|
||||
* @device_id: Variable to hold device ID
|
||||
* @family_id: Variable to hold family ID
|
||||
* @product_id: Variable to hold product ID
|
||||
*
|
||||
* Requests device information.
|
||||
*
|
||||
* Return value: 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
context = g_option_context_new(NULL);
|
||||
g_option_context_add_main_entries(context, options, NULL);
|
||||
g_option_context_add_group(context, gtk_get_option_group(TRUE));
|
||||
|
||||
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
||||
g_message("option parsing failed: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
g_option_context_free(context);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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 - is it connected?");
|
||||
} else {
|
||||
gui_create();
|
||||
gtk_main();
|
||||
gui_free();
|
||||
}
|
||||
}
|
||||
|
||||
if (output != NULL)
|
||||
snd_rawmidi_close(output);
|
||||
if (input != NULL)
|
||||
snd_rawmidi_close(input);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
248
gdigi.h
248
gdigi.h
@@ -14,7 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_H
|
||||
#define GDIGI_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
enum {
|
||||
WAH_TYPE_CRY = 132,
|
||||
@@ -121,6 +125,31 @@ enum {
|
||||
#define PRESET_POSITION 18
|
||||
#define PRESET_LEVEL 2626
|
||||
|
||||
enum {
|
||||
AMP_TYPE_TWEED_CHAMP = 307,
|
||||
AMP_TYPE_TWEED_DELUXE = 308,
|
||||
AMP_TYPE_TWEED_BASSMAN = 309,
|
||||
AMP_TYPE_BLACKFACE_TWIN = 311,
|
||||
AMP_TYPE_BLACKFACE_DELUXE = 312,
|
||||
AMP_TYPE_SUPER_LEAD_PLEXI = 314,
|
||||
AMP_TYPE_MASTER_VOLUME = 316,
|
||||
AMP_TYPE_JCM800 = 317,
|
||||
AMP_TYPE_JCM900 = 318,
|
||||
AMP_TYPE_AC15 = 322,
|
||||
AMP_TYPE_AC30TB = 323,
|
||||
AMP_TYPE_HIWATT_100 = 324,
|
||||
AMP_TYPE_BOOGIE_MARK_II = 320,
|
||||
AMP_TYPE_DUAL_RECTIFIER = 321,
|
||||
AMP_TYPE_MATCHLESS_HC30 = 326,
|
||||
AMP_TYPE_SOLO = 331,
|
||||
AMP_TYPE_METAL = 332,
|
||||
AMP_TYPE_BRIGHT = 333,
|
||||
AMP_TYPE_CLEAN = 335,
|
||||
AMP_TYPE_HIGH_GAIN = 337,
|
||||
AMP_TYPE_ACOUSTIC = 341,
|
||||
AMP_TYPE_DIRECT = 306
|
||||
};
|
||||
|
||||
enum {
|
||||
EQ_TYPE_BRIGHT = 1474,
|
||||
EQ_TYPE_MIDBOOST = 1472,
|
||||
@@ -128,11 +157,33 @@ enum {
|
||||
EQ_TYPE_WARM = 1475
|
||||
};
|
||||
|
||||
#define AMP_TYPE 2496
|
||||
#define AMP_ON_OFF 265
|
||||
#define AMP_POSITION 8
|
||||
|
||||
#define AMP_GAIN 2497
|
||||
#define AMP_LEVEL 2498
|
||||
|
||||
#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_TWIN 576
|
||||
#define AMP_CAB_BRITISH2_12 613
|
||||
#define AMP_CAB_BASSMAN 579
|
||||
#define AMP_CAB_BRITISH4_12 614
|
||||
#define AMP_CAB_BRITISH_GREEN 616
|
||||
#define AMP_CAB_VINTAGE 622
|
||||
#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 EQ_TYPE 3202
|
||||
#define EQ_ON_OFF 3212
|
||||
#define EQ_POSITION 24
|
||||
@@ -317,7 +368,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
|
||||
|
||||
@@ -405,60 +456,165 @@ 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
|
||||
|
||||
typedef enum {
|
||||
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_user_preset(int x);
|
||||
void switch_system_preset(int x);
|
||||
void switch_preset(guint bank, guint x);
|
||||
void store_preset_name(int x, const gchar *name);
|
||||
void set_preset_level(int level);
|
||||
GStrv query_preset_names(gchar bank);
|
||||
GString *get_current_preset();
|
||||
|
||||
#endif /* GDIGI_H */
|
||||
|
||||
918
gtkknob.c
Normal file
918
gtkknob.c
Normal file
@@ -0,0 +1,918 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <gtk/gtkmain.h>
|
||||
#include <gtk/gtksignal.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()
|
||||
*
|
||||
*****************************************************************************/
|
||||
guint
|
||||
gtk_knob_get_type(void) {
|
||||
static guint knob_type = 0;
|
||||
|
||||
if (!knob_type) {
|
||||
GtkTypeInfo knob_info = {
|
||||
"GtkKnob",
|
||||
sizeof (GtkKnob),
|
||||
sizeof (GtkKnobClass),
|
||||
(GtkClassInitFunc) gtk_knob_class_init,
|
||||
(GtkObjectInitFunc) gtk_knob_init,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
knob_type = gtk_type_unique (gtk_widget_get_type (), &knob_info);
|
||||
}
|
||||
|
||||
return knob_type;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* gtk_knob_class_init()
|
||||
*
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_class_init (GtkKnobClass *class) {
|
||||
GtkObjectClass *object_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
|
||||
object_class = (GtkObjectClass*) class;
|
||||
widget_class = (GtkWidgetClass*) class;
|
||||
|
||||
parent_class = gtk_type_class (gtk_widget_get_type ());
|
||||
|
||||
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 = gtk_type_new (gtk_knob_get_type ());
|
||||
|
||||
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);
|
||||
|
||||
if (knob->adjustment) {
|
||||
gtk_object_unref (GTK_OBJECT (knob->adjustment));
|
||||
knob->adjustment = NULL;
|
||||
}
|
||||
/* FIXME: needs ref counting for automatic GtkKnobAnim cleanup
|
||||
if (knob->anim) {
|
||||
gtk_knob_anim_unref (knob->anim);
|
||||
knob->anim = NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
if (knob->mask) {
|
||||
gdk_bitmap_unref (knob->mask);
|
||||
knob->mask = NULL;
|
||||
}
|
||||
|
||||
if (knob->mask_gc) {
|
||||
gdk_gc_unref (knob->mask_gc);
|
||||
knob->mask_gc = NULL;
|
||||
}
|
||||
if (knob->red_gc) {
|
||||
gdk_gc_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) {
|
||||
gtk_signal_disconnect_by_data (GTK_OBJECT (knob->adjustment),
|
||||
(gpointer)knob);
|
||||
gtk_object_unref (GTK_OBJECT (knob->adjustment));
|
||||
}
|
||||
|
||||
knob->adjustment = adjustment;
|
||||
gtk_object_ref (GTK_OBJECT (knob->adjustment));
|
||||
gtk_object_sink (GTK_OBJECT (knob->adjustment));
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
|
||||
GTK_SIGNAL_FUNC (gtk_knob_adjustment_changed),
|
||||
(gpointer)knob);
|
||||
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
|
||||
GTK_SIGNAL_FUNC (gtk_knob_adjustment_value_changed),
|
||||
(gpointer)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);
|
||||
|
||||
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);
|
||||
|
||||
knob = GTK_KNOB (widget);
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
knob->adjustment->value += knob->adjustment->step_increment;
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (knob->adjustment),
|
||||
"value_changed");
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
knob->adjustment->value -= knob->adjustment->step_increment;
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (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);
|
||||
|
||||
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);
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (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);
|
||||
|
||||
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)
|
||||
{
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (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);
|
||||
|
||||
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);
|
||||
|
||||
if (knob->policy == GTK_UPDATE_DELAYED) {
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (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) {
|
||||
|
||||
if (knob->policy == GTK_UPDATE_CONTINUOUS) {
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (knob->adjustment),
|
||||
"value_changed");
|
||||
}
|
||||
else {
|
||||
gtk_widget_draw (GTK_WIDGET (knob), NULL);
|
||||
|
||||
if (knob->policy == GTK_UPDATE_DELAYED) {
|
||||
if (knob->timer) {
|
||||
gtk_timeout_remove (knob->timer);
|
||||
}
|
||||
knob->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
|
||||
(GtkFunction) 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));
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
gtk_signal_emit_by_name (GTK_OBJECT (knob->adjustment),
|
||||
"value_changed");
|
||||
}
|
||||
|
||||
gtk_widget_draw (GTK_WIDGET (knob), NULL);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
104
gtkknob.h
Normal file
104
gtkknob.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 <gdk/gdk.h>
|
||||
#include <gtk/gtkadjustment.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define GTK_KNOB(obj) GTK_CHECK_CAST(obj, gtk_knob_get_type(), GtkKnob)
|
||||
#define GTK_KNOB_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_knob_get_type(), GtkKnobClass)
|
||||
#define GTK_IS_KNOB(obj) GTK_CHECK_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 guint 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
|
||||
717
gui.c
717
gui.c
@@ -18,62 +18,257 @@
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
#include "effects.h"
|
||||
#include "preset.h"
|
||||
#include "gtkknob.h"
|
||||
#include "knob.h"
|
||||
|
||||
extern EffectList effects[];
|
||||
extern int n_effects;
|
||||
|
||||
void value_changed_option_cb(GtkSpinButton *spinbutton, EffectSettings *setting)
|
||||
typedef struct {
|
||||
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 */
|
||||
} WidgetListElem;
|
||||
|
||||
static GtkKnobAnim *knob_anim = NULL; /* animation used by knobs */
|
||||
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 */
|
||||
|
||||
/**
|
||||
* show_error_message:
|
||||
* @parent: transient parent, or NULL for none
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* value_changed_option_cb:
|
||||
* @adj: the object which emitted the signal
|
||||
* @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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* toggled_cb:
|
||||
* @button: the object which emitted the signal
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* widget_list_add:
|
||||
* @widget: GtkObject to add to widget list
|
||||
* @id: object controlled ID
|
||||
* @position: object controlled position
|
||||
* @value: effect value type (if widget is GtkComboBox, otherwise -1)
|
||||
* @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_slice_new(WidgetListElem);
|
||||
el->widget = widget;
|
||||
el->id = id;
|
||||
el->position = position;
|
||||
el->value = value;
|
||||
el->x = x;
|
||||
|
||||
widget_list = g_list_prepend(widget_list, el);
|
||||
}
|
||||
|
||||
/**
|
||||
* apply_widget_setting:
|
||||
* @el: widget list element
|
||||
* @param: parameter to set
|
||||
*
|
||||
* Sets widget list element value to param value.
|
||||
**/
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* apply_preset_to_gui:
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply_current_preset:
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* create_table:
|
||||
* @settings: effect parameters
|
||||
* @amt: amount of effect parameters
|
||||
*
|
||||
* Creates knobs that allow user to set effect parameters.
|
||||
*
|
||||
* Return value: GtkTable containing necessary widgets to set effect parameters.
|
||||
**/
|
||||
GtkWidget *create_table(EffectSettings *settings, gint amt)
|
||||
{
|
||||
GtkWidget *table, *label, *widget;
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* create_on_off_button:
|
||||
* @effect: Effect that can be turned on/off
|
||||
*
|
||||
* Creates toggle button that allow user to turn effect on/off.
|
||||
*
|
||||
* Return value: GtkToggleButton
|
||||
**/
|
||||
GtkWidget *create_on_off_button(Effect *effect)
|
||||
{
|
||||
GtkWidget *button = gtk_toggle_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(GTK_OBJECT(button), effect->id, effect->position, -1, -1);
|
||||
return button;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gint id; /* effect group ID (value) */
|
||||
gint option; /* option ID */
|
||||
gint type; /* effect group type (value) */
|
||||
gint id; /* option ID */
|
||||
gint position; /* position */
|
||||
GtkWidget *child; /* child widget */
|
||||
} EffectSettingsGroup;
|
||||
|
||||
/**
|
||||
* effect_settings_group_free:
|
||||
* @group: group to be freed
|
||||
*
|
||||
* Frees all memory used by group
|
||||
**/
|
||||
void effect_settings_group_free(EffectSettingsGroup *group)
|
||||
{
|
||||
/* destroy widget without parent */
|
||||
@@ -81,9 +276,16 @@ void effect_settings_group_free(EffectSettingsGroup *group)
|
||||
gtk_widget_destroy(group->child);
|
||||
|
||||
g_object_unref(group->child);
|
||||
g_free(group);
|
||||
g_slice_free(EffectSettingsGroup, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* combo_box_changed_cb:
|
||||
* @widget: the object which emitted the signal
|
||||
* @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;
|
||||
@@ -100,8 +302,8 @@ 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) {
|
||||
@@ -113,6 +315,15 @@ void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create_widget_container:
|
||||
* @group: Effect type groups
|
||||
* @amt: amount of effect groups
|
||||
*
|
||||
* Creates widget allowing user to choose effect type.
|
||||
*
|
||||
* Return value: widget that allow user to set effect type.
|
||||
**/
|
||||
GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
@@ -139,11 +350,12 @@ GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
widget = create_table(group[x].settings, group[x].settings_amt);
|
||||
g_object_ref_sink(widget);
|
||||
|
||||
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(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));
|
||||
@@ -155,8 +367,17 @@ GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
}
|
||||
|
||||
return vbox;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* create_vbox:
|
||||
* @widgets: Effect descriptions
|
||||
* @amt: amount of effect descriptions
|
||||
*
|
||||
* Creates vbox containing widgets allowing user to set effect options.
|
||||
*
|
||||
* Return value: widget that allow user to set effect options.
|
||||
**/
|
||||
GtkWidget *create_vbox(Effect *widgets, gint amt)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
@@ -182,21 +403,460 @@ GtkWidget *create_vbox(Effect *widgets, gint amt)
|
||||
return vbox;
|
||||
}
|
||||
|
||||
void create_window()
|
||||
enum {
|
||||
PRESET_NAME_COLUMN = 0,
|
||||
PRESET_NUMBER_COLUMN,
|
||||
PRESET_BANK_COLUMN,
|
||||
NUM_COLUMNS
|
||||
};
|
||||
|
||||
/**
|
||||
* row_activate_cb:
|
||||
* @treeview: the object which emitted the signal
|
||||
* @path: the GtkTreePath for the activated row
|
||||
* @column: the GtkTreeViewColumn in which the activation occurred
|
||||
* @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;
|
||||
gint bank;
|
||||
|
||||
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)) {
|
||||
switch_preset(bank, id);
|
||||
apply_current_preset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_store_with_presets:
|
||||
* @model: model to fill
|
||||
* @bank: preset bank
|
||||
* @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;
|
||||
GtkTreeIter child_iter;
|
||||
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,
|
||||
PRESET_NUMBER_COLUMN, -1,
|
||||
PRESET_BANK_COLUMN, -1,
|
||||
-1);
|
||||
|
||||
for (x=0; x<g_strv_length(presets); x++) {
|
||||
gtk_tree_store_append(model, &child_iter, &iter);
|
||||
gtk_tree_store_set(model, &child_iter,
|
||||
PRESET_NAME_COLUMN, presets[x],
|
||||
PRESET_NUMBER_COLUMN, x,
|
||||
PRESET_BANK_COLUMN, bank,
|
||||
-1);
|
||||
}
|
||||
g_strfreev(presets);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_store:
|
||||
* @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");
|
||||
}
|
||||
|
||||
/**
|
||||
* create_preset_tree:
|
||||
*
|
||||
* Creates treeview showing list of presets available on device.
|
||||
*
|
||||
* Return value: treeview containing all preset names found on device.
|
||||
**/
|
||||
GtkWidget *create_preset_tree()
|
||||
{
|
||||
GtkWidget *treeview;
|
||||
GtkTreeStore *store;
|
||||
GtkCellRenderer *renderer;
|
||||
|
||||
store = gtk_tree_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
|
||||
fill_store(store);
|
||||
|
||||
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
g_object_unref(store);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "Preset name",
|
||||
renderer, "text",
|
||||
PRESET_NAME_COLUMN, NULL);
|
||||
|
||||
g_object_set(G_OBJECT(treeview), "headers-visible", FALSE, NULL);
|
||||
g_signal_connect(G_OBJECT(treeview), "realize", G_CALLBACK(gtk_tree_view_expand_all), NULL);
|
||||
g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(row_activate_cb), GTK_TREE_MODEL(store));
|
||||
|
||||
return treeview;
|
||||
}
|
||||
|
||||
/**
|
||||
* show_store_preset_window:
|
||||
* @window: application toplevel window
|
||||
* @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;
|
||||
GStrv names;
|
||||
int x;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons("Store preset",
|
||||
GTK_WINDOW(window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
table = gtk_table_new(2, 2, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
|
||||
|
||||
cmbox = gtk_combo_box_new_text();
|
||||
names = query_preset_names(PRESETS_USER);
|
||||
for (x=0; x<g_strv_length(names); x++) {
|
||||
gchar *title = g_strdup_printf("%d - %s", x+1, names[x]);
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(cmbox), title);
|
||||
g_free(title);
|
||||
}
|
||||
g_strfreev(names);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), cmbox, 1, 2, 0, 1);
|
||||
|
||||
entry = gtk_entry_new();
|
||||
if (default_name != NULL)
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), default_name);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2);
|
||||
|
||||
label = gtk_label_new("Preset slot:");
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
|
||||
|
||||
label = gtk_label_new("Preset name:");
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
|
||||
|
||||
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(cmbox));
|
||||
if (number != -1) {
|
||||
store_preset_name(number, gtk_entry_get_text(GTK_ENTRY(entry)));
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* action_store_cb:
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* action_show_about_dialog_cb:
|
||||
* @action: the object which emitted the signal
|
||||
*
|
||||
* Shows about dialog.
|
||||
**/
|
||||
static void action_show_about_dialog_cb(GtkAction *action)
|
||||
{
|
||||
static const gchar * const authors[] = {
|
||||
"Tomasz Moń <desowin@gmail.com>",
|
||||
NULL
|
||||
};
|
||||
static const gchar copyright[] = "Copyright \xc2\xa9 2009 Tomasz Moń";
|
||||
static const gchar website[] = "http://desowin.org/gdigi/";
|
||||
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
|
||||
gtk_show_about_dialog(GTK_WINDOW(window),
|
||||
"authors", authors,
|
||||
"copyright", copyright,
|
||||
"website", website,
|
||||
NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
gchar *suffix;
|
||||
} SupportedFileTypes;
|
||||
|
||||
static SupportedFileTypes file_types[] = {
|
||||
{"RP250Preset", "*.rp250p"},
|
||||
};
|
||||
static guint n_file_types = G_N_ELEMENTS(file_types);
|
||||
|
||||
/**
|
||||
* action_open_preset_cb:
|
||||
* @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;
|
||||
|
||||
if (dialog != NULL)
|
||||
return;
|
||||
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new("Open Preset", GTK_WINDOW(window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
GtkFileFilter *filter;
|
||||
filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "All Supported Types");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
|
||||
int x;
|
||||
for (x=0; x<n_file_types; x++) {
|
||||
GtkFileFilter *current_filter = gtk_file_filter_new();
|
||||
|
||||
gtk_file_filter_set_name(current_filter, file_types[x].name);
|
||||
gtk_file_filter_add_pattern(current_filter, file_types[x].suffix);
|
||||
gtk_file_filter_add_pattern(filter, file_types[x].suffix);
|
||||
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), current_filter);
|
||||
}
|
||||
|
||||
gboolean loaded = FALSE;
|
||||
while (!loaded && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
Preset *preset = create_preset_from_xml_file(filename);
|
||||
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;
|
||||
|
||||
g_string_append_printf(msg, "%c%c%c",
|
||||
((param->id & 0xFF00) >> 8),
|
||||
(param->id & 0xFF),
|
||||
param->position);
|
||||
|
||||
append_value(msg, param->value);
|
||||
};
|
||||
|
||||
GString *start = g_string_new(NULL);
|
||||
g_string_append_printf(start,
|
||||
"%c%c%s%c%c%c",
|
||||
PRESETS_EDIT_BUFFER, 0,
|
||||
preset->name, 0 /* NULL terminated string */,
|
||||
0 /* modified */, 2 /* messages to follow */);
|
||||
|
||||
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;
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
dialog = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* widget_list_free:
|
||||
* @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_slice_free(WidgetListElem, iter->data);
|
||||
}
|
||||
g_list_free(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* action_quit_cb:
|
||||
* @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");
|
||||
|
||||
gtk_widget_destroy(window);
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
static GtkActionEntry entries[] = {
|
||||
{"File", NULL, "_File"},
|
||||
{"Preset", NULL, "_Preset"},
|
||||
{"Help", NULL, "_Help"},
|
||||
{"Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open preset file", G_CALLBACK(action_open_preset_cb)},
|
||||
{"Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q", "Quit", G_CALLBACK(action_quit_cb)},
|
||||
{"Store", NULL, "_Store", "<control>S", "Store", G_CALLBACK(action_store_cb)},
|
||||
{"About", GTK_STOCK_ABOUT, "_About", "<control>A", "About", G_CALLBACK(action_show_about_dialog_cb)},
|
||||
};
|
||||
static guint n_entries = G_N_ELEMENTS(entries);
|
||||
|
||||
static const gchar *menu_info =
|
||||
"<ui>"
|
||||
" <menubar name='MenuBar'>"
|
||||
" <menu action='File'>"
|
||||
" <menuitem action='Open'/>"
|
||||
" <separator/>"
|
||||
" <menuitem action='Quit'/>"
|
||||
" </menu>"
|
||||
" <menu action='Preset'>"
|
||||
" <menuitem action='Store'/>"
|
||||
" </menu>"
|
||||
" <menu action='Help'>"
|
||||
" <menuitem action='About'/>"
|
||||
" </menu>"
|
||||
" </menubar>"
|
||||
"</ui>";
|
||||
|
||||
/**
|
||||
* add_action_data:
|
||||
* @ui: GtkUIManager to lookup actions
|
||||
* @path: path to action
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* add_menubar:
|
||||
* @window: toplevel window
|
||||
* @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;
|
||||
GError *error = NULL;
|
||||
|
||||
actions = gtk_action_group_new("Actions");
|
||||
gtk_action_group_add_actions(actions, entries, n_entries, NULL);
|
||||
|
||||
ui = gtk_ui_manager_new();
|
||||
gtk_ui_manager_insert_action_group(ui, actions, 0);
|
||||
g_object_unref(actions);
|
||||
gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui));
|
||||
|
||||
if (!gtk_ui_manager_add_ui_from_string(ui, menu_info, -1, &error)) {
|
||||
g_message("building menus failed: %s", error->message);
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
gtk_box_pack_start(GTK_BOX(vbox),
|
||||
gtk_ui_manager_get_widget(ui, "/MenuBar"),
|
||||
FALSE, FALSE, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* gui_create:
|
||||
*
|
||||
* Creates main window.
|
||||
**/
|
||||
void gui_create()
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *sw; /* scrolled window to carry preset treeview */
|
||||
gint x;
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "gdigi");
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
||||
|
||||
add_menubar(window, vbox);
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), hbox);
|
||||
|
||||
sw = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), sw, FALSE, FALSE, 0);
|
||||
|
||||
widget = create_preset_tree();
|
||||
gtk_container_add(GTK_CONTAINER(sw), widget);
|
||||
|
||||
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 % 2) == 0) {
|
||||
if ((x % 3) == 0) {
|
||||
hbox = gtk_hbox_new(TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);
|
||||
}
|
||||
@@ -204,7 +864,22 @@ void create_window()
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* gui_free:
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
9
gui.h
9
gui.h
@@ -14,4 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
void create_window();
|
||||
#ifndef GDIGI_GUI_H
|
||||
#define GDIGI_GUI_H
|
||||
|
||||
void show_error_message(GtkWidget *parent, gchar *message);
|
||||
void gui_create();
|
||||
void gui_free();
|
||||
|
||||
#endif /* GDIGI_GUI_H */
|
||||
|
||||
250
preset.c
Normal file
250
preset.c
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Tomasz Moń <desowin@gmail.com>
|
||||
*
|
||||
* 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; under version 3 of the License.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <expat.h>
|
||||
#include <string.h>
|
||||
#include "preset.h"
|
||||
|
||||
enum {
|
||||
PARSER_TYPE_NOT_SET = -1,
|
||||
PARSER_TYPE_PRESET_NAME = 0,
|
||||
PARSER_TYPE_PARAM_ID,
|
||||
PARSER_TYPE_PARAM_POSITION,
|
||||
PARSER_TYPE_PARAM_VALUE,
|
||||
PARSER_TYPE_PARAM_NAME,
|
||||
PARSER_TYPE_PARAM_TEXT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int depth;
|
||||
int id;
|
||||
Preset *preset;
|
||||
} AppData;
|
||||
|
||||
static void XMLCALL start(void *data, const char *el, const char **attr) {
|
||||
AppData *ad = (AppData *) data;
|
||||
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
if (g_strcmp0(el, "Name") == 0) {
|
||||
if (ad->depth == 1) {
|
||||
ad->id = PARSER_TYPE_PRESET_NAME;
|
||||
} else if (ad->depth == 3) {
|
||||
ad->id = PARSER_TYPE_PARAM_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strcmp0(el, "Params") == 0) {
|
||||
if (ad->preset->params != NULL)
|
||||
g_message("Params aleady exists!");
|
||||
} else if (g_strcmp0(el, "Param") == 0) {
|
||||
SettingParam *param = g_slice_new(SettingParam);
|
||||
param->id = -1;
|
||||
param->position = -1;
|
||||
param->value = -1;
|
||||
ad->preset->params = g_list_prepend(ad->preset->params, param);
|
||||
} else if (g_strcmp0(el, "ID") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_ID;
|
||||
} else if (g_strcmp0(el, "Position") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_POSITION;
|
||||
} else if (g_strcmp0(el, "Value") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_VALUE;
|
||||
} else if (g_strcmp0(el, "Text") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_TEXT;
|
||||
}
|
||||
|
||||
ad->depth++;
|
||||
}
|
||||
|
||||
static void XMLCALL end(void *data, const char *el) {
|
||||
AppData *ad = (AppData *) data;
|
||||
ad->depth--;
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
}
|
||||
|
||||
static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
{
|
||||
AppData *ad = (AppData *) data;
|
||||
|
||||
if ((ad == NULL) || (ad->preset == NULL))
|
||||
return;
|
||||
|
||||
if (ad->id == PARSER_TYPE_PRESET_NAME) {
|
||||
if (ad->preset->name != NULL)
|
||||
g_free(ad->preset->name);
|
||||
ad->preset->name = g_strndup(text, len);
|
||||
}
|
||||
|
||||
if (ad->preset->params == NULL)
|
||||
return;
|
||||
|
||||
SettingParam *param = (SettingParam *) ad->preset->params->data;
|
||||
if (param == NULL)
|
||||
return;
|
||||
|
||||
gchar *value = g_strndup(text, len);
|
||||
|
||||
switch (ad->id) {
|
||||
case PARSER_TYPE_PARAM_ID:
|
||||
param->id = atoi(value);
|
||||
break;
|
||||
case PARSER_TYPE_PARAM_POSITION:
|
||||
param->position = atoi(value);
|
||||
break;
|
||||
case PARSER_TYPE_PARAM_VALUE:
|
||||
param->value = atoi(value);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* create_preset_from_xml_file:
|
||||
* @filename: valid path to file
|
||||
*
|
||||
* Tries to open file pointed by path, then parses it.
|
||||
*
|
||||
* Return value: Preset which must be freed using preset_free, or NULL on error.
|
||||
**/
|
||||
Preset *create_preset_from_xml_file(gchar *filename)
|
||||
{
|
||||
GFile *file;
|
||||
GError *error = 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);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AppData *ad = g_slice_new(AppData);
|
||||
ad->depth = 0;
|
||||
ad->preset = g_slice_new(Preset);
|
||||
ad->preset->name = NULL;
|
||||
ad->preset->params = NULL;
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
|
||||
XML_Parser p;
|
||||
p = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(p, (void *) ad);
|
||||
XML_SetElementHandler(p, start, end);
|
||||
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)));
|
||||
preset_free(ad->preset);
|
||||
g_slice_free(AppData, ad);
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Preset *preset = ad->preset;
|
||||
preset->params = g_list_reverse(preset->params);
|
||||
|
||||
XML_ParserFree(p);
|
||||
g_slice_free(AppData, ad);
|
||||
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return preset;
|
||||
}
|
||||
|
||||
/**
|
||||
* create_preset_from_data:
|
||||
* @data: unpacked RECEIVE_PRESET_PARAMETERS message
|
||||
*
|
||||
* Parses message
|
||||
*
|
||||
* Return value: 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* preset_free:
|
||||
* @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) {
|
||||
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_slice_free(Preset, preset);
|
||||
}
|
||||
37
preset.h
Normal file
37
preset.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Tomasz Moń <desowin@gmail.com>
|
||||
*
|
||||
* 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; under version 3 of the License.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_PRESET_H
|
||||
#define GDIGI_PRESET_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int position;
|
||||
int value;
|
||||
} SettingParam;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
GList *params;
|
||||
} Preset;
|
||||
|
||||
Preset *create_preset_from_xml_file(gchar *filename);
|
||||
Preset *create_preset_from_data(GString *data);
|
||||
void preset_free(Preset *preset);
|
||||
|
||||
#endif /* GDIGI_PRESET_H */
|
||||
251
tests.c
251
tests.c
@@ -206,13 +206,10 @@ void test_presets()
|
||||
int x;
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_user_preset(x);
|
||||
switch_preset(PRESETS_USER, x);
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_system_preset(x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_preset_level(x);
|
||||
switch_preset(PRESETS_SYSTEM, 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();
|
||||
}
|
||||
|
||||
6
tests.h
6
tests.h
@@ -14,6 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_TESTS_H
|
||||
#define GDIGI_TESTS_H
|
||||
|
||||
#include "gdigi.h"
|
||||
|
||||
void test_wah();
|
||||
@@ -26,6 +29,7 @@ void test_noisegate();
|
||||
void test_chorusfx();
|
||||
void test_delay();
|
||||
void test_reverb();
|
||||
void test_exp();
|
||||
void test_usb();
|
||||
void test_all();
|
||||
|
||||
#endif /* GDIGI_TESTS_H */
|
||||
|
||||
Reference in New Issue
Block a user