Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eadaf198ba | ||
|
|
97547476e4 | ||
|
|
35e42dc653 | ||
|
|
ce296d2698 | ||
|
|
fd0369dc7c | ||
|
|
2c921df204 | ||
|
|
ee2fcd181e | ||
|
|
2eb4e97810 | ||
|
|
907a3d0ed9 | ||
|
|
5dc5f0652f | ||
|
|
5a44076e4f | ||
|
|
0bb0f6db71 | ||
|
|
dcf66adfa9 | ||
|
|
0886ba00c1 | ||
|
|
e12de97fab | ||
|
|
59753a61dc | ||
|
|
ff0be8230e | ||
|
|
07cfd70941 | ||
|
|
2523b27205 | ||
|
|
530dd397c5 | ||
|
|
158fd081a5 | ||
|
|
a8bac07f68 | ||
|
|
87bb59f43a | ||
|
|
cdeb821deb | ||
|
|
ce463b29d8 | ||
|
|
159bca158e | ||
|
|
6ae750c4fb | ||
|
|
5f21c62a2f | ||
|
|
08b20b398f | ||
|
|
1be664e82f | ||
|
|
3ab55054c1 | ||
|
|
97b8c9fd6d | ||
|
|
211df27cf8 | ||
|
|
dfe28ac81d | ||
|
|
3da458d370 | ||
|
|
ba04930133 | ||
|
|
18f137636d | ||
|
|
eba8bbe5aa | ||
|
|
7a6e3b159c | ||
|
|
cc85da9c71 | ||
|
|
9586f6cd31 | ||
|
|
4a7ab848e7 | ||
|
|
2703e79d39 | ||
|
|
dbab804d52 | ||
|
|
c3f82416f5 | ||
|
|
145b41cb6c | ||
|
|
26d1db9e4f | ||
|
|
cc311f4f18 | ||
|
|
d85e83c89e | ||
|
|
55b9b08230 | ||
|
|
400e221a4f | ||
|
|
5b93c91bfe | ||
|
|
cbd07a9709 | ||
|
|
def4917a07 | ||
|
|
e9c0ed8b38 | ||
|
|
400a7d41f8 | ||
|
|
40a9d06e4c | ||
|
|
e820ce0cc4 | ||
|
|
ebc603143e | ||
|
|
c74290d8e1 | ||
|
|
295e932bf1 | ||
|
|
1a65deb8d5 | ||
|
|
4509c14bbc | ||
|
|
d7f10eb509 | ||
|
|
b1a8d69dba | ||
|
|
20769ace01 | ||
|
|
2633bac5d8 | ||
|
|
af1d3a2906 | ||
|
|
06fd3eee66 | ||
|
|
acb1c1e273 | ||
|
|
7bf55352b8 | ||
|
|
6a1d1de390 | ||
|
|
b798d6ee39 | ||
|
|
ba810bf4f8 | ||
|
|
24a1c2718b | ||
|
|
31a635839a | ||
|
|
d7b3f7a3d6 | ||
|
|
6512696240 | ||
|
|
f1359d18e4 | ||
|
|
85ce157bb8 | ||
|
|
6daaf47cd8 | ||
|
|
3a849de954 | ||
|
|
a06c5dc07e |
10
AUTHORS
10
AUTHORS
@@ -1 +1,11 @@
|
||||
Tomasz Moń <desowin@gmail.com>
|
||||
Stephen Rigler <riglersc@gmail.com>
|
||||
Jaco Kroon <jaco@kroon.co.za>
|
||||
Rafael Moreno <laocanfei@yahoo.com>
|
||||
Andrew O. Shadoura <bugzilla@tut.by>
|
||||
Andreas Karajannis <aakara13@googlemail.com>
|
||||
Miklos Aubert <miklos.aubert@gmail.com>
|
||||
Jonathan A. Tice <jonandtice@gmail.com>
|
||||
John Hammen <jhammen@gmail.com>
|
||||
Ahmed Toulan <thelinuxer@gmail.com>
|
||||
Tim LaBerge <tlaberge@visi.com>
|
||||
|
||||
70
HACKING
70
HACKING
@@ -3,43 +3,57 @@ In general everything brings down to figure out:
|
||||
-Position
|
||||
-Possible value range
|
||||
|
||||
There seems to be two possible ways to figure that out.
|
||||
There seems to be three possible ways to figure that out.
|
||||
1) Use USB sniffer together with X-Edit
|
||||
Once you set up X-Edit and usb sniffer, set some option.
|
||||
USB sniffer should report something like this being sent to device:
|
||||
(all numbers here are hex)
|
||||
04 F0 00 00 04 10 00 5E 04 02 41 00 04 30 09 00 07 00 34 F7
|
||||
|
||||
To get SysEx command out of it, remove every 4th byte, so we have:
|
||||
MIDI data is transferred over USB using 32-bit USB-MIDI Event Packets.
|
||||
Byte 0 is Cable Number (high nibble) and Code Index Number (low nibble).
|
||||
Bytes 1, 2 and 3 are data.
|
||||
Every bulk transfer on USB MIDI endpoint contains atleast one such packet
|
||||
(those are sent one after each other).
|
||||
In case of Digitech devices, the Cable Number seems to be 0 (correct me,
|
||||
if I'm wrong).
|
||||
There are three different Code Index Numbers that are being used in this
|
||||
particular case:
|
||||
0x4 - SysEx starts or continues (Byte 1, 2 and 3 from this packet are
|
||||
part of our MIDI message)
|
||||
0x5 - SysEx ends with following single byte (we just need to take Byte 1
|
||||
from this packet)
|
||||
0x6 - SysEx ends with following two bytes (we just need to take Byte 1 and 2
|
||||
from this packet)
|
||||
0x7 - SysEx ends with following three bytes (we need to take Byte 1, 2 and 3
|
||||
from this packet)
|
||||
|
||||
Unused bytes in USB-MIDI packets are supposed to be 0.
|
||||
|
||||
To get SysEx command out of it, apply above rules, so we have:
|
||||
F0 00 00 10 00 5E 02 41 00 30 09 00 00 34 F7
|
||||
|
||||
SysEx message format seems to be formed like this:
|
||||
magic bytes - F0 00 00 10 00 5E 02 41
|
||||
status byte - in this example 00
|
||||
SysEx start byte - F0
|
||||
Manufacturer ID - 00 00 10
|
||||
Device ID - 00
|
||||
Family ID - 5E (RP)
|
||||
Product ID - 02 (RP250)
|
||||
Procedure - 41 (see MessageID in gdigi.h)
|
||||
|
||||
As MIDI messages must not contain bytes with MSB bit set, Digitech
|
||||
devices use packing system.
|
||||
First byte contains MSB bits from following 7 bytes (this scheme
|
||||
continues as many times as needed) (see pack_data() and unpack_message() in
|
||||
gdigi.c for details).
|
||||
|
||||
Assuming message has been unpacked, the meaning of next bytes:
|
||||
ID - in this example 30 09
|
||||
Position - in this example 00
|
||||
Value - in this example 00 (can be more bytes long, see below)
|
||||
Checksum - to calculate it, XOR all bytes, and then XOR it with 07
|
||||
Checksum - to calculate it, XOR all bytes (of packed message)
|
||||
Every message ends with F7
|
||||
|
||||
Status byte bits explained:
|
||||
7th - ???
|
||||
6th - if active add 80 to ID
|
||||
5th - ???
|
||||
4th - is active when value will start with length
|
||||
In such case value can be something like:
|
||||
01 12 or 02 12 34 or 03 12 34 56
|
||||
and proper values are:
|
||||
01 - 12
|
||||
02 - 1234
|
||||
03 - 123456
|
||||
3rd - when 4th bit is also active, and first value byte is 01
|
||||
then add 80 to value
|
||||
2nd - when 4th bit is also active, and first value byte is 02
|
||||
then add 80 to value
|
||||
1st - when 4th bit is also active, and first value byte is 03
|
||||
then add 80 to value
|
||||
|
||||
So for above example:
|
||||
ID = 3009 (hex) = 12297 (decimal)
|
||||
Position = 0
|
||||
@@ -66,3 +80,13 @@ There seems to be two possible ways to figure that out.
|
||||
save new patch
|
||||
check patch file and note the change
|
||||
while you don't have all possible values
|
||||
3) Use gdigi
|
||||
After starting gdigi turn the knobs on your device.
|
||||
Check out console output, you should notice something like this:
|
||||
** Message: Received parameter change ID: 210 Position: 4 Value: 0
|
||||
ID is ID, Position is Position and Value is one of possible values.
|
||||
To get all possible values keep turning knobs and watch the output.
|
||||
If you change effect type usually there's more messages - where,
|
||||
usually the first one is type change, and rest are default values.
|
||||
This way you *CANNOT* gather all information (there're X-Edit only
|
||||
controlled values, check device manual for more information).
|
||||
|
||||
59
Makefile
59
Makefile
@@ -1,35 +1,44 @@
|
||||
CC = gcc
|
||||
CFLAGS = `pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0` -Wall -g -ansi -std=c99
|
||||
OFLAG = -o
|
||||
LIBS = `pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 alsa` -lexpat
|
||||
EXTRA_CFLAGS ?=
|
||||
EXTRA_LDFLAGS ?=
|
||||
CFLAGS := $(shell pkg-config --cflags glib-2.0 gio-2.0 gtk+-3.0 libxml-2.0) -Wall -g -ansi -std=c99 $(EXTRA_CFLAGS)
|
||||
LDFLAGS = $(EXTRA_LDFLAGS) -Wl,--as-needed
|
||||
LDADD := $(shell pkg-config --libs glib-2.0 gio-2.0 gtk+-3.0 gthread-2.0 alsa libxml-2.0) -lexpat
|
||||
OBJECTS = gdigi.o gui.o effects.o preset.o gtkknob.o preset_xml.o
|
||||
DEPFILES = $(foreach m,$(OBJECTS:.o=),.$(m).m)
|
||||
|
||||
.SUFFIXES : .o .c
|
||||
.c.o :
|
||||
.PHONY : clean distclean all
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
.%.m : %.c
|
||||
$(CC) $(CFLAGS) -M -MF $@ -MG $<
|
||||
|
||||
all: gdigi
|
||||
|
||||
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
|
||||
|
||||
tests.o: tests.c
|
||||
|
||||
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 > $@
|
||||
gdigi: $(OBJECTS)
|
||||
$(CC) $(LDFLAGS) -o $@ $+ $(LDADD)
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
rm -f *.o
|
||||
|
||||
distclean : clean
|
||||
rm -f .*.m
|
||||
rm -f gdigi
|
||||
|
||||
install: gdigi
|
||||
install gdigi $(DESTDIR)/usr/bin
|
||||
install gdigi.desktop $(DESTDIR)/usr/share/applications/
|
||||
|
||||
NODEP_TARGETS := clean distclean
|
||||
depinc := 1
|
||||
ifneq (,$(filter $(NODEP_TARGETS),$(MAKECMDGOALS)))
|
||||
depinc := 0
|
||||
endif
|
||||
ifneq (,$(fitler-out $(NODEP_TARGETS),$(MAKECMDGOALS)))
|
||||
depinc := 1
|
||||
endif
|
||||
|
||||
ifeq ($(depinc),1)
|
||||
-include $(DEPFILES)
|
||||
endif
|
||||
|
||||
2
README
2
README
@@ -1,4 +1,4 @@
|
||||
Requirments: alsa, gtk+, glib, expat
|
||||
Requirments: alsa, gtk+, glib, expat, libxml-2
|
||||
|
||||
Getting started guide:
|
||||
-to compile: make
|
||||
|
||||
8
TODO
8
TODO
@@ -1,7 +1,5 @@
|
||||
-make complete gui
|
||||
-effects level
|
||||
-make complete gui (expression pedal settings, usb settings, effect level, preset level)
|
||||
-handling presets (saving, exporting to xml patches)
|
||||
-buildsystem (install knob.png to share dir, don't use inline knob pixbuf)
|
||||
-add expression pedal settings to gui
|
||||
-read asynchronously from MIDI IN
|
||||
-guess device port when user doesn't explicitly provide it (don't use hardcoded "hw:1,0,0")
|
||||
-various fixes to MIDI IN messages handling
|
||||
-optimizations
|
||||
|
||||
68
effects.h
68
effects.h
@@ -19,10 +19,31 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct {
|
||||
typedef enum {
|
||||
VALUE_TYPE_PLAIN = 0, /**< value displayed directly */
|
||||
VALUE_TYPE_SUFFIX = 1 << 0, /**< use suffix for displaying */
|
||||
VALUE_TYPE_OFFSET = 1 << 1, /**< use value offset */
|
||||
VALUE_TYPE_STEP = 1 << 2, /**< use value step different than 1 */
|
||||
VALUE_TYPE_LABEL = 1 << 3, /**< use value labels (overrides any other option) */
|
||||
VALUE_TYPE_EXTRA = 1 << 4, /**< use extra values */
|
||||
VALUE_TYPE_DECIMAL= 1 << 5, /**< display decimal places */
|
||||
VALUE_TYPE_NONE = 1 << 6, /**< no value displayed */
|
||||
} ValueType;
|
||||
|
||||
typedef struct _EffectValues {
|
||||
gdouble min; /**< Minumum value */
|
||||
gdouble max; /**< Maximum value */
|
||||
gint type; /**< value type bitmask (ValueType) */
|
||||
|
||||
GStrv labels; /**< value labels */
|
||||
gint offset; /**< value offset */
|
||||
gdouble step; /**< value step */
|
||||
gchar *suffix; /**< value suffix */
|
||||
|
||||
struct _EffectValues *extra;
|
||||
/**< additional value range,
|
||||
use it when there're different range types */
|
||||
gint decimal; /**< amount of decimal places to display */
|
||||
} EffectValues;
|
||||
|
||||
typedef struct {
|
||||
@@ -35,8 +56,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
guint type; /**< value (type) */
|
||||
gchar *label; /**< Effect name */
|
||||
guint id; /**< ID (to set effect type) */
|
||||
guint position; /**< position */
|
||||
EffectSettings *settings; /**< possible parameters */
|
||||
gint settings_amt; /**< possible parameters length */
|
||||
} EffectGroup;
|
||||
@@ -44,6 +63,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
gchar *label; /**< Group label */
|
||||
guint id; /**< ID to set effect on/off, or if it isn't on/off group then -1 */
|
||||
guint type; /**< ID to set effect type */
|
||||
guint position; /**< position */
|
||||
EffectGroup *group; /**< possible effect types */
|
||||
gint group_amt; /**< possible effect types length */
|
||||
@@ -56,20 +76,52 @@ typedef struct {
|
||||
} EffectList;
|
||||
|
||||
typedef struct {
|
||||
guint type; /**< ID to set effect type */
|
||||
guint position;
|
||||
EffectGroup *group;
|
||||
gint group_amt;
|
||||
} ModifierGroup;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
EffectList *list;
|
||||
int n_list;
|
||||
} SupportedDevices;
|
||||
EffectList *effects;
|
||||
gint n_effects;
|
||||
gint n_rows;
|
||||
} EffectPage;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
PresetBank bank;
|
||||
} Banks;
|
||||
|
||||
enum product_id {
|
||||
RP150 = 1,
|
||||
RP250 = 2,
|
||||
GNX4 = 3,
|
||||
GNX3000 = 4,
|
||||
RP500 = 5,
|
||||
RP1000 = 6,
|
||||
RP155 = 7,
|
||||
RP255 = 8,
|
||||
RP355 = 9,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
unsigned char family_id;
|
||||
unsigned char product_id;
|
||||
EffectPage *pages;
|
||||
gint n_pages;
|
||||
Banks *banks;
|
||||
gint n_banks;
|
||||
} Device;
|
||||
|
||||
ModifierGroup *modifier_linkable_list();
|
||||
void modifier_group_free(ModifierGroup *modifier_group);
|
||||
gboolean get_effect_list(unsigned char device_id, unsigned char family_id,
|
||||
void get_values_info(EffectValues *values,
|
||||
gdouble *min, gdouble *max, gboolean *custom);
|
||||
gboolean get_device_info(unsigned char device_id, unsigned char family_id,
|
||||
unsigned char product_id,
|
||||
EffectList **list, int *n_list);
|
||||
Device **device);
|
||||
|
||||
#endif /* GDIGI_EFFECTS_H */
|
||||
|
||||
74
gdigi.1
Normal file
74
gdigi.1
Normal file
@@ -0,0 +1,74 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH GDIGI 1 "October 07, 2010"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
.\" .nh disable hyphenation
|
||||
.\" .hy enable hyphenation
|
||||
.\" .ad l left justify
|
||||
.\" .ad b justify to both left and right margins
|
||||
.\" .nf disable filling
|
||||
.\" .fi enable filling
|
||||
.\" .br insert line break
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
gdigi \- utility to control DigiTech effect pedals
|
||||
.SH SYNOPSIS
|
||||
.B gdigi
|
||||
.RI [OPTION...]
|
||||
.SH DESCRIPTION
|
||||
gdigi is a tool aimed to provide X-Edit functionality to Linux users
|
||||
.PP
|
||||
Supported devices:
|
||||
.IP \(bu
|
||||
RP250
|
||||
.IP \(bu
|
||||
RP255
|
||||
.IP \(bu
|
||||
RP355
|
||||
.IP \(bu
|
||||
RP500
|
||||
.IP \(bu
|
||||
RP1000
|
||||
.IP \(bu
|
||||
GNX3000
|
||||
.IP \(bu
|
||||
GNX4K
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
These programs follow the usual GNU command line syntax, with long
|
||||
options starting with two dashes (`\-').
|
||||
A summary of options is included below.
|
||||
For a complete description, see the Info files.
|
||||
.TP
|
||||
.B \-?, \-\-help
|
||||
Show summary of options.
|
||||
.TP
|
||||
.B \-\-help\-all
|
||||
Show all help options.
|
||||
.TP
|
||||
.B \-\-help\-gtk
|
||||
Show GTK+ options.
|
||||
.TP
|
||||
.B \-\-display=\fIDISPLAY\fR
|
||||
X display to use.
|
||||
.TP
|
||||
.B \-d, \-\-device
|
||||
MIDI device port to use.
|
||||
.SH AUTHOR
|
||||
gdigi was written by Tomasz Moń <desowin@gmail.com>.
|
||||
.PP
|
||||
Send comments, bug reports and patches to gdigi
|
||||
mailinglist at Google Groups.
|
||||
.PP
|
||||
This manual page was written by Andrew O. Shadoura <bugzilla@tut.by>,
|
||||
for the Debian project (but may be used by others).
|
||||
.PP
|
||||
Permission is granted to copy, distribute and/or modify this document under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, under version 3 of the License.
|
||||
|
||||
802
gdigi.c
802
gdigi.c
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gio/gio.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alloca.h>
|
||||
@@ -24,11 +25,31 @@
|
||||
|
||||
static unsigned char device_id = 0x7F;
|
||||
static unsigned char family_id = 0x7F;
|
||||
static unsigned char product_id = 0x7F;
|
||||
unsigned char product_id = 0x7F;
|
||||
|
||||
static snd_rawmidi_t *output = NULL;
|
||||
static snd_rawmidi_t *input = NULL;
|
||||
static char *device = "hw:1,0,0";
|
||||
static char *device_port = NULL;
|
||||
|
||||
static GQueue *message_queue = NULL;
|
||||
static GMutex *message_queue_mutex = NULL;
|
||||
static GCond *message_queue_cond = NULL;
|
||||
|
||||
/**
|
||||
* Registers an error quark for gdigi if necessary.
|
||||
*
|
||||
* \return error quark used for gdigi errors
|
||||
**/
|
||||
static GQuark gdigi_error_quark()
|
||||
{
|
||||
static GQuark quark = 0;
|
||||
|
||||
if (quark == 0) {
|
||||
quark = g_quark_from_static_string("gdigi-error");
|
||||
}
|
||||
|
||||
return quark;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param array data to calculate checksum
|
||||
@@ -59,9 +80,9 @@ gboolean open_device()
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_open(&input, &output, device, SND_RAWMIDI_NONBLOCK);
|
||||
err = snd_rawmidi_open(&input, &output, device_port, SND_RAWMIDI_SYNC);
|
||||
if (err) {
|
||||
fprintf(stderr, "snd_rawmidi_open %s failed: %d\n", device, err);
|
||||
fprintf(stderr, "snd_rawmidi_open %s failed: %d\n", device_port, err);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -101,13 +122,11 @@ GString *pack_data(gchar *data, gint len)
|
||||
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++) {
|
||||
@@ -125,6 +144,11 @@ GString *pack_data(gchar *data, gint len)
|
||||
return packed;
|
||||
}
|
||||
|
||||
static void message_free_func(GString *msg, gpointer user_data)
|
||||
{
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param msg message to unpack
|
||||
*
|
||||
@@ -150,36 +174,120 @@ static void unpack_message(GString *msg)
|
||||
do {
|
||||
offset += 8;
|
||||
status = str[offset-1];
|
||||
for (x=0; x<7; x++) {
|
||||
for (x=0; x<7 && !stop; x++) {
|
||||
if (offset+x >= msg->len) {
|
||||
i++;
|
||||
stop = TRUE;
|
||||
break;
|
||||
}
|
||||
if (str[offset+x] == 0xF7) {
|
||||
if (x == 0) {
|
||||
str[i] = status;
|
||||
i++;
|
||||
}
|
||||
str[i] = 0xF7;
|
||||
i++;
|
||||
stop = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
str[i] = (((status << (x+1)) & 0x80) | str[x+offset]);
|
||||
i++;
|
||||
}
|
||||
} while (!stop && (offset+x < msg->len));
|
||||
} while (!stop);
|
||||
|
||||
g_string_truncate(msg, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from MIDI IN. This function uses global input variable.
|
||||
* \param msg SysEx message
|
||||
*
|
||||
* \return GString containing data, or NULL when no data was read.
|
||||
* Checks message ID.
|
||||
*
|
||||
* \return MessageID, or -1 on error.
|
||||
**/
|
||||
GString* read_data()
|
||||
MessageID get_message_id(GString *msg)
|
||||
{
|
||||
/** \todo check if msg is valid SysEx message */
|
||||
g_return_val_if_fail(msg != NULL, -1);
|
||||
g_return_val_if_fail(msg->str != NULL, -1);
|
||||
|
||||
if (msg->len > 7) {
|
||||
return (unsigned char)msg->str[7];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void push_message(GString *msg)
|
||||
{
|
||||
if (((unsigned char)msg->str[0] == 0xF0) && ((unsigned char)msg->str[msg->len-1] == 0xF7))
|
||||
g_message("Pushing correct message!");
|
||||
else
|
||||
g_warning("Pushing incorrect message!");
|
||||
|
||||
int x;
|
||||
for (x = 0; x<msg->len; x++)
|
||||
printf("%02x ", (unsigned char)msg->str[x]);
|
||||
printf("\n");
|
||||
|
||||
switch (get_message_id(msg)) {
|
||||
case ACK:
|
||||
g_message("Received ACK");
|
||||
g_string_free(msg, TRUE);
|
||||
return;
|
||||
|
||||
case NACK:
|
||||
g_message("Received NACK");
|
||||
g_string_free(msg, TRUE);
|
||||
return;
|
||||
|
||||
case RECEIVE_PARAMETER_VALUE:
|
||||
unpack_message(msg);
|
||||
SettingParam *param = setting_param_new_from_data(&msg->str[8], NULL);
|
||||
g_message("Received parameter change ID: %d Position: %d Value: %d", param->id, param->position, param->value);
|
||||
|
||||
GDK_THREADS_ENTER();
|
||||
apply_setting_param_to_gui(param);
|
||||
GDK_THREADS_LEAVE();
|
||||
|
||||
setting_param_free(param);
|
||||
g_string_free(msg, TRUE);
|
||||
return;
|
||||
|
||||
case RECEIVE_DEVICE_NOTIFICATION:
|
||||
unpack_message(msg);
|
||||
unsigned char *str = (unsigned char*)msg->str;
|
||||
switch (str[8]) {
|
||||
case NOTIFY_PRESET_MOVED:
|
||||
if (str[11] == PRESETS_EDIT_BUFFER && str[12] == 0) {
|
||||
g_message("Loaded preset %d from bank %d", str[10], str[9]);
|
||||
|
||||
GDK_THREADS_ENTER();
|
||||
g_timeout_add(0, apply_current_preset_to_gui, NULL);
|
||||
GDK_THREADS_LEAVE();
|
||||
} else {
|
||||
g_message("%d %d moved to %d %d", str[9], str[10], str[11], str[12]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_message("Received unhandled device notification 0x%x", str[11]);
|
||||
}
|
||||
g_string_free(msg, TRUE);
|
||||
return;
|
||||
default:
|
||||
g_mutex_lock(message_queue_mutex);
|
||||
g_queue_push_tail(message_queue, msg);
|
||||
g_cond_signal(message_queue_cond);
|
||||
g_mutex_unlock(message_queue_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
gpointer read_data_thread(gboolean *stop)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
@@ -188,10 +296,14 @@ GString* read_data()
|
||||
snd_rawmidi_poll_descriptors(input, pfds, npfds);
|
||||
|
||||
do {
|
||||
char buf[20];
|
||||
unsigned char buf[256];
|
||||
int i, length;
|
||||
unsigned short revents;
|
||||
|
||||
/* SysEx messages can't contain bytes with 8th bit set.
|
||||
memset our buffer to 0xFF, so if for some reason we'll get out of reply bounds, we'll catch it */
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
|
||||
err = poll(pfds, npfds, 200);
|
||||
if (err < 0 && errno == EINTR)
|
||||
break;
|
||||
@@ -218,22 +330,47 @@ GString* read_data()
|
||||
|
||||
length = 0;
|
||||
for (i = 0; i < err; ++i)
|
||||
if (buf[i] != 0xFE) /* ignore active sensing */
|
||||
if ((unsigned char)buf[i] != 0xFE) /* ignore active sensing */
|
||||
buf[length++] = buf[i];
|
||||
|
||||
if ((unsigned char)buf[length-1] == 0xF7)
|
||||
stop = TRUE;
|
||||
i = 0;
|
||||
|
||||
while (i < length) {
|
||||
int pos;
|
||||
int bytes;
|
||||
|
||||
if (length != 0) {
|
||||
if (string == NULL) {
|
||||
string = g_string_new_len(buf, length);
|
||||
} else {
|
||||
string = g_string_append_len(string, buf, length);
|
||||
while (buf[i] != 0xF0 && i < length)
|
||||
i++;
|
||||
}
|
||||
|
||||
pos = i;
|
||||
|
||||
for (bytes = 0; (bytes<length-i) && (buf[i+bytes] != 0xF7); bytes++);
|
||||
|
||||
if (buf[i+bytes] == 0xF7) bytes++;
|
||||
|
||||
i += bytes;
|
||||
|
||||
if (string == NULL)
|
||||
string = g_string_new_len((gchar*)&buf[pos], bytes);
|
||||
else
|
||||
g_string_append_len(string, (gchar*)&buf[pos], bytes);
|
||||
|
||||
if ((unsigned char)string->str[string->len-1] == 0xF7) {
|
||||
/* push message on stack */
|
||||
push_message(string);
|
||||
string = NULL;
|
||||
}
|
||||
}
|
||||
} while ((err != 0) && (stop == FALSE));
|
||||
} while (*stop == FALSE);
|
||||
|
||||
return string;
|
||||
if (string) {
|
||||
g_string_free(string, TRUE);
|
||||
string = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -268,40 +405,36 @@ void send_message(gint procedure, gchar *data, gint len)
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param msg SysEx message
|
||||
*
|
||||
* Checks message ID.
|
||||
*
|
||||
* \return MessageID, or -1 on error.
|
||||
**/
|
||||
static MessageID get_message_id(GString *msg)
|
||||
{
|
||||
/** \todo check if msg is valid SysEx message */
|
||||
g_return_val_if_fail(msg != NULL, -1);
|
||||
|
||||
if (msg->len > 7) {
|
||||
return (unsigned char)msg->str[7];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param id MessageID of requested message
|
||||
*
|
||||
* Reads data from MIDI IN until message with matching id is found.
|
||||
* Reads data from message queue until message with matching id is found.
|
||||
*
|
||||
* \return GString containing unpacked message.
|
||||
**/
|
||||
GString *get_message_by_id(MessageID id)
|
||||
{
|
||||
GString *data = NULL;
|
||||
guint x, len;
|
||||
gboolean found = FALSE;
|
||||
|
||||
g_mutex_lock(message_queue_mutex);
|
||||
do {
|
||||
if (data)
|
||||
g_string_free(data, TRUE);
|
||||
data = read_data();
|
||||
} while (get_message_id(data) != id);
|
||||
len = g_queue_get_length(message_queue);
|
||||
for (x = 0; x<len; x++) {
|
||||
data = g_queue_peek_nth(message_queue, x);
|
||||
if (get_message_id(data) == id) {
|
||||
found = TRUE;
|
||||
g_queue_pop_nth(message_queue, x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == FALSE)
|
||||
g_cond_wait(message_queue_cond, message_queue_mutex);
|
||||
|
||||
} while (found == FALSE);
|
||||
g_mutex_unlock(message_queue_mutex);
|
||||
|
||||
unpack_message(data);
|
||||
|
||||
@@ -341,6 +474,158 @@ void append_value(GString *msg, guint value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \param str pointer to value to unpack
|
||||
* \param len return location for how many bytes value is encoded on (length is added to current value)
|
||||
*
|
||||
* Unpacks value using scheme used on all newer DigiTech products.
|
||||
*
|
||||
* \return unpacked value
|
||||
**/
|
||||
guint unpack_value(gchar *str, int *len)
|
||||
{
|
||||
guint value;
|
||||
gint tmp;
|
||||
|
||||
value = (unsigned char)str[0];
|
||||
if (len != NULL)
|
||||
*len += 1;
|
||||
|
||||
if (value > 0x80) {
|
||||
tmp = value & 0x7F;
|
||||
value = 0;
|
||||
gint i;
|
||||
for (i = 0; i<tmp; i++) {
|
||||
value |= ((unsigned char)str[1+i] << (8*(tmp-i-1)));
|
||||
}
|
||||
|
||||
if (len != NULL)
|
||||
*len += tmp;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates memory for SettingParam.
|
||||
*
|
||||
* \return SettingParam which must be freed using setting_param_free.
|
||||
**/
|
||||
SettingParam *setting_param_new()
|
||||
{
|
||||
SettingParam *param = g_slice_new(SettingParam);
|
||||
param->id = -1;
|
||||
param->position = -1;
|
||||
param->value = -1;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param str pointer to setting param in message
|
||||
* \param len return location for how many bytes value is encoded on (length is added to current value)
|
||||
*
|
||||
* Creates SettingParam basing on data.
|
||||
* This function expects str to point on:
|
||||
* -Parameter ID - 2 bytes
|
||||
* -Parameter position - 1 byte
|
||||
* -Parameter value - var
|
||||
*
|
||||
* \return newly created SettingParam which must be freed using setting_param_free.
|
||||
**/
|
||||
SettingParam *setting_param_new_from_data(gchar *str, gint *len)
|
||||
{
|
||||
gint id;
|
||||
gint position;
|
||||
guint value;
|
||||
|
||||
id = ((unsigned char)str[0] << 8) | (unsigned char)str[1];
|
||||
position = (unsigned char)str[2];
|
||||
if (len != NULL)
|
||||
*len += 3;
|
||||
|
||||
value = unpack_value(&str[3], len);
|
||||
|
||||
SettingParam *param = g_slice_new(SettingParam);
|
||||
param->id = id;
|
||||
param->position = position;
|
||||
param->value = value;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param param SettingParam to be freed
|
||||
*
|
||||
* Frees all memory used by SettingParam.
|
||||
**/
|
||||
void setting_param_free(SettingParam *param)
|
||||
{
|
||||
g_slice_free(SettingParam, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates memory for SettingGenetx.
|
||||
*
|
||||
* \return SettingGenetx which must be freed using setting_genetx_free.
|
||||
**/
|
||||
SettingGenetx *setting_genetx_new()
|
||||
{
|
||||
SettingGenetx *genetx = g_slice_new(SettingGenetx);
|
||||
/* Older patches don't specify GeNetX version */
|
||||
genetx->version = GENETX_VERSION_1;
|
||||
genetx->type = GENETX_TYPE_NOT_SET;
|
||||
genetx->channel = -1;
|
||||
genetx->name = NULL;
|
||||
genetx->data = NULL;
|
||||
|
||||
return genetx;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param genetx SettingGenetx to be freed
|
||||
*
|
||||
* Frees all memory used by SettingGenetx.
|
||||
**/
|
||||
void setting_genetx_free(SettingGenetx *genetx)
|
||||
{
|
||||
g_free(genetx->name);
|
||||
if (genetx->data != NULL) {
|
||||
g_string_free(genetx->data, TRUE);
|
||||
}
|
||||
g_slice_free(SettingGenetx, genetx);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param version GeNetX version
|
||||
* \param type GeNetX type
|
||||
*
|
||||
* Retrieves SectionID for specified GeNetX version and type.
|
||||
*
|
||||
* \return SectionID specified by version and type, or -1 on error.
|
||||
**/
|
||||
SectionID get_genetx_section_id(gint version, gint type)
|
||||
{
|
||||
if (version == GENETX_VERSION_1) {
|
||||
if (type == GENETX_TYPE_AMP) {
|
||||
return SECTION_GENETX_AMP;
|
||||
} else if (type == GENETX_TYPE_CABINET) {
|
||||
return SECTION_GENETX_CABINET;
|
||||
}
|
||||
} else if (version == GENETX_VERSION_2) {
|
||||
if (type == GENETX_TYPE_AMP) {
|
||||
return SECTION_GENETX2_AMP;
|
||||
} else if (type == GENETX_TYPE_CABINET) {
|
||||
return SECTION_GENETX2_CABINET;
|
||||
}
|
||||
}
|
||||
|
||||
g_message("This version of gdigi don't know what to do with this "
|
||||
"GeNetX version (%d) and type (%d)", version, type);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param id Parameter ID
|
||||
* \param position Parameter position
|
||||
@@ -359,6 +644,68 @@ void set_option(guint id, guint position, guint value)
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param section data section ID
|
||||
* \param bank section-specific bank number
|
||||
* \param index index of the desired object within the bank
|
||||
* \param name object name
|
||||
* \param data GString containing object data
|
||||
*
|
||||
* Forms RECEIVE_OBJECT SysEx message then sends it to device.
|
||||
**/
|
||||
void send_object(SectionID section, guint bank, guint index,
|
||||
gchar *name, GString *data)
|
||||
{
|
||||
GString *msg = g_string_new(NULL);
|
||||
|
||||
gint len = data->len;
|
||||
|
||||
g_string_append_printf(msg,
|
||||
"%c%c%c%c%s%c%c%c",
|
||||
section, bank,
|
||||
((index & 0xFF00) >> 8), (index & 0xFF),
|
||||
name, 0 /* NULL terminated string */,
|
||||
((len & 0xFF00) >> 8), (len & 0xFF));
|
||||
|
||||
g_string_append_len(msg, data->str, data->len);
|
||||
|
||||
send_message(RECEIVE_OBJECT, msg->str, msg->len);
|
||||
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param params GList containing SettingParam
|
||||
*
|
||||
* Forms RECEIVE_PRESET_PARAMETERS SysEx message then sends it to device.
|
||||
**/
|
||||
void send_preset_parameters(GList *params)
|
||||
{
|
||||
GString *msg = g_string_sized_new(500);
|
||||
GList *iter = params;
|
||||
gint len = g_list_length(iter);
|
||||
|
||||
g_string_append_printf(msg, "%c%c",
|
||||
((len & 0xFF00) >> 8),
|
||||
(len & 0xFF));
|
||||
|
||||
while (iter) {
|
||||
SettingParam *param = (SettingParam *) iter->data;
|
||||
iter = iter->next;
|
||||
|
||||
g_string_append_printf(msg, "%c%c%c",
|
||||
((param->id & 0xFF00) >> 8),
|
||||
(param->id & 0xFF),
|
||||
param->position);
|
||||
|
||||
append_value(msg, param->value);
|
||||
};
|
||||
|
||||
send_message(RECEIVE_PRESET_PARAMETERS, msg->str, msg->len);
|
||||
|
||||
g_string_free(msg, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \param bank preset bank
|
||||
* \param x preset index
|
||||
@@ -441,7 +788,7 @@ GStrv query_preset_names(gchar bank)
|
||||
}
|
||||
|
||||
for (x=10; ((x<data->len) && (n<n_total)); x++) {
|
||||
if (data->str[x] == 0xF7) /* every message ends with 0xF7 */
|
||||
if ((unsigned char)data->str[x] == 0xF7) /* every message ends with 0xF7 */
|
||||
break;
|
||||
|
||||
str_array[n] = g_strdup(&data->str[x]);
|
||||
@@ -454,20 +801,242 @@ GStrv query_preset_names(gchar bank)
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries current edit buffer.
|
||||
* Reads multiple messages and puts them into GList.
|
||||
*
|
||||
* \return GString containing RECEIVE_PRESET_PARAMETERS SysEx message.
|
||||
* \param id MessageID starting message sequence
|
||||
*
|
||||
* \return GList with SysEx messages, which must be freed using message_list_free.
|
||||
**/
|
||||
GString *get_current_preset()
|
||||
GList *get_message_list(MessageID id)
|
||||
{
|
||||
GString *data = NULL;
|
||||
GList *list = NULL;
|
||||
guint x, len;
|
||||
gboolean found = FALSE;
|
||||
gboolean done = FALSE;
|
||||
|
||||
send_message(REQUEST_PRESET, "\x04\x00", 3);
|
||||
g_mutex_lock(message_queue_mutex);
|
||||
do {
|
||||
len = g_queue_get_length(message_queue);
|
||||
|
||||
/* read reply */
|
||||
data = get_message_by_id(RECEIVE_PRESET_PARAMETERS);
|
||||
for (x = 0; x<len && (found == FALSE); x++) {
|
||||
data = g_queue_peek_nth(message_queue, x);
|
||||
if (get_message_id(data) == id) {
|
||||
found = TRUE;
|
||||
g_queue_pop_nth(message_queue, x);
|
||||
unpack_message(data);
|
||||
list = g_list_append(list, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
if (found == TRUE) {
|
||||
int i;
|
||||
int amt;
|
||||
|
||||
switch (id) {
|
||||
case RECEIVE_PRESET_START:
|
||||
for (i = 10; (i < data->len) && data->str[i]; i++);
|
||||
amt = (unsigned char)data->str[i+2];
|
||||
break;
|
||||
case RECEIVE_BULK_DUMP_START:
|
||||
amt = ((unsigned char)data->str[8] << 8) | (unsigned char)data->str[9];
|
||||
break;
|
||||
default:
|
||||
g_error("get_message_list() doesn't support followning id: %d", id);
|
||||
g_string_free(data, TRUE);
|
||||
g_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (amt) {
|
||||
g_message("%d messages left", amt);
|
||||
data = g_queue_pop_nth(message_queue, x);
|
||||
if (data == NULL) {
|
||||
g_cond_wait(message_queue_cond, message_queue_mutex);
|
||||
} else {
|
||||
unpack_message(data);
|
||||
list = g_list_append(list, data);
|
||||
amt--;
|
||||
}
|
||||
}
|
||||
|
||||
done = TRUE;
|
||||
} else {
|
||||
/* id not found in message queue */
|
||||
g_cond_wait(message_queue_cond, message_queue_mutex);
|
||||
}
|
||||
} while (done == FALSE);
|
||||
g_mutex_unlock(message_queue_mutex);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param list list to be freed
|
||||
*
|
||||
* Frees all memory used by message list.
|
||||
**/
|
||||
void message_list_free(GList *list)
|
||||
{
|
||||
g_return_if_fail(list != NULL);
|
||||
|
||||
g_list_foreach(list, (GFunc) message_free_func, NULL);
|
||||
g_list_free(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries current edit buffer.
|
||||
*
|
||||
* \return GList with preset SysEx messages, which must be freed using message_list_free.
|
||||
**/
|
||||
GList *get_current_preset()
|
||||
{
|
||||
send_message(REQUEST_PRESET, "\x04\x00", 2);
|
||||
return get_message_list(RECEIVE_PRESET_START);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates backup file.
|
||||
*
|
||||
* \param file backup file handle
|
||||
* \param error a GError
|
||||
*
|
||||
* \return FALSE on success, TRUE on error.
|
||||
**/
|
||||
static gboolean create_backup_file(GFile *file, GError **error)
|
||||
{
|
||||
GFileOutputStream *output = NULL;
|
||||
GList *list = NULL, *iter = NULL;
|
||||
const gchar header[] = {'\x01', '\x00'};
|
||||
gsize written;
|
||||
gboolean val;
|
||||
|
||||
if (error)
|
||||
*error = NULL;
|
||||
output = g_file_create(file, G_FILE_CREATE_NONE, NULL, error);
|
||||
if (output == NULL)
|
||||
return TRUE;
|
||||
|
||||
if (error)
|
||||
*error = NULL;
|
||||
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), header,
|
||||
sizeof(header), &written, NULL, error);
|
||||
if (val == FALSE) {
|
||||
g_object_unref(output);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
send_message(REQUEST_BULK_DUMP, "\x00", 1);
|
||||
list = get_message_list(RECEIVE_BULK_DUMP_START);
|
||||
|
||||
for (iter = list; iter; iter = g_list_next(iter)) {
|
||||
GString *str;
|
||||
guchar id; /* message id */
|
||||
guint32 len; /* message length */
|
||||
|
||||
str = (GString*) iter->data;
|
||||
|
||||
id = get_message_id(str);
|
||||
if (error)
|
||||
*error = NULL;
|
||||
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &id,
|
||||
sizeof(id), &written, NULL, error);
|
||||
if (val == FALSE) {
|
||||
message_list_free(list);
|
||||
g_object_unref(output);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
len = GUINT32_TO_LE(str->len - 10);
|
||||
if (error)
|
||||
*error = NULL;
|
||||
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &len,
|
||||
sizeof(len), &written, NULL, error);
|
||||
if (val == FALSE) {
|
||||
message_list_free(list);
|
||||
g_object_unref(output);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (error)
|
||||
*error = NULL;
|
||||
val = g_output_stream_write_all(G_OUTPUT_STREAM(output), &str->str[8],
|
||||
str->len - 10, &written, NULL, error);
|
||||
if (val == FALSE) {
|
||||
message_list_free(list);
|
||||
g_object_unref(output);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
message_list_free(list);
|
||||
|
||||
if (error)
|
||||
*error = NULL;
|
||||
val = g_output_stream_close(G_OUTPUT_STREAM(output), NULL, error);
|
||||
g_object_unref(output);
|
||||
return !val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores backup file.
|
||||
*
|
||||
* \param filename backup filename
|
||||
* \param error a GError
|
||||
*
|
||||
* \return FALSE on success, TRUE on error.
|
||||
**/
|
||||
static gboolean restore_backup_file(const gchar *filename, GError **error)
|
||||
{
|
||||
gchar *data;
|
||||
gsize length;
|
||||
gsize x;
|
||||
|
||||
if (g_file_get_contents(filename, &data, &length, error) == FALSE)
|
||||
return TRUE;
|
||||
|
||||
if (error)
|
||||
*error = NULL;
|
||||
|
||||
if (!(data[0] == 0x01 && data[1] == 0x00)) {
|
||||
g_free(data);
|
||||
g_set_error_literal(error, gdigi_error_quark(), 0,
|
||||
"Magic byte doesn't match");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
x = 0x02;
|
||||
while (x < length) {
|
||||
gchar id;
|
||||
guint32 len;
|
||||
|
||||
id = data[x];
|
||||
x++;
|
||||
|
||||
if (x+4 <= length) {
|
||||
len = GUINT32_FROM_LE(*((guint32*) &data[x]));
|
||||
x += 4;
|
||||
} else {
|
||||
g_free(data);
|
||||
g_set_error_literal(error, gdigi_error_quark(), 0,
|
||||
"Unexpected end of data");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (x+len <= length) {
|
||||
send_message(id, &data[x], len);
|
||||
x += len;
|
||||
} else {
|
||||
g_free(data);
|
||||
g_set_error_literal(error, gdigi_error_quark(), 0,
|
||||
"Unexpected end of data");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(data);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,18 +1051,17 @@ GString *get_current_preset()
|
||||
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);
|
||||
send_message(REQUEST_WHO_AM_I, "\x7F\x7F\x7F", 3);
|
||||
|
||||
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;
|
||||
}
|
||||
GString *data = get_message_by_id(RECEIVE_WHO_AM_I);
|
||||
if ((data != NULL) && (data->len > 11)) {
|
||||
*device_id = data->str[8];
|
||||
*family_id = data->str[9];
|
||||
*product_id = data->str[10];
|
||||
g_message("I am device id %d family %d product id %d.",
|
||||
*device_id, *family_id, *product_id);
|
||||
g_string_free(data, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -538,15 +1106,46 @@ static void request_device_configuration()
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
|
||||
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device_port, "MIDI device port to use", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
|
||||
|
||||
/**
|
||||
* \param[out] devices GList containing numbers (packed into pointers)
|
||||
* of connected DigiTech devices
|
||||
*
|
||||
* Checks available soundcards for DigiTech devices.
|
||||
*
|
||||
* \return the number of connected DigiTech devices.
|
||||
**/
|
||||
static gint get_digitech_devices(GList **devices)
|
||||
{
|
||||
gint card_num = -1;
|
||||
gint number = 0;
|
||||
|
||||
while (!snd_card_next(&card_num) && (card_num > -1)) {
|
||||
char* name;
|
||||
snd_card_get_longname(card_num, &name);
|
||||
if (strspn(name,"DigiTech") > 0) {
|
||||
number++;
|
||||
*devices = g_list_append(*devices, GINT_TO_POINTER(card_num));
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
static gboolean stop_read_thread = FALSE;
|
||||
GThread *read_thread = NULL;
|
||||
|
||||
g_thread_init(NULL);
|
||||
gdk_threads_init();
|
||||
|
||||
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));
|
||||
@@ -558,35 +1157,94 @@ int main(int argc, char *argv[]) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (device_port == NULL) {
|
||||
/* port not given explicitly in commandline - search for devices */
|
||||
GList *devices = NULL;
|
||||
GList *device = NULL;
|
||||
int num_devices = 0;
|
||||
int chosen_device = 0;
|
||||
if ((num_devices = get_digitech_devices(&devices)) <= 0) {
|
||||
g_message("Couldn't find any DigiTech devices!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (num_devices > 1) {
|
||||
chosen_device = select_device_dialog(devices);
|
||||
if (chosen_device < 0) {
|
||||
show_error_message(NULL, "No device chosen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
device = g_list_nth(devices, chosen_device);
|
||||
device_port = g_strdup_printf("hw:%d,0,0",
|
||||
GPOINTER_TO_INT(device->data));
|
||||
g_list_free(devices);
|
||||
g_message("Found device %s", device_port);
|
||||
} else {
|
||||
g_message("Using device %s", device_port);
|
||||
}
|
||||
|
||||
g_option_context_free(context);
|
||||
|
||||
if (open_device() == TRUE) {
|
||||
show_error_message(NULL, "Failed to open MIDI device");
|
||||
} else {
|
||||
message_queue = g_queue_new();
|
||||
message_queue_mutex = g_mutex_new();
|
||||
message_queue_cond = g_cond_new();
|
||||
read_thread = g_thread_create((GThreadFunc)read_data_thread,
|
||||
&stop_read_thread,
|
||||
TRUE, NULL);
|
||||
|
||||
if (request_who_am_i(&device_id, &family_id, &product_id) == FALSE) {
|
||||
show_error_message(NULL, "No suitable reply from device");
|
||||
} else {
|
||||
EffectList *list = NULL;
|
||||
int n_list = -1;
|
||||
Device *device = NULL;
|
||||
|
||||
if (get_effect_list(device_id, family_id, product_id, &list, &n_list) == FALSE) {
|
||||
if (unsupported_device_dialog(&list, &n_list) == FALSE) {
|
||||
if (get_device_info(device_id, family_id, product_id, &device) == FALSE) {
|
||||
if (unsupported_device_dialog(&device) == FALSE) {
|
||||
g_message("Shutting down");
|
||||
}
|
||||
}
|
||||
|
||||
if (list != NULL && n_list != -1) {
|
||||
gui_create(list, n_list);
|
||||
if (device != NULL) {
|
||||
/* enable GUI mode */
|
||||
set_option(GUI_MODE_ON_OFF, USB_POSITION, 1);
|
||||
|
||||
gui_create(device);
|
||||
gtk_main();
|
||||
gui_free();
|
||||
|
||||
/* disable GUI mode */
|
||||
set_option(GUI_MODE_ON_OFF, USB_POSITION, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (output != NULL)
|
||||
if (read_thread != NULL) {
|
||||
stop_read_thread = TRUE;
|
||||
g_thread_join(read_thread);
|
||||
}
|
||||
|
||||
if (message_queue_mutex != NULL) {
|
||||
g_mutex_free(message_queue_mutex);
|
||||
}
|
||||
|
||||
if (message_queue != NULL) {
|
||||
g_message("%d unread messages in queue",
|
||||
g_queue_get_length(message_queue));
|
||||
g_queue_foreach(message_queue, (GFunc) message_free_func, NULL);
|
||||
g_queue_free(message_queue);
|
||||
}
|
||||
|
||||
if (output != NULL) {
|
||||
snd_rawmidi_drain(output);
|
||||
snd_rawmidi_close(output);
|
||||
if (input != NULL)
|
||||
}
|
||||
|
||||
if (input != NULL) {
|
||||
snd_rawmidi_drain(input);
|
||||
snd_rawmidi_close(input);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
7
gdigi.desktop
Normal file
7
gdigi.desktop
Normal file
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=gdigi
|
||||
Exec=gdigi
|
||||
Categories=GNOME;Audio;AudioVideo;
|
||||
|
||||
@@ -14,22 +14,26 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_TESTS_H
|
||||
#define GDIGI_TESTS_H
|
||||
#ifndef GDIGI_XML_H
|
||||
#define GDIGI_XML_H
|
||||
|
||||
#include "gdigi.h"
|
||||
#include <glib.h>
|
||||
#include "effects.h"
|
||||
typedef struct {
|
||||
guint type;
|
||||
gchar *label;
|
||||
} XmlLabel;
|
||||
|
||||
void test_wah();
|
||||
void test_compressor();
|
||||
void test_dist();
|
||||
void test_presets();
|
||||
void test_pickups();
|
||||
void test_eq();
|
||||
void test_noisegate();
|
||||
void test_chorusfx();
|
||||
void test_delay();
|
||||
void test_reverb();
|
||||
void test_usb();
|
||||
void test_all();
|
||||
typedef struct {
|
||||
guint id;
|
||||
guint position;
|
||||
gchar *label;
|
||||
EffectValues *values;
|
||||
XmlLabel *xml_labels; /* 'type' id's have a label group. */
|
||||
guint xml_labels_amt;
|
||||
} XmlSettings;
|
||||
|
||||
#endif /* GDIGI_TESTS_H */
|
||||
// XmlSettings *get_xml_settings(guint id, guint position);
|
||||
// gchar *get_xml_label(guint id, guint position, gint type);
|
||||
|
||||
#endif /* GDIGI_XML_H */
|
||||
414
gtkknob.c
414
gtkknob.c
@@ -4,7 +4,7 @@
|
||||
* 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
|
||||
* copyright (C) 2009-2011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -24,8 +24,9 @@
|
||||
#include <math.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <string.h>
|
||||
#include "gtkknob.h"
|
||||
|
||||
#include "knob.h"
|
||||
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.14159265358979323846 /* pi */
|
||||
@@ -44,11 +45,15 @@
|
||||
|
||||
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_destroy(GtkWidget *object);
|
||||
static void gtk_knob_realize(GtkWidget *widget);
|
||||
static void gtk_knob_size_request(GtkWidget *widget, GtkRequisition *requisition);
|
||||
static void gtk_knob_unrealize(GtkWidget *widget);
|
||||
static void gtk_knob_map(GtkWidget *widget);
|
||||
static void gtk_knob_unmap(GtkWidget *widget);
|
||||
static void gtk_knob_get_preferred_width(GtkWidget *widget, gint *minimum_width, gint *natural_width);
|
||||
static void gtk_knob_get_preferred_height(GtkWidget *widget, gint *minimum_height, gint *natural_height);
|
||||
static void gtk_knob_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
|
||||
static gint gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event);
|
||||
static gboolean gtk_knob_draw(GtkWidget *widget, cairo_t *cr);
|
||||
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);
|
||||
@@ -102,25 +107,27 @@ gtk_knob_get_type(void) {
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_class_init (GtkKnobClass *klass) {
|
||||
GtkObjectClass *object_class;
|
||||
GtkWidgetClass *widget_class;
|
||||
|
||||
object_class = (GtkObjectClass*) klass;
|
||||
widget_class = (GtkWidgetClass*) klass;
|
||||
|
||||
parent_class = g_type_class_peek_parent(klass);
|
||||
|
||||
object_class->destroy = gtk_knob_destroy;
|
||||
widget_class->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->unrealize = gtk_knob_unrealize;
|
||||
widget_class->draw = gtk_knob_draw;
|
||||
widget_class->get_preferred_width = gtk_knob_get_preferred_width;
|
||||
widget_class->get_preferred_height = gtk_knob_get_preferred_height;
|
||||
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;
|
||||
widget_class->map = gtk_knob_map;
|
||||
widget_class->unmap = gtk_knob_unmap;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,19 +138,21 @@ gtk_knob_class_init (GtkKnobClass *klass) {
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_init (GtkKnob *knob) {
|
||||
knob->policy = GTK_UPDATE_CONTINUOUS;
|
||||
knob->policy = GTK_KNOB_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_widget_set_can_focus(GTK_WIDGET(knob), TRUE);
|
||||
gtk_widget_set_has_window(GTK_WIDGET(knob), FALSE);
|
||||
gtk_widget_set_hexpand(GTK_WIDGET(knob), FALSE);
|
||||
gtk_widget_set_vexpand(GTK_WIDGET(knob), FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +166,6 @@ gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim) {
|
||||
GtkKnob *knob;
|
||||
|
||||
g_return_val_if_fail (anim != NULL, NULL);
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF (anim->pixbuf), NULL);
|
||||
|
||||
knob = g_object_new (gtk_knob_get_type (), NULL);
|
||||
|
||||
@@ -180,7 +188,7 @@ gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim) {
|
||||
*
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_destroy(GtkObject *object) {
|
||||
gtk_knob_destroy(GtkWidget *object) {
|
||||
GtkKnob *knob;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
@@ -196,22 +204,8 @@ gtk_knob_destroy(GtkObject *object) {
|
||||
}
|
||||
*/
|
||||
|
||||
if (knob->mask) {
|
||||
g_object_unref (knob->mask);
|
||||
knob->mask = NULL;
|
||||
}
|
||||
|
||||
if (knob->mask_gc) {
|
||||
g_object_unref (knob->mask_gc);
|
||||
knob->mask_gc = NULL;
|
||||
}
|
||||
if (knob->red_gc) {
|
||||
g_object_unref (knob->red_gc);
|
||||
knob->red_gc = NULL;
|
||||
}
|
||||
|
||||
if (GTK_OBJECT_CLASS (parent_class)->destroy) {
|
||||
(*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
||||
if (GTK_WIDGET_CLASS(parent_class)->destroy) {
|
||||
(*GTK_WIDGET_CLASS (parent_class)->destroy) (object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +231,7 @@ gtk_knob_get_adjustment(GtkKnob *knob) {
|
||||
*
|
||||
*****************************************************************************/
|
||||
void
|
||||
gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy) {
|
||||
gtk_knob_set_update_policy(GtkKnob *knob, GtkKnobUpdateType policy) {
|
||||
|
||||
g_return_if_fail (knob != NULL);
|
||||
g_return_if_fail (GTK_IS_KNOB (knob));
|
||||
@@ -276,9 +270,9 @@ gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment) {
|
||||
G_CALLBACK(gtk_knob_adjustment_value_changed),
|
||||
knob);
|
||||
|
||||
knob->old_value = adjustment->value;
|
||||
knob->old_lower = adjustment->lower;
|
||||
knob->old_upper = adjustment->upper;
|
||||
knob->old_value = gtk_adjustment_get_value(adjustment);
|
||||
knob->old_lower = gtk_adjustment_get_lower(adjustment);
|
||||
knob->old_upper = gtk_adjustment_get_upper(adjustment);
|
||||
|
||||
gtk_knob_update (knob);
|
||||
}
|
||||
@@ -293,66 +287,98 @@ gtk_knob_set_adjustment(GtkKnob *knob, GtkAdjustment *adjustment) {
|
||||
static void
|
||||
gtk_knob_realize(GtkWidget *widget) {
|
||||
GtkKnob *knob;
|
||||
GdkWindow *window;
|
||||
GdkWindowAttr attributes;
|
||||
GtkAllocation allocation;
|
||||
|
||||
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);
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
gtk_widget_set_realized(widget, TRUE);
|
||||
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.x = allocation.x;
|
||||
attributes.y = allocation.y;
|
||||
attributes.width = allocation.width;
|
||||
attributes.height = allocation.height;
|
||||
attributes.wclass = GDK_INPUT_ONLY;;
|
||||
attributes.event_mask =
|
||||
gtk_widget_get_events (widget) |
|
||||
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_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;
|
||||
attributes_mask = GDK_WA_X | GDK_WA_Y;
|
||||
|
||||
widget->window = gdk_window_new (widget->parent->window,
|
||||
&attributes, attributes_mask);
|
||||
window = gtk_widget_get_parent_window(widget);
|
||||
gtk_widget_set_window(widget, window);
|
||||
g_object_ref(window);
|
||||
|
||||
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);
|
||||
knob->event_window = gdk_window_new(window, &attributes, attributes_mask);
|
||||
gdk_window_set_user_data(knob->event_window, knob);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* gtk_knob_size_request()
|
||||
*
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_size_request (GtkWidget *widget, GtkRequisition *requisition) {
|
||||
gtk_knob_unrealize(GtkWidget *widget)
|
||||
{
|
||||
GtkKnob *knob = GTK_KNOB(widget);
|
||||
|
||||
if (knob->event_window)
|
||||
{
|
||||
gdk_window_set_user_data(knob->event_window, NULL);
|
||||
gdk_window_destroy(knob->event_window);
|
||||
knob->event_window = NULL;
|
||||
}
|
||||
|
||||
GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_knob_map(GtkWidget *widget)
|
||||
{
|
||||
GtkKnob *knob = GTK_KNOB(widget);
|
||||
|
||||
GTK_WIDGET_CLASS(parent_class)->map(widget);
|
||||
|
||||
if (knob->event_window)
|
||||
gdk_window_show(knob->event_window);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_knob_unmap(GtkWidget *widget)
|
||||
{
|
||||
GtkKnob *knob = GTK_KNOB(widget);
|
||||
|
||||
if (knob->event_window)
|
||||
gdk_window_hide(knob->event_window);
|
||||
|
||||
GTK_WIDGET_CLASS(parent_class)->unmap(widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_knob_get_preferred_width(GtkWidget *widget,
|
||||
gint *minimum_width,
|
||||
gint *natural_width)
|
||||
{
|
||||
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;
|
||||
*minimum_width = *natural_width = GTK_KNOB(widget)->width;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_knob_get_preferred_height(GtkWidget *widget,
|
||||
gint *minimum_height,
|
||||
gint *natural_height)
|
||||
{
|
||||
g_return_if_fail (widget != NULL);
|
||||
g_return_if_fail (GTK_IS_KNOB (widget));
|
||||
|
||||
*minimum_height = *natural_height = GTK_KNOB(widget)->height;
|
||||
}
|
||||
|
||||
|
||||
@@ -369,11 +395,11 @@ gtk_knob_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
|
||||
g_return_if_fail (GTK_IS_KNOB (widget));
|
||||
g_return_if_fail (allocation != NULL);
|
||||
|
||||
widget->allocation = *allocation;
|
||||
gtk_widget_set_allocation(widget, allocation);
|
||||
knob = GTK_KNOB (widget);
|
||||
|
||||
if (GTK_WIDGET_REALIZED (widget)) {
|
||||
gdk_window_move_resize (widget->window,
|
||||
if (gtk_widget_get_realized (widget)) {
|
||||
gdk_window_move_resize (knob->event_window,
|
||||
allocation->x, allocation->y,
|
||||
allocation->width, allocation->height);
|
||||
}
|
||||
@@ -382,39 +408,50 @@ gtk_knob_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* gtk_knob_expose()
|
||||
* gtk_knob_draw()
|
||||
*
|
||||
*****************************************************************************/
|
||||
static gint
|
||||
gtk_knob_expose(GtkWidget *widget, GdkEventExpose *event) {
|
||||
static gboolean
|
||||
gtk_knob_draw(GtkWidget *widget, cairo_t *cr) {
|
||||
GtkKnob *knob;
|
||||
gfloat dx, dy;
|
||||
gdouble dx, dy;
|
||||
gint frames;
|
||||
|
||||
g_return_val_if_fail (widget != NULL, FALSE);
|
||||
g_return_val_if_fail (GTK_IS_KNOB (widget), FALSE);
|
||||
g_return_val_if_fail (event != NULL, FALSE);
|
||||
g_return_val_if_fail (cr != NULL, FALSE);
|
||||
g_return_val_if_fail (GTK_IS_ADJUSTMENT (GTK_KNOB (widget)->adjustment), FALSE);
|
||||
|
||||
if (event->count > 0)
|
||||
return FALSE;
|
||||
|
||||
knob = GTK_KNOB (widget);
|
||||
|
||||
frames = ((knob->anim->width / knob->anim->frame_width) - 1);
|
||||
dx = knob->adjustment->value - knob->adjustment->lower; /* value, from 0 */
|
||||
dy = knob->adjustment->upper - knob->adjustment->lower; /* range */
|
||||
dx = gtk_adjustment_get_value(knob->adjustment) - gtk_adjustment_get_lower(knob->adjustment); /* value, from 0 */
|
||||
dy = gtk_adjustment_get_upper(knob->adjustment) - gtk_adjustment_get_lower(knob->adjustment); /* 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);
|
||||
cairo_surface_t *surface =
|
||||
cairo_surface_create_for_rectangle(knob->anim->image,
|
||||
dx, 0.0,
|
||||
(double)knob->width,
|
||||
(double)knob->height);
|
||||
cairo_set_source_surface(cr, surface, 0, 0);
|
||||
cairo_paint(cr);
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
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);
|
||||
if (gtk_widget_has_focus(widget)) {
|
||||
GtkStyleContext *context;
|
||||
|
||||
context = gtk_widget_get_style_context(widget);
|
||||
gtk_style_context_save(context);
|
||||
gtk_style_context_set_state(context, gtk_widget_get_state_flags (widget));
|
||||
cairo_save(cr);
|
||||
gtk_render_focus(context, cr,
|
||||
0, 0,
|
||||
gtk_widget_get_allocated_width(widget),
|
||||
gtk_widget_get_allocated_height(widget));
|
||||
cairo_restore(cr);
|
||||
gtk_style_context_restore(context);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@@ -439,11 +476,15 @@ gtk_knob_scroll(GtkWidget *widget, GdkEventScroll *event) {
|
||||
|
||||
switch (event->direction) {
|
||||
case GDK_SCROLL_UP:
|
||||
knob->adjustment->value += knob->adjustment->step_increment;
|
||||
gtk_adjustment_set_value(knob->adjustment,
|
||||
gtk_adjustment_get_value(knob->adjustment) +
|
||||
gtk_adjustment_get_step_increment(knob->adjustment));
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
knob->adjustment->value -= knob->adjustment->step_increment;
|
||||
gtk_adjustment_set_value(knob->adjustment,
|
||||
gtk_adjustment_get_value(knob->adjustment) -
|
||||
gtk_adjustment_get_step_increment(knob->adjustment));
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
break;
|
||||
default:
|
||||
@@ -475,16 +516,17 @@ gtk_knob_button_press(GtkWidget *widget, GdkEventButton *event) {
|
||||
switch (event->button) {
|
||||
case 1:
|
||||
case 3:
|
||||
if (!GTK_WIDGET_HAS_FOCUS(widget))
|
||||
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_adjustment_set_value(knob->adjustment,
|
||||
floor ((gtk_adjustment_get_lower(knob->adjustment) +
|
||||
gtk_adjustment_get_upper(knob->adjustment) + 1.0)
|
||||
* 0.5));
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
break;
|
||||
}
|
||||
@@ -523,8 +565,8 @@ gtk_knob_button_release(GtkWidget *widget, GdkEventButton *event) {
|
||||
switch (event->button) {
|
||||
case 1:
|
||||
case 3:
|
||||
if (knob->policy != GTK_UPDATE_CONTINUOUS
|
||||
&& knob->old_value != knob->adjustment->value)
|
||||
if (knob->policy != GTK_KNOB_UPDATE_CONTINUOUS
|
||||
&& knob->old_value != gtk_adjustment_get_value(knob->adjustment))
|
||||
{
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
}
|
||||
@@ -550,20 +592,20 @@ static gint gtk_knob_key_press(GtkWidget *widget, GdkEventKey *event)
|
||||
|
||||
switch (event->keyval) {
|
||||
|
||||
case GDK_Up:
|
||||
if (GTK_WIDGET_HAS_FOCUS (widget))
|
||||
case GDK_KEY_Up:
|
||||
if (gtk_widget_has_focus (widget))
|
||||
{
|
||||
gtk_adjustment_set_value (knob->adjustment,
|
||||
knob->old_value + knob->adjustment->step_increment);
|
||||
knob->old_value + gtk_adjustment_get_step_increment(knob->adjustment));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case GDK_Down:
|
||||
if (GTK_WIDGET_HAS_FOCUS (widget))
|
||||
case GDK_KEY_Down:
|
||||
if (gtk_widget_has_focus (widget))
|
||||
{
|
||||
gtk_adjustment_set_value (knob->adjustment,
|
||||
knob->old_value - knob->adjustment->step_increment);
|
||||
knob->old_value - gtk_adjustment_get_step_increment(knob->adjustment));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@@ -594,8 +636,8 @@ gtk_knob_motion_notify(GtkWidget *widget, GdkEventMotion *event) {
|
||||
x = event->x;
|
||||
y = event->y;
|
||||
|
||||
if (event->is_hint || (event->window != widget->window)) {
|
||||
gdk_window_get_pointer (widget->window, &x, &y, &mods);
|
||||
if (event->is_hint || (event->window != gtk_widget_get_window(widget))) {
|
||||
gdk_window_get_pointer(gtk_widget_get_window(widget), &x, &y, &mods);
|
||||
}
|
||||
|
||||
switch (knob->state) {
|
||||
@@ -632,7 +674,7 @@ gtk_knob_timer(GtkKnob *knob) {
|
||||
g_return_val_if_fail (GTK_IS_KNOB (knob), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment), FALSE);
|
||||
|
||||
if (knob->policy == GTK_UPDATE_DELAYED) {
|
||||
if (knob->policy == GTK_KNOB_UPDATE_DELAYED) {
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
}
|
||||
|
||||
@@ -650,13 +692,13 @@ static void
|
||||
gtk_knob_update_mouse_update(GtkKnob *knob) {
|
||||
g_return_if_fail(GTK_IS_ADJUSTMENT (knob->adjustment));
|
||||
|
||||
if (knob->policy == GTK_UPDATE_CONTINUOUS) {
|
||||
if (knob->policy == GTK_KNOB_UPDATE_CONTINUOUS) {
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
}
|
||||
else {
|
||||
gtk_widget_queue_draw (GTK_WIDGET (knob));
|
||||
|
||||
if (knob->policy == GTK_UPDATE_DELAYED) {
|
||||
if (knob->policy == GTK_KNOB_UPDATE_DELAYED) {
|
||||
if (knob->timer) {
|
||||
g_source_remove (knob->timer);
|
||||
}
|
||||
@@ -675,14 +717,14 @@ gtk_knob_update_mouse_update(GtkKnob *knob) {
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step) {
|
||||
gfloat old_value, new_value, dv, dh;
|
||||
gfloat angle;
|
||||
gdouble old_value, new_value, dv, dh;
|
||||
gdouble angle;
|
||||
|
||||
g_return_if_fail (knob != NULL);
|
||||
g_return_if_fail (GTK_IS_KNOB (knob));
|
||||
g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment));
|
||||
|
||||
old_value = knob->adjustment->value;
|
||||
old_value = gtk_adjustment_get_value(knob->adjustment);
|
||||
|
||||
angle = atan2f (-y + (knob->height >> 1), x - (knob->width >> 1));
|
||||
|
||||
@@ -699,17 +741,17 @@ gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step) {
|
||||
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 = gtk_adjustment_get_value(knob->adjustment) +
|
||||
dv * (step ? gtk_adjustment_get_step_increment(knob->adjustment) : gtk_adjustment_get_page_increment(knob->adjustment)) +
|
||||
dh * (gtk_adjustment_get_upper(knob->adjustment) -
|
||||
gtk_adjustment_get_lower(knob->adjustment)) * 0.005; /* 0.005 == (1 / 200) */
|
||||
|
||||
new_value = MAX (MIN (new_value, knob->adjustment->upper),
|
||||
knob->adjustment->lower);
|
||||
new_value = MAX (MIN (new_value, gtk_adjustment_get_upper(knob->adjustment)),
|
||||
gtk_adjustment_get_lower(knob->adjustment));
|
||||
|
||||
knob->adjustment->value = new_value;
|
||||
gtk_adjustment_set_value(knob->adjustment, new_value);
|
||||
|
||||
if (knob->adjustment->value != old_value) {
|
||||
if (gtk_adjustment_get_value(knob->adjustment) != old_value) {
|
||||
gtk_knob_update_mouse_update (knob);
|
||||
}
|
||||
}
|
||||
@@ -722,29 +764,29 @@ gtk_knob_update_mouse(GtkKnob *knob, gint x, gint y, gboolean step) {
|
||||
*****************************************************************************/
|
||||
static void
|
||||
gtk_knob_update(GtkKnob *knob) {
|
||||
gfloat new_value;
|
||||
gdouble new_value;
|
||||
|
||||
g_return_if_fail (knob != NULL);
|
||||
g_return_if_fail (GTK_IS_KNOB (knob));
|
||||
g_return_if_fail (GTK_IS_ADJUSTMENT (knob->adjustment));
|
||||
|
||||
if (knob->adjustment->step_increment == 1) {
|
||||
new_value = floor (knob->adjustment->value + 0.5);
|
||||
if (gtk_adjustment_get_step_increment(knob->adjustment) == 1) {
|
||||
new_value = floor (gtk_adjustment_get_value(knob->adjustment) + 0.5);
|
||||
}
|
||||
else {
|
||||
new_value = knob->adjustment->value;
|
||||
new_value = gtk_adjustment_get_value(knob->adjustment);
|
||||
}
|
||||
|
||||
if (new_value < knob->adjustment->lower) {
|
||||
new_value = knob->adjustment->lower;
|
||||
if (new_value < gtk_adjustment_get_lower(knob->adjustment)) {
|
||||
new_value = gtk_adjustment_get_lower(knob->adjustment);
|
||||
}
|
||||
|
||||
if (new_value > knob->adjustment->upper) {
|
||||
new_value = knob->adjustment->upper;
|
||||
if (new_value > gtk_adjustment_get_upper(knob->adjustment)) {
|
||||
new_value = gtk_adjustment_get_upper(knob->adjustment);
|
||||
}
|
||||
|
||||
if (new_value != knob->adjustment->value) {
|
||||
knob->adjustment->value = new_value;
|
||||
if (new_value != gtk_adjustment_get_value(knob->adjustment)) {
|
||||
gtk_adjustment_set_value(knob->adjustment, new_value);
|
||||
g_signal_emit_by_name (knob->adjustment, "value_changed");
|
||||
}
|
||||
|
||||
@@ -766,15 +808,15 @@ gtk_knob_adjustment_changed(GtkAdjustment *adjustment, gpointer data) {
|
||||
|
||||
knob = GTK_KNOB (data);
|
||||
|
||||
if ((knob->old_value != adjustment->value) ||
|
||||
(knob->old_lower != adjustment->lower) ||
|
||||
(knob->old_upper != adjustment->upper))
|
||||
if ((knob->old_value != gtk_adjustment_get_value(adjustment)) ||
|
||||
(knob->old_lower != gtk_adjustment_get_lower(adjustment)) ||
|
||||
(knob->old_upper != gtk_adjustment_get_upper(adjustment)))
|
||||
{
|
||||
gtk_knob_update (knob);
|
||||
|
||||
knob->old_value = adjustment->value;
|
||||
knob->old_lower = adjustment->lower;
|
||||
knob->old_upper = adjustment->upper;
|
||||
knob->old_value = gtk_adjustment_get_value(adjustment);
|
||||
knob->old_lower = gtk_adjustment_get_lower(adjustment);
|
||||
knob->old_upper = gtk_adjustment_get_upper(adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,9 +835,9 @@ gtk_knob_adjustment_value_changed (GtkAdjustment *adjustment, gpointer data) {
|
||||
|
||||
knob = GTK_KNOB (data);
|
||||
|
||||
if (knob->old_value != adjustment->value) {
|
||||
if (knob->old_value != gtk_adjustment_get_value(adjustment)) {
|
||||
gtk_knob_update (knob);
|
||||
knob->old_value = adjustment->value;
|
||||
knob->old_value = gtk_adjustment_get_value(adjustment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,29 +852,31 @@ 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)) {
|
||||
if (gtk_widget_get_realized (GTK_WIDGET(knob))) {
|
||||
gtk_widget_queue_resize (GTK_WIDGET (knob));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads embedded knob image
|
||||
**/
|
||||
static cairo_status_t
|
||||
get_knob_image(void *closure, unsigned char *data, unsigned int length)
|
||||
{
|
||||
int *offset = (int *)closure;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* gtk_knob_animation_new_from_file()
|
||||
*
|
||||
*****************************************************************************/
|
||||
GtkKnobAnim *
|
||||
gtk_knob_animation_new_from_file(gchar *filename) {
|
||||
GtkKnobAnim *anim;
|
||||
if ((*offset + length) > sizeof (knob_png))
|
||||
return CAIRO_STATUS_READ_ERROR;
|
||||
|
||||
anim = gtk_knob_animation_new_from_file_full (filename, -1, -1, KNOB_SIZE);
|
||||
return anim;
|
||||
memcpy (data, knob_png + *offset, length);
|
||||
*offset = *offset + length;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -841,68 +885,20 @@ gtk_knob_animation_new_from_file(gchar *filename) {
|
||||
*
|
||||
*****************************************************************************/
|
||||
GtkKnobAnim *
|
||||
gtk_knob_animation_new_from_inline(const guint8 *pixbuf) {
|
||||
gtk_knob_animation_new_from_inline() {
|
||||
GtkKnobAnim *anim = g_new0 (GtkKnobAnim, 1);
|
||||
int offset = 0;
|
||||
|
||||
g_return_val_if_fail((pixbuf != NULL), NULL);
|
||||
anim->image =
|
||||
cairo_image_surface_create_from_png_stream(get_knob_image, &offset);
|
||||
|
||||
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->width = cairo_image_surface_get_width(anim->image);
|
||||
anim->height = cairo_image_surface_get_height(anim->image);
|
||||
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()
|
||||
@@ -912,8 +908,8 @@ void
|
||||
gtk_knob_animation_free(GtkKnobAnim *anim) {
|
||||
g_return_if_fail (anim != NULL);
|
||||
|
||||
if (anim->pixbuf)
|
||||
g_object_unref (anim->pixbuf);
|
||||
if (anim->image)
|
||||
cairo_surface_destroy(anim->image);
|
||||
|
||||
g_free (anim);
|
||||
}
|
||||
|
||||
31
gtkknob.h
31
gtkknob.h
@@ -3,7 +3,7 @@
|
||||
* Most of this code comes from gAlan 0.2.0, copyright (C) 1999
|
||||
* Tony Garnock-Jones, with modifications by Sean Bolton,
|
||||
* copyright (C) 2004, and minor modifications by William Weston,
|
||||
* copyright (C) 2007, Tomasz Moń, copyright (C) 2009
|
||||
* copyright (C) 2007, Tomasz Moń, copyright (C) 2009-2011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -36,9 +36,16 @@ typedef struct _GtkKnob GtkKnob;
|
||||
typedef struct _GtkKnobClass GtkKnobClass;
|
||||
typedef struct _GtkKnobAnim GtkKnobAnim;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GTK_KNOB_UPDATE_CONTINUOUS,
|
||||
GTK_KNOB_UPDATE_DISCONTINUOUS,
|
||||
GTK_KNOB_UPDATE_DELAYED
|
||||
} GtkKnobUpdateType;
|
||||
|
||||
/* better to make this an object and let widgets ref/deref it perhaps */
|
||||
struct _GtkKnobAnim {
|
||||
GdkPixbuf *pixbuf;
|
||||
cairo_surface_t *image;
|
||||
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 */
|
||||
@@ -47,6 +54,7 @@ typedef struct _GtkKnobAnim GtkKnobAnim;
|
||||
struct _GtkKnob {
|
||||
GtkWidget widget;
|
||||
|
||||
GdkWindow *event_window;
|
||||
/* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
|
||||
guint policy : 2;
|
||||
|
||||
@@ -61,14 +69,10 @@ typedef struct _GtkKnobAnim GtkKnobAnim;
|
||||
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;
|
||||
gdouble old_value;
|
||||
gdouble old_lower;
|
||||
gdouble old_upper;
|
||||
|
||||
/* The adjustment object that stores the data for this knob */
|
||||
GtkAdjustment *adjustment;
|
||||
@@ -82,16 +86,11 @@ typedef struct _GtkKnobAnim GtkKnobAnim;
|
||||
extern GtkWidget *gtk_knob_new(GtkAdjustment *adjustment, GtkKnobAnim *anim);
|
||||
extern GType gtk_knob_get_type(void);
|
||||
extern GtkAdjustment *gtk_knob_get_adjustment(GtkKnob *knob);
|
||||
extern void gtk_knob_set_update_policy(GtkKnob *knob, GtkUpdateType policy);
|
||||
extern void gtk_knob_set_update_policy(GtkKnob *knob, GtkKnobUpdateType 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_inline();
|
||||
|
||||
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);
|
||||
|
||||
|
||||
9
gui.h
9
gui.h
@@ -17,12 +17,17 @@
|
||||
#ifndef GDIGI_GUI_H
|
||||
#define GDIGI_GUI_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
#include "effects.h"
|
||||
|
||||
gchar * get_preset_filename(int prod_id);
|
||||
void show_error_message(GtkWidget *parent, gchar *message);
|
||||
void gui_create(EffectList *list, int n_list);
|
||||
void apply_setting_param_to_gui(SettingParam *param);
|
||||
gboolean apply_current_preset_to_gui(gpointer data);
|
||||
void gui_create(Device *device);
|
||||
void gui_free();
|
||||
gboolean unsupported_device_dialog(EffectList **list, int *n_list);
|
||||
gboolean unsupported_device_dialog(Device **device);
|
||||
gint select_device_dialog (GList *devices);
|
||||
|
||||
#endif /* GDIGI_GUI_H */
|
||||
|
||||
261
preset.c
261
preset.c
@@ -18,6 +18,7 @@
|
||||
#include <expat.h>
|
||||
#include <string.h>
|
||||
#include "preset.h"
|
||||
#include "gdigi.h"
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
@@ -28,12 +29,24 @@ enum {
|
||||
PARSER_TYPE_PARAM_POSITION,
|
||||
PARSER_TYPE_PARAM_VALUE,
|
||||
PARSER_TYPE_PARAM_NAME,
|
||||
PARSER_TYPE_PARAM_TEXT
|
||||
PARSER_TYPE_PARAM_TEXT,
|
||||
PARSER_TYPE_GENETX_VERSION,
|
||||
PARSER_TYPE_GENETX_TYPE,
|
||||
PARSER_TYPE_GENETX_CHANNEL,
|
||||
PARSER_TYPE_GENETX_NAME,
|
||||
PARSER_TYPE_GENETX_DATA
|
||||
};
|
||||
|
||||
enum {
|
||||
SECTION_NOT_SET = -1,
|
||||
SECTION_PARAMS,
|
||||
SECTION_GENETX
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int depth;
|
||||
int id;
|
||||
int section;
|
||||
Preset *preset;
|
||||
} AppData;
|
||||
|
||||
@@ -45,18 +58,20 @@ static void XMLCALL start(void *data, const char *el, const char **attr) {
|
||||
if (ad->depth == 1) {
|
||||
ad->id = PARSER_TYPE_PRESET_NAME;
|
||||
} else if (ad->depth == 3) {
|
||||
ad->id = PARSER_TYPE_PARAM_NAME;
|
||||
if (ad->section == SECTION_PARAMS) {
|
||||
ad->id = PARSER_TYPE_PARAM_NAME;
|
||||
} else if (ad->section == SECTION_GENETX) {
|
||||
ad->id = PARSER_TYPE_GENETX_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strcmp0(el, "Params") == 0) {
|
||||
ad->section = SECTION_PARAMS;
|
||||
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;
|
||||
SettingParam *param = setting_param_new();
|
||||
ad->preset->params = g_list_prepend(ad->preset->params, param);
|
||||
} else if (g_strcmp0(el, "ID") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_ID;
|
||||
@@ -66,6 +81,21 @@ static void XMLCALL start(void *data, const char *el, const char **attr) {
|
||||
ad->id = PARSER_TYPE_PARAM_VALUE;
|
||||
} else if (g_strcmp0(el, "Text") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_TEXT;
|
||||
} else if (g_strcmp0(el, "Genetx") == 0) {
|
||||
ad->section = SECTION_GENETX;
|
||||
if (ad->preset->genetxs != NULL)
|
||||
g_message("Genetx already exists!");
|
||||
} else if (g_strcmp0(el, "GenetxModel") == 0) {
|
||||
SettingGenetx *genetx = setting_genetx_new();
|
||||
ad->preset->genetxs = g_list_prepend(ad->preset->genetxs, genetx);
|
||||
} else if (g_strcmp0(el, "Version") == 0) {
|
||||
ad->id = PARSER_TYPE_GENETX_VERSION;
|
||||
} else if (g_strcmp0(el, "Type") == 0) {
|
||||
ad->id = PARSER_TYPE_GENETX_TYPE;
|
||||
} else if (g_strcmp0(el, "Channel") == 0) {
|
||||
ad->id = PARSER_TYPE_GENETX_CHANNEL;
|
||||
} else if (g_strcmp0(el, "Data") == 0) {
|
||||
ad->id = PARSER_TYPE_GENETX_DATA;
|
||||
}
|
||||
|
||||
ad->depth++;
|
||||
@@ -90,28 +120,87 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
ad->preset->name = g_strndup(text, len);
|
||||
}
|
||||
|
||||
if (ad->preset->params == NULL)
|
||||
return;
|
||||
if (ad->section == SECTION_PARAMS) {
|
||||
if (ad->preset->params == NULL)
|
||||
return;
|
||||
|
||||
SettingParam *param = (SettingParam *) ad->preset->params->data;
|
||||
if (param == NULL)
|
||||
return;
|
||||
SettingParam *param = (SettingParam *) ad->preset->params->data;
|
||||
if (param == NULL)
|
||||
return;
|
||||
|
||||
gchar *value = g_strndup(text, len);
|
||||
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;
|
||||
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);
|
||||
} else if (ad->section == SECTION_GENETX) {
|
||||
if (ad->preset->genetxs == NULL)
|
||||
return;
|
||||
|
||||
SettingGenetx *genetx = (SettingGenetx *) ad->preset->genetxs->data;
|
||||
if (genetx == NULL)
|
||||
return;
|
||||
|
||||
gchar *value = g_strndup(text, len);
|
||||
|
||||
switch (ad->id) {
|
||||
case PARSER_TYPE_GENETX_VERSION:
|
||||
if (g_strcmp0(value, "Version1") == 0) {
|
||||
genetx->version = GENETX_VERSION_1;
|
||||
} else if (g_strcmp0(value, "Version2") == 0) {
|
||||
genetx->version = GENETX_VERSION_2;
|
||||
} else {
|
||||
g_message("Unknown GeNetX version: %s", value);
|
||||
}
|
||||
break;
|
||||
case PARSER_TYPE_GENETX_TYPE:
|
||||
if (g_strcmp0(value, "Amp") == 0) {
|
||||
genetx->type = GENETX_TYPE_AMP;
|
||||
} else if (g_strcmp0(value, "Cabinet") == 0) {
|
||||
genetx->type = GENETX_TYPE_CABINET;
|
||||
} else {
|
||||
g_message("Unknown GeNetX type: %s", value);
|
||||
}
|
||||
break;
|
||||
case PARSER_TYPE_GENETX_CHANNEL:
|
||||
if (g_strcmp0(value, "Channel1") == 0) {
|
||||
genetx->channel = GENETX_CHANNEL1;
|
||||
} else if (g_strcmp0(value, "Channel2") == 0) {
|
||||
genetx->channel = GENETX_CHANNEL2;
|
||||
} else {
|
||||
g_message("Unknown GeNetX channel: %s", value);
|
||||
}
|
||||
break;
|
||||
case PARSER_TYPE_GENETX_NAME:
|
||||
/* reassign pointer */
|
||||
genetx->name = value;
|
||||
value = NULL;
|
||||
break;
|
||||
case PARSER_TYPE_GENETX_DATA:
|
||||
{
|
||||
guchar *data = NULL;
|
||||
gsize length = 0;
|
||||
|
||||
data = g_base64_decode(value, &length);
|
||||
genetx->data = g_string_new_len((gchar *) data, length);
|
||||
|
||||
g_free(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
|
||||
@@ -126,16 +215,13 @@ static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
**/
|
||||
Preset *create_preset_from_xml_file(gchar *filename, GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GError *err = NULL;
|
||||
gchar *contents;
|
||||
|
||||
file = g_file_new_for_path(filename);
|
||||
if (g_file_get_contents(filename, &contents, NULL, &err) == FALSE) {
|
||||
g_message("Failed to get %s contents: %s", filename, err->message);
|
||||
*error = g_error_copy(err);
|
||||
g_error_free(err);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -144,6 +230,7 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error)
|
||||
ad->preset = g_slice_new(Preset);
|
||||
ad->preset->name = NULL;
|
||||
ad->preset->params = NULL;
|
||||
ad->preset->genetxs = NULL;
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
|
||||
XML_Parser p;
|
||||
@@ -159,74 +246,97 @@ Preset *create_preset_from_xml_file(gchar *filename, GError **error)
|
||||
preset_free(ad->preset);
|
||||
g_slice_free(AppData, ad);
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Preset *preset = ad->preset;
|
||||
preset->params = g_list_reverse(preset->params);
|
||||
preset->genetxs = g_list_reverse(preset->genetxs);
|
||||
|
||||
XML_ParserFree(p);
|
||||
g_slice_free(AppData, ad);
|
||||
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return preset;
|
||||
}
|
||||
|
||||
gint params_cmp(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const SettingParam *param_a = a;
|
||||
const SettingParam *param_b = b;
|
||||
|
||||
if (param_a->position != param_b->position) {
|
||||
return (param_a->position > param_b->position) ? 1 : -1;
|
||||
}
|
||||
if (param_a->id != param_b->id) {
|
||||
return (param_a->id > param_b->id) ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \param data unpacked RECEIVE_PRESET_PARAMETERS message
|
||||
* \param list list containing unpacked preset SysEx messages.
|
||||
*
|
||||
* Parses message
|
||||
*
|
||||
* \return Preset which must be freed using preset_free, or NULL on error.
|
||||
**/
|
||||
Preset *create_preset_from_data(GString *data)
|
||||
Preset *create_preset_from_data(GList *list)
|
||||
{
|
||||
gint total;
|
||||
gint n;
|
||||
gint id;
|
||||
gint position;
|
||||
guint value;
|
||||
gint x;
|
||||
gint tmp;
|
||||
GString *data;
|
||||
GList *iter;
|
||||
gint total, n, x;
|
||||
gint bank, number, modified;
|
||||
gchar *name;
|
||||
|
||||
g_return_val_if_fail(data != NULL, NULL);
|
||||
|
||||
x = 0x09;
|
||||
n = 0;
|
||||
total = (unsigned char)data->str[x];
|
||||
x++;
|
||||
g_return_val_if_fail(list != NULL, NULL);
|
||||
|
||||
Preset *preset = g_slice_new(Preset);
|
||||
preset->name = NULL; /* TODO */
|
||||
preset->name = NULL;
|
||||
preset->params = NULL;
|
||||
preset->genetxs = 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;
|
||||
iter = list;
|
||||
for (iter = list; iter; iter = g_list_next(iter)) {
|
||||
data = (GString*) iter->data;
|
||||
switch (get_message_id(data)) {
|
||||
case RECEIVE_PRESET_START:
|
||||
bank = (unsigned char)data->str[8];
|
||||
number = (unsigned char)data->str[9];
|
||||
name = g_strdup(&data->str[10]);
|
||||
modified = (unsigned char)data->str[11+strlen(name)];
|
||||
|
||||
if ((bank == PRESETS_EDIT_BUFFER) && (number == 0)) {
|
||||
g_message("Received current edit buffer");
|
||||
} else {
|
||||
g_message("Received preset %d from bank %d", number, bank);
|
||||
}
|
||||
|
||||
g_message("Modified flag: %d Name: %s", modified, name);
|
||||
preset->name = name;
|
||||
break;
|
||||
case RECEIVE_PRESET_PARAMETERS:
|
||||
x = 0x09;
|
||||
n = 0;
|
||||
total = (unsigned char)data->str[x];
|
||||
x++;
|
||||
|
||||
do {
|
||||
SettingParam *param = setting_param_new_from_data(&data->str[x], &x);
|
||||
n++;
|
||||
preset->params = g_list_prepend(preset->params, param);
|
||||
g_message("%d ID %d Position %d Value %d", n, param->id, param->position, param->value);
|
||||
} while ((x < data->len) && n<total);
|
||||
g_message("TOTAL %d", total);
|
||||
preset->params = g_list_sort(preset->params, params_cmp);
|
||||
break;
|
||||
case RECEIVE_PRESET_END:
|
||||
break;
|
||||
default:
|
||||
g_message("Unhandled message in preset messages list");
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -243,13 +353,20 @@ void preset_free(Preset *preset)
|
||||
if (preset->params != NULL) {
|
||||
GList *iter;
|
||||
for (iter = preset->params; iter; iter = iter->next) {
|
||||
g_slice_free(SettingParam, iter->data);
|
||||
setting_param_free((SettingParam*)iter->data);
|
||||
}
|
||||
g_list_free(preset->params);
|
||||
}
|
||||
|
||||
if (preset->name != NULL)
|
||||
g_free(preset->name);
|
||||
if (preset->genetxs != NULL) {
|
||||
GList *iter;
|
||||
for (iter = preset->genetxs; iter; iter = iter->next) {
|
||||
setting_genetx_free((SettingGenetx*)iter->data);
|
||||
}
|
||||
g_list_free(preset->genetxs);
|
||||
}
|
||||
|
||||
g_free(preset->name);
|
||||
|
||||
g_slice_free(Preset, preset);
|
||||
}
|
||||
|
||||
11
preset.h
11
preset.h
@@ -19,19 +19,14 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int position;
|
||||
int value;
|
||||
} SettingParam;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
GList *params;
|
||||
GList *genetxs;
|
||||
} Preset;
|
||||
|
||||
Preset *create_preset_from_xml_file(gchar *filename, GError **error);
|
||||
Preset *create_preset_from_data(GString *data);
|
||||
Preset *create_preset_from_data(GList *list);
|
||||
void preset_free(Preset *preset);
|
||||
|
||||
void write_preset_to_xml(Preset *preset, gchar *filename);
|
||||
#endif /* GDIGI_PRESET_H */
|
||||
|
||||
262
preset_xml.c
Normal file
262
preset_xml.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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 <libxml/encoding.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/xmlwriter.h>
|
||||
#include <string.h>
|
||||
#include "preset.h"
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
#include "gdigi_xml.h"
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
// FIXME: Bring the xml settings into this module?
|
||||
extern XmlSettings xml_settings[];
|
||||
extern guint n_xml_settings;
|
||||
extern EffectValues values_on_off;
|
||||
/**
|
||||
* \param id modifier ID
|
||||
* \param position modifier position
|
||||
*
|
||||
* Gets modifier info.
|
||||
*
|
||||
* \return Modifier which must not be freed, or NULL if no matching Modifier has been found.
|
||||
*/
|
||||
XmlSettings *get_xml_settings (guint id, guint position)
|
||||
{
|
||||
gint x;
|
||||
|
||||
for (x=0; x< n_xml_settings; x++) {
|
||||
if ((xml_settings[x].id == id) && (xml_settings[x].position == position)) {
|
||||
return xml_settings + x;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar *
|
||||
map_xml_value(XmlSettings *xml, gint value)
|
||||
{
|
||||
switch (xml->values->type) {
|
||||
case VALUE_TYPE_LABEL:
|
||||
if ((xml->values == &values_on_off) && (value > 1)) {
|
||||
g_message("Skipping modifier->label %s\n", xml->label);
|
||||
return NULL;
|
||||
}
|
||||
if (value > xml->values->max || value < xml->values->min) {
|
||||
g_message("%s value %d out of range %0.1f %0.1f", xml->label, value, xml->values->min, xml->values->max);
|
||||
}
|
||||
{
|
||||
XmlLabel *labels = xml->xml_labels;
|
||||
guint labels_amt = xml->xml_labels_amt;
|
||||
gint i;
|
||||
|
||||
// Maybe this can be a computation: i = xml->values->min + val
|
||||
for (i = 0; i < labels_amt; i++) {
|
||||
if (labels[i].type == value) {
|
||||
return (labels[i].label);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
gboolean value_is_extra (EffectValues *val, SettingParam *param)
|
||||
{
|
||||
if ((param->value < val->min) || (param->value > val->max)) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define GDIGI_ENCODING "utf-8"
|
||||
void
|
||||
write_preset_to_xml(Preset *preset, gchar *filename)
|
||||
{
|
||||
|
||||
int rc;
|
||||
xmlTextWriterPtr writer;
|
||||
GList *iter_params = preset->params;
|
||||
guint last_id = 0;
|
||||
guint last_position = 0;
|
||||
|
||||
printf("Creating a new xml doc\n");
|
||||
/* Create a new XmlWriter for uri, with no compression. */
|
||||
writer = xmlNewTextWriterFilename(filename, 0);
|
||||
if (writer == NULL) {
|
||||
printf("testXmlwriterFilename: Error creating the xml writer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the document with the xml default for the version,
|
||||
* encoding and the default for the standalone declaration.
|
||||
*/
|
||||
rc = xmlTextWriterStartDocument(writer, NULL, GDIGI_ENCODING, NULL);
|
||||
if (rc < 0) {
|
||||
printf
|
||||
("testXmlwriterFilename: Error at xmlTextWriterStartDocument\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rc = xmlTextWriterSetIndent(writer, 1);
|
||||
rc = xmlTextWriterSetIndentString(writer, BAD_CAST " ");
|
||||
/* Write the tag identifying type of prefix, schema version and ns. */
|
||||
rc = xmlTextWriterStartElement(writer, BAD_CAST get_preset_filename(product_id));
|
||||
|
||||
rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "SchemaVersion",
|
||||
BAD_CAST "1.2");
|
||||
|
||||
|
||||
rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "xmlns",
|
||||
BAD_CAST "http://www.digitech.com/xml/preset");
|
||||
|
||||
/* Write the Name tag. */
|
||||
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Name", BAD_CAST preset->name);
|
||||
|
||||
rc = xmlTextWriterStartElement(writer, BAD_CAST "Params");
|
||||
|
||||
while (iter_params) {
|
||||
XmlSettings *xml;
|
||||
SettingParam *param = (SettingParam *) iter_params->data;
|
||||
|
||||
if (param->id == last_id && param->position == last_position) {
|
||||
g_message("Skipping duplicate parameter id %d position %d",
|
||||
last_id, last_position);
|
||||
iter_params = iter_params->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = xmlTextWriterStartElement(writer, BAD_CAST "Param");
|
||||
|
||||
rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ID",
|
||||
"%d", param->id);
|
||||
rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "Position",
|
||||
"%d", param->position);
|
||||
rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "Value",
|
||||
"%d", param->value);
|
||||
|
||||
last_id = param->id;
|
||||
last_position = param->position;
|
||||
xml = get_xml_settings(param->id, param->position);
|
||||
if (!xml) {
|
||||
printf("Failed to get xml settings for id %d position %d\n",
|
||||
param->id, param->position);
|
||||
} else {
|
||||
ValueType type;
|
||||
gchar *suffix = "";
|
||||
gdouble step = 1.0;
|
||||
gint offset = 0;
|
||||
gboolean decimal = FALSE;
|
||||
EffectValues *values = NULL;
|
||||
|
||||
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Name",
|
||||
BAD_CAST xml->label);
|
||||
values = xml->values;
|
||||
type = values->type;
|
||||
while ((type & VALUE_TYPE_EXTRA) && value_is_extra(values, param)) {
|
||||
values = values->extra;
|
||||
type = values->type;
|
||||
}
|
||||
type &= ~VALUE_TYPE_EXTRA;
|
||||
|
||||
if (type & VALUE_TYPE_OFFSET) {
|
||||
offset = values->offset;
|
||||
type &= ~VALUE_TYPE_OFFSET;
|
||||
}
|
||||
|
||||
if (type & VALUE_TYPE_STEP) {
|
||||
step = values->step;
|
||||
type &= ~VALUE_TYPE_STEP;
|
||||
}
|
||||
|
||||
if (type & VALUE_TYPE_SUFFIX) {
|
||||
suffix = values->suffix;
|
||||
type &= ~VALUE_TYPE_SUFFIX;
|
||||
}
|
||||
|
||||
if (type & VALUE_TYPE_DECIMAL) {
|
||||
decimal = TRUE;
|
||||
type &= ~VALUE_TYPE_DECIMAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case VALUE_TYPE_LABEL:
|
||||
{
|
||||
char *textp = map_xml_value(xml, param->value);
|
||||
if (!textp) {
|
||||
g_message("Unable to map %s value %d for id %d position %d",
|
||||
xml->label, param->value, param->id, param->position);
|
||||
textp = "";
|
||||
}
|
||||
rc = xmlTextWriterWriteElement(writer, BAD_CAST "Text",
|
||||
BAD_CAST textp);
|
||||
break;
|
||||
}
|
||||
|
||||
case VALUE_TYPE_PLAIN:
|
||||
{
|
||||
if (decimal) {
|
||||
double value = (param->value + offset) * step;
|
||||
rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "Text",
|
||||
"%0.2f%s", value, suffix);
|
||||
} else {
|
||||
gint value = (param->value + offset) * step;
|
||||
rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "Text",
|
||||
"%d%s", value, suffix);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
case VALUE_TYPE_NONE:
|
||||
rc = xmlTextWriterStartElement(writer, BAD_CAST "Text");
|
||||
rc = xmlTextWriterEndElement(writer);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_message("Unhandled value type %d", type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = xmlTextWriterEndElement(writer);
|
||||
|
||||
iter_params = iter_params->next;
|
||||
}
|
||||
|
||||
/* Here we could close the elements ORDER and EXAMPLE using the
|
||||
* function xmlTextWriterEndElement, but since we do not want to
|
||||
* write any other elements, we simply call xmlTextWriterEndDocument,
|
||||
* which will do all the work. */
|
||||
rc = xmlTextWriterEndDocument(writer);
|
||||
if (rc < 0) {
|
||||
printf("testXmlwriterFilename: Error at xmlTextWriterEndDocument\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xmlFreeTextWriter(writer);
|
||||
}
|
||||
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
|
||||
644
tests.c
644
tests.c
@@ -1,644 +0,0 @@
|
||||
/*
|
||||
* 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 "gdigi.h"
|
||||
|
||||
void test_wah()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(WAH_TYPE, WAH_POSITION, WAH_TYPE_CRY);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MIN, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MAX, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=12; x++)
|
||||
set_option(WAH_LEVEL, WAH_POSITION, x);
|
||||
|
||||
set_option(WAH_TYPE, WAH_POSITION, WAH_TYPE_FULLRANGE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MIN, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MAX, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=12; x++)
|
||||
set_option(WAH_LEVEL, WAH_POSITION, x);
|
||||
|
||||
set_option(WAH_TYPE, WAH_POSITION, WAH_TYPE_CLYDE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MIN, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WAH_MAX, WAH_POSITION_MIN_MAX, x);
|
||||
|
||||
for (x=0; x<=12; x++)
|
||||
set_option(WAH_LEVEL, WAH_POSITION, x);
|
||||
|
||||
set_option(WAH_ON_OFF, WAH_POSITION, 1);
|
||||
set_option(WAH_ON_OFF, WAH_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_compressor()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(COMP_TYPE, COMP_POSITION, COMP_TYPE_DIGI);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_SUSTAIN, COMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_TONE, COMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_ATTACK, COMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_LEVEL, COMP_POSITION, x);
|
||||
|
||||
set_option(COMP_TYPE, COMP_POSITION, COMP_TYPE_CS);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_SUSTAIN, COMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_ATTACK, COMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(COMP_LEVEL, COMP_POSITION, x);
|
||||
|
||||
set_option(COMP_ON_OFF, COMP_POSITION, 1);
|
||||
set_option(COMP_ON_OFF, COMP_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_dist()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_SCREAMER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_SCREAMER_DRIVE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_SCREAMER_TONE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_SCREAMER_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_808);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_808_OVERDRIVE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_808_TONE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_808_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_GUYOD);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GUYOD_DRIVE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GUYOD_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_DOD250);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DOD250_GAIN, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DOD250_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_RODENT);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_RODENT_DIST, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_RODENT_FILTER, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_RODENT_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_MX);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_MX_DIST, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_MX_OUTPUT, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_DS);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DS_GAIN, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DS_TONE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DS_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_GRUNGE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GRUNGE_GRUNGE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GRUNGE_FACE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GRUNGE_LOUD, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GRUNGE_BUTT, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_ZONE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_GAIN, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_LOW, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_MID_LVL, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_MID_FREQ, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_HIGH, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_ZONE_LEVEL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_DEATH);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DEATH_LOW, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DEATH_MID, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DEATH_HIGH, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_DEATH_LVL, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_GONK);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GONK_GONK, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GONK_SMEAR, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GONK_SUCK, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_GONK_HEAVE, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_FUZZY);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_FUZZY_FUZZ, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_FUZZY_VOLUME, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_TYPE, DIST_POSITION, DIST_TYPE_MP);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_MP_SUSTAIN, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_MP_TONE, DIST_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIST_MP_VOLUME, DIST_POSITION, x);
|
||||
|
||||
set_option(DIST_ON_OFF, DIST_POSITION, 1);
|
||||
set_option(DIST_ON_OFF, DIST_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_presets()
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_preset(PRESETS_USER, x);
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_preset(PRESETS_SYSTEM, x);
|
||||
}
|
||||
|
||||
void test_pickups()
|
||||
{
|
||||
set_option(PICKUP_TYPE, PICKUP_POSITION, PICKUP_TYPE_HB_SC);
|
||||
set_option(PICKUP_TYPE, PICKUP_POSITION, PICKUP_TYPE_SC_HB);
|
||||
|
||||
set_option(PICKUP_ON_OFF, PICKUP_POSITION, 1);
|
||||
set_option(PICKUP_ON_OFF, PICKUP_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_eq()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(EQ_TYPE, EQ_POSITION, EQ_TYPE_BRIGHT);
|
||||
set_option(EQ_TYPE, EQ_POSITION, EQ_TYPE_MIDBOOST);
|
||||
set_option(EQ_TYPE, EQ_POSITION, EQ_TYPE_SCOOP);
|
||||
set_option(EQ_TYPE, EQ_POSITION, EQ_TYPE_WARM);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(AMP_GAIN, AMP_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(AMP_LEVEL, AMP_POSITION, x);
|
||||
|
||||
for (x=0; x<=0x18; x++)
|
||||
set_option(EQ_BASS, EQ_POSITION, x);
|
||||
for (x=0; x<=0x18; x++)
|
||||
set_option(EQ_MID, EQ_POSITION, x);
|
||||
for (x=0; x<=4700; x++)
|
||||
set_option(EQ_MID_HZ, EQ_POSITION, x);
|
||||
for (x=0; x<=0x18; x++)
|
||||
set_option(EQ_TREBLE, EQ_POSITION, x);
|
||||
for (x=0; x<=7500; x++)
|
||||
set_option(EQ_TREBLE_HZ, EQ_POSITION, x);
|
||||
|
||||
set_option(EQ_ON_OFF, EQ_POSITION, 1);
|
||||
set_option(EQ_ON_OFF, EQ_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_noisegate()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(NOISEGATE_TYPE, NOISEGATE_POSITION, NOISEGATE_GATE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_GATE_TRESHOLD, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_ATTACK, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_RELEASE, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_ATTN, NOISEGATE_POSITION, x);
|
||||
|
||||
set_option(NOISEGATE_TYPE, NOISEGATE_POSITION, NOISEGATE_SWELL);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_SWELL_SENS, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_ATTACK, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_RELEASE, NOISEGATE_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(NOISEGATE_ATTN, NOISEGATE_POSITION, x);
|
||||
|
||||
set_option(NOISEGATE_ON_OFF, NOISEGATE_POSITION, 1);
|
||||
set_option(NOISEGATE_ON_OFF, NOISEGATE_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_chorusfx()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_CE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(CE_CHORUS_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(CE_CHORUS_DEPTH, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_DUAL);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DUAL_CHORUS_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DUAL_CHORUS_DEPTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DUAL_CHORUS_LEVEL, CHORUSFX_POSITION, x);
|
||||
set_option(DUAL_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(DUAL_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(DUAL_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_MULTI);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MULTI_CHORUS_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MULTI_CHORUS_DEPTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MULTI_CHORUS_LEVEL, CHORUSFX_POSITION, x);
|
||||
set_option(MULTI_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(MULTI_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(MULTI_CHORUS_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_FLANGER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(FLANGER_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(FLANGER_DEPTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(FLANGER_REGEN, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(FLANGER_LEVEL, CHORUSFX_POSITION, x);
|
||||
set_option(FLANGER_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(FLANGER_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(FLANGER_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_MXR_FLANGER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MXR_FLANGER_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MXR_FLANGER_WIDTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MXR_FLANGER_REGEN, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MXR_FLANGER_MANUAL, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_PHASER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PHASER_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PHASER_DEPTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PHASER_REGEN, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PHASER_LEVEL, CHORUSFX_POSITION, x);
|
||||
set_option(PHASER_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(PHASER_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(PHASER_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_VIBRATO);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(VIBRATO_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(VIBRATO_DEPTH, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_ROTARY);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ROTARY_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ROTARY_INTENSITY, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ROTARY_DOPPLER, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ROTARY_CROSSOVER, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_VIBROPAN);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(VIBROPAN_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(VIBROPAN_DEPTH, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(VIBROPAN_VIBRA, CHORUSFX_POSITION, x);
|
||||
set_option(VIBROPAN_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(VIBROPAN_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(VIBROPAN_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_TREMOLO);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TREMOLO_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TREMOLO_DEPTH, CHORUSFX_POSITION, x);
|
||||
set_option(TREMOLO_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(TREMOLO_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(TREMOLO_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_PANNER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PANNER_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PANNER_DEPTH, CHORUSFX_POSITION, x);
|
||||
set_option(PANNER_WAVE, CHORUSFX_POSITION, WAVE_TRI);
|
||||
set_option(PANNER_WAVE, CHORUSFX_POSITION, WAVE_SINE);
|
||||
set_option(PANNER_WAVE, CHORUSFX_POSITION, WAVE_SQUARE);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_ENVELOPE);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ENVELOPE_SENSITIVITY, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ENVELOPE_RANGE, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_AUTOYA);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(AUTOYA_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(AUTOYA_INTENSITY, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=0x31; x++)
|
||||
set_option(AUTOYA_RANGE, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_YAYA);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(YAYA_PEDAL, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(YAYA_INTENSITY, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=0x31; x++)
|
||||
set_option(YAYA_RANGE, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_STEP_FILTER);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(STEP_FILTER_SPEED, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(STEP_FILTER_INTENSITY, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_WHAMMY);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_OCT_UP);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_2OCT_UP);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_2ND_DN);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_RV_2ND);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_4TH_DN);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_OCT_DN);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_2OCT_DN);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_DIV_BMB);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_M3_MA);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_2ND_MA3);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_3RD_4TH);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_4TH_5TH);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_5TH_OCT);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_HOCT_UP);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_HOCT_DN);
|
||||
set_option(WHAMMY_AMOUNT, CHORUSFX_POSITION, WHAMMY_OCT_UD);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WHAMMY_PEDAL, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(WHAMMY_MIX, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_PITCH_SHIFT);
|
||||
for (x=0; x<=0x30; x++)
|
||||
set_option(PITCH_AMOUNT, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PITCH_MIX, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_DETUNE);
|
||||
for (x=0; x<=0x30; x++)
|
||||
set_option(DETUNE_AMOUNT, CHORUSFX_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DETUNE_LEVEL, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_TYPE, CHORUSFX_POSITION, CHORUS_TYPE_IPS);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_OCT_D);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_7TH_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_6TH_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_5TH_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_4TH_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_3RD_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_2ND_DN);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_2ND_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_3RD_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_4TH_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_5TH_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_6TH_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_7TH_UP);
|
||||
set_option(IPS_SHIFT_AMOUNT, CHORUSFX_POSITION, IPS_OCT_U);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_E);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_F);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_GB);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_G);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_AB);
|
||||
set_option(IPS_KEY, CHORUSFX_POSITION, IPS_A);
|
||||
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_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);
|
||||
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_MINOR);
|
||||
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_DORIA);
|
||||
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_MIXLYD);
|
||||
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_LYDIAN);
|
||||
set_option(IPS_SCALE, CHORUSFX_POSITION, IPS_HMINO);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(IPS_LEVEL, CHORUSFX_POSITION, x);
|
||||
|
||||
set_option(CHORUSFX_ON_OFF, CHORUSFX_POSITION, 1);
|
||||
set_option(CHORUSFX_ON_OFF, CHORUSFX_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_delay()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(DELAY_TYPE, DELAY_POSITION, DELAY_TYPE_ANALOG);
|
||||
for (x=0; x<=139; x++)
|
||||
set_option(DELAY_TIME, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(ANALOG_LEVEL, DELAY_POSITION, x);
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(ANALOG_REPEATS, DELAY_POSITION, x);
|
||||
|
||||
set_option(DELAY_TYPE, DELAY_POSITION, DELAY_TYPE_DIGITAL);
|
||||
for (x=0; x<=139; x++)
|
||||
set_option(DELAY_TIME, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIGITAL_LEVEL, DELAY_POSITION, x);
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(DIGITAL_REPEATS, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIGITAL_DUCKER_THRESH, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(DIGITAL_DUCKER_LEVEL, DELAY_POSITION, x);
|
||||
|
||||
set_option(DELAY_TYPE, DELAY_POSITION, DELAY_TYPE_MODULATED);
|
||||
for (x=0; x<=139; x++)
|
||||
set_option(DELAY_TIME, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MODULATED_LEVEL, DELAY_POSITION, x);
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(MODULATED_REPEATS, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(MODULATED_DEPTH, DELAY_POSITION, x);
|
||||
|
||||
set_option(DELAY_TYPE, DELAY_POSITION, DELAY_TYPE_PONG);
|
||||
for (x=0; x<=139; x++)
|
||||
set_option(DELAY_TIME, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PONG_LEVEL, DELAY_POSITION, x);
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(PONG_REPEATS, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PONG_DUCKER_THRESH, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(PONG_DUCKER_LEVEL, DELAY_POSITION, x);
|
||||
|
||||
set_option(DELAY_TYPE, DELAY_POSITION, DELAY_TYPE_TAPE);
|
||||
for (x=0; x<=139; x++)
|
||||
set_option(DELAY_TIME, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TAPE_LEVEL, DELAY_POSITION, x);
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(TAPE_REPEATS, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TAPE_WOW, DELAY_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TAPE_FLUTTER, DELAY_POSITION, x);
|
||||
|
||||
set_option(DELAY_ON_OFF, DELAY_POSITION, 1);
|
||||
set_option(DELAY_ON_OFF, DELAY_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_reverb()
|
||||
{
|
||||
int x;
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_TWIN);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(TWIN_REVERB, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_LEX_AMBIENCE);
|
||||
for (x=0; x<=15; x++)
|
||||
set_option(LEX_AMBIENCE_PREDELAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_AMBIENCE_DECAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_AMBIENCE_LIVELINESS, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_AMBIENCE_LEVEL, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_LEX_STUDIO);
|
||||
for (x=0; x<=15; x++)
|
||||
set_option(LEX_STUDIO_PREDELAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_STUDIO_DECAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_STUDIO_LIVELINESS, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_STUDIO_LEVEL, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_LEX_ROOM);
|
||||
for (x=0; x<=15; x++)
|
||||
set_option(LEX_ROOM_PREDELAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_ROOM_DECAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_ROOM_LIVELINESS, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_ROOM_LEVEL, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_LEX_HALL);
|
||||
for (x=0; x<=15; x++)
|
||||
set_option(LEX_HALL_PREDELAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_HALL_DECAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_HALL_LIVELINESS, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(LEX_HALL_LEVEL, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_TYPE, REVERB_POSITION, REVERB_TYPE_EMT240_PLATE);
|
||||
for (x=0; x<=15; x++)
|
||||
set_option(EMT240_PLATE_PREDELAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(EMT240_PLATE_DECAY, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(EMT240_PLATE_LIVELINESS, REVERB_POSITION, x);
|
||||
for (x=0; x<=99; x++)
|
||||
set_option(EMT240_PLATE_LEVEL, REVERB_POSITION, x);
|
||||
|
||||
set_option(REVERB_ON_OFF, REVERB_POSITION, 1);
|
||||
set_option(REVERB_ON_OFF, REVERB_POSITION, 0);
|
||||
}
|
||||
|
||||
void test_usb()
|
||||
{
|
||||
int x;
|
||||
|
||||
for (x=0; x<=100; x++)
|
||||
set_option(USB_AUDIO_PLAYBACK_MIX, USB_POSITION, x);
|
||||
|
||||
for (x=0; x<=36; x++)
|
||||
set_option(USB_AUDIO_LEVEL, USB_POSITION, x);
|
||||
}
|
||||
|
||||
void test_all()
|
||||
{
|
||||
test_wah();
|
||||
test_compressor();
|
||||
test_dist();
|
||||
test_presets();
|
||||
test_pickups();
|
||||
test_eq();
|
||||
test_noisegate();
|
||||
test_chorusfx();
|
||||
test_delay();
|
||||
test_reverb();
|
||||
test_usb();
|
||||
}
|
||||
Reference in New Issue
Block a user