Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4740bef10f | ||
|
|
968d2947a7 | ||
|
|
e2cb03ab32 | ||
|
|
ce5fe3fe0c | ||
|
|
966fc748af | ||
|
|
709406f3ef | ||
|
|
ce522227c7 | ||
|
|
7d13b2a7ea | ||
|
|
d4c86b3a60 | ||
|
|
ca23f2c94c | ||
|
|
bfc285ad0f | ||
|
|
4e5f2438d3 | ||
|
|
10aac46dde |
10
Makefile
10
Makefile
@@ -1,7 +1,7 @@
|
||||
CC = gcc
|
||||
CFLAGS = `pkg-config --cflags glib-2.0 gtk+-2.0` -Wall -g
|
||||
CFLAGS = `pkg-config --cflags glib-2.0 gio-2.0 gtk+-2.0` -Wall -g
|
||||
OFLAG = -o
|
||||
LIBS = `pkg-config --libs glib-2.0 gtk+-2.0 alsa`
|
||||
LIBS = `pkg-config --libs glib-2.0 gio-2.0 gtk+-2.0 alsa` -lexpat
|
||||
|
||||
.SUFFIXES : .o .c
|
||||
.c.o :
|
||||
@@ -9,8 +9,8 @@ LIBS = `pkg-config --libs glib-2.0 gtk+-2.0 alsa`
|
||||
|
||||
all: gdigi
|
||||
|
||||
gdigi: gdigi.o tests.o gui.o effects.o
|
||||
$(CC) $(LIBS) $(OFLAG) gdigi gdigi.o tests.o gui.o effects.o
|
||||
gdigi: gdigi.o tests.o gui.o effects.o preset.o
|
||||
$(CC) $(LIBS) $(OFLAG) gdigi gdigi.o tests.o gui.o effects.o preset.o
|
||||
|
||||
gdigi.o: gdigi.c
|
||||
|
||||
@@ -20,6 +20,8 @@ gui.o: gui.c
|
||||
|
||||
effects.o: effects.c
|
||||
|
||||
preset.o: preset.c
|
||||
|
||||
clean:
|
||||
rm *.o
|
||||
|
||||
|
||||
2
README
2
README
@@ -1,4 +1,4 @@
|
||||
Requirments: alsa, gtk+, glib
|
||||
Requirments: alsa, gtk+, glib, expat
|
||||
|
||||
Getting started guide:
|
||||
-to compile: make
|
||||
|
||||
24
TODO
24
TODO
@@ -1,10 +1,26 @@
|
||||
-figure out all magic commands
|
||||
-make complete gui
|
||||
-amp/cabinet models
|
||||
-cabinet models
|
||||
-tone library
|
||||
-effects library
|
||||
-effects level
|
||||
-handling presets (loading, saving, exporting/importing to/from xml patches)
|
||||
-handling presets (loading, saving, exporting to xml patches)
|
||||
-buildsystem
|
||||
-figure out how to get current device settings, start gui with proper values
|
||||
-fix expression pedal settings (possible types depend on active preset)
|
||||
-start gui with proper values
|
||||
To do so we need to figure out reply formatting of command querying preset.
|
||||
amidi --port=hw:1,0,0 --send-hex F0 00 00 10 00 5E 02 2a 00 04 00 62 F7 --receive=preset
|
||||
will create file named preset (give a while for it, and then hit ctrl+c)
|
||||
this file should have around 440 bytes (depends on actual preset)
|
||||
0x21 byte holds amount of options
|
||||
from 0x22 byte starts effects configuration which is:
|
||||
-2 bytes for ID
|
||||
-1 byte for position
|
||||
-1 to 3 bytes for value
|
||||
Each 8th byte (beginning from 0x27) seems to be status byte which describes
|
||||
whether or not we shall add 0x80 to ID or value and whether or not value
|
||||
will be multibyte. So far I couldn't figure the exact meaning of those bytes.
|
||||
To check you can download some patch from DigiTech Sound Community, apply
|
||||
it to your device, and then do this amidi command.
|
||||
Open resulting file in hex editor, and open patch file in text editor.
|
||||
Every ID, position and value found in patch will appear in the binary file.
|
||||
-fix expression pedal settings (possible types depend on active effects)
|
||||
|
||||
41
effects.c
41
effects.c
@@ -116,9 +116,16 @@ static EffectSettings dist_mp_settings[] = {
|
||||
{"MP volume", 0.0, 99.0, DIST_MP_VOLUME, DIST_POSITION},
|
||||
};
|
||||
|
||||
static EffectSettings amp_settings[] = {
|
||||
{"AMP gain", 0.0, 99.0, AMP_GAIN, AMP_POSITION},
|
||||
{"AMP level", 0.0, 99.0, AMP_LEVEL, AMP_POSITION},
|
||||
};
|
||||
|
||||
static EffectSettings amp_settings2[] = {
|
||||
{"AMP level", 0.0, 99.0, AMP_LEVEL, AMP_POSITION},
|
||||
};
|
||||
|
||||
static EffectSettings eq_settings[] = {
|
||||
{"EQ gain", 0.0, 99.0, AMP_GAIN, AMP_POSITION},
|
||||
{"EQ level", 0.0, 99.0, AMP_LEVEL, AMP_POSITION},
|
||||
// TODO: make those display propertly (display range -12 to 12)
|
||||
{"EQ bass", 0.0, 24.0, EQ_BASS, EQ_POSITION},
|
||||
{"EQ mid", 0.0, 24.0, EQ_MID, EQ_POSITION},
|
||||
@@ -432,6 +439,31 @@ static EffectGroup reverb_group[] = {
|
||||
{REVERB_TYPE_EMT240_PLATE, "EMT240 Plate", REVERB_TYPE, REVERB_POSITION, reverb_emt240_plate_settings, G_N_ELEMENTS(reverb_emt240_plate_settings)},
|
||||
};
|
||||
|
||||
static EffectGroup amp_group[] = {
|
||||
{AMP_TYPE_TWEED_CHAMP, "Tweed Champ", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_TWEED_DELUXE, "Tweed Deluxe", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_TWEED_BASSMAN, "Tweed Bassman", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_BLACKFACE_TWIN, "Blackface Twin", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_BLACKFACE_DELUXE, "Blackface Deluxe", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_SUPER_LEAD_PLEXI, "Super Lead Plexi", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_MASTER_VOLUME, "Master Volume", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_JCM800, "JCM800", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_JCM900, "JCM900", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_AC15, "AC15", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_AC30TB, "AC30TB", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_HIWATT_100, "Hiwatt 100", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_BOOGIE_MARK_II, "Boogie Mark II", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_DUAL_RECTIFIER, "Dual Rectifier", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_MATCHLESS_HC30, "Matchless HC30", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_SOLO, "Solo", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_METAL, "Metal", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_BRIGHT, "Bright", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_CLEAN, "Clean", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_HIGH_GAIN, "High Gain", AMP_TYPE, AMP_POSITION, amp_settings, G_N_ELEMENTS(amp_settings)},
|
||||
{AMP_TYPE_ACOUSTIC, "Acoustic", AMP_TYPE, AMP_POSITION, amp_settings2, G_N_ELEMENTS(amp_settings2)},
|
||||
{AMP_TYPE_DIRECT, "Direct", AMP_TYPE, AMP_POSITION, amp_settings2, G_N_ELEMENTS(amp_settings2)},
|
||||
};
|
||||
|
||||
static EffectGroup eq_group[] = {
|
||||
{EQ_TYPE_BRIGHT, "Bright", EQ_TYPE, EQ_POSITION, eq_settings, G_N_ELEMENTS(eq_settings)},
|
||||
{EQ_TYPE_MIDBOOST, "Mid Boost", EQ_TYPE, EQ_POSITION, eq_settings, G_N_ELEMENTS(eq_settings)},
|
||||
@@ -467,12 +499,17 @@ static Effect reverb_effect[] = {
|
||||
{"Reverb", REVERB_ON_OFF, REVERB_POSITION, reverb_group, G_N_ELEMENTS(reverb_group)},
|
||||
};
|
||||
|
||||
static Effect amp_effect[] = {
|
||||
{"Amp", AMP_ON_OFF, AMP_POSITION, amp_group, G_N_ELEMENTS(amp_group)},
|
||||
};
|
||||
|
||||
static Effect eq_effect[] = {
|
||||
{"EQ", EQ_ON_OFF, EQ_POSITION, eq_group, G_N_ELEMENTS(eq_group)},
|
||||
};
|
||||
|
||||
EffectList effects[] = {
|
||||
{wah_effect, G_N_ELEMENTS(wah_effect)},
|
||||
{amp_effect, G_N_ELEMENTS(amp_effect)},
|
||||
{eq_effect, G_N_ELEMENTS(eq_effect)},
|
||||
{comp_effect, G_N_ELEMENTS(comp_effect)},
|
||||
{dist_effect, G_N_ELEMENTS(dist_effect)},
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_EFFECTS_H
|
||||
#define GDIGI_EFFECTS_H
|
||||
|
||||
#include <glib/gtypes.h>
|
||||
|
||||
typedef struct {
|
||||
@@ -45,3 +48,5 @@ typedef struct {
|
||||
Effect *effect; /* list of supported effects */
|
||||
gint amt; /* list of supported effects length */
|
||||
} EffectList;
|
||||
|
||||
#endif /* GDIGI_EFFECTS_H */
|
||||
|
||||
231
gdigi.c
231
gdigi.c
@@ -18,11 +18,12 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <string.h>
|
||||
#include <alloca.h>
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
|
||||
static snd_rawmidi_t *output;
|
||||
static snd_rawmidi_t *output = NULL;
|
||||
static snd_rawmidi_t *input = NULL;
|
||||
static char *device = "hw:1,0,0";
|
||||
|
||||
/*
|
||||
@@ -54,7 +55,7 @@ gboolean open_device()
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_open(NULL, &output, device, SND_RAWMIDI_NONBLOCK);
|
||||
err = snd_rawmidi_open(&input, &output, device, SND_RAWMIDI_NONBLOCK);
|
||||
if (err) {
|
||||
fprintf(stderr, "snd_rawmidi_open %s failed: %d\n", device, err);
|
||||
return TRUE;
|
||||
@@ -65,6 +66,9 @@ gboolean open_device()
|
||||
fprintf(stderr, "snd_rawmidi_nonblock failed: %d\n", err);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
snd_rawmidi_read(input, NULL, 0); /* trigger reading */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -76,6 +80,68 @@ void send_data(char *data, int length)
|
||||
snd_rawmidi_write(output, data, length);
|
||||
}
|
||||
|
||||
/*
|
||||
reads data from MIDI IN
|
||||
returns GString containing data
|
||||
if no data was read it returns NULL
|
||||
*/
|
||||
GString* read_data()
|
||||
{
|
||||
/* This is mostly taken straight from alsa-utils-1.0.19 amidi/amidi.c
|
||||
by Clemens Ladisch <clemens@ladisch.de> */
|
||||
int err;
|
||||
int npfds;
|
||||
struct pollfd *pfds;
|
||||
GString *string = NULL;
|
||||
|
||||
npfds = snd_rawmidi_poll_descriptors_count(input);
|
||||
pfds = alloca(npfds * sizeof(struct pollfd));
|
||||
snd_rawmidi_poll_descriptors(input, pfds, npfds);
|
||||
|
||||
do {
|
||||
char buf[20];
|
||||
int i, length;
|
||||
unsigned short revents;
|
||||
|
||||
err = poll(pfds, npfds, 200);
|
||||
if (err < 0 && errno == EINTR)
|
||||
break;
|
||||
if (err < 0) {
|
||||
g_error("poll failed: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
if ((err = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) {
|
||||
g_error("cannot get poll events: %s", snd_strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (revents & (POLLERR | POLLHUP))
|
||||
break;
|
||||
if (!(revents & POLLIN))
|
||||
continue;
|
||||
err = snd_rawmidi_read(input, buf, sizeof(buf));
|
||||
if (err == -EAGAIN)
|
||||
continue;
|
||||
if (err < 0) {
|
||||
g_error("cannot read: %s", snd_strerror(err));
|
||||
break;
|
||||
}
|
||||
length = 0;
|
||||
for (i = 0; i < err; ++i)
|
||||
if (buf[i] != 0xFE) // ignore active sensing
|
||||
buf[length++] = buf[i];
|
||||
|
||||
if (length != 0) {
|
||||
if (string == NULL) {
|
||||
string = g_string_new_len(buf, length);
|
||||
} else {
|
||||
string = g_string_append_len(string, buf, length);
|
||||
}
|
||||
}
|
||||
} while (err != 0);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/*
|
||||
id - ID as found in preset file
|
||||
position - Position as found in preset file
|
||||
@@ -151,21 +217,11 @@ void set_option(guint id, guint position, guint value)
|
||||
}
|
||||
|
||||
/* x = 0 to 60 */
|
||||
void switch_user_preset(int x)
|
||||
void switch_preset(guint bank, guint x)
|
||||
{
|
||||
static char switch_preset[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x39, 0x00, 0x01 /* bank = user */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
|
||||
|
||||
switch_preset[11] = x;
|
||||
switch_preset[16] = calculate_checksum(switch_preset, sizeof(switch_preset), 16);
|
||||
|
||||
send_data(switch_preset, sizeof(switch_preset));
|
||||
}
|
||||
|
||||
/* x = 0 to 60 */
|
||||
void switch_system_preset(int x)
|
||||
{
|
||||
static char switch_preset[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x39, 0x00, 0x00 /* bank = system */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
|
||||
static char switch_preset[] = {0x00, 0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x39, 0x00, 0x00 /* bank */, 0x00 /* no */, 0x04, 0x00, 0x00, 0x01, 0x00 /* confirm */, 0xF7};
|
||||
|
||||
switch_preset[10] = bank;
|
||||
switch_preset[11] = x;
|
||||
switch_preset[16] = calculate_checksum(switch_preset, sizeof(switch_preset), 16);
|
||||
|
||||
@@ -178,6 +234,38 @@ void set_preset_level(int level)
|
||||
set_option(PRESET_LEVEL, PRESET_POSITION, level);
|
||||
}
|
||||
|
||||
void store_preset_name(int x, const gchar *name)
|
||||
{
|
||||
static char set_name[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5e, 0x02, 0x39, 0x00, 0x04, 0x00, 0x01, 0x00 /* preset number */, 0x00 /* name starts here */, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
set_name[12] = x;
|
||||
|
||||
int a;
|
||||
int b;
|
||||
b = 0;
|
||||
for (a=0; (name != NULL && a<strlen(name)) && a<10 ; a++) {
|
||||
if (a == 3) {
|
||||
set_name[13+a] = 0x00;
|
||||
b++;
|
||||
}
|
||||
set_name[13+a+b] = name[a];
|
||||
}
|
||||
|
||||
if (a == 3) {
|
||||
set_name[13+a+1+b] = 0x00;
|
||||
a++;
|
||||
} else
|
||||
set_name[13+a+b] = 0x00;
|
||||
|
||||
set_name[13+a+1+b] = 0x00;
|
||||
set_name[13+a+3+b] = 0xF7;
|
||||
set_name[13+a+2+b] = calculate_checksum(set_name, 13+a+4+b, 13+a+2+b);
|
||||
|
||||
send_data(set_name, 14+a+3+b);
|
||||
|
||||
switch_preset(PRESETS_USER, x);
|
||||
}
|
||||
|
||||
/* x = 0 to 59 (preset number) */
|
||||
void set_preset_name(int x, gchar *name)
|
||||
{
|
||||
@@ -207,28 +295,99 @@ void set_preset_name(int x, gchar *name)
|
||||
send_data(set_name, 13+a+3+b);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
gtk_init(&argc, &argv);
|
||||
/*
|
||||
Queries user preset names
|
||||
Valid bank values are PRESETS_SYSTEM and PRESETS_USER
|
||||
Returns GStrv which must be freed with g_strfreev
|
||||
Returns NULL on error
|
||||
*/
|
||||
GStrv query_preset_names(guint bank)
|
||||
{
|
||||
GString *data = NULL;
|
||||
int x; /* used to iterate over whole reply */
|
||||
int n = 0; /* current preset number */
|
||||
int n_total; /* total number of presets */
|
||||
gchar **str_array = NULL;
|
||||
|
||||
int c;
|
||||
while (1) {
|
||||
static struct option long_options[] = {
|
||||
{"device", required_argument, 0, 'd'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index = 0;
|
||||
c = getopt_long(argc, argv, "d:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
/* clear MIDI IN buffer */
|
||||
data = read_data();
|
||||
if (data != NULL)
|
||||
g_string_free(data, TRUE);
|
||||
|
||||
switch(c) {
|
||||
case 'd':
|
||||
device = optarg;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
/* query user preset names */
|
||||
char command[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x21, 0x00, 0x00 /* bank */, 0x00 /* checksum */, 0xF7};
|
||||
command[9] = bank;
|
||||
command[10] = calculate_checksum(command, sizeof(command), 10);
|
||||
send_data(command, sizeof(command));
|
||||
|
||||
/* read reply */
|
||||
data = read_data();
|
||||
|
||||
if (data != NULL) {
|
||||
char preset_reply_magic[] = {0xF0, 0x00, 0x00, 0x10, 0x00, 0x5E, 0x02, 0x22, 0x00, 0x01};
|
||||
if (strncmp(data->str, preset_reply_magic, sizeof(preset_reply_magic)) == 0) {
|
||||
char buf[10]; /* temporary, used to read single preset name */
|
||||
int b = 0; /* used to iterate over buf */
|
||||
|
||||
if (data->len >= 10) {
|
||||
n_total = data->str[10];
|
||||
str_array = g_new(gchar*, n_total + 1);
|
||||
str_array[n_total] = NULL;
|
||||
}
|
||||
|
||||
for (x=11; ((x<data->len) && (n<n_total)); x++) {
|
||||
if ((x % 8) == 0) // every 8th byte is 0x00
|
||||
continue;
|
||||
|
||||
if (data->str[x] == 0xF7) // every message ends with 0xF7
|
||||
break;
|
||||
|
||||
if (data->str[x] == 0) { // presets are splitted with 0x00
|
||||
gchar *name;
|
||||
|
||||
name = g_new(gchar, b+1);
|
||||
strncpy(name, buf, b);
|
||||
name[b] = 0;
|
||||
if (n < n_total)
|
||||
str_array[n] = name;
|
||||
|
||||
b = 0;
|
||||
n++;
|
||||
} else {
|
||||
if (b < 10) {
|
||||
buf[b] = data->str[x];
|
||||
b++;
|
||||
} else {
|
||||
g_message("Preset name seems to be longer than 10 chars!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g_string_free(data, TRUE);
|
||||
}
|
||||
return str_array;
|
||||
}
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{"device", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &device, "MIDI device port to use", NULL},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
context = g_option_context_new(NULL);
|
||||
g_option_context_add_main_entries(context, options, NULL);
|
||||
g_option_context_add_group(context, gtk_get_option_group(TRUE));
|
||||
|
||||
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
||||
g_message("option parsing failed: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
g_option_context_free(context);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_option_context_free(context);
|
||||
|
||||
if (open_device() == TRUE) {
|
||||
GtkWidget *msg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
|
||||
@@ -245,6 +404,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (output != NULL)
|
||||
snd_rawmidi_close(output);
|
||||
if (input != NULL)
|
||||
snd_rawmidi_close(input);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
43
gdigi.h
43
gdigi.h
@@ -14,7 +14,11 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_H
|
||||
#define GDIGI_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
enum {
|
||||
WAH_TYPE_CRY = 132,
|
||||
@@ -121,6 +125,31 @@ enum {
|
||||
#define PRESET_POSITION 18
|
||||
#define PRESET_LEVEL 2626
|
||||
|
||||
enum {
|
||||
AMP_TYPE_TWEED_CHAMP = 307,
|
||||
AMP_TYPE_TWEED_DELUXE = 308,
|
||||
AMP_TYPE_TWEED_BASSMAN = 309,
|
||||
AMP_TYPE_BLACKFACE_TWIN = 311,
|
||||
AMP_TYPE_BLACKFACE_DELUXE = 312,
|
||||
AMP_TYPE_SUPER_LEAD_PLEXI = 314,
|
||||
AMP_TYPE_MASTER_VOLUME = 316,
|
||||
AMP_TYPE_JCM800 = 317,
|
||||
AMP_TYPE_JCM900 = 318,
|
||||
AMP_TYPE_AC15 = 322,
|
||||
AMP_TYPE_AC30TB = 323,
|
||||
AMP_TYPE_HIWATT_100 = 324,
|
||||
AMP_TYPE_BOOGIE_MARK_II = 320,
|
||||
AMP_TYPE_DUAL_RECTIFIER = 321,
|
||||
AMP_TYPE_MATCHLESS_HC30 = 326,
|
||||
AMP_TYPE_SOLO = 331,
|
||||
AMP_TYPE_METAL = 332,
|
||||
AMP_TYPE_BRIGHT = 333,
|
||||
AMP_TYPE_CLEAN = 335,
|
||||
AMP_TYPE_HIGH_GAIN = 337,
|
||||
AMP_TYPE_ACOUSTIC = 341,
|
||||
AMP_TYPE_DIRECT = 306
|
||||
};
|
||||
|
||||
enum {
|
||||
EQ_TYPE_BRIGHT = 1474,
|
||||
EQ_TYPE_MIDBOOST = 1472,
|
||||
@@ -128,6 +157,8 @@ enum {
|
||||
EQ_TYPE_WARM = 1475
|
||||
};
|
||||
|
||||
#define AMP_TYPE 2496
|
||||
#define AMP_ON_OFF 265
|
||||
#define AMP_POSITION 8
|
||||
|
||||
#define AMP_GAIN 2497
|
||||
@@ -458,7 +489,15 @@ enum {
|
||||
#define USB_AUDIO_PLAYBACK_MIX 12297
|
||||
#define USB_AUDIO_LEVEL 12307
|
||||
|
||||
typedef enum {
|
||||
PRESETS_SYSTEM = 0,
|
||||
PRESETS_USER = 1
|
||||
} PresetBank;
|
||||
|
||||
void set_option(guint id, guint position, guint value);
|
||||
void switch_user_preset(int x);
|
||||
void switch_system_preset(int x);
|
||||
void switch_preset(guint bank, guint x);
|
||||
void store_preset_name(int x, const gchar *name);
|
||||
void set_preset_level(int level);
|
||||
GStrv query_preset_names(PresetBank bank);
|
||||
|
||||
#endif /* GDIGI_H */
|
||||
|
||||
405
gui.c
405
gui.c
@@ -18,10 +18,21 @@
|
||||
#include "gdigi.h"
|
||||
#include "gui.h"
|
||||
#include "effects.h"
|
||||
#include "preset.h"
|
||||
|
||||
extern EffectList effects[];
|
||||
extern int n_effects;
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *widget;
|
||||
gint id;
|
||||
gint position;
|
||||
|
||||
/* used for combo boxes, if widget isn't combo box, then both value and x are -1 */
|
||||
gint value; /* effect type value */
|
||||
gint x; /* combo box item number */
|
||||
} WidgetListElem;
|
||||
|
||||
void value_changed_option_cb(GtkSpinButton *spinbutton, EffectSettings *setting)
|
||||
{
|
||||
g_return_if_fail(setting != NULL);
|
||||
@@ -38,7 +49,21 @@ void toggled_cb(GtkToggleButton *button, Effect *effect)
|
||||
set_option(effect->option, effect->position, val);
|
||||
}
|
||||
|
||||
GtkWidget *create_table(EffectSettings *settings, gint amt)
|
||||
static void widget_list_add(GList **list, GtkWidget *widget, gint id, gint position, gint value, gint x)
|
||||
{
|
||||
WidgetListElem *el;
|
||||
|
||||
el = g_malloc(sizeof(WidgetListElem));
|
||||
el->widget = widget;
|
||||
el->id = id;
|
||||
el->position = position;
|
||||
el->value = value;
|
||||
el->x = x;
|
||||
|
||||
*list = g_list_prepend(*list, el);
|
||||
}
|
||||
|
||||
GtkWidget *create_table(GList **list, EffectSettings *settings, gint amt)
|
||||
{
|
||||
GtkWidget *table, *label, *widget;
|
||||
GtkObject *adj;
|
||||
@@ -51,7 +76,7 @@ GtkWidget *create_table(EffectSettings *settings, gint amt)
|
||||
adj = gtk_adjustment_new(0.0, settings[x].min, settings[x].max, 1.0, 1.0, 1.0);
|
||||
widget = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1.0, 0);
|
||||
g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK(value_changed_option_cb), &settings[x]);
|
||||
|
||||
widget_list_add(list, widget, settings[x].option, settings[x].position, -1, -1);
|
||||
gtk_table_attach(GTK_TABLE(table), label, 0, 1, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
|
||||
gtk_table_attach(GTK_TABLE(table), widget, 1, 2, x, x+1, GTK_SHRINK, GTK_SHRINK, 2, 2);
|
||||
}
|
||||
@@ -59,11 +84,12 @@ GtkWidget *create_table(EffectSettings *settings, gint amt)
|
||||
return table;
|
||||
}
|
||||
|
||||
GtkWidget *create_on_off_button(Effect *effect)
|
||||
GtkWidget *create_on_off_button(GList **list, Effect *effect)
|
||||
{
|
||||
GtkWidget *button = gtk_toggle_button_new_with_label(effect->label);
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggled_cb), effect);
|
||||
widget_list_add(list, button, effect->option, effect->position, -1, -1);
|
||||
return button;
|
||||
}
|
||||
|
||||
@@ -113,7 +139,7 @@ void combo_box_changed_cb(GtkComboBox *widget, gpointer data)
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
GtkWidget *create_widget_container(GList **list, EffectGroup *group, gint amt)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *widget;
|
||||
@@ -136,7 +162,7 @@ GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box), group[x].label);
|
||||
cmbox_no++;
|
||||
|
||||
widget = create_table(group[x].settings, group[x].settings_amt);
|
||||
widget = create_table(list, group[x].settings, group[x].settings_amt);
|
||||
g_object_ref_sink(widget);
|
||||
|
||||
settings = g_malloc(sizeof(EffectSettingsGroup));
|
||||
@@ -144,12 +170,13 @@ GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
settings->option = group[x].option;
|
||||
settings->position = group[x].position;
|
||||
settings->child = widget;
|
||||
widget_list_add(list, combo_box, group[x].option, group[x].position, group[x].id, x);
|
||||
|
||||
name = g_strdup_printf("SettingsGroup%d", cmbox_no);
|
||||
g_object_set_data_full(G_OBJECT(combo_box), name, settings, ((GDestroyNotify)effect_settings_group_free));
|
||||
g_free(name);
|
||||
} else {
|
||||
widget = create_table(group[x].settings, group[x].settings_amt);
|
||||
widget = create_table(list, group[x].settings, group[x].settings_amt);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), widget);
|
||||
}
|
||||
}
|
||||
@@ -157,7 +184,7 @@ GtkWidget *create_widget_container(EffectGroup *group, gint amt)
|
||||
return vbox;
|
||||
};
|
||||
|
||||
GtkWidget *create_vbox(Effect *widgets, gint amt)
|
||||
GtkWidget *create_vbox(GList **list, Effect *widgets, gint amt)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
@@ -171,10 +198,10 @@ GtkWidget *create_vbox(Effect *widgets, gint amt)
|
||||
gtk_box_set_homogeneous(GTK_BOX(hbox), TRUE);
|
||||
|
||||
for (x = 0; x<amt; x++) {
|
||||
widget = create_on_off_button(&widgets[x]);
|
||||
widget = create_on_off_button(list, &widgets[x]);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
|
||||
|
||||
table = create_widget_container(widgets[x].group, widgets[x].group_amt);
|
||||
table = create_widget_container(list, widgets[x].group, widgets[x].group_amt);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 2);
|
||||
}
|
||||
|
||||
@@ -182,25 +209,381 @@ GtkWidget *create_vbox(Effect *widgets, gint amt)
|
||||
return vbox;
|
||||
}
|
||||
|
||||
enum {
|
||||
PRESET_NAME_COLUMN = 0,
|
||||
PRESET_NUMBER_COLUMN,
|
||||
PRESET_BANK_COLUMN,
|
||||
NUM_COLUMNS
|
||||
};
|
||||
|
||||
void row_activate_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, GtkTreeModel *model) {
|
||||
GtkTreeIter iter;
|
||||
gint id;
|
||||
gint bank;
|
||||
|
||||
gtk_tree_model_get_iter(model, &iter, path);
|
||||
gtk_tree_model_get(model, &iter, PRESET_NUMBER_COLUMN, &id, PRESET_BANK_COLUMN, &bank, -1);
|
||||
|
||||
if ((bank != -1) && (id != -1))
|
||||
switch_preset(bank, id);
|
||||
}
|
||||
|
||||
static void fill_store_with_presets(GtkTreeStore *model, guint bank, gchar *name)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter child_iter;
|
||||
int x;
|
||||
|
||||
GStrv presets = query_preset_names(bank);
|
||||
gtk_tree_store_append(model, &iter, NULL);
|
||||
gtk_tree_store_set(model, &iter,
|
||||
PRESET_NAME_COLUMN, name,
|
||||
PRESET_NUMBER_COLUMN, -1,
|
||||
PRESET_BANK_COLUMN, -1,
|
||||
-1);
|
||||
|
||||
for (x=0; x<g_strv_length(presets); x++) {
|
||||
gtk_tree_store_append(model, &child_iter, &iter);
|
||||
gtk_tree_store_set(model, &child_iter,
|
||||
PRESET_NAME_COLUMN, presets[x],
|
||||
PRESET_NUMBER_COLUMN, x,
|
||||
PRESET_BANK_COLUMN, bank,
|
||||
-1);
|
||||
}
|
||||
g_strfreev(presets);
|
||||
}
|
||||
|
||||
static void fill_store(GtkTreeStore *model)
|
||||
{
|
||||
fill_store_with_presets(model, PRESETS_USER, "User Presets");
|
||||
fill_store_with_presets(model, PRESETS_SYSTEM, "System Presets");
|
||||
}
|
||||
|
||||
GtkWidget *create_preset_tree()
|
||||
{
|
||||
GtkWidget *treeview;
|
||||
GtkTreeStore *store;
|
||||
GtkCellRenderer *renderer;
|
||||
|
||||
store = gtk_tree_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
|
||||
fill_store(store);
|
||||
|
||||
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
g_object_unref(store);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(treeview),
|
||||
-1, "Preset name",
|
||||
renderer, "text",
|
||||
PRESET_NAME_COLUMN, NULL);
|
||||
|
||||
g_object_set(G_OBJECT(treeview), "headers-visible", FALSE, NULL);
|
||||
g_signal_connect(G_OBJECT(treeview), "realize", G_CALLBACK(gtk_tree_view_expand_all), NULL);
|
||||
g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(row_activate_cb), GTK_TREE_MODEL(store));
|
||||
|
||||
return treeview;
|
||||
}
|
||||
|
||||
static void show_store_preset_window(GtkWidget *window, gchar *default_name)
|
||||
{
|
||||
GtkWidget *dialog, *cmbox, *entry, *table, *label;
|
||||
GStrv names;
|
||||
int x;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons("Store preset",
|
||||
GTK_WINDOW(window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
table = gtk_table_new(2, 2, FALSE);
|
||||
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
|
||||
|
||||
cmbox = gtk_combo_box_new_text();
|
||||
names = query_preset_names(PRESETS_USER);
|
||||
for (x=0; x<g_strv_length(names); x++) {
|
||||
gchar *title = g_strdup_printf("%d - %s", x+1, names[x]);
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(cmbox), title);
|
||||
g_free(title);
|
||||
}
|
||||
g_strfreev(names);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), cmbox, 1, 2, 0, 1);
|
||||
|
||||
entry = gtk_entry_new();
|
||||
if (default_name != NULL)
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), default_name);
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), entry, 1, 2, 1, 2);
|
||||
|
||||
label = gtk_label_new("Preset slot:");
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
|
||||
|
||||
label = gtk_label_new("Preset name:");
|
||||
gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
|
||||
|
||||
gtk_widget_show_all(GTK_DIALOG(dialog)->vbox);
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
gint number = gtk_combo_box_get_active(GTK_COMBO_BOX(cmbox));
|
||||
if (number != -1) {
|
||||
store_preset_name(number, gtk_entry_get_text(GTK_ENTRY(entry)));
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
static void apply_widget_setting(WidgetListElem *el, SettingParam *param)
|
||||
{
|
||||
if ((el->id == param->id) && (el->position == param->position)) {
|
||||
if (el->value == -1) {
|
||||
if (GTK_IS_TOGGLE_BUTTON(el->widget))
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(el->widget), (param->value == 0) ? FALSE : TRUE);
|
||||
else if (GTK_IS_SPIN_BUTTON(el->widget))
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(el->widget), param->value);
|
||||
} else { /* combo box */
|
||||
if (el->value == param->value)
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(el->widget), el->x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_preset_to_gui(GList *list, Preset *preset)
|
||||
{
|
||||
GList *iter = preset->params;
|
||||
while (iter) {
|
||||
SettingParam *param = iter->data;
|
||||
iter = iter->next;
|
||||
|
||||
if (param != NULL)
|
||||
g_list_foreach(list, (GFunc)apply_widget_setting, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void action_store_cb(GtkAction *action)
|
||||
{
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
show_store_preset_window(window, NULL);
|
||||
}
|
||||
|
||||
static void action_show_about_dialog_cb(GtkAction *action)
|
||||
{
|
||||
static const gchar * const authors[] = {
|
||||
"Tomasz Moń <desowin@gmail.com>",
|
||||
NULL
|
||||
};
|
||||
static const gchar copyright[] = "Copyright \xc2\xa9 2009 Tomasz Moń";
|
||||
static const gchar website[] = "http://desowin.org/gdigi/";
|
||||
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
|
||||
gtk_show_about_dialog(GTK_WINDOW(window),
|
||||
"authors", authors,
|
||||
"copyright", copyright,
|
||||
"website", website,
|
||||
NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
gchar *suffix;
|
||||
} SupportedFileTypes;
|
||||
|
||||
static SupportedFileTypes file_types[] = {
|
||||
{"RP250Preset", "*.rp250p"},
|
||||
};
|
||||
static guint n_file_types = G_N_ELEMENTS(file_types);
|
||||
|
||||
static void action_open_preset_cb(GtkAction *action)
|
||||
{
|
||||
static GtkWidget *dialog = NULL;
|
||||
|
||||
if (dialog != NULL)
|
||||
return;
|
||||
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
GList **list = g_object_get_data(G_OBJECT(action), "widget-list");
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new("Open Preset", GTK_WINDOW(window),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
|
||||
GtkFileFilter *filter;
|
||||
filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, "All Supported Types");
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
|
||||
int x;
|
||||
for (x=0; x<n_file_types; x++) {
|
||||
GtkFileFilter *current_filter = gtk_file_filter_new();
|
||||
|
||||
gtk_file_filter_set_name(current_filter, file_types[x].name);
|
||||
gtk_file_filter_add_pattern(current_filter, file_types[x].suffix);
|
||||
gtk_file_filter_add_pattern(filter, file_types[x].suffix);
|
||||
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), current_filter);
|
||||
}
|
||||
|
||||
gboolean loaded = FALSE;
|
||||
while (!loaded && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
Preset *preset = create_preset_from_xml_file(filename);
|
||||
if (preset != NULL) {
|
||||
if (list != NULL)
|
||||
apply_preset_to_gui(*list, preset);
|
||||
|
||||
gtk_widget_hide(dialog);
|
||||
|
||||
GList *iter = preset->params;
|
||||
while (iter) {
|
||||
SettingParam *param = iter->data;
|
||||
iter = iter->next;
|
||||
|
||||
/* sending those is likely to freeze/reboot device */
|
||||
if ((param->id == 8704) || (param->id == 8705))
|
||||
continue;
|
||||
|
||||
set_option(param->id, param->position, param->value);
|
||||
};
|
||||
show_store_preset_window(window, preset->name);
|
||||
|
||||
preset_free(preset);
|
||||
loaded = TRUE;
|
||||
}
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
dialog = NULL;
|
||||
}
|
||||
|
||||
static void widget_list_free(GList *list)
|
||||
{
|
||||
GList *iter;
|
||||
for (iter = list; iter; iter = iter->next) {
|
||||
g_free(iter->data);
|
||||
}
|
||||
g_list_free(list);
|
||||
}
|
||||
|
||||
static void action_quit_cb(GtkAction *action)
|
||||
{
|
||||
GtkWidget *window = g_object_get_data(G_OBJECT(action), "window");
|
||||
GList **list = g_object_get_data(G_OBJECT(action), "widget-list");
|
||||
|
||||
widget_list_free(*list);
|
||||
*list = NULL;
|
||||
|
||||
gtk_widget_destroy(window);
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
static GtkActionEntry entries[] = {
|
||||
{"File", NULL, "_File"},
|
||||
{"Preset", NULL, "_Preset"},
|
||||
{"Help", NULL, "_Help"},
|
||||
{"Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open preset file", G_CALLBACK(action_open_preset_cb)},
|
||||
{"Quit", GTK_STOCK_QUIT, "_Quit", "<control>Q", "Quit", G_CALLBACK(action_quit_cb)},
|
||||
{"Store", NULL, "_Store", "<control>S", "Store", G_CALLBACK(action_store_cb)},
|
||||
{"About", GTK_STOCK_ABOUT, "_About", "<control>A", "About", G_CALLBACK(action_show_about_dialog_cb)},
|
||||
};
|
||||
static guint n_entries = G_N_ELEMENTS(entries);
|
||||
|
||||
static const gchar *menu_info =
|
||||
"<ui>"
|
||||
" <menubar name='MenuBar'>"
|
||||
" <menu action='File'>"
|
||||
" <menuitem action='Open'/>"
|
||||
" <separator/>"
|
||||
" <menuitem action='Quit'/>"
|
||||
" </menu>"
|
||||
" <menu action='Preset'>"
|
||||
" <menuitem action='Store'/>"
|
||||
" </menu>"
|
||||
" <menu action='Help'>"
|
||||
" <menuitem action='About'/>"
|
||||
" </menu>"
|
||||
" </menubar>"
|
||||
"</ui>";
|
||||
|
||||
static void add_action_data(GtkUIManager *ui, const gchar *path, GtkWidget *window, GList **list)
|
||||
{
|
||||
GtkAction *action;
|
||||
|
||||
action = gtk_ui_manager_get_action(ui, path);
|
||||
g_object_set_data(G_OBJECT(action), "window", window);
|
||||
g_object_set_data(G_OBJECT(action), "widget-list", list);
|
||||
}
|
||||
|
||||
static void add_menubar(GList **list, GtkWidget *window, GtkWidget *vbox)
|
||||
{
|
||||
GtkUIManager *ui;
|
||||
GtkActionGroup *actions;
|
||||
GError *error = NULL;
|
||||
|
||||
actions = gtk_action_group_new("Actions");
|
||||
gtk_action_group_add_actions(actions, entries, n_entries, NULL);
|
||||
|
||||
ui = gtk_ui_manager_new();
|
||||
gtk_ui_manager_insert_action_group(ui, actions, 0);
|
||||
g_object_unref(actions);
|
||||
gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui));
|
||||
|
||||
if (!gtk_ui_manager_add_ui_from_string(ui, menu_info, -1, &error)) {
|
||||
g_message("building menus failed: %s", error->message);
|
||||
g_error_free(error);
|
||||
error = NULL;
|
||||
}
|
||||
gtk_box_pack_start(GTK_BOX(vbox),
|
||||
gtk_ui_manager_get_widget(ui, "/MenuBar"),
|
||||
FALSE, FALSE, 0);
|
||||
|
||||
add_action_data(ui, "/MenuBar/File/Quit", window, list);
|
||||
add_action_data(ui, "/MenuBar/File/Open", window, list);
|
||||
add_action_data(ui, "/MenuBar/Preset/Store", window, list);
|
||||
add_action_data(ui, "/MenuBar/Help/About", window, list);
|
||||
|
||||
g_object_unref(ui);
|
||||
}
|
||||
|
||||
void create_window()
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *sw; /* scrolled window to carry preset treeview */
|
||||
static GList *list = NULL; /* widget list (every data element is WidgetListElem) */
|
||||
gint x;
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "gdigi");
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(window), vbox);
|
||||
|
||||
add_menubar(&list, window, vbox);
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(vbox), hbox);
|
||||
|
||||
sw = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), sw, FALSE, FALSE, 0);
|
||||
|
||||
widget = create_preset_tree();
|
||||
gtk_container_add(GTK_CONTAINER(sw), widget);
|
||||
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 2);
|
||||
|
||||
for (x = 0; x<n_effects; x++) {
|
||||
if ((x % 2) == 0) {
|
||||
if ((x % 3) == 0) {
|
||||
hbox = gtk_hbox_new(TRUE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 2);
|
||||
}
|
||||
widget = create_vbox(effects[x].effect, effects[x].amt);
|
||||
widget = create_vbox(&list, effects[x].effect, effects[x].amt);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 2);
|
||||
}
|
||||
|
||||
|
||||
5
gui.h
5
gui.h
@@ -14,4 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_GUI_H
|
||||
#define GDIGI_GUI_H
|
||||
|
||||
void create_window();
|
||||
|
||||
#endif /* GDIGI_GUI_H */
|
||||
|
||||
181
preset.c
Normal file
181
preset.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Tomasz Moń <desowin@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <expat.h>
|
||||
#include <string.h>
|
||||
#include "preset.h"
|
||||
|
||||
enum {
|
||||
PARSER_TYPE_NOT_SET = -1,
|
||||
PARSER_TYPE_PRESET_NAME = 0,
|
||||
PARSER_TYPE_PARAM_ID,
|
||||
PARSER_TYPE_PARAM_POSITION,
|
||||
PARSER_TYPE_PARAM_VALUE,
|
||||
PARSER_TYPE_PARAM_NAME,
|
||||
PARSER_TYPE_PARAM_TEXT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int depth;
|
||||
int id;
|
||||
Preset *preset;
|
||||
} AppData;
|
||||
|
||||
static void XMLCALL start(void *data, const char *el, const char **attr) {
|
||||
AppData *ad = (AppData *) data;
|
||||
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
if (g_strcmp0(el, "Name") == 0) {
|
||||
if (ad->depth == 1) {
|
||||
ad->id = PARSER_TYPE_PRESET_NAME;
|
||||
} else if (ad->depth == 3) {
|
||||
ad->id = PARSER_TYPE_PARAM_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_strcmp0(el, "Params") == 0) {
|
||||
if (ad->preset->params != NULL)
|
||||
g_message("Params aleady exists!");
|
||||
} else if (g_strcmp0(el, "Param") == 0) {
|
||||
SettingParam *param = (SettingParam *)g_malloc(sizeof(SettingParam));
|
||||
param->id = -1;
|
||||
param->position = -1;
|
||||
param->value = -1;
|
||||
ad->preset->params = g_list_prepend(ad->preset->params, param);
|
||||
} else if (g_strcmp0(el, "ID") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_ID;
|
||||
} else if (g_strcmp0(el, "Position") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_POSITION;
|
||||
} else if (g_strcmp0(el, "Value") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_VALUE;
|
||||
} else if (g_strcmp0(el, "Text") == 0) {
|
||||
ad->id = PARSER_TYPE_PARAM_TEXT;
|
||||
}
|
||||
|
||||
ad->depth++;
|
||||
}
|
||||
|
||||
static void XMLCALL end(void *data, const char *el) {
|
||||
AppData *ad = (AppData *) data;
|
||||
ad->depth--;
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
}
|
||||
|
||||
static void XMLCALL text_cb(void *data, const char* text, int len)
|
||||
{
|
||||
AppData *ad = (AppData *) data;
|
||||
|
||||
if ((ad == NULL) || (ad->preset == NULL))
|
||||
return;
|
||||
|
||||
if (ad->id == PARSER_TYPE_PRESET_NAME) {
|
||||
if (ad->preset->name != NULL)
|
||||
g_free(ad->preset->name);
|
||||
ad->preset->name = g_strndup(text, len);
|
||||
}
|
||||
|
||||
if (ad->preset->params == NULL)
|
||||
return;
|
||||
|
||||
SettingParam *param = (SettingParam *) ad->preset->params->data;
|
||||
if (param == NULL)
|
||||
return;
|
||||
|
||||
gchar *value = g_strndup(text, len);
|
||||
|
||||
switch (ad->id) {
|
||||
case PARSER_TYPE_PARAM_ID:
|
||||
param->id = atoi(value);
|
||||
break;
|
||||
case PARSER_TYPE_PARAM_POSITION:
|
||||
param->position = atoi(value);
|
||||
break;
|
||||
case PARSER_TYPE_PARAM_VALUE:
|
||||
param->value = atoi(value);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
/*
|
||||
Parses preset file
|
||||
On success returns Preset which must be freed using preset_free, or NULL on error
|
||||
*/
|
||||
Preset *create_preset_from_xml_file(gchar *filename)
|
||||
{
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
gchar *contents;
|
||||
|
||||
file = g_file_new_for_path(filename);
|
||||
if (g_file_get_contents(filename, &contents, NULL, &error) == FALSE) {
|
||||
g_message("Failed to get %s contents: %s", filename, error->message);
|
||||
g_error_free(error);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AppData *ad = (AppData *) g_malloc(sizeof(AppData));
|
||||
ad->depth = 0;
|
||||
ad->preset = g_malloc(sizeof(Preset));
|
||||
ad->preset->name = NULL;
|
||||
ad->preset->params = NULL;
|
||||
ad->id = PARSER_TYPE_NOT_SET;
|
||||
|
||||
XML_Parser p;
|
||||
p = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(p, (void *) ad);
|
||||
XML_SetElementHandler(p, start, end);
|
||||
XML_SetCharacterDataHandler(p, text_cb);
|
||||
|
||||
if (XML_Parse(p, contents, strlen(contents), XML_TRUE) != XML_STATUS_OK) {
|
||||
g_warning("Parse error at line %d:\n%s",
|
||||
(int)XML_GetCurrentLineNumber(p),
|
||||
XML_ErrorString(XML_GetErrorCode(p)));
|
||||
preset_free(ad->preset);
|
||||
g_free(ad);
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Preset *preset = ad->preset;
|
||||
preset->params = g_list_reverse(preset->params);
|
||||
|
||||
XML_ParserFree(p);
|
||||
g_free(ad);
|
||||
|
||||
g_free(contents);
|
||||
g_object_unref(file);
|
||||
return preset;
|
||||
}
|
||||
|
||||
void preset_free(Preset *preset)
|
||||
{
|
||||
g_return_if_fail(preset != NULL);
|
||||
|
||||
if (preset->params != NULL) {
|
||||
g_list_foreach(preset->params, (GFunc)g_free, NULL);
|
||||
g_list_free(preset->params);
|
||||
}
|
||||
|
||||
if (preset->name != NULL)
|
||||
g_free(preset->name);
|
||||
|
||||
g_free(preset);
|
||||
}
|
||||
36
preset.h
Normal file
36
preset.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Tomasz Moń <desowin@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_PRESET_H
|
||||
#define GDIGI_PRESET_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int position;
|
||||
int value;
|
||||
} SettingParam;
|
||||
|
||||
typedef struct {
|
||||
gchar *name;
|
||||
GList *params;
|
||||
} Preset;
|
||||
|
||||
Preset *create_preset_from_xml_file(gchar *filename);
|
||||
void preset_free(Preset *preset);
|
||||
|
||||
#endif /* GDIGI_PRESET_H */
|
||||
4
tests.c
4
tests.c
@@ -206,10 +206,10 @@ void test_presets()
|
||||
int x;
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_user_preset(x);
|
||||
switch_preset(PRESETS_USER, x);
|
||||
|
||||
for (x=0; x<=60; x++)
|
||||
switch_system_preset(x);
|
||||
switch_preset(PRESETS_SYSTEM, x);
|
||||
|
||||
for (x=0; x<=99; x++)
|
||||
set_preset_level(x);
|
||||
|
||||
5
tests.h
5
tests.h
@@ -14,6 +14,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses>.
|
||||
*/
|
||||
|
||||
#ifndef GDIGI_TESTS_H
|
||||
#define GDIGI_TESTS_H
|
||||
|
||||
#include "gdigi.h"
|
||||
|
||||
void test_wah();
|
||||
@@ -29,3 +32,5 @@ void test_reverb();
|
||||
void test_exp();
|
||||
void test_usb();
|
||||
void test_all();
|
||||
|
||||
#endif /* GDIGI_TESTS_H */
|
||||
|
||||
Reference in New Issue
Block a user