/***************************************************************************
    usbua100mix.cpp  -  A Linux Mixer/Control Panel for the Roland UA-100
                             -------------------
    begin                : QT June 6, 2001; MOTIF October 10, 2002
    copyright            : (C) 2001 by Michael Minn
    email                : michael@michaelminn.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; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/MainW.h>
#include <Xm/Scale.h>
#include <Xm/Label.h>
#include <Xm/FileSB.h>
#include <Xm/MessageB.h>
#include <Xm/ScrolledW.h>
#include <Xm/ScrollBar.h>
#include <Xm/Separator.h>
#include <Xm/RowColumn.h>

#define UA100MIX_VERSION  "UA100MIX v2003.06.28"
#define UA100MIX_ABOUT    UA100MIX_VERSION " (c)2001-2003 by Michael Minn"

#define UA100_PATH_LINE           0
#define UA100_PATH_MIC2           1
#define UA100_PATH_WAVE1          2
#define UA100_PATH_WAVE2          3
#define UA100_PATH_SYS1           4
#define UA100_PATH_SYS2           5

#define UA100MIX_EFFECT_SYS1_DELAY 0x0021
#define UA100MIX_EFFECT_SYS1_CHORUS 0x0022

#define UA100MIX_EFFECT_SYS2_DELAY 0x0031
#define UA100MIX_EFFECT_SYS2_REVERB 0x0032

#define UA100MIX_EFFECT_FULL_REVERB         0x0011
#define UA100MIX_EFFECT_FULL_MIC_SIMULATOR  0x0012
#define UA100MIX_EFFECT_FULL_VOCODER        0x0013
#define UA100MIX_EFFECT_FULL_VOCAL_MULTI    0x0014
#define UA100MIX_EFFECT_FULL_GAME           0x0015
#define UA100MIX_EFFECT_FULL_ROTARY_MULTI   0x0016
#define UA100MIX_EFFECT_FULL_GUITAR_MULTI_1 0x0017
#define UA100MIX_EFFECT_FULL_GUITAR_MULTI_2 0x0018
#define UA100MIX_EFFECT_FULL_GUITAR_MULTI_3 0x0019
#define UA100MIX_EFFECT_FULL_CLEAN_MULTI_1  0x001A
#define UA100MIX_EFFECT_FULL_CLEAN_MULTI_2  0x001B
#define UA100MIX_EFFECT_FULL_BASS_MULTI     0x001C
#define UA100MIX_EFFECT_FULL_PIANO_MULTI    0x001D
#define UA100MIX_EFFECT_FULL_KEYBOARD_MULTI 0x001E

#define UA100MIX_EFFECT_INSERTION_NOISE_SUPPRESSOR 0x0000
#define UA100MIX_EFFECT_INSERTION_STEREO_EQ 0x0100
#define UA100MIX_EFFECT_INSERTION_SPECTRUM 0x0101
#define UA100MIX_EFFECT_INSERTION_ENHANCER 0x0102
#define UA100MIX_EFFECT_INSERTION_HUMANIZER 0x0103
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE 0x0110
#define UA100MIX_EFFECT_INSERTION_DISTORTION 0x0111
#define UA100MIX_EFFECT_INSERTION_PHASER 0x0120
#define UA100MIX_EFFECT_INSERTION_AUTO_WAH 0x0121
#define UA100MIX_EFFECT_INSERTION_ROTARY 0x0122
#define UA100MIX_EFFECT_INSERTION_STEREO_FLANGER 0x0123
#define UA100MIX_EFFECT_INSERTION_STEP_FLANGER 0x0124
#define UA100MIX_EFFECT_INSERTION_TREMELO 0x0125
#define UA100MIX_EFFECT_INSERTION_AUTO_PAN 0x0126
#define UA100MIX_EFFECT_INSERTION_COMPRESSOR 0x0130
#define UA100MIX_EFFECT_INSERTION_LIMITER 0x0131
#define UA100MIX_EFFECT_INSERTION_HEXA_CHORUS 0x0140
#define UA100MIX_EFFECT_INSERTION_TREMELO_CHORUS 0x0141
#define UA100MIX_EFFECT_INSERTION_STEREO_CHORUS 0x0142
#define UA100MIX_EFFECT_INSERTION_SPACE_D_CHORUS 0x0143
#define UA100MIX_EFFECT_INSERTION_3D_CHORUS 0x0144
#define UA100MIX_EFFECT_INSERTION_STEREO_DELAY 0x0150
#define UA100MIX_EFFECT_INSERTION_MODULATION_DELAY 0x0151
#define UA100MIX_EFFECT_INSERTION_3_TAP_DELAY 0x0152
#define UA100MIX_EFFECT_INSERTION_4_TAP_DELAY 0x0153
#define UA100MIX_EFFECT_INSERTION_TIME_CONTROL_DELAY 0x0154
#define UA100MIX_EFFECT_INSERTION_REVERB 0x0155
#define UA100MIX_EFFECT_INSERTION_GATE_REVERB 0x0156
#define UA100MIX_EFFECT_INSERTION_3D_DELAY 0x0157
#define UA100MIX_EFFECT_INSERTION_2_VOICE_PITCH 0x0160
#define UA100MIX_EFFECT_INSERTION_FEEDBACK_PITCH 0x0161
#define UA100MIX_EFFECT_INSERTION_3D_AUTO 0x0170
#define UA100MIX_EFFECT_INSERTION_3D_MANUAL 0x0171
#define UA100MIX_EFFECT_INSERTION_LO_FI_1 0x0172
#define UA100MIX_EFFECT_INSERTION_LO_FI_2 0x0173
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_CHORUS 0x0200
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_FLANGER 0x0201
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_DELAY 0x0202
#define UA100MIX_EFFECT_INSERTION_DISTORTION_CHORUS 0x0203
#define UA100MIX_EFFECT_INSERTION_DISTORTION_FLANGER 0x0204
#define UA100MIX_EFFECT_INSERTION_DISTORTION_DELAY 0x0205
#define UA100MIX_EFFECT_INSERTION_ENHANCER_CHORUS 0x0206
#define UA100MIX_EFFECT_INSERTION_ENHANCER_FLANGER 0x0207
#define UA100MIX_EFFECT_INSERTION_ENHANCER_DELAY 0x0208
#define UA100MIX_EFFECT_INSERTION_CHORUS_DELAY 0x0209
#define UA100MIX_EFFECT_INSERTION_FLANGER_DELAY 0x020a
#define UA100MIX_EFFECT_INSERTION_CHORUS_FLANGER 0x020b
#define UA100MIX_EFFECT_INSERTION_ROTARY_MULTI 0x0300
#define UA100MIX_EFFECT_INSERTION_GUITAR_MULTI1 0x0400
#define UA100MIX_EFFECT_INSERTION_GUITAR_MULTI2 0x0401
#define UA100MIX_EFFECT_INSERTION_GUITAR_MULTI3 0x0402
#define UA100MIX_EFFECT_INSERTION_CLEAN_MULTI1 0x0403
#define UA100MIX_EFFECT_INSERTION_CLEAN_MULTI2 0x0404
#define UA100MIX_EFFECT_INSERTION_BASS_BULTI 0x0405
#define UA100MIX_EFFECT_INSERTION_PIANO_MULTI 0x0406
#define UA100MIX_EFFECT_INSERTION_KEYBOARD_MULTI 0x0500
#define UA100MIX_EFFECT_INSERTION_CHORUS_DELAY_PARALLEL 0x1100
#define UA100MIX_EFFECT_INSERTION_FLANGER_DELAY_PARALLEL 0x1101
#define UA100MIX_EFFECT_INSERTION_CHORUS_FLANGER_PARALLEL 0x1102
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_DISTORTION 0x1103
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_ROTARY 0x1104
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_PHASER 0x1105
#define UA100MIX_EFFECT_INSERTION_OVERDRIVE_AUTOWAH 0x1106
#define UA100MIX_EFFECT_INSERTION_PHASER_ROTARY 0x1107
#define UA100MIX_EFFECT_INSERTION_PHASER_AUTOWAH 0x1108

class ua100mix
{
	public:
	ua100mix(char *program_name, char *midi_device_name);
	int errno_dialog(char *caption, int errno_value);
	int update_message_bar(char *message);
	int write_data(char *hex_string);
	int select_effect(int address, char *name);
	int clear_effect();

	XtAppContext application;
	Widget shell;
	Widget main_window;
	Widget message_bar;
	Widget fader_area;
	Widget menu_bar;
	Widget file_menu;
	Widget path_menu;
	Widget effect_menu;
	Widget full_submenu;
	Widget system_submenu;
	Widget filter_submenu;
	Widget distortion_submenu;
	Widget modulation_submenu;
	Widget compressor_submenu;
	Widget chorus_submenu;
	Widget reverb_submenu;
	Widget pitch_submenu;
	Widget other_submenu;
	Widget two_series_submenu;
	Widget multi_series_submenu;
	Widget parallel_submenu;

	int midi_device;
	int effect_path;
	char *effect_name;
};

class ua100mix_fader
{
	public:
	ua100mix_fader(ua100mix *mixer, char *title, char *hex_string, char **values, int low_value, int default_value, int high_value);
	ua100mix_fader(ua100mix *mixer, char *title, int parameter_number, char **values, int low_value, int default_value, int high_value);
	~ua100mix_fader();
	int create_widgets(char *title, int low_value, int default_value, int high_value);

	Widget container;
	Widget title_label;
	Widget value_label;
	Widget fader;
	int low_value;
	int high_value;
	int current_value;
	int is_effect;
	char *hex_string;
	char **values;
	ua100mix *mixer;
};


/***************************************************************************/

static char *ua100mix_input_source[11] = 
{ 
	"Mic", "Line", "Mic1+2", NULL 
};

static char *ua100mix_parameter_channel[11] =
{
	"Mic/Line", "Mic2", "Wave1", "Wave2", 
	"Mic FX", "Mic2 FX", "Wave1 FX", "Wave2 FX", "Submstr", "Main", NULL
};

static char *ua100mix_parameter_127[129] =
{
	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
	"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
	"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
	"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
	"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
	"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
	"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
	"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
	"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
	"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
	"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
	"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
	"120", "121", "122", "123", "124", "125", "126", "127", NULL
};

static char *ua100mix_parameter_low_eq_freq[3] =
{
	"200hz", "400hz", NULL
};

static char *ua100mix_parameter_speaker_phones[3] =
{
	"Spkr", "Phones", NULL
};

static char *ua100mix_parameter_hi_eq_freq[3] =
{
	"4khz", "8khz", NULL
};

static char *ua100mix_parameter_ccw_cw[3] =
{
	"CCW", "CW", NULL
};

static char *ua100mix_parameter_off_on[3] =
{
	"Off", "On", NULL
};

static char *ua100mix_parameter_overdrive_distortion[3] =
{
	"Overdrive", "Distortion", NULL
};

static char *ua100mix_parameter_chorus_flanger[3] =
{
	"Chorus", "Flanger", NULL
};

static char *ua100mix_parameter_wide_narrow[3] =
{
	"Wide", "Narrow", NULL
};

static char *ua100mix_parameter_noise_type[3] =
{
	"White", "Pink", NULL
};

static char *ua100mix_parameter_filter_type[4] =
{
	"Off", "LPF", "HPF", NULL
};

static char *ua100mix_parameter_down_up[3] =
{
	"Down", "Up", NULL
};

static char *ua100mix_parameter_hum[3] =
{
	"50", "60", NULL
};

static char *ua100mix_parameter_mono[3] =
{
	"Mono", "Stereo", NULL
};

static char *ua100mix_parameter_vowel[6] =
{
	"A", "I", "U", "E", "O", NULL
};

static char *ua100mix_parameter_amp[5] =
{
	"Small", "Built-in", "2-Stack", "3-Stack", NULL
};

static char *ua100mix_parameter_q[6] =
{
	"0.5", "1.0", "2.0", "4.0", "9.0", NULL
};

static char *ua100mix_parameter_reverb[7] =
{
	"Room1", "Room2", "Plate1", "Plate2", "Hall1", "Hall2", NULL
};

static char *ua100mix_parameter_reverb2[7] =
{
	"Room1", "Room2", "Stage1", "Stage2", "Hall1", "Hall2", NULL
};

static char *ua100mix_parameter_disc[5] =
{
	"LP", "EP", "SP", "RND", NULL
};

static char *ua100mix_parameter_5[7] =
{
	"0", "1", "2", "3",
	"4", "5", NULL
};

static char *ua100mix_parameter_negative_10[12] =
{
	"-10", "-9", "-8", "-7",
	"-6", "-5", "-4", "-3",
	"-2", "-1", "0", NULL
};

static char *ua100mix_parameter_post_gain_db[5] =
{
	"0db", "+6db", "+12db", "+18db", NULL
};

static char *ua100mix_parameter_plus_minus_12db[78] =
{
	"-12db", "-11db", "-10db", "-9db",
	"-8db", "-7db", "-6db", "-5db", "-4db", "-3db", "-2db", "-1db",
	"0db", "1db", "2db", "3db", "4db", "5db", "6db", "7db",
	"8db", "9db", "10db", "11db", "12db", NULL
};

static char *ua100mix_parameter_percent[129] =
{
	"0%", "0%", "1%", "2%", "3%", "3%", "4%", "5%",
	"6%", "7%", "7%", "8%", "9%", "10%", "11%", "11%",
	"12%", "13%", "14%", "14%", "15%", "16%", "17%", "18%",
	"18%", "19%", "20%", "21%", "22%", "22%", "23%", "24%",
	"25%", "25%", "26%", "27%", "28%", "29%", "29%", "30%",
	"31%", "32%", "33%", "33%", "34%", "35%", "36%", "37%",
	"37%", "38%", "39%", "40%", "40%", "41%", "42%", "43%",
	"44%", "44%", "45%", "46%", "47%", "48%", "48%", "49%",
	"50%", "51%", "51%", "52%", "53%", "54%", "55%", "55%",
	"56%", "57%", "58%", "59%", "59%", "60%", "61%", "62%",
	"62%", "63%", "64%", "65%", "66%", "66%", "67%", "68%",
	"69%", "70%", "70%", "71%", "72%", "73%", "74%", "74%",
	"75%", "76%", "77%", "77%", "78%", "79%", "80%", "81%",
	"81%", "82%", "83%", "84%", "85%", "85%", "86%", "87%",
	"88%", "88%", "89%", "90%", "91%", "92%", "92%", "93%",
	"94%", "95%", "96%", "96%", "97%", "98%", "99%", "100%", NULL
};

static char *ua100mix_parameter_pre_delay_time[129] =
{
	"0.0ms", "0.1ms", "0.2ms", "0.3ms", "0.4ms", "0.5ms", "0.6ms", "0.7ms",
	"0.8ms", "0.9ms", "1.0ms", "1.1ms", "1.2ms", "1.3ms", "1.4ms", "1.5ms",
	"1.6ms", "1.7ms", "1.8ms", "1.9ms", "2.0ms", "2.1ms", "2.2ms", "2.3ms",
	"2.4ms", "2.5ms", "2.6ms", "2.7ms", "2.8ms", "2.9ms", "3.0ms", "3.1ms",
	"3.2ms", "3.3ms", "3.4ms", "3.5ms", "3.6ms", "3.7ms", "3.8ms", "3.9ms",
	"4.0ms", "4.1ms", "4.2ms", "4.3ms", "4.4ms", "4.5ms", "4.6ms", "4.7ms",
	"4.8ms", "4.9ms", "5.0ms", "5.5ms", "6.0ms", "6.5ms", "7.0ms", "7.5ms",
	"8.0ms", "8.5ms", "9.0ms", "9.5ms", "10ms", "11ms", "12ms", "13ms",
	"14ms", "15ms", "16ms", "17ms", "18ms", "19ms", "20ms", "21ms",
	"22ms", "23ms", "24ms", "25ms", "26ms", "27ms", "28ms", "29ms",
	"30ms", "31ms", "32ms", "33ms", "34ms", "35ms", "36ms", "37ms",
	"38ms", "39ms", "40ms", "41ms", "42ms", "43ms", "44ms", "45ms",
	"46ms", "47ms", "48ms", "49ms", "50ms", "52ms", "54ms", "56ms",
	"58ms", "60ms", "62ms", "64ms", "66ms", "68ms", "70ms", "72ms",
	"74ms", "76ms", "78ms", "80ms", "82ms", "84ms", "86ms", "88ms",
	"90ms", "92ms", "94ms", "96ms", "98ms", "100ms", "100ms", "100ms", NULL
};

#if 0 // options are here for whenever we get around to finishing effects parameters
static char *ua100mix_parameter_delay1[129] =
{
	"200ms", "205ms", "210ms", "215ms", "220ms", "225ms", "230ms", "235ms",
	"240ms", "245ms", "250ms", "255ms", "260ms", "265ms", "270ms", "275ms",
	"280ms", "285ms", "290ms", "295ms", "300ms", "305ms", "310ms", "315ms",
	"320ms", "325ms", "330ms", "335ms", "340ms", "345ms", "350ms", "355ms",
	"360ms", "365ms", "370ms", "375ms", "380ms", "385ms", "390ms", "395ms",
	"400ms", "405ms", "410ms", "415ms", "420ms", "425ms", "430ms", "435ms",
	"440ms", "445ms", "450ms", "455ms", "460ms", "465ms", "470ms", "475ms",
	"480ms", "485ms", "490ms", "495ms", "500ms", "505ms", "510ms", "515ms",
	"520ms", "525ms", "530ms", "535ms", "540ms", "545ms", "550ms", "560ms",
	"570ms", "580ms", "590ms", "600ms", "610ms", "620ms", "630ms", "640ms",
	"650ms", "660ms", "670ms", "680ms", "690ms", "700ms", "710ms", "720ms",
	"730ms", "740ms", "750ms", "760ms", "770ms", "780ms", "790ms", "800ms",
	"810ms", "820ms", "830ms", "840ms", "850ms", "860ms", "870ms", "880ms",
	"890ms", "900ms", "910ms", "920ms", "930ms", "940ms", "950ms", "960ms",
	"970ms", "980ms", "990ms" "1000ms", "--", "--", "--", "--",
	"--", "--", "--", "--", "--", "--", "--", "--", NULL
};

static char *ua100mix_parameter_delay2[129] =
{
	"200ms", "205ms", "210ms", "215ms", "220ms", "225ms", "230ms", "235ms",
	"240ms", "245ms", "250ms", "255ms", "260ms", "265ms", "270ms", "275ms",
	"280ms", "285ms", "290ms", "295ms", "300ms", "305ms", "310ms", "315ms",
	"320ms", "325ms", "330ms", "335ms", "340ms", "345ms", "350ms", "355ms",
	"360ms", "365ms", "370ms", "375ms", "380ms", "385ms", "390ms", "395ms",
	"400ms", "405ms", "410ms", "415ms", "420ms", "425ms", "430ms", "435ms",
	"440ms", "445ms", "450ms", "455ms", "460ms", "465ms", "470ms", "475ms",
	"480ms", "485ms", "490ms", "495ms", "500ms", "505ms", "510ms", "515ms",
	"520ms", "525ms", "530ms", "535ms", "540ms", "545ms", "550ms", "555ms",
	"560ms", "565ms", "570ms", "575ms", "580ms", "585ms", "590ms", "595ms",
	"600ms", "610ms", "620ms", "630ms", "640ms", "650ms", "660ms", "670ms",
	"680ms", "690ms", "700ms", "710ms", "720ms", "730ms", "740ms", "750ms",
	"760ms", "770ms", "780ms", "790ms", "800ms", "810ms", "820ms", "830ms",
	"840ms", "850ms", "860ms", "870ms", "880ms", "890ms", "900ms", "910ms",
	"920ms", "930ms", "94ms", "950ms", "960ms", "970ms", "980ms", "990ms"
	"1000ms", "1000ms", "1000ms", "1000ms", "1000ms", "1000ms", "1000ms", "1000ms", NULL
};

static char *ua100mix_parameter_delay3[129] =
{
	"0.0ms", "0.1ms", "0.2ms", "0.3ms", "0.4ms", "0.5ms", "0.6ms", "0.7ms",
	"0.8ms", "0.9ms", "1.0ms", "1.1ms", "1.2ms", "1.3ms", "1.4ms", "1.5ms",
	"1.6ms", "1.7ms", "1.8ms", "1.9ms", "2.0ms", "2.1ms", "2.2ms", "2.3ms",
	"2.4ms", "2.5ms", "2.6ms", "2.7ms", "2.8ms", "2.9ms", "3.0ms", "3.1ms",
	"3.2ms", "3.3ms", "3.4ms", "3.5ms", "3.6ms", "3.7ms", "3.8ms", "3.9ms",
	"4.0ms", "4.1ms", "4.2ms", "4.3ms", "4.4ms", "4.5ms", "4.6ms", "4.7ms",
	"4.8ms", "4.9ms", "5.0ms", "5.5ms", "6.0ms", "6.5ms", "7.0ms", "7.5ms",
	"8.0ms", "8.5ms", "9.0ms", "9.5ms", "10ms", "11ms", "12ms", "13ms",
	"14ms", "15ms", "16ms", "17ms", "18ms", "19ms", "20ms", "21ms",
	"22ms", "23ms", "24ms", "25ms", "26ms", "27ms", "28ms", "29ms",
	"30ms", "31ms", "32ms", "33ms", "34ms", "35ms", "36ms", "37ms",
	"38ms", "39ms", "40ms", "50ms", "60ms", "70ms", "80ms", "90ms",
	"100ms", "110ms", "120ms", "130ms", "140ms", "150ms", "160ms", "170ms",
	"180ms", "190ms", "200ms", "210ms", "220ms", "230ms", "240ms", "250ms",
	"260ms", "270ms", "280ms", "290ms", "300ms", "320ms", "340ms", "360ms",
	"380ms", "400ms", "420ms", "440ms", "460ms", "480ms", "500ms", "500ms", NULL
};
#endif

static char *ua100mix_parameter_delay4[129] =
{
	"0ms", "5ms", "10ms", "15ms", "20ms", "25ms", "30ms", "35ms",
	"40ms", "45ms", "50ms", "55ms", "60ms", "65ms", "70ms", "75ms",
	"80ms", "85ms", "90ms", "95ms", "100ms", "105ms", "110ms", "115ms",
	"120ms", "125ms", "130ms", "135ms", "140ms", "145ms", "150ms", "155ms",
	"160ms", "165ms", "170ms", "175ms", "180ms", "185ms", "190ms", "195ms",
	"200ms", "205ms", "210ms", "215ms", "220ms", "225ms", "230ms", "235ms",
	"240ms", "245ms", "250ms", "255ms", "260ms", "265ms", "270ms", "275ms",
	"280ms", "285ms", "290ms", "295ms", "300ms", "305ms", "310ms", "315ms",
	"320ms", "325ms", "330ms", "335ms", "340ms", "345ms", "350ms", "355ms",
	"360ms", "365ms", "370ms", "375ms", "380ms", "385ms", "390ms", "395ms",
	"400ms", "405ms", "441ms", "415ms", "420ms", "425ms", "430ms", "435ms",
	"440ms", "445ms", "450ms", "455ms", "460ms", "465ms", "470ms", "475ms",
	"480ms", "485ms", "490ms", "495ms", "500ms", "505ms", "510ms", "515ms",
	"520ms", "525ms", "530ms", "535ms", "540ms", "545ms", "550ms", "555ms",
	"560ms", "565ms", "570ms", "575ms", "580ms", "585ms", "590ms", "595ms",
	"600ms", "605ms", "610ms", "615ms", "620ms", "625ms", "630ms", "635ms", NULL
};

static char *ua100mix_parameter_reverb_time[129] = // this is a faked series
{
	"0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8",
	"0.9", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6",
	"1.7", "1.8", "1.9", "2.0", "2.1", "2.2", "2.3", "2.4",
	"2.5", "2.6", "2.7", "2.8", "2.9", "3.0", "3.1", "3.2",
	"3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "4.0",
	"4.2", "4.4", "4.6", "4.8", "5.0", "5.2", "5.4", "5.6",
	"5.8", "6.0", "6.2", "6.4", "6.6", "6.8", "7.0", "7.2",
	"7.4", "7.6", "7.8", "8.0", "8.2", "8.4", "8.6", "8.8",
	"9.0", "9.2", "9.4", "9.4", "9.8", "10.0", "10.2", "10.4",
	"10.6", "11.0", "11.5", "12.0", "12.5", "13.0", "13.5", "14.0",
	"14.5", "15.0", "15.5", "16.0", "16.5", "17.0", "17.5", "18.0",
	"18.5", "19.0", "19.5", "20.0", "20.5", "21.0", "21.5", "22.0",
	"22.5", "23.0", "23.5", "24.0", "24.5", "25.0", "25.5", "26.0",
	"26.5", "27.0", "27.5", "28.0", "28.5", "29.0", "29.5", "30.0",
	"30.5", "31.0", "31.5", "32.0", "32.5", "33.0", "33.5", "34.0",
	"34.5", "35.0", "35.5", "36.0", "36.5", "37.0", "37.5", "38.0", NULL
};

static char *ua100mix_parameter_rate1[129] =
{
	"0.05hz", "0.10hz", "0.15hz", "0.20hz", "0.25hz", "0.30hz", "0.35hz", "0.40hz",
	"0.45hz", "0.50hz", "0.55hz", "0.60hz", "0.65hz", "0.70hz", "0.75hz", "0.80hz",
	"0.85hz", "0.90hz", "0.95hz", "1.00hz", "1.05hz", "1.10hz", "1.15hz", "1.20hz",
	"1.25hz", "1.30hz", "1.35hz", "1.40hz", "1.45hz", "1.50hz", "1.55hz", "1.60hz",
	"1.65hz", "1.70hz", "1.75hz", "1.80hz", "1.85hz", "1.90hz", "1.95hz", "2.00hz",
	"2.05hz", "2.10hz", "2.15hz", "2.20hz", "2.25hz", "2.30hz", "2.35hz", "2.40hz",
	"2.45hz", "2.50hz", "2.55hz", "2.60hz", "2.65hz", "2.70hz", "2.75hz", "2.80hz",
	"2.85hz", "2.90hz", "2.95hz", "3.00hz", "3.05hz", "3.10hz", "3.15hz", "3.20hz",
	"3.25hz", "3.30hz", "3.35hz", "3.40hz", "3.45hz", "3.50hz", "3.55hz", "3.60hz",
	"3.65hz", "3.70hz", "3.75hz", "3.80hz", "3.85hz", "3.90hz", "3.95hz", "4.00hz",
	"4.05hz", "4.10hz", "4.15hz", "4.20hz", "4.25hz", "4.30hz", "4.35hz", "4.40hz",
	"4.45hz", "4.50hz", "4.55hz", "4.60hz", "4.65hz", "4.70hz", "4.75hz", "4.80hz",
	"4.85hz", "4.90hz", "4.95hz", "5.00hz", "5.10hz", "5.20hz", "5.30hz", "5.40hz",
	"5.50hz", "5.60hz", "5.70hz", "5.80hz", "5.90hz", "6.00hz", "6.10hz", "6.20hz",
	"6.30hz", "6.40hz", "6.50hz", "6.60hz", "6.70hz", "6.80hz", "6.90hz", "7.00hz",
	"7.50hz", "8.00hz", "8.50hz", "9.00hz", "9.50hz", "10hz", "10hz", "10hz", NULL
};

static char *ua100mix_parameter_rate2[129] =
{
	"0.05hz", "0.10hz", "0.15hz", "0.20hz", "0.25hz", "0.30hz", "0.35hz", "0.40hz",
	"0.45hz", "0.50hz", "0.55hz", "0.60hz", "0.65hz", "0.70hz", "0.75hz", "0.80hz",
	"0.85hz", "0.90hz", "0.95hz", "1.00hz", "1.05hz", "1.10hz", "1.15hz", "1.20hz",
	"1.25hz", "1.30hz", "1.35hz", "1.40hz", "1.45hz", "1.50hz", "1.55hz", "1.60hz",
	"1.65hz", "1.70hz", "1.75hz", "1.80hz", "1.85hz", "1.90hz", "1.95hz", "2.00hz",
	"2.05hz", "2.10hz", "2.15hz", "2.20hz", "2.25hz", "2.30hz", "2.35hz", "2.40hz",
	"2.45hz", "2.50hz", "2.55hz", "2.60hz", "2.65hz", "2.70hz", "2.75hz", "2.80hz",
	"2.85hz", "2.90hz", "2.95hz", "3.00hz", "3.05hz", "3.10hz", "3.15hz", "3.20hz",
	"3.25hz", "3.30hz", "3.35hz", "3.40hz", "3.45hz", "3.50hz", "3.55hz", "3.60hz",
	"3.65hz", "3.70hz", "3.75hz", "3.80hz", "3.85hz", "3.90hz", "3.95hz", "4.00hz",
	"4.05hz", "4.10hz", "4.15hz", "4.20hz", "4.25hz", "4.30hz", "4.35hz", "4.40hz",
	"4.45hz", "4.50hz", "4.55hz", "4.60hz", "4.65hz", "4.70hz", "4.75hz", "4.80hz",
	"4.85hz", "4.90hz", "4.95hz", "5.00hz", "5.05hz", "5.10hz", "5.15hz", "5.20hz",
	"5.25hz", "5.30hz", "5.35hz", "5.40hz", "5.45hz", "5.50hz", "5.55hz", "5.60hz",
	"5.65hz", "5.70hz", "5.75hz", "5.80hz", "5.85hz", "5.90hz", "5.95hz", "6.00hz",
	"6.05hz", "6.10hz", "6.15hz", "6.20hz", "6.25hz", "6.30hz", "6.35hz", "6.40hz", NULL
};

static char *ua100mix_parameter_hfdamp[129] =
{
	"315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz",
	"400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz",
	"500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz",
	"630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz",
	"800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz",
	"1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz",
	"1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz",
	"1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz",
	"2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz",
	"2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz",
	"3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz",
	"4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz",
	"5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz",
	"6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz",
	"8khz", "8khz", "8khz", "8khz", "8khz", "8khz", "8khz", "8khz",
	"bypass", "bypass", "bypass", "bypass", "bypass", "bypass", "bypass", "bypass", NULL
};

static char *ua100mix_parameter_cutoff[129] =
{
	"250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz",
	"315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz",
	"400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz",
	"500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz",
	"630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz",
	"800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz",
	"1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz",
	"1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz",
	"1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz",
	"2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz",
	"2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz",
	"3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz",
	"4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz",
	"5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz",
	"6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz",
	"8khz", "8khz", "8khz", "8khz", "8khz", "8khz", "8khz", "8khz", NULL
};

static char *ua100mix_parameter_eq_freq[129] =
{
	"200hz", "200hz", "200hz", "200hz", "200hz", "200hz", "200hz", "200hz",
	"250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz",
	"315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz",
	"400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz",
	"500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz",
	"630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz",
	"800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz",
	"1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz",
	"1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz",
	"1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz",
	"2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz",
	"2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz",
	"3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz",
	"4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz",
	"5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz",
	"6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", NULL
};

static char *ua100mix_parameter_lpf[129] =
{
	"250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz", "250hz",
	"315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz", "315hz",
	"400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz", "400hz",
	"500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz", "500hz",
	"630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz", "630hz",
	"800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz", "800hz",
	"1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz", "1khz",
	"1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz", "1250hz",
	"1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz", "1.6khz",
	"2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz", "2khz",
	"2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz", "2.5khz",
	"3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz", "3150hz",
	"4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz", "4khz",
	"5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz", "5khz",
	"6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz", "6.3khz",
	"bypass", "bypass", "bypass", "bypass", "bypass", "bypass", "bypass", "bypass", NULL
};

static char *ua100mix_parameter_manual[129] =
{
	"100hz", "110hz", "120hz", "130hz", "140hz", "150hz", "160hz", "170hz",
	"180hz", "190hz", "200hz", "210hz", "220hz", "230hz", "240hz", "250hz",
	"260hz", "270hz", "280hz", "290hz", "300hz", "320hz", "340hz", "360hz",
	"380hz", "400hz", "420hz", "440hz", "460hz", "480hz", "500hz", "520hz",
	"540hz", "560hz", "580hz", "600hz", "620hz", "640hz", "660hz", "680hz",
	"700hz", "720hz", "740hz", "760hz", "780hz", "800hz", "820hz", "840hz",
	"860hz", "880hz", "900hz", "920hz", "940hz", "960hz", "980hz", "1khz",
	"1.1khz", "1.2khz", "1.3khz", "1.4khz", "1.5khz", "1.6khz", "1.7khz", "1.8khz",
	"1.9khz", "2.0khz", "2.1khz", "2.2khz", "2.3khz", "2.4khz", "2.5khz", "2.6khz",
	"2.7khz", "2.8khz", "2.9khz", "3.0khz", "3.1khz", "3.2khz", "3.3khz", "3.4khz",
	"3.5khz", "3.6khz", "3.7khz", "3.8khz", "3.9khz", "4.0khz", "4.1khz", "4.2khz",
	"4.3khz", "4.4khz", "4.5khz", "4.6khz", "4.7khz", "4.8khz", "4.9khz", "5.0khz",
	"5.1khz", "5.2khz", "5.3khz", "5.4khz", "5.5khz", "5.6khz", "5.7khz", "5.8khz",
	"5.9khz", "6.0khz", "6.1khz", "6.2khz", "6.3khz", "6.4khz", "6.5khz", "6.6khz",
	"6.7khz", "6.8khz", "6.9khz", "7.0khz", "7.1khz", "7.2khz", "7.3khz", "7.4khz",
	"7.5khz", "7.6khz", "7.7khz", "7.8khz", "7.9khz", "8.0khz", "8.0khz", "8.0khz", NULL
};

static char *ua100mix_parameter_azimuth[129] =
{
	"L180", "L180", "L180", "L180", "L180", "L180", "L168", "L168",
	"L168", "L168", "L156", "L156", "L156", "L156", "L144", "L144",
	"L144", "L144", "L132", "L132", "L132", "L132", "L120", "L120",
	"L120", "L120", "L108", "L108", "L108", "L108", "L96", "L96",
	"L96", "L96", "L84", "L84", "L84", "L84", "L72", "L72",
	"L72", "L72", "L60", "L60", "L60", "L60", "L48", "L48",
	"L48", "L48", "L36", "L36", "L36", "L36", "L24", "L24",
	"L24", "L24", "L12", "L12", "L12", "L12", "Center", "Center",
	"Center", "Center", "R12", "R12", "R12", "R12", "R24", "R24",
	"R24", "R24", "R36", "R36", "R36", "R36", "R48", "R48",
	"R48", "R48", "R60", "R60", "R60", "R60", "R72", "R72",
	"R72", "R72", "R84", "R84", "R84", "R84", "R96", "R96",
	"R96", "R96", "R108", "R108", "R108", "R108", "R120", "R120",
	"R120", "R120", "R132", "R132", "R132", "R132", "R144", "R144",
	"R144", "R144", "R156", "R156", "R156", "R156", "R168", "R168",
	"R168", "R168", "R180", "R180", "R180", "R180", "R180", "R180",
};

static char *ua100mix_parameter_pan[129] =
{
	"L63", "L62", "L61", "L60", "L59", "L58", "L57", "L56",
	"L55", "L54", "L53", "L52", "L51", "L50", "L49", "L48",
	"L47", "L46", "L45", "L44", "L43", "L42", "L41", "L40",
	"L39", "L38", "L37", "L36", "L35", "L34", "L33", "L32",
	"L31", "L30", "L29", "L28", "L27", "L26", "L25", "L24",
	"L23", "L22", "L21", "L20", "L19", "L18", "L17", "L16",
	"L15", "L14", "L13", "L12", "L11", "L10", "L9", "L8",
	"L7", "L6", "L5", "L4", "L3", "L2", "L1", "Center",
	"Center", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
	"R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
	"R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
	"R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31",
	"R32", "R33", "R34", "R35", "R36", "R37", "R38", "R39",
	"R40", "R41", "R42", "R42", "R44", "R45", "R46", "R47",
	"R48", "R49", "R50", "R51", "R52", "R53", "R54", "R55",
	"R56", "R57", "R58", "R59", "R60", "R61", "R62", "R63", NULL
};

/***************************************************************************/

static void file_menu_callback(Widget widget, XtPointer client_data, XtPointer call_data)
{
	// ua100mix *mixer = NULL;
	// XtVaGetValues(XtParent(widget), XmNuserData, &mixer, NULL);
	// switch ((int)client_data)
	exit(0);
}

static void path_menu_callback(Widget widget, XtPointer client_data, XtPointer call_data)
{
	ua100mix *mixer = NULL;
	XtVaGetValues(XtParent(widget), XmNuserData, &mixer, NULL);
	mixer->clear_effect();
	mixer->effect_path = (int)client_data;
}

static void effect_menu_callback(Widget widget, XtPointer client_data, XtPointer call_data)
{
 	int menu_item = (int) client_data;
	ua100mix *mixer = NULL;
	XtVaGetValues(XtParent(widget), XmNuserData, &mixer, NULL);

	if ((XtParent(widget) == mixer->effect_menu) && (menu_item == 0))
	{
		mixer->clear_effect();
		mixer->write_data("F04110001112004000000400F7");
		mixer->write_data("F04110001112004040000400F7");
	}

	else if ((XtParent(widget) == mixer->effect_menu) && (menu_item == 1))
	{
		mixer->effect_name = "Vocal Transformer";
		mixer->write_data("F04110001112004000000100F7");
		mixer->write_data("F04110001112004040000100F7");
	}

	else if ((XtParent(widget) == mixer->full_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_FULL_REVERB, "High-Quality Reverb");
		new ua100mix_fader(mixer, "Type", 1, ua100mix_parameter_reverb, 0, 0, 5);
		new ua100mix_fader(mixer, "PreDelay", 2, ua100mix_parameter_delay4, 0, 3, 127);
		new ua100mix_fader(mixer, "Time", 3, ua100mix_parameter_reverb_time, 0, 120, 127);
		new ua100mix_fader(mixer, "Balance", 10, ua100mix_parameter_127, 0, 25, 127);
		new ua100mix_fader(mixer, "Damp", 4, ua100mix_parameter_hfdamp, 0, 0x68, 127); // really -10 - 0?
		new ua100mix_fader(mixer, "ER Del", 5, ua100mix_parameter_delay4, 0, 8, 127);
		new ua100mix_fader(mixer, "ER Mix", 6, ua100mix_parameter_percent, 0, 15, 127);
		new ua100mix_fader(mixer, "Diffuse", 7, ua100mix_parameter_negative_10, 0, 9, 9);
		new ua100mix_fader(mixer, "Rev Lo", 8, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "Rev Hi", 9, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "Lo Gain", 12, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "Mid1 Gain", 15, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "Mid2 Gain", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "Hi Gain", 20, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "EQ Lo", 11, ua100mix_parameter_low_eq_freq, 0, 1, 1);
		new ua100mix_fader(mixer, "Mid1 Q", 14, ua100mix_parameter_q, 0, 0, 4);
		new ua100mix_fader(mixer, "Mid1 Freq", 13, ua100mix_parameter_eq_freq, 0, 0x48, 127);
		new ua100mix_fader(mixer, "Mid2 Q", 17, ua100mix_parameter_q, 0, 0, 4);
		new ua100mix_fader(mixer, "Mid2 Freq", 16, ua100mix_parameter_eq_freq, 0, 0x38, 127);
		new ua100mix_fader(mixer, "EQ Hi", 19, ua100mix_parameter_hi_eq_freq, 0, 1, 1);
	}

	else if ((XtParent(widget) == mixer->full_submenu) && (menu_item == 6))
	{
		// Full effect version of this doesn't work for some reason
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_GUITAR_MULTI1, "Guitar Multi 1");
		new ua100mix_fader(mixer, "Attack", 1, ua100mix_parameter_percent, 0, 100, 127);
		new ua100mix_fader(mixer, "Sustn", 2, ua100mix_parameter_percent, 0, 80, 127);
		new ua100mix_fader(mixer, "Comp", 3, ua100mix_parameter_percent, 0, 100, 127);
		new ua100mix_fader(mixer, "Comp", 4, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "OD/Dist", 5, ua100mix_parameter_overdrive_distortion, 0, 0, 1);
		new ua100mix_fader(mixer, "Drive", 6, ua100mix_parameter_percent, 0, 80, 127);
		new ua100mix_fader(mixer, "Amp", 7, ua100mix_parameter_amp, 0, 0, 3);
		new ua100mix_fader(mixer, "Amp", 8, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "OD Lo", 9, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "OD Hi", 10, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4C);
		new ua100mix_fader(mixer, "OD", 11, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "Ch/Fl", 12, ua100mix_parameter_chorus_flanger, 0, 1, 1);
		new ua100mix_fader(mixer, "Mod Rt", 13, ua100mix_parameter_rate2, 0, 8, 127);
		new ua100mix_fader(mixer, "Mod Dep", 14, ua100mix_parameter_percent, 0, 30, 127);
		new ua100mix_fader(mixer, "Chr FB", 15, ua100mix_parameter_percent, 0, 102, 127);
		new ua100mix_fader(mixer, "Chr Mx", 16, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Delay", 17, ua100mix_parameter_delay4, 0, 0x3c, 127);
		new ua100mix_fader(mixer, "Del FB", 18, ua100mix_parameter_percent, 0, 34, 127);
		new ua100mix_fader(mixer, "Del Mx", 19, ua100mix_parameter_percent, 0, 15, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 110, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->full_submenu) && (menu_item == 9))
	{
		// Full effect version of this doesn't work for some reason
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_CLEAN_MULTI1, "Clean Guitar Multi 1");
		new ua100mix_fader(mixer, "Attck", 1, ua100mix_parameter_percent, 0, 50, 127);
		new ua100mix_fader(mixer, "Sust", 2, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Comp", 3, ua100mix_parameter_percent, 0, 75, 127);
		new ua100mix_fader(mixer, "Comp", 4, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "Low", 5, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Mid", 6, ua100mix_parameter_eq_freq, 0, 0, 127);
		new ua100mix_fader(mixer, "Mid Q", 7, ua100mix_parameter_q, 0, 2, 4);
		new ua100mix_fader(mixer, "Mid", 8, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Hi", 9, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Ch/Fl", 10, ua100mix_parameter_chorus_flanger, 0, 0, 1);
		new ua100mix_fader(mixer, "Mod Rate", 11, ua100mix_parameter_rate2, 0, 8, 127);
		new ua100mix_fader(mixer, "Mod Dep", 12, ua100mix_parameter_percent, 0, 30, 127);
		new ua100mix_fader(mixer, "Chr FB", 13, ua100mix_parameter_percent, 0, 102, 127);
		new ua100mix_fader(mixer, "Chr Mx", 14, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Delay", 15, ua100mix_parameter_delay4, 0, 0x3c, 127);
		new ua100mix_fader(mixer, "Del FB", 16, ua100mix_parameter_percent, 0, 34, 127);
		new ua100mix_fader(mixer, "Del Cut", 17, ua100mix_parameter_hfdamp, 0, 34, 127);
		new ua100mix_fader(mixer, "Del Mx", 18, ua100mix_parameter_percent, 0, 15, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 110, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->filter_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_NOISE_SUPPRESSOR, "Noise Gate");
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->filter_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_STEREO_EQ, "Stereo EQ");
		new ua100mix_fader(mixer, "Low", 2, ua100mix_parameter_plus_minus_12db, 0x34, 0x45, 0x4c);
		new ua100mix_fader(mixer, "Mid1", 7, ua100mix_parameter_plus_minus_12db, 0x34, 0x48, 0x4c);
		new ua100mix_fader(mixer, "Mid2", 10, ua100mix_parameter_plus_minus_12db, 0x34, 0x38, 0x4c);
		new ua100mix_fader(mixer, "Hi", 4, ua100mix_parameter_plus_minus_12db, 0x34, 0x34, 0x4c);
		new ua100mix_fader(mixer, "Low", 1, ua100mix_parameter_low_eq_freq, 0, 1, 1);
		new ua100mix_fader(mixer, "Mid1", 5, ua100mix_parameter_eq_freq, 0, 72, 127);
		new ua100mix_fader(mixer, "Mid2", 8, ua100mix_parameter_eq_freq, 0, 56, 127);
		new ua100mix_fader(mixer, "Hi", 3, ua100mix_parameter_hi_eq_freq, 0, 1, 1);
		new ua100mix_fader(mixer, "Mid1 Q", 6, ua100mix_parameter_q, 0, 0, 4);
		new ua100mix_fader(mixer, "Mid2 Q", 9, ua100mix_parameter_q, 0, 0, 4);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->filter_submenu) && (menu_item == 2))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_SPECTRUM, "Spectrum EQ");
		new ua100mix_fader(mixer, "250", 1, ua100mix_parameter_plus_minus_12db, 0x34, 0x3c, 0x4c);
		new ua100mix_fader(mixer, "500", 2, ua100mix_parameter_plus_minus_12db, 0x34, 0x41, 0x4c);
		new ua100mix_fader(mixer, "1K", 3, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "1.3K", 4, ua100mix_parameter_plus_minus_12db, 0x34, 0x46, 0x4c);
		new ua100mix_fader(mixer, "2K", 5, ua100mix_parameter_plus_minus_12db, 0x34, 0x42, 0x4c);
		new ua100mix_fader(mixer, "3.2", 6, ua100mix_parameter_plus_minus_12db, 0x34, 0x3f, 0x4c);
		new ua100mix_fader(mixer, "4K", 7, ua100mix_parameter_plus_minus_12db, 0x34, 0x3c, 0x4c);
		new ua100mix_fader(mixer, "8K", 8, ua100mix_parameter_plus_minus_12db, 0x34, 0x3b, 0x4c);
		new ua100mix_fader(mixer, "Width", 9, ua100mix_parameter_q, 0, 2, 4);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->filter_submenu) && (menu_item == 3))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_ENHANCER, "Enhancer");
		new ua100mix_fader(mixer, "Sens.", 1, ua100mix_parameter_percent, 0, 64, 127);
		new ua100mix_fader(mixer, "Mix", 2, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->filter_submenu) && (menu_item == 4))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_HUMANIZER, "Enhancer");
		new ua100mix_fader(mixer, "Drive", 1, ua100mix_parameter_percent, 0, 48, 127);
		new ua100mix_fader(mixer, "Dist", 2, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "Vowel", 3, ua100mix_parameter_vowel, 0, 0, 5);
		new ua100mix_fader(mixer, "Speed", 4, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->distortion_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_OVERDRIVE, "Overdrive");
		new ua100mix_fader(mixer, "Drive", 1, ua100mix_parameter_percent, 0, 48, 127);
		new ua100mix_fader(mixer, "Amp", 2, ua100mix_parameter_amp, 0, 1, 4);
		new ua100mix_fader(mixer, "Amp", 3, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->distortion_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_DISTORTION, "Distortion");
		new ua100mix_fader(mixer, "Drive", 1, ua100mix_parameter_percent, 0, 48, 127);
		new ua100mix_fader(mixer, "Amp", 2, ua100mix_parameter_amp, 0, 1, 4);
		new ua100mix_fader(mixer, "Amp", 3, ua100mix_parameter_off_on, 0, 1, 1);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_PHASER, "Phaser");
		new ua100mix_fader(mixer, "Freq", 1, ua100mix_parameter_manual, 0, 36, 127);
		new ua100mix_fader(mixer, "Rate", 2, ua100mix_parameter_rate1, 0, 16, 127);
		new ua100mix_fader(mixer, "Depth", 3, ua100mix_parameter_percent, 0, 64, 127);
		new ua100mix_fader(mixer, "Reso", 4, ua100mix_parameter_percent, 0, 16, 127);
		new ua100mix_fader(mixer, "Mix", 5, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_AUTO_WAH, "Auto-Wah");
		new ua100mix_fader(mixer, "Filter", 1, ua100mix_parameter_wide_narrow, 0, 1, 1);
		new ua100mix_fader(mixer, "Sens.", 2, ua100mix_parameter_percent, 0, 0, 127);
		new ua100mix_fader(mixer, "Freq", 3, ua100mix_parameter_manual, 0, 68, 127);
		new ua100mix_fader(mixer, "Peak", 4, ua100mix_parameter_percent, 0, 62, 127);
		new ua100mix_fader(mixer, "Rate", 5, ua100mix_parameter_rate1, 0, 16, 127);
		new ua100mix_fader(mixer, "Depth", 6, ua100mix_parameter_percent, 0, 64, 127);
		new ua100mix_fader(mixer, "Polarity", 7, ua100mix_parameter_down_up, 0, 1, 1);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 2))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_ROTARY, "Rotary Speaker");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 3))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_STEREO_FLANGER, "Stereo Flanger");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 4))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_STEP_FLANGER, "Step Flanger");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 5))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_TREMELO, "Tremelo");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->modulation_submenu) && (menu_item == 6))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_AUTO_PAN, "Auto Pan");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->compressor_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_COMPRESSOR, "Compressor");
		new ua100mix_fader(mixer, "Attack", 1, ua100mix_parameter_127, 0, 127, 127);
		new ua100mix_fader(mixer, "Sustain", 2, ua100mix_parameter_127, 0, 127, 127);
		new ua100mix_fader(mixer, "Post Gain", 3, ua100mix_parameter_post_gain_db, 0, 3, 0);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->compressor_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_LIMITER, "Limiter");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 64, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->chorus_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_HEXA_CHORUS, "Hexa Chorus");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->chorus_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_TREMELO_CHORUS, "Tremelo Chorus");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->chorus_submenu) && (menu_item == 2))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_STEREO_CHORUS, "Stereo Chorus");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->chorus_submenu) && (menu_item == 3))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_SPACE_D_CHORUS, "Space D Chorus");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->chorus_submenu) && (menu_item == 4))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_3D_CHORUS, "3-D Chorus");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_STEREO_DELAY, "Stereo Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_MODULATION_DELAY, "Modulation Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 2))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_3_TAP_DELAY, "3-Tap Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 3))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_4_TAP_DELAY, "4-Tap Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 4))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_TIME_CONTROL_DELAY, "Time Control Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 5))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_REVERB, "Reverb");
		new ua100mix_fader(mixer, "Type", 1, ua100mix_parameter_reverb2, 0, 3, 5);
		new ua100mix_fader(mixer, "Pre Del", 2, ua100mix_parameter_pre_delay_time, 0, 112, 127);
		new ua100mix_fader(mixer, "Length", 3, ua100mix_parameter_percent, 0, 120, 127);
		new ua100mix_fader(mixer, "HF Cut", 4, ua100mix_parameter_hfdamp, 0, 0x67, 127);
		new ua100mix_fader(mixer, "Balance", 16, ua100mix_parameter_127, 0, 25, 127);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 6))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_GATE_REVERB, "Gate Reverb");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->reverb_submenu) && (menu_item == 7))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_3D_DELAY, "3-D Delay");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->pitch_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_2_VOICE_PITCH, "2-Voice Pitch Shift");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->pitch_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_FEEDBACK_PITCH, "Feedback Pitch Shift");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->other_submenu) && (menu_item == 0))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_3D_AUTO, "3-D Auto Rotate");
		new ua100mix_fader(mixer, "Azimuth", 1, ua100mix_parameter_azimuth, 0, 64, 127);
		new ua100mix_fader(mixer, "Speed", 2, ua100mix_parameter_rate1, 0, 64, 127);
		new ua100mix_fader(mixer, "Dir", 3, ua100mix_parameter_ccw_cw, 0, 0, 1);
		new ua100mix_fader(mixer, "Turn", 4, ua100mix_parameter_off_on, 0, 0, 1);
		new ua100mix_fader(mixer, "Turn", 15, ua100mix_parameter_speaker_phones, 0, 0, 1);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->other_submenu) && (menu_item == 1))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_3D_MANUAL, "3-D Manual Rotate");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->other_submenu) && (menu_item == 2))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_LO_FI_1, "Lo-Fi #1");
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

	else if ((XtParent(widget) == mixer->other_submenu) && (menu_item == 3))
	{
		mixer->select_effect(UA100MIX_EFFECT_INSERTION_LO_FI_2, "Lo-Fi #2");
		new ua100mix_fader(mixer, "Type", 1, ua100mix_parameter_5, 0, 1, 5);
		new ua100mix_fader(mixer, "Filter", 2, ua100mix_parameter_filter_type, 0, 1, 2);
		new ua100mix_fader(mixer, "Cutoff", 3, ua100mix_parameter_cutoff, 0, 32, 127);
		new ua100mix_fader(mixer, "Radio Tun", 4, ua100mix_parameter_percent, 0, 0, 127);
		new ua100mix_fader(mixer, "Radio Nz", 5, ua100mix_parameter_percent, 0, 64, 127);
		new ua100mix_fader(mixer, "Nz", 6, ua100mix_parameter_noise_type, 0, 1, 1);
		new ua100mix_fader(mixer, "Nz Cut", 7, ua100mix_parameter_lpf, 0, 127, 127);
		new ua100mix_fader(mixer, "Nz Lev", 8, ua100mix_parameter_percent, 0, 0, 127);
		new ua100mix_fader(mixer, "Disc", 9, ua100mix_parameter_disc, 0, 0, 3);
		new ua100mix_fader(mixer, "Disc Cut", 10, ua100mix_parameter_lpf, 0, 127, 127);
		new ua100mix_fader(mixer, "Disc Lev", 11, ua100mix_parameter_percent, 0, 0, 127);
		new ua100mix_fader(mixer, "Hum", 12, ua100mix_parameter_hum, 0, 0, 1);
		new ua100mix_fader(mixer, "Hum Cut", 13, ua100mix_parameter_lpf, 0, 127, 127);
		new ua100mix_fader(mixer, "Hum Lev", 14, ua100mix_parameter_percent, 0, 0, 127);
		new ua100mix_fader(mixer, "Mono", 15, ua100mix_parameter_mono, 0, 0, 1);
		new ua100mix_fader(mixer, "Mix", 16, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Low", 17, ua100mix_parameter_plus_minus_12db, 0x34, 0x43, 0x4c);
		new ua100mix_fader(mixer, "Hi", 18, ua100mix_parameter_plus_minus_12db, 0x34, 0x40, 0x4c);
		new ua100mix_fader(mixer, "Pan", 19, ua100mix_parameter_pan, 0, 0x40, 127);
		new ua100mix_fader(mixer, "Level", 20, ua100mix_parameter_percent, 0, 127, 127);
		new ua100mix_fader(mixer, "Gate", 35, ua100mix_parameter_percent, 0, 10, 127);
	}

/**********
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_CHORUS;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_FLANGER;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_DELAY;
	UA100MIX_EFFECT_INSERTION_DISTORTION_CHORUS;
	UA100MIX_EFFECT_INSERTION_DISTORTION_FLANGER;
	UA100MIX_EFFECT_INSERTION_DISTORTION_DELAY;
	UA100MIX_EFFECT_INSERTION_ENHANCER_CHORUS;
	UA100MIX_EFFECT_INSERTION_ENHANCER_FLANGER;
	UA100MIX_EFFECT_INSERTION_ENHANCER_DELAY;
	UA100MIX_EFFECT_INSERTION_CHORUS_DELAY;
	UA100MIX_EFFECT_INSERTION_FLANGER_DELAY;
	UA100MIX_EFFECT_INSERTION_CHORUS_FLANGER;
	UA100MIX_EFFECT_INSERTION_ROTARY_MULTI;
	UA100MIX_EFFECT_INSERTION_GUITAR_MULTI2;
	UA100MIX_EFFECT_INSERTION_GUITAR_MULTI3;
	UA100MIX_EFFECT_INSERTION_CLEAN_MULTI2;
	UA100MIX_EFFECT_INSERTION_BASS_BULTI;
	UA100MIX_EFFECT_INSERTION_PIANO_MULTI;
	UA100MIX_EFFECT_INSERTION_KEYBOARD_MULTI;
	UA100MIX_EFFECT_INSERTION_CHORUS_DELAY_PARALLEL;
	UA100MIX_EFFECT_INSERTION_FLANGER_DELAY_PARALLEL;
	UA100MIX_EFFECT_INSERTION_CHORUS_FLANGER_PARALLEL;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_DISTORTION;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_ROTARY;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_PHASER;
	UA100MIX_EFFECT_INSERTION_OVERDRIVE_AUTOWAH;
	UA100MIX_EFFECT_INSERTION_PHASER_ROTARY;
	UA100MIX_EFFECT_INSERTION_PHASER_AUTOWAH;
********/

/****
	// This is a kludge - when adding faders that expand beyond the size of the window,
	// the main window resizes, but the scrolling area disappears beyond the R side of
	// the window. But it pops back into normal view if a resizing edge is dragged.
	// This solves the problem the first time, but not the second time widgets are added
	int width = 0;
	int height = 0;
	XtVaGetValues(mixer->shell, XmNwidth, &width, XmNheight, &height, NULL);
	XtVaSetValues(mixer->shell, XmNwidth, width + 5, XmNheight, height, NULL);

	// Scrolls the new faders into view
	Widget scroll_bar = XtNameToWidget(mixer->main_window, "HorScrollBar");
	if (scroll_bar)
	{
		int maximum = 0;
		XtVaGetValues(scroll_bar, XmNmaximum, &maximum, NULL);
		XmScrollBarSetValues(scroll_bar, maximum, 0, 0, 0, 1);
	}
****/

}

ua100mix::ua100mix(char *program_name, char *midi_device_name)
{
	memset(this, 0, sizeof(*this));

	String default_resources[] = {
		"ua100mix*background: white",
		"ua100mix*foreground: black",
		NULL };

	int shell_argc = 1;
	shell = XtVaOpenApplication (&application, "ua100mix", NULL, 0,
		&shell_argc, &program_name, default_resources, sessionShellWidgetClass,
		XmNwidth, 600,
		XmNheight, 220,
		XmNtitle, UA100MIX_VERSION,
		NULL);

	main_window = XtVaCreateManagedWidget("main_window", xmMainWindowWidgetClass, shell,
		XmNscrollingPolicy, XmAUTOMATIC, NULL);

	menu_bar = XmVaCreateSimpleMenuBar(main_window, "menu_bar",
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("File"), 'F',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Path"), 'P',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Effect"), 'E',
		NULL);
	XtManageChild(menu_bar);

	file_menu = XmVaCreateSimplePulldownMenu(menu_bar, "file_menu", 0, file_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Open..."), 'O', "Ctrl<Key>o", XmStringCreateLocalized ("Ctrl-O"),
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Save..."), 'S', "Ctrl<Key>s", XmStringCreateLocalized ("Ctrl-S"),
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Quit"), 'Q', "Ctrl<Key>q", XmStringCreateLocalized ("Ctrl-Q"),
		XmNuserData, this, NULL);

	path_menu = XmVaCreateSimplePulldownMenu(menu_bar, "path_menu", 1, path_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Line/Mic"), 'M', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Mic 2"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Wave 1"), 'W', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Wave 2"), 'A', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Sys 1"), 'S', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized ("Efx Sys 2"), 'Y', NULL, NULL,
		XmNuserData, this, NULL);

	effect_menu = XmVaCreateSimplePulldownMenu(menu_bar, "effect_menu", 2, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Effects Off"), 'O', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Vocal Transformer"), 'V', NULL, NULL,
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Full"), 'F',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("System"), 'S',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Filter"), 'I',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Distortion"), 'D',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Modulation"), 'M',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Compressor"), 'C',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Chorus"), 'H',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Reverb"), 'R',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Pitch"), 'P',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Other"), 'O',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Series (2)"), '2',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Series (3-5)"), '3',
		XmVaCASCADEBUTTON, XmStringCreateLocalized ("Parallel"), 'L',
		XmNuserData, this, NULL);

	full_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 2, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("01 : High Quality Reverb"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("02 : Mic Simulator"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("03 : Vocoder"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("04 : Vocal Multi"), '4', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("05 : Game (with 3D Reverb)"), '5', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("06 : Rotary Multi"), '6', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("07 : GTR Multi 1 (Guitar Multi 1)"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("08 : GTR Multi 2 (Guitar Multi 2)"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("09 : GTR Multi 3 (Guitar Multi 3)"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("10 : Clean Gt Multi 1 (Clean Guitar Multi 1)"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("11 : Clean Gt Multi 2 (Clean Guitar Multi 2)"), 'A', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("12 : Bass Multi"), 'B', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("13 : E.Piano Multi"), 'C', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("14 : Keyboard Multi"), 'D', NULL, NULL,
		XmNuserData, this, NULL);

	system_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 3, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Delay (Sys1)"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Chorus (Sys1)"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Delay (Sys2)"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("Reverb (Sys2)"), '3', NULL, NULL,
		XmNuserData, this, NULL);

	filter_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 4, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("00 : Noise Suppressor"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("01 : Stereo-EQ (Stereo Equalizer)"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("02 : Spectrum"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("03 : Enhancer"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("04 : Humanizer"), '4', NULL, NULL,
		XmNuserData, this, NULL);

	distortion_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 5, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("05 : Overdrive"), '5', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("06 : Distortion"), '6', NULL, NULL,
		XmNuserData, this, NULL);

	modulation_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 6, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("07 : Phaser"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("08 : Auto Wah"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("09 : Rotary"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("10 : Stereo Flanger"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("11 : Step Flanger"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("12 : Tremolo"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("13 : Auto Pan"), '3', NULL, NULL,
		XmNuserData, this, NULL);

	compressor_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 7, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("14 : Compressor"), '4', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("15 : Limiter"), '5', NULL, NULL,
		XmNuserData, this, NULL);

	chorus_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 8, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("16 : Hexa Chorus"), '6', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("17 : Tremolo Chorus"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("18 : Stereo Chorus"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("19 : Space D"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("20 : 3D Chorus"), '0', NULL, NULL,
		XmNuserData, this, NULL);

	reverb_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 9, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("21 : Stereo Delay"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("22 : Modulation Delay"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("23 : Triple Tap Delay"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("24 : Quadruple Tap Delay"), '4', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("25 : Time Control Delay"), '5', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("26 : Reverb"), '6', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("27 : Gate Reverb"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("28 : 3D Delay"), '8', NULL, NULL,
		XmNuserData, this, NULL);

	pitch_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 10, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("29 : 2-voice Pitch Shifter"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("30 : Feedback Pitch Shifter"), '0', NULL, NULL,
		XmNuserData, this, NULL);

	other_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 11, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("31 : 3D Auto"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("32 : 3D Manual"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("33 : Lo-Fi 1"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("34 : Lo-Fi 2"), '4', NULL, NULL,
		XmNuserData, this, NULL);

	two_series_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 12, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("35 : OD => Chorus (Overdrive -> Chorus)"), '5', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("36 : OD => Flanger (Overdrive -> Flanger)"), '6', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("37 : OD => Delay (Overdrive -> Delay)"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("38 : DS => Chorus (Distortion => Chorus)"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("39 : DS => Flanger (Distortion => Flanger)"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("40 : DS => Delay (Distortion => Delay)"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("41 : EH => Chorus (Enhancer => Chorus)"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("42 : EH => Flanger (Enhancer => Flanger)"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("43 : EH => Delay (Enhancer => Delay)"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("44 : Cho => Delay (Chorus => Delay)"), '4', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("45 : FL => Delay (Flanger => Delay)"), 'F', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("46 : Cho => Flanger (Chorus => Flanger)"), 'C', NULL, NULL,
		XmNuserData, this, NULL);

	multi_series_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 13, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("47 : Rotary Multi"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("48 : GTR Multi 1 (Guitar Multi1)"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("49 : GTR Multi 2 (Guitar Multi2)"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("50 : GTR Multi 3 (Guitar Multi3)"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("51 : Clean Gt Multi1 (Clean Guitar Multi1)"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("52 : Clean Gt Multi2 (Clean Guitar Multi2)"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("53 : Bass Multi"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("54 : E.Piano Multi"), '4', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("55 : Keyboard Multi"), '5', NULL, NULL,
		XmNuserData, this, NULL);

	parallel_submenu = XmVaCreateSimplePulldownMenu(effect_menu, "submenu", 14, effect_menu_callback,
		XmVaPUSHBUTTON, XmStringCreateLocalized("56 : Cho / Delay (Chorus/Delay)"), '6', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("57 : FL / Delay (Flanger/Delay)"), '7', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("58 : Cho / Flanger (Chorus/Flanger)"), '8', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("59 : OD1 / OD2 (Overdrive/Distortion1,2)"), '9', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("60 : OD / Rotary (Overdrive/Distortion, Rotary)"), '0', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("61 : OD / Phaser (Overdrive/Distortion, Phaser)"), '1', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("62 : OD / AutoWah (Overdrive/Distortion, Auto-wah)"), '2', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("63 : PH / Rotary (Phaser, Rotary)"), '3', NULL, NULL,
		XmVaPUSHBUTTON, XmStringCreateLocalized("64 : PH / Auto Wah (Phaser, Auto-wah)"), '4', NULL, NULL,
		XmNuserData, this, NULL);

	// Must be created before workWindow or sizing is strange
	message_bar = XtVaCreateManagedWidget("message_bar", xmLabelWidgetClass, main_window,
		XmNlabelType, XmSTRING, NULL);
	XtVaSetValues(main_window, XmNmessageWindow, message_bar, NULL);
	update_message_bar("");

	fader_area = XtVaCreateManagedWidget("fader_area", xmRowColumnWidgetClass, main_window,
		XmNorientation, XmHORIZONTAL, NULL);

	midi_device = open(midi_device_name, O_WRONLY);
	if (midi_device <= 0)
		errno_dialog(midi_device_name, errno);

	new ua100mix_fader(this, "Mic/Line", "F0411000111200401105%02X00F7", ua100mix_parameter_127, 0, 100, 127);
	new ua100mix_fader(this, "Mic 2", "F0411000111200401205%02X00F7", ua100mix_parameter_127, 0, 100, 127);
	new ua100mix_fader(this, "Wave 1", "F0411000111200401305%02X00F7", ua100mix_parameter_127, 0, 100, 127);
	new ua100mix_fader(this, "Wave 2", "F0411000111200401405%02X00F7", ua100mix_parameter_127, 0, 100, 127);
	new ua100mix_fader(this, "Input", "F0411000111200401000%02X00F7", ua100mix_input_source, 0, 0, 2);
	new ua100mix_fader(this, "Record", "F0411000111200405000%02X00F7", ua100mix_parameter_channel, 0, 9, 9);
	new ua100mix_fader(this, "Output", "F0411000111200405001%02X00F7", ua100mix_parameter_channel, 0, 9, 9);
	new ua100mix_fader(this, "Main", "F0411000111200405003%02X00F7", ua100mix_parameter_127, 0, 100, 127);
}


int ua100mix::errno_dialog(char *caption, int errno_value)
{
	XmString caption_string = XmStringCreateLocalized(caption);
	XmString message_string = XmStringCreateLocalized(strerror(errno_value));
	Widget dialog = XmCreateErrorDialog(shell, "errno", NULL, 0);
	XtVaSetValues(dialog, XmNdialogTitle, caption_string, XmNmessageString, message_string, NULL);
	XmStringFree(caption_string);
	XmStringFree(message_string);
	XtUnmanageChild(XtNameToWidget(dialog, "Cancel"));
	XtUnmanageChild(XtNameToWidget(dialog, "Help"));
	XtManageChild(dialog);
	return -errno;
}

int ua100mix::update_message_bar(char *hex_string)
{
	char message[256] = "";

	/****
	switch (input_source)
	{
		case 0: strcpy(message, "Input Mic, "); break;
		case 1: strcpy(message, "Input Line, "); break;
		case 2: strcpy(message, "Input Mic1+2, "); break;
	}
	****/

	if (!effect_name)
		strcat(message, "Effects Off ");
	else
	{
		strcat(message, effect_name);
		strcat(message, " ");

		switch (effect_path)
		{
			case UA100_PATH_LINE: strcat(message, "(Line/Mic) "); break;
			case UA100_PATH_MIC2: strcat(message, "(Mic 2) "); break;
			case UA100_PATH_WAVE1: strcat(message, "(Wave 1) "); break;
			case UA100_PATH_WAVE2: strcat(message, "(Wave 2) "); break;
			case UA100_PATH_SYS1: strcat(message, "(Sys 1) "); break;
			case UA100_PATH_SYS2: strcat(message, "(Sys 2) "); break;
		}
	}

	if (hex_string)
		strcat(message, hex_string);
	
	XmString label = XmStringCreateSimple(message);
	XtVaSetValues(message_bar, XmNlabelString, label, NULL);
	XmStringFree(label);

	return 0;
}

int ua100mix::write_data(char *hex_string)
{
	// UA-100 sysex format: F04110001112aaaaaaaadd00F7

	unsigned char message[256];
	for (int scan = 0; scan < (int) strlen(hex_string); ++scan)
	{
		unsigned char data = 0;
		if ((hex_string[scan] >= 'A') && (hex_string[scan] <= 'F'))
			data = 10 + hex_string[scan] - 'A';
		else if ((hex_string[scan] >= 'a') && (hex_string[scan] <= 'f'))
			data = 10 + hex_string[scan] - 'a';
		else
			data = hex_string[scan] - '0';

		if (scan & 1)
			message[scan / 2] = message[scan / 2] | (data & 0x0F);
		else
			message[scan / 2] = data << 4;
	}

	if (message[0] == 0xF0)
	{
		int check_sum = 0;
		for (int check_scan = 6; check_scan < ((int)(strlen(hex_string) / 2) - 2); ++check_scan)
			check_sum += message[check_scan];

		message[(strlen(hex_string) / 2) - 2] = 128 - (check_sum & 0x7F);
	}

	char hex_message[256] = "";
	for (int scan = 0; scan < ((int)strlen(hex_string) / 2); ++scan)
		sprintf(&hex_message[strlen(hex_message)], "%02x ", message[scan]);

	update_message_bar(hex_message);
	printf("%s\n", hex_message);

	if (midi_device > 0)
		return write(midi_device, message, strlen(hex_string) / 2);
	else
		return -1;
}

int ua100mix::select_effect(int address, char *name)
{
	clear_effect();
	effect_name = name;

	if ((address == UA100MIX_EFFECT_INSERTION_NOISE_SUPPRESSOR) || (address & 0xff00))
	{
		// "Compact" effects mode
		write_data("F04110001112004000000300F7");
		write_data("F04110001112004040000300F7");
	}
	else
	{
		// "Full" effects mode
		write_data("F04110001112004000000400F7");
		write_data("F04110001112004040000400F7");
	}

	// Select effect type
	char message[256];
	sprintf(message, "F0411000111200400%X00%04X00F7", effect_path + 1, address); 
	write_data(message);

	// Then turn the path switch on - must do this after selecting effect type, not before
	sprintf(message, "F041100011120040400%d0100F7", effect_path + 1); 
	return write_data(message);
}

int ua100mix::clear_effect()
{
	if (effect_name)
	{
		int child_count = 0;
		WidgetList widget_list = NULL;
		XtVaGetValues(fader_area, XmNchildren, &widget_list, XmNnumChildren, &child_count, NULL);

		for (int scan = 0; scan < child_count; ++scan)
		{
			ua100mix_fader *fader = NULL;

			XtVaGetValues(widget_list[scan], XmNuserData, &fader, NULL);
			if (fader && fader->is_effect)
				delete fader;
		}

		write_data("F04110001112004040010000F7");
		write_data("F04110001112004040020000F7");
		write_data("F04110001112004040030000F7");
		write_data("F04110001112004040040000F7");
		write_data("F04110001112004040050000F7");
		write_data("F04110001112004040060000F7");

		effect_name = NULL;
	}

	return 0;
}

/***************************************************************************/

static void fader_callback (Widget widget, XtPointer client_data, XtPointer call_data)
{
	ua100mix_fader *fader = (ua100mix_fader*) client_data;

	int value = 0;
	XmScaleGetValue(fader->fader, &value);

	// don't write redundant message if value is not changed
	if (value == fader->current_value)
		return; 

	fader->current_value = value;
	XmString label = XmStringCreateLocalized(fader->values[value - fader->low_value]);
	XtVaSetValues(fader->value_label, XmNlabelString, label, NULL);
	XmStringFree(label);

	char message[256];
	sprintf(message, fader->hex_string, value);
	fader->mixer->write_data(message);
}

ua100mix_fader::ua100mix_fader(ua100mix *mixer, char *title, char *hex_string, char **values, int low_value, int default_value, int high_value)
{
	memset(this, 0, sizeof(*this));
	this->mixer = mixer;
	this->values = values;

	this->hex_string = new char[strlen(hex_string) + 1];
	strcpy(this->hex_string, hex_string);
	is_effect = 0;

	create_widgets(title, low_value, default_value, high_value);
}


ua100mix_fader::ua100mix_fader(ua100mix *mixer, char *title, int parameter_number, char **values, int low_value, int default_value, int high_value)
{
	memset(this, 0, sizeof(*this));
	this->mixer = mixer;
	this->values = values;

	hex_string = new char[36];
	sprintf(hex_string, "F0411000111200400%X%02X%%02X00F7", mixer->effect_path + 1, parameter_number + 2);
	is_effect = 1;
	
	create_widgets(title, low_value, default_value, high_value);
}

ua100mix_fader::~ua100mix_fader() 
{ 
	if (hex_string) 
		delete hex_string; 

	XtDestroyWidget(container);
}

int ua100mix_fader::create_widgets(char *title, int low_value, int default_value, int high_value)
{
	this->low_value = low_value;
	this->high_value = high_value;
	this->current_value = default_value;

	container = XtVaCreateManagedWidget("channel", xmFormWidgetClass, mixer->fader_area,
		// XmNborderWidth, 1,
		// XmNborderColor, BlackPixelOfScreen(XtScreen(mixer->fader_area)),
		XmNresizePolicy, XmRESIZE_NONE,
		XmNuserData, this, 
		XmNwidth, 55, 
		NULL);

	XmString label = XmStringCreateLocalized(title);
	title_label = XtVaCreateManagedWidget("title_label", xmLabelWidgetClass, container,
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNlabelType, XmSTRING,
		XmNlabelString, label,
		NULL);
	XmStringFree(label);

	label = XmStringCreateLocalized(values[default_value - low_value]);
	value_label = XtVaCreateManagedWidget("value_label", xmLabelWidgetClass, container,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, title_label,
		XmNleftAttachment, XmATTACH_FORM,
		XmNlabelType, XmSTRING,
		XmNlabelString, label,
		NULL);
	XmStringFree(label);

	fader = XtVaCreateManagedWidget("fader", xmScaleWidgetClass, container,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, value_label,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNorientation, XmVERTICAL,
		XmNminimum, low_value,
		XmNmaximum, high_value,
		XmNvalue, default_value,
		XmNwidth, 30,
		XmNscaleWidth, 30,
		NULL);
	XtAddCallback(fader, XmNdragCallback, fader_callback, (XtPointer)this);
	XtAddCallback(fader, XmNvalueChangedCallback, fader_callback, (XtPointer)this);

	XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass, container,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNorientation, XmVERTICAL,
		NULL);

	return 0;
}

/***************************************************************************/

int main(int argc, char **argv)
{
	fprintf(stderr, "%s\n", UA100MIX_ABOUT);

	if (argc != 2)
		return fprintf(stderr, "SYNTAX: ua100mix <midi_device_name>\n");

	ua100mix mixer(argv[0], argv[1]);

	XtRealizeWidget(mixer.shell);

	XtAppMainLoop(mixer.application);

	return 0;
}


/***************************************************************************/

#if 0


int ua100mix::save_mixer_settings(const char *file_name)
{
	FILE *file = fopen(file_name, "w");

	if (!file)
	{
		perror(file_name);
		QMessageBox::information(this, file_name, "Failure saving settings", QMessageBox::Ok);
		return 0;
	}

	fprintf(file, "[MODE]\nUA100CONTROLLER=True\n");
	if (full_effect->name_box->currentItem() > 0)
		fprintf(file, "EFFMODE=2\n");
	else
		fprintf(file, "EFFMODE=1\n"); // ???
	fprintf(file, "SUBMODE=0\n\n");

	fprintf(file, "[INPUT]\nMICLINE=%d\n", channels[0]->input_mode->currentItem());
	fprintf(file, "0_PAN=64\n1_PAN=64\n");

	for (int channel = 0; channel < 4; ++channel)
    {
		fprintf(file, "%d_SEND1=%d\n", channel, 127 - channels[channel]->send1->value());
		fprintf(file, "%d_SEND2=%d\n", channel, 127 - channels[channel]->send2->value());
		fprintf(file, "%d_SUB=100\n", channel);
	}

	for (int channel = 0; channel < 4; ++channel)
		fprintf(file, "%d_FADER=%d\n", channel, 127 - channels[channel]->fader->value());

	fprintf(file, "\n[SYSTEM]\n");
	fprintf(file, "0_RETURN=%d\n0_SUB=100\n", 127 - channels[4]->send1->value());
	fprintf(file, "1_RETURN=%d\n1_SUB=100\n", 127 - channels[4]->send2->value());

	fprintf(file, "\n[OUTPUT]\n");

	if (channels[0]->record->isOn()) // ????
		fprintf(file, "1_SELECT=0\n");
	else if (channels[1]->record->isOn())
		fprintf(file, "1_SELECT=1\n");
	else if (channels[2]->record->isOn())
		fprintf(file, "1_SELECT=2\n");
	else if (channels[3]->record->isOn())
		fprintf(file, "1_SELECT=3\n");
	else
		fprintf(file, "1_SELECT=8\n");

	if (channels[0]->output->isOn()) // ????
		fprintf(file, "2_SELECT=0\n");
	else if (channels[1]->output->isOn())
		fprintf(file, "2_SELECT=1\n");
	else if (channels[2]->output->isOn())
		fprintf(file, "2_SELECT=2\n");
	else if (channels[3]->output->isOn())
		fprintf(file, "2_SELECT=3\n");
	else
		fprintf(file, "2_SELECT=8\n");

	fprintf(file, "0_FADER=%d\n", 127 - channels[4]->fader->value()); //?????
	fprintf(file, "1_FADER=100\n");

	fprintf(file, "\n[EFFECT]\n");
	for (int path = 0; path < 6; ++path)
		if (full_effect && (full_effect->path == path))
			fprintf(file, "%d_SWITCH=1\n", path);
		else if (insertion_effect && (full_effect->path == path))
			fprintf(file, "%d_SWITCH=1\n", path);
		else
			fprintf(file, "%d_SWITCH=0\n", path);

	if (full_effect->name_box->currentItem() > 0)
	{
		fprintf(file, "\n[EFFECT%02d]\n", full_effect->path + 1);
		fprintf(file, "TYPE=%d\n", full_effect->name_box->currentItem() - 1);
		fprintf(file, "NUM=%d\n", full_effect->number_of_parameters());
		for (int scan = 0; scan < ua100mix_parameterS; ++scan)
			if (full_effect->parameter[scan])
				fprintf(file, "VALUE_%02d=%d\n", scan, full_effect->parameter[scan]->currentItem());
	}

	if (insertion_effect->name_box->currentItem() > 0)
	{
		fprintf(file, "\n[EFFECT%02d]\n", insertion_effect->path + 1);

		if (insertion_effect->name_box->currentItem() < 6)
		{
			fprintf(file, "TYPE1=0\n"); // filter
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 1);
		}
		else if (insertion_effect->name_box->currentItem() < 8)
		{
			fprintf(file, "TYPE1=1\n"); // distortion
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 6);
		}
		else if (insertion_effect->name_box->currentItem() < 15)
		{
			fprintf(file, "TYPE1=2\n"); // modulation
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 8);
		}
		else if (insertion_effect->name_box->currentItem() < 17)
		{
			fprintf(file, "TYPE1=3\n"); // compressor
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 15);
		}
		else if (insertion_effect->name_box->currentItem() < 22)
		{
			fprintf(file, "TYPE1=4\n"); // chorus
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 17);
		}
		else if (insertion_effect->name_box->currentItem() < 30)
		{
			fprintf(file, "TYPE1=5\n"); // reverb
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 22);
		}
		else if (insertion_effect->name_box->currentItem() < 32)
		{
			fprintf(file, "TYPE1=6\n"); // pitch shift
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 30);
		}
		else if (insertion_effect->name_box->currentItem() < 36)
		{
			fprintf(file, "TYPE1=7\n"); // 2 in series
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 32);
		}
		else if (insertion_effect->name_box->currentItem() < 48)
		{
			fprintf(file, "TYPE1=8\n"); // Multi
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 36);
		}
		else if (insertion_effect->name_box->currentItem() < 57)
		{
			fprintf(file, "TYPE1=9\n"); // 3 in series
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 48);
		}
		else
		{
			fprintf(file, "TYPE1=10\n"); // 2 in parallel
			fprintf(file, "TYPE2=%d\n", insertion_effect->name_box->currentItem() - 57);
		}

		fprintf(file, "NUM=%d\n", insertion_effect->number_of_parameters());
		for (int scan = 0; scan < ua100mix_parameterS; ++scan)
			if (insertion_effect->parameter[scan])
				fprintf(file, "VALUE_%02d=%d\n", scan, insertion_effect->parameter[scan]->currentItem());
	}

	if (system_effect_1->name_box->currentItem() > 0)
	{
		fprintf(file, "\n[EFFECT05]\n");
		fprintf(file, "TYPE=%d\n", system_effect_1->name_box->currentItem() - 1);
		fprintf(file, "NUM=%d\n", system_effect_1->number_of_parameters());
		for (int scan = 0; scan < ua100mix_parameterS; ++scan)
			if (system_effect_1->parameter[scan])
				fprintf(file, "VALUE_%02d=%d\n", scan, system_effect_1->parameter[scan]->currentItem());
	}

	if (system_effect_2->name_box->currentItem() > 0)
	{
		fprintf(file, "\n[EFFECT06]\n");
		fprintf(file, "TYPE=%d\n", system_effect_2->name_box->currentItem() - 1);
		fprintf(file, "NUM=%d\n", system_effect_2->number_of_parameters());
		for (int scan = 0; scan < ua100mix_parameterS; ++scan)
			if (system_effect_2->parameter[scan])
				fprintf(file, "VALUE_%02d=%d\n", scan, system_effect_2->parameter[scan]->currentItem());
	}

	fclose(file);

    return 0;
}

int ua100mix::load_mixer_settings(const char *file_name)
{
	FILE *file = fopen(file_name, "r");
	char buffer[256];
	int effect_mode = 1; // 1=compact, 2=full
	int effect_path = 0; // 0=mic/line, 1=mic2, 2=wave1, 3=wave2, 4=sys1, 5=sys2
	int is_input = 1;
	ua100mix_effect *current_effect = NULL;

	if (!file)
	{
		perror(file_name);
		QMessageBox::information(this, file_name, "Failure loading settings", QMessageBox::Ok);
		return 0;
	}

	channels[0]->input_mode->setCurrentItem(0);

	while (fgets(buffer, sizeof(buffer), file))
		if (strncmp(buffer, "EFFMODE=", 8) == 0)
			effect_mode = atoi(&buffer[8]);

		else if (strncmp(buffer, "MICLINE=", 8) == 0)
			channels[0]->input_mode->setCurrentItem(atoi(&buffer[8]));

		else if (strncmp(&buffer[2], "SEND1=", 6) == 0)
			channels[atoi(buffer)]->send1->setValue(127 - atoi(&buffer[8]));

		else if (strncmp(&buffer[2], "SEND2=", 6) == 0)
			channels[atoi(buffer)]->send2->setValue(127 - atoi(&buffer[8]));

		else if (strncmp(buffer, "[OUTPUT]", 8) == 0)
			is_input = 0;

		else if (is_input && (strncmp(&buffer[2], "FADER=", 6) == 0))
			channels[atoi(buffer)]->fader->setValue(127 - atoi(&buffer[8]));

		else if (strncmp(buffer, "1_FADER=", 8) == 0)
			channels[4]->fader->setValue(127 - atoi(&buffer[8]));

		else if (strncmp(buffer, "0_RETURN=", 9) == 0)
			channels[4]->send1->setValue(127 - atoi(&buffer[9]));

		else if (strncmp(buffer, "1_RETURN=", 9) == 0)
			channels[4]->send2->setValue(127 - atoi(&buffer[9]));

		else if (strncmp(buffer, "1_SELECT=", 9) == 0)
		{
			if (channels[0]->input_mode->currentItem() == 0) // 2 microphones
				switch (atoi(&buffer[9]))
				{
					case 0: channels[0]->output->setOn(1); break;
					case 1: channels[1]->output->setOn(1); break;
					case 2: channels[2]->output->setOn(1); break;
					case 3: channels[3]->output->setOn(1); break;
					default: channels[4]->output->setOn(1);
				}
			else // line
				switch (atoi(&buffer[9]))
				{
					case 0: channels[0]->output->setOn(1); break;
					case 1: channels[2]->output->setOn(1); break;
					case 2: channels[3]->output->setOn(1); break;
					default: channels[4]->output->setOn(1);
				}
		}

		else if (strncmp(buffer, "2_SELECT=", 9) == 0)
		{
			if (channels[0]->input_mode->currentItem() == 0) // 2 microphones
				switch (atoi(&buffer[9]))
				{
					case 0: channels[0]->record->setOn(1); break;
					case 1: channels[1]->record->setOn(1); break;
					case 2: channels[2]->record->setOn(1); break;
					case 3: channels[3]->record->setOn(1); break;
					default: channels[4]->record->setOn(1);
				}
			else // line
				switch (atoi(&buffer[9]))
				{
					case 0: channels[0]->record->setOn(1); break;
					case 1: channels[2]->record->setOn(1); break;
					case 2: channels[3]->record->setOn(1); break;
					default: channels[4]->record->setOn(1);
				}
		}

		else if (strncmp(buffer, "[EFFECT", 7) == 0)
		{
			effect_path = atoi(&buffer[7]);
			if (effect_mode == 2)
			{
				current_effect = full_effect;
				full_effect->path_box->setCurrentItem(effect_path - 1);
			}
			else if (effect_path < 4)
			{
				current_effect = insertion_effect;
				insertion_effect->path_box->setCurrentItem(effect_path - 1);
			}
			else if (effect_path == 4)
				current_effect = system_effect_1;
			else if (effect_path == 5)
				current_effect = system_effect_2;
		}

		else if (strncmp(buffer, "TYPE=", 5) == 0)
		{
			if (current_effect == full_effect)
				slotChangeFullEffect(atoi(&buffer[5]) + 1);
			else if (current_effect == system_effect_1)
				slotChangeSystemEffect1(atoi(&buffer[5]) + 1);
			else if (current_effect == system_effect_2)
				slotChangeSystemEffect2(atoi(&buffer[5]) + 1);
		}

		else if (strncmp(buffer, "TYPE1=", 6) == 0)
		{
			int type1 = atoi(&buffer[6]);
			fgets(buffer, sizeof(buffer), file);
			int type2 = atoi(&buffer[6]);
			current_effect = insertion_effect;

			if (type1 == 0) // filter
				slotChangeInsertionEffect(1 + type2);
			else if (type1 == 1) // distortion
				slotChangeInsertionEffect(6 + type2);
			else if (type1 == 2) // modulation
				slotChangeInsertionEffect(8 + type2);
			else if (type1 == 3) // compressor
				slotChangeInsertionEffect(15 + type2);
			else if (type1 == 4) // chorus
				slotChangeInsertionEffect(17 + type2);
			else if (type1 == 5) // reverb
				slotChangeInsertionEffect(22 + type2);
			else if (type1 == 6) // pitch shift
				slotChangeInsertionEffect(30 + type2);
			else if (type1 == 7) // 2 in series
				slotChangeInsertionEffect(32 + type2);
			else if (type1 == 8) // multi effects
				slotChangeInsertionEffect(36 + type2);
			else if (type1 == 9) // 3 in series
				slotChangeInsertionEffect(48 + type2);
			else if (type1 == 10) // 2 in parallel
				slotChangeInsertionEffect(57 + type2);
		}

		else if (strncmp(buffer, "VALUE_", 6) == 0)
		{
			int parameter_number = atoi(&buffer[6]);
			if (current_effect && current_effect->parameter[parameter_number])
				current_effect->parameter[parameter_number]->setCurrentItem(atoi(&buffer[9]));
		}

	return 0;
}

/****************************** Effect Parameter Values **************************************/

/********************** Slots ************************/

void ua100mix::slotFileOpen()
{
	struct stat file_status;

	QString file_name = QFileDialog::getOpenFileName(0, "Mixer Settings (*.uax);;All Files (*.*)", this);

	if (file_name.isEmpty())
		return;

	else if (stat(file_name, &file_status) < 0)
		QMessageBox::information(this, strerror(errno), "Failure opening file", QMessageBox::Ok);

	else
	{
		load_mixer_settings(file_name);
		setCaption(file_name);
		statusBar()->message("New Settings");
	}
}

void ua100mix::slotFileSave()
{
	if (caption().isEmpty())
		slotFileSaveAs();

	else
		save_mixer_settings(caption());

	statusBar()->message("Mixer settings saved");
}

void ua100mix::slotFileSaveAs()
{
	statusBar()->message("Saving file under new filename...");

	QString file_name = QFileDialog::getSaveFileName(NULL, "Mixer settings (*.uax);;All Files (*.*)", this);

	if (!file_name.isEmpty())
	{
		if (!strstr(file_name, ".uax"))
			file_name.append(".uax");

		setCaption(file_name);
		slotFileSave();
	}
	else
		statusBar()->message("Mixer settings not saved");
}

void ua100mix::slotFileExit()
{
	qApp->quit();
}

void ua100mix::slotHelpAbout()
{
	QMessageBox::about(this,"About...", UA100MIX_VERSION);
}

void ua100mix::slotFullEffect()
{
	full_effect->show();
	insertion_effect->hide();
	system_effect_1->hide();
	system_effect_2->hide();
}

void ua100mix::slotInsertionEffect()
{
	full_effect->hide();
	insertion_effect->show();
	system_effect_1->hide();
	system_effect_2->hide();
}

void ua100mix::slotSystemEffect1()
{
	full_effect->hide();
	insertion_effect->hide();
	system_effect_1->show();
	system_effect_2->hide();
}

void ua100mix::slotSystemEffect2()
{
	full_effect->hide();
	insertion_effect->hide();
	system_effect_1->hide();
	system_effect_2->show();
}

void ua100mix::slotChangeFullEffect(int index)
{
	send_ua100_sysex_message(0x00404000, 04); // full effects mode

	full_effect->clear_effect();
	insertion_effect->clear_effect();
	system_effect_1->clear_effect();
	system_effect_2->clear_effect();

	full_effect->name_box->setCurrentItem(index);

	if (index == 0)
	{
		send_ua100_sysex_message(0x00404000, 03); // compact effects mode
		return;
	}


	else if (index == 2)
		full_effect->effect_number = UA100MIX_EFFECT_FULL_MICROPHONE_SIMULATOR;

	else if (index == 3)
		full_effect->effect_number = UA100MIX_EFFECT_FULL_VOCODER;

	else if (index == 4)
		full_effect->effect_number = UA100MIX_EFFECT_FULL_VOCAL_MULTI;

	else if (index == 5)
		full_effect->effect_number = UA100MIX_EFFECT_FULL_GAME;

	send_ua100_sysex_message(0x00400100 + (full_effect->path << 8), full_effect->effect_number, 2);
	send_ua100_sysex_message(0x00404001 + full_effect->path, 1);
	channels[0]->slotModeChange(channels[0]->input_mode->currentItem()); // doesn't apply effect to input otherwise
}

void ua100mix::slotChangeInsertionEffect(int index)
{
	if (full_effect->name_box->currentItem() > 0)
	{
		full_effect->clear_effect();
		send_ua100_sysex_message(0x00404000, 03); // compact effects mode
	}

	insertion_effect->clear_effect();
	insertion_effect->name_box->setCurrentItem(index);

	// The Parameter area for combo boxes is 2,27 to 294,200
	// Combo boxes: 2 across = 145 x 23; 3 across = 95 x 23
	if (index == 0)
		return;



	send_ua100_sysex_message(0x00400100 + (insertion_effect->path << 8), insertion_effect->effect_number, 2);
	send_ua100_sysex_message(0x00404001 + insertion_effect->path, 1);
	channels[0]->slotModeChange(channels[0]->input_mode->currentItem()); // doesn't apply effect to input otherwise
}

void ua100mix::slotChangeSystemEffect1(int index)
{
	if (full_effect->name_box->currentItem() > 0)
	{
		full_effect->clear_effect();
		send_ua100_sysex_message(0x00404000, 03); // compact effects mode
	}

	system_effect_1->clear_effect();
	system_effect_1->name_box->setCurrentItem(index);

	if (index == 0)
		return;

	else if (index == 1)
		system_effect_1->effect_number = UA100MIX_EFFECT_SYS1_DELAY;

	else if (index == 2)
		system_effect_1->effect_number = UA100MIX_EFFECT_SYS1_CHORUS;

	send_ua100_sysex_message(0x00400500, system_effect_1->effect_number, 2);
	send_ua100_sysex_message(0x00404005, 1);
	channels[0]->slotModeChange(channels[0]->input_mode->currentItem()); // doesn't apply effect to input otherwise
}

void ua100mix::slotChangeSystemEffect2(int index)
{
	if (full_effect->name_box->currentItem() > 0)
	{
		full_effect->clear_effect();
		send_ua100_sysex_message(0x00404000, 03); // compact effects mode
	}

	system_effect_2->clear_effect();
	system_effect_2->name_box->setCurrentItem(index);

	if (index == 0)
		return;

	else if (index == 1)
		system_effect_2->effect_number = UA100MIX_EFFECT_SYS2_DELAY;

	else if (index == 2)
	{
		/***
		system_effect_2->effect_number = UA100MIX_EFFECT_SYS2_REVERB;
		system_effect_2->parameter[0] = new ua100mix_parameter(system_effect_2, 154, 2, 298, 25, 0, 3, "Room1", "Room2", "Stage1", "Stage2", "Hall1", "Hall2");
		system_effect_2->parameter[1] = new ua100mix_parameter(system_effect_2, 2, 25, 32, 78, 1, "Pre", 0, 127, 0x70);
		system_effect_2->parameter[2] = new ua100mix_parameter(system_effect_2, 34, 25, 64, 78, 2, "Time", 0, 127, 120);
		system_effect_2->parameter[3] = new ua100mix_parameter(system_effect_2, 66, 25, 96, 78, 3, "Damp", 0, 127, 0x67);
		system_effect_2->parameter[4] = new ua100mix_parameter(system_effect_2, 98, 25, 128, 78, 4, "Lo", 0x34, 0x4c, 0x40);
		system_effect_2->parameter[5] = new ua100mix_parameter(system_effect_2, 130, 25, 160, 78, 5, "Hi", 0x34, 0x4c, 0x40);
		system_effect_2->parameter[6] = new ua100mix_parameter(system_effect_2, 162, 25, 192, 78, 6, "Balance", 0, 127, 0x40);
		***/
	}

	send_ua100_sysex_message(0x00400600, system_effect_2->effect_number, 2);
	send_ua100_sysex_message(0x00404006, 1);
	channels[0]->slotModeChange(channels[0]->input_mode->currentItem()); // doesn't apply effect to input otherwise
}


/********************** Events ************************/

void ua100mix::closeEvent(QCloseEvent *event)
{
	QWidget::closeEvent(event);
}

void ua100mix::keyPressEvent(QKeyEvent *event)
{
	/* QMessageBox::information(this, "Keystrokes", "Feature Not Implemented", QMessageBox::Ok); */

	QMainWindow::keyPressEvent(event);
}


/****************************** Effect Base Widget **************************************/

ua100mix_effect::ua100mix_effect(ua100mix *mixer, int path) : QWidget(mixer)
{
	move(302, 50);
	resize(296, 225);

	name_box = new QComboBox(this);
	name_box->move(2, 2);
	name_box->resize(196, 23);

	if (path >= 0)
	{
		this->path = path;
		path_box = NULL;
	}
	else
	{
		path_box = new QComboBox(this);
		path_box->move(200, 2);
		path_box->resize(94, 23);
		path_box->insertItem("Line/Mic 1");
		path_box->insertItem("Mic 2");
		path_box->insertItem("Wave 1");
		path_box->insertItem("Wave 2");
		path_box->insertItem("Sys 1");
		path_box->insertItem("Sys 2");
		path_box->setCurrentItem(0);
		path_box->setEditable(FALSE);
		connect(path_box, SIGNAL(activated(int)), this, SLOT(slotPathChanged(int)));
		this->path = 0;
	}

	setBackgroundMode(QWidget::PaletteMid);

	this->effect_number = 0;
	this->mixer = mixer;
	memset(parameter, 0, sizeof(parameter));
}

void ua100mix_effect::add_parameter(int parameter_number, char *prefix, char **values, int default_value)
{
	int left_x = 2 + (99 * (number_of_parameters() % 3));
	int top_y = 27 + (23 * (number_of_parameters() / 3));

	parameter[parameter_number] = new QComboBox(this);
	parameter[parameter_number]->move(left_x, top_y);
	parameter[parameter_number]->resize(97, 25);

	for (int entry = 0; values[entry] && (entry < 128); ++entry)
	{
		char composite[64];
		sprintf(composite, "%s %s", prefix, values[entry]);
		parameter[parameter_number]->insertItem(composite);
	}

	parameter[parameter_number]->setCurrentItem(default_value);
	parameter[parameter_number]->setEditable(FALSE);
	mixer->send_ua100_sysex_message(0x00400103 + (path << 8) + parameter_number, default_value);

	connect(parameter[parameter_number], SIGNAL(activated(int)), this, SLOT(slotParameterChanged(int)));
	parameter[parameter_number]->show();
}

void ua100mix_effect::clear_effect()
{
	mixer->send_ua100_sysex_message(0x00404001 + path, 0);

	for (int scan = 0; scan < ua100mix_parameterS; ++scan)
		if (parameter[scan])
		{
			delete parameter[scan];
			parameter[scan] = NULL;
		}

	name_box->setCurrentItem(0);
}

void ua100mix_effect::slotPathChanged(int new_path)
{
	clear_effect();
	path = new_path;
	mixer->send_ua100_sysex_message(0x00404001 + path, 1);
}

void ua100mix_effect::slotParameterChanged(int value)
{
	QComboBox *parameter_box = (QComboBox*) sender();
	int parameter_number = 0;

	while ((parameter_number < ua100mix_parameterS) && (parameter[parameter_number] != parameter_box))
		++parameter_number;

	if (mixer && (parameter_number < ua100mix_parameterS))
		mixer->send_ua100_sysex_message(0x00400103 + (path << 8) + parameter_number, value);
}

/********************** Main Program Entry Function ************************/

int main(int argc, char *argv[])
{
	ua100mix_application application(argc, argv);
	application.connect(&application, SIGNAL(lastWindowClosed()), &application, SLOT(quit()));

	printf("%s\n", UA100MIX_VERSION);
	if (argc != 2)
		return printf("SYNTAX: ua100mix <midi device>\nExample: ua100mix /dev/midi02\n");

	application.mixer = new ua100mix(argv[1]);

	application.mixer->show();

	return application.exec();
}

#endif









