diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..e69de29 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f4d865d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +project(prodatum) +cmake_minimum_required(VERSION 2.6) + +SET( VER 1.1.0 ) +SET( SYSEX_MAX_SIZE 138 ) +SET( RINGBUFFER_WRITE 138 ) +SET( RINGBUFFER_READ 512 ) +SET( PATH_MAX 512 ) +SET( LOG_BUFFER_SIZE 48000 ) +CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/config.h.in ${CMAKE_SOURCE_DIR}/config.h ) + +include_directories (${prodatum_SOURCE_DIR}/include) +link_directories (${prodatum_SOURCE_DIR}/lib) + +file (GLOB prodatum_SOURCES *.C) +add_executable (prodatum ${prodatum_SOURCES}) + +if(WIN32) + ADD_DEFINITIONS(-DWIN32) + set(CMAKE_EXE_LINKER_FLAGS "-mwindows -m32 -static-libgcc -static-libstdc++") + set(ADDITIONAL_LIBRARIES winmm ole32 uuid comctl32 wsock32) +endif(WIN32) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + ADD_DEFINITIONS(-DOSX -DUSE_MLOCK) + set(ADDITIONAL_LIBRARIES "-framework Carbon -framework ApplicationServices -framework CoreMIDI -framework CoreAudio") +endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + ADD_DEFINITIONS(-DUSE_MLOCK) + set(ADDITIONAL_LIBRARIES X11 Xft fontconfig Xinerama asound pthread) +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + +target_link_libraries (prodatum fltk.a portmidi_s.a ${ADDITIONAL_LIBRARIES} ) diff --git a/README b/README new file mode 100644 index 0000000..8bb6aae --- /dev/null +++ b/README @@ -0,0 +1,7 @@ + +This git version is not for public use! +Does NOT WORK! +This is an experimental tree. + +IF YOU NEED WORKING CODE, USE THE SVN VERSION + diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/cfg.C b/cfg.C new file mode 100644 index 0000000..dbe4439 --- /dev/null +++ b/cfg.C @@ -0,0 +1,208 @@ +// This file is part of prodatum. +// Copyright 2011 Jan Eidtmann +// +// prodatum 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 3 of the License, or +// (at your option) any later version. +// +// prodatum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with prodatum. If not, see . + +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "cfg.H" +#include "debug.H" + +// ms to wait between name requests on init and when a WAIT is received +int request_delay; +// colors used in ui and widgets +unsigned char colors[5]; + +Cfg::Cfg(const char* n, int ac) +{ + pmesg(40, "Cfg::Cfg(%s, %d) \n", n, ac); + // defaults +#ifdef WINDOWS + set_export_dir(getenv("USERPROFILE")); + snprintf(config_dir, BUF_PATHS, "%s/prodatum", getenv("APPDATA")); +#else + set_export_dir(getenv("HOME")); + snprintf(config_dir, BUF_PATHS, "%s/.prodatum", export_dir); +#endif + snprintf(config_name, 32, "%s", n); + defaults.resize(NOOPTION, 0); + defaults[CFG_MIDI_OUT] = -1; + defaults[CFG_MIDI_IN] = -1; + defaults[CFG_MIDI_THRU] = -1; + defaults[CFG_CONTROL_CHANNEL] = 0; + defaults[CFG_AUTOMAP] = 1; + defaults[CFG_DEVICE_ID] = 0; + defaults[CFG_AUTOCONNECT] = ac; + defaults[CFG_SPEED] = 0; + defaults[CFG_CLOSED_LOOP_UPLOAD] = 0; + defaults[CFG_CLOSED_LOOP_DOWNLOAD] = 0; + defaults[CFG_TOOLTIPS] = 1; + defaults[CFG_KNOBMODE] = 1; + defaults[CFG_CONFIRM_EXIT] = 0; + defaults[CFG_CONFIRM_RAND] = 1; + defaults[CFG_CONFIRM_DISMISS] = 1; + defaults[CFG_SYNCVIEW] = 0; + defaults[CFG_DRLS] = 1; + defaults[CFG_BG] = 170; // 170 140 + defaults[CFG_BG2] = 15; // 5 215 + defaults[CFG_RR] = 92; // 82 68 + defaults[CFG_GG] = 102; // 92 74 + defaults[CFG_BB] = 97; // 87 77 + defaults[CFG_COLORED_BG] = 1; + defaults[CFG_SHINY_KNOBS] = 0; + defaults[CFG_LOG_SYSEX_OUT] = 0; + defaults[CFG_LOG_SYSEX_IN] = 0; + defaults[CFG_LOG_EVENTS_OUT] = 0; + defaults[CFG_LOG_EVENTS_IN] = 0; + defaults[CFG_WINDOW_WIDTH] = 843; + defaults[CFG_WINDOW_HEIGHT] = 615; + defaults[CFG_AUDIT_IMPORT] = 1; + // load config + struct stat sbuf; + if (stat(config_dir, &sbuf) == -1) + { + + if (mkdir(config_dir, S_IRWXU| S_IRWXG | S_IROTH | S_IXOTH) == -1) + { + char message[BUF_MSG]; + snprintf(message, BUF_MSG, + "Could not create configuration directory:\n%s - %s\n", + config_dir, strerror(errno)); + pmesg(1, message); + fl_alert("%s", message); + throw 1; + } + } + // load config + option.resize(NOOPTION, 0); + char config_path[BUF_PATHS]; + snprintf(config_path, BUF_PATHS, "%s/%s", config_dir, config_name); + std::ifstream file(config_path); + if (!file.is_open()) + { + //ui->message("Could not load the config,\nusing defaults."); + for (int i = 0; i < NOOPTION; i++) + option[i] = defaults[i]; + return; + } + int check_file, check = 1; + for (int i = 0; i < NOOPTION; i++) + { + file >> option[i]; + check += option[i] * ((i % 5) + 1); + } + // checksum + file >> check_file; + // get export directory + char buf[BUF_PATHS]; + file.getline(0, 0); + file.getline(buf, BUF_PATHS); + if (!file.fail()) + set_export_dir(buf); + file.close(); + if (check_file != check) + { + fl_message("Configuration updated, using default values.\n" + "Sorry for the inconvenience! I've opted for a\n" + "brainless but uber-fast configuration parser."); + for (int i = 0; i < NOOPTION; i++) + option[i] = defaults[i]; + } + request_delay = option[CFG_SPEED] * 25 + 25; +} + +Cfg::~Cfg() +{ + pmesg(40, "Cfg::~Cfg() \n"); + // save config + char config_path[BUF_PATHS]; + snprintf(config_path, BUF_PATHS, "%s/%s", config_dir, config_name); + std::ofstream file(config_path, std::ios::trunc); + if (!file.is_open()) + { + fl_message("Warning:\nCould not write the config file."); + return; + } + // calc checksum + int check = 1; + for (int i = 0; i < NOOPTION; i++) + { + file << option[i] << " "; + check += option[i] * ((i % 5) + 1); + } + file << check << std::endl; + file << export_dir << std::endl; + file.close(); +} + +void Cfg::set_cfg_option(int opt, int value) +{ + pmesg(40, "Cfg::set_cfg_option(%d, %d) \n", opt, value); + if (opt < NOOPTION && opt >= 0) + option[opt] = value; + if (opt == CFG_SPEED) + request_delay = value * 25 + 25; +} + +int Cfg::get_cfg_option(int opt) const +{ + pmesg(80, "Cfg::get_cfg_option(%d) \n", opt); + if (opt < NOOPTION && opt >= 0) + return option[opt]; + return 0; +} + +int Cfg::getset_default(int opt) +{ + pmesg(40, "Cfg::getset_default(%d) \n", opt); + if (opt < NOOPTION && opt >= 0) + { + option[opt] = defaults[opt]; + return defaults[opt]; + } + return 0; +} + +const char* Cfg::get_config_dir() const +{ + pmesg(40, "Cfg::get_config_dir() \n"); + return config_dir; +} + +const char* Cfg::get_export_dir() const +{ + pmesg(40, "Cfg::get_export_dir() \n"); + return export_dir; +} + +void Cfg::set_export_dir(const char* dir) +{ + pmesg(40, "Cfg::set_export_dir(%s) \n", dir); + // add trailing slash + if (dir[strlen(dir) - 1] != '/' && dir[strlen(dir) - 1] != '\\') + snprintf(export_dir, BUF_PATHS, "%s/", dir); + else + snprintf(export_dir, BUF_PATHS, "%s", dir); +} diff --git a/cfg.H b/cfg.H new file mode 100644 index 0000000..ebb6fb0 --- /dev/null +++ b/cfg.H @@ -0,0 +1,114 @@ +// $Id$ +#ifndef CFG_H_ +#define CFG_H_ +/** + \defgroup pd_cfg prodatum Configurations + @{ +*/ +#ifdef WINDOWS +# include +# define mkdir(x,m) _mkdir(x) +#else +# define mkdir(x,m) mkdir(x,m) +#endif + +#define SYSEX_MESSAGE_BUFFER 1024 +#define RING_READ_BUFFER_SIZE 2048 +#define RING_WRITE_BUFFER_SIZE SYSEX_MESSAGE_BUFFER +#define MAX_ARPS 300 +#define MAX_RIFFS 1000 +#define LOG_BUFFER_SIZE 1000000 +#include + +/** + * Enum of config options + */ +enum CONFIG +{ + CFG_MIDI_OUT, + CFG_MIDI_IN, + CFG_MIDI_THRU, + CFG_CONTROL_CHANNEL, + CFG_AUTOMAP, + CFG_DEVICE_ID, + CFG_AUTOCONNECT, + CFG_SPEED, + CFG_CLOSED_LOOP_UPLOAD, + CFG_CLOSED_LOOP_DOWNLOAD, + CFG_TOOLTIPS, + CFG_KNOBMODE, + CFG_CONFIRM_EXIT, + CFG_CONFIRM_RAND, + CFG_CONFIRM_DISMISS, + CFG_SYNCVIEW, + CFG_DRLS, + CFG_BG, + CFG_BG2, + CFG_RR, + CFG_GG, + CFG_BB, + CFG_COLORED_BG, + CFG_SHINY_KNOBS, + CFG_LOG_SYSEX_OUT, + CFG_LOG_SYSEX_IN, + CFG_LOG_EVENTS_OUT, + CFG_LOG_EVENTS_IN, + CFG_WINDOW_WIDTH, + CFG_WINDOW_HEIGHT, + CFG_AUDIT_IMPORT, + NOOPTION +}; + +/** + * Enum of colors + */ +enum +{ + BG, BG2, RR, GG, BB, DEFAULT, CURRENT, KNOBS +}; + +/** + * Configuration class. + * loads, saves and manages all configuration options + */ +class Cfg +{ + /// config name + char config_name[64]; + /// configuration directory + char config_dir[BUF_PATHS]; + /// path to export directory + char export_dir[BUF_PATHS]; + std::vector defaults; + std::vector option; + +public: + /** + * CTOR parses config file + */ + Cfg(const char* n, int ac); + /** + * DTOR saves config file + */ + ~Cfg(); + /// returns the config directory path + const char* get_config_dir() const; + const char* get_export_dir() const; + void set_export_dir(const char* dir); + /** + * updates a configuration value + * @param option the parameter to update + * @param value the new value for the parameter + */ + void set_cfg_option(int option, int value); + /** + * get a configuration option + * @param option parameter to get + * @return parameter value + */ + int get_cfg_option(int option) const; + int getset_default(int option); +}; + +#endif /* CFG_H_ */ +/** @} */ diff --git a/data.C b/data.C new file mode 100644 index 0000000..5e92a6b --- /dev/null +++ b/data.C @@ -0,0 +1,1762 @@ +// This file is part of prodatum. +// Copyright 2011 Jan Eidtmann +// +// prodatum 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 3 of the License, or +// (at your option) any later version. +// +// prodatum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with prodatum. If not, see . + +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "data.H" +#include "midi.H" +#include "cfg.H" +#include "pd.H" +#include "ui.H" + +#include "debug.H" + +extern MIDI* midi; +extern Cfg* cfg; +extern PD* pd; +extern PD_UI* ui; +extern bool time_incoming_midi; +extern std::map rom_id_map; +extern PD_Arp_Step* arp_step[32]; + +/** + * calculates integer value of two nibbelized MIDI bytes + * @param lsb least significant byte of value + * @param msb most significant byte of value + * @returns integer value + */ +static int unibble(const unsigned char* lsb, const unsigned char* msb) +{ + int raw_value; + raw_value = (*msb * 128) + *lsb; + if (raw_value >= 8192) + raw_value -= 16384; + return raw_value; +} + +// ############### +// Preset_Dump class +// ################# +Preset_Dump::Preset_Dump(int dump_size, const unsigned char* dump_data, + int p_size, bool update) +{ + pmesg(40, "Preset_Dump::Preset_Dump(size: %d, data, packet_size: %d)\n", + dump_size, p_size); + disable_add_undo = false; + data_is_changed = false; + size = dump_size; + packet_size = p_size; + (size > 1607) ? extra_controller = 4 : extra_controller = 0; + a2k = 0; + if (size == 1605) + a2k = 1; + data = 0; + number = pd->selected_preset; + rom_id = pd->selected_preset_rom; + if (dump_data) + { + data = new unsigned char[size]; + memcpy(data, dump_data, size); + snprintf((char*) name, 17, "%s", data + DUMP_HEADER_SIZE + 9); + } + // silently update outside name changes + if (update) + { + if (rom_id == 0 && number >= 0 && pd->rom[0]) + { + pd->rom[0]->set_name(PRESET, number, name); + ui->preset->load_n(PRESET, 0, number); + if (ui->copy_arp_rom->value() == 0) + ui->copy_browser->load_n(PRESET, 0, number); + } + } +} + +Preset_Dump::~Preset_Dump() +{ + pmesg(90, "Preset_Dump::~Preset_Dump()\n"); + delete[] data; +} + +bool Preset_Dump::is_changed() const +{ + return data_is_changed; +} + +void Preset_Dump::set_changed(bool set) +{ + if (set) + data_is_changed = true; + else + { + data_is_changed = false; + undo_s.clear(); + redo_s.clear(); + } +} + +int Preset_Dump::get_extra_controller() +{ + return extra_controller; +} + +void Preset_Dump::clone(Preset_Dump* dst) const +{ + memcpy(dst->data, data, size); +} + +const char* Preset_Dump::get_name() +{ + static char n[17]; + snprintf(n, 17, "%s", name); + n[3] = '_'; + while (n[strlen(n) - 1] == ' ') + n[strlen(n) - 1] = '\0'; + return (const char*) n; +} + +int Preset_Dump::get_number() const +{ + return number; +} + +int Preset_Dump::get_rom_id() const +{ + return rom_id; +} + +int Preset_Dump::get_value(int id, int layer) const +{ + pmesg(80, "Preset_Dump::get_value(id: %d, layer: %d)\n", id, layer); + int offset = 0; + idmap(id, layer, offset); + if (offset == 0) + return -999; + return unibble(data + offset, data + offset + 1); +} + +int Preset_Dump::get_dump_size() const +{ + return size; +} +const unsigned char* Preset_Dump::get_data() const +{ + return data; +} +int Preset_Dump::get_p_size() const +{ + return packet_size; +} + +int Preset_Dump::set_value(int id, int value, int layer) +{ + //pmesg(90, "Preset_Dump::set_value(id: %d, value: %d, layer: %d)\n", id, + // value, layer); + int offset = 0; + idmap(id, layer, offset); + if (offset == 0) + return 0; + if (value < 0) + value += 16384; + // check wether value is the same + if (unibble((const unsigned char*) data + offset, + (const unsigned char*) data + offset + 1) == value) + return 0; + // save undo + if (!disable_add_undo && id > 914 && !(ui->eall && layer > 0)) + { + // but not all steps and not if we are undoing + if (!undo_s.empty()) + { + parameter current = undo_s.front(); + if (current.id != id || current.layer != layer) + add_undo(id, value, layer); + } + else + add_undo(id, value, layer); + } + // for names, only one byte is used per character... + data[offset] = value % 128; + if (id > 914) // ...otherwise 2 + data[offset + 1] = value / 128; + if (!data_is_changed) + data_is_changed = true; + return 1; +} + +// type 0 = category, type 1 = name +void Preset_Dump::set_name(const char* val, int type, int position) +{ + int len; + int offset; + if (type == 0) //category + { + len = 3; + offset = 0; + } + else if (type == 1) // name + { + len = 12; + offset = 4; + } + else + return; + // check input + char buf[30]; + bool updated = false; + snprintf(buf, len + 1, "%s ", val); + for (int i = 0; i < len; i++) + if (!isascii(buf[i])) + { + buf[i] = '_'; + updated = true; + break; + } + // update internal data + for (int j = 0; j < len; j++) + { + name[j + offset] = buf[j]; + set_value(899 + j + offset, name[j + offset]); + } + // update ui + if (updated) + { + while (buf[strlen(buf) - 1] == ' ') + buf[strlen(buf) - 1] = '\0'; + if (type == 0) + { + ui->n_cat_m->value(buf); + ui->n_cat_m->position(position); + } + else + { + ui->n_name_m->value(buf); + ui->n_name_m->position(position); + } + } + snprintf(buf, 30, "%02d.%03d.%d %s", rom_id, number % 128, number / 128, + name); + ui->main->preset_name->copy_label((char*) buf); + // update the name on the device, just for fun + for (int i = offset; i < len + offset; i++) + midi->edit_parameter_value(899 + i, *(name + i)); +} + +void Preset_Dump::update_highlight_buttons() +{ + // used by set color to update the colors of the highlight buttons in the navi bar + pwid[1025][0]->set_value(get_value(1025)); // preset arp +} + +void Preset_Dump::show() +{ + pmesg(40, "Preset_Dump::show()\n"); + char buf[30]; + snprintf(buf, 30, "%02d.%03d.%d %s", rom_id, number % 128, number / 128, + name); + ui->main->preset_name->copy_label((char*) buf); + snprintf(buf, 30, "%02d.%03d.%d", rom_id, number % 128, number / 128); + ui->n_n_m->copy_label(buf); + snprintf(buf, 17, "%s", name); + while (buf[strlen(buf) - 1] == ' ') + buf[strlen(buf) - 1] = '\0'; + ui->n_name_m->value((const char*) buf + 4); + //buf[3] = '\0'; + while (strlen(buf) > 3 || buf[strlen(buf) - 1] == ' ') + buf[strlen(buf) - 1] = '\0'; + ui->n_cat_m->value((const char*) buf); + // first we wanna load the names into the browsers + // so they are available for selection + for (int j = 0; j < 4; j++) + if (pwid[1439][j]) // instruments + pwid[1439][j]->set_value(get_value(1439, j)); + if (pwid[929][0]) // riffs + pwid[929][0]->set_value(get_value(929)); + if (pwid[1042][0]) // arp + pwid[1042][0]->set_value(get_value(1042)); + if (pwid[1299][0]) // link 1 + pwid[1299][0]->set_value(get_value(1299)); + if (pwid[1300][0]) // link 2 + pwid[1300][0]->set_value(get_value(1300)); + + for (int i = 915; i <= 1300; i++) // preset params + { + if ((i > 1152 && i < 1169) || i == 929) // skip fx & riff rom + continue; + if (pwid[i][0]) + pwid[i][0]->set_value(get_value(i)); + } + for (int i = 1409; i <= 1992; i++) // layer params + { + // skip roms + if (i == 1439 || i == 1042 || i == 1299 || i == 1300) + continue; + for (int j = 0; j < 4; j++) + if (pwid[i][j]) + pwid[i][j]->set_value(get_value(i, j)); + } + update_piano(); + update_envelopes(); + if (pd->midi_mode != MULTI || pd->selected_fx_channel != -1) + show_fx(); +} + +void Preset_Dump::show_fx() const +{ + pmesg(40, "Preset_Dump::show_fx()\n"); + for (int i = 1153; i < 1169; i++) + if (pwid[i][0]) + pwid[i][0]->set_value(get_value(i)); +} + +void Preset_Dump::update_piano() const +{ + // update piano + int id = 1413; + for (int m = 0; m < 3; m++) // modes + for (int i = 0; i < 4; i++) // layers + ui->piano->set_range_values(m, i, get_value(id + m * 4, i), + get_value(id + 1 + m * 4, i), get_value(id + 2 + m * 4, i), + get_value(id + 3 + m * 4, i)); + // arp ranges + ui->piano->set_range_values(0, 4, get_value(1039), 0, get_value(1040), 0); + if (pd->setup) + ui->piano->set_range_values(0, 5, pd->setup->get_value(655), 0, + pd->setup->get_value(656), 0); + // link ranges + ui->piano->set_range_values(0, 6, get_value(1286), 0, get_value(1287), 0); + ui->piano->set_range_values(0, 7, get_value(1295), 0, get_value(1296), 0); + // transpose + ui->piano->set_transpose(get_value(1429, 0), get_value(1429, 1), + get_value(1429, 2), get_value(1429, 3)); +} + +void Preset_Dump::update_envelopes() const +{ + pmesg(70, "Preset_Dump::update_envelopes()\n"); + static int stages[12]; + int mode = 0; + int repeat = -1; + int id = 1793; + for (int l = 0; l < 4; l++) // for all 4 layers + { + for (int m = 0; m < 3; m++) // for all three envelopes + { + mode = get_value(id + m * 13, l); + for (int i = 0; i < 6; i++) + { + *(stages + i * 2) = get_value(id + m * 13 + 2 * i + 1, l); + *(stages + i * 2 + 1) = get_value(id + m * 13 + 2 * i + 2, l); + } + switch (m) + { + case 1: + repeat = get_value(1833, l); + break; + case 2: + repeat = get_value(1834, l); + break; + default: // volume env has no repeat + repeat = -1; + } + ui->layer_editor[l]->envelope_editor->set_data(m, stages, mode, + repeat); + } + } +} + +void Preset_Dump::upload(int packet, int closed, bool show) +{ + pmesg(40, "Preset_Dump::upload(packet: %d, closed: %d)\n", packet, closed); + if (!data) + return; + const static int chunks = (size - DUMP_HEADER_SIZE) / packet_size; + const static int tail = (size - DUMP_HEADER_SIZE) % packet_size; + static int status = 0; + static int offset; + static int chunk_size = 0; + static int closed_loop = 0; + static int previous_packet = -1; + static bool show_preset = false; + if (packet == 0 && closed != -1) + { + closed_loop = closed; + show_preset = show; + update_checksum(); + if (closed_loop) + pd->loading(); + } + ui->progress->value((float) status); + if (closed_loop) + { + // first we send the dump header + if (packet == 0) + { + data[3] = (unsigned char) (cfg->get_cfg_option(CFG_DEVICE_ID) + & 0xFF); + data[6] = 0x01; + offset = 0; + chunk_size = DUMP_HEADER_SIZE; + status = chunk_size; + } + else + { + if (previous_packet != packet) + { + if (packet == 1) + offset += DUMP_HEADER_SIZE; + else + offset += packet_size; + } + data[offset + 3] = (unsigned char) (cfg->get_cfg_option( + CFG_DEVICE_ID) & 0xFF); + data[offset + 6] = 0x02; + chunk_size = packet_size; + if (packet == chunks + 1) + chunk_size = tail; + status += chunk_size; + } + // ack of tail...send eof + if (packet == chunks + 2) + { + midi->eof(); + if (show_preset) + pd->show_preset(); + if (unibble(data + 7, data + 8) == -1) + pd->display_status("Upload successful."); + else + pd->display_status("Program saved."); + status = 0; + ui->loading_w->hide(); + } + else + midi->write_sysex(data + offset, chunk_size); + previous_packet = packet; + } + else + { + for (int i = 0; i < chunks + 2; i++) + { + if (i == 0) + { + data[3] = (unsigned char) (cfg->get_cfg_option(CFG_DEVICE_ID) + & 0xFF); + data[6] = 0x03; + offset = 0; + chunk_size = DUMP_HEADER_SIZE; + status = chunk_size; + } + else + { + if (i == 1) + offset += DUMP_HEADER_SIZE; + else + offset += packet_size; + data[offset + 3] = (unsigned char) (cfg->get_cfg_option( + CFG_DEVICE_ID) & 0xFF); + data[offset + 6] = 0x04; + chunk_size = packet_size; + if (i == chunks + 1) + chunk_size = tail; + status += chunk_size; + } + midi->write_sysex(data + offset, chunk_size); + ui->progress->value((float) status); + if (i == chunks + 1) + { + if (show_preset) + pd->show_preset(); + if (unibble(data + 7, data + 8) == -1) + pd->display_status("Upload successful."); + else + pd->display_status("Program saved."); + status = 0; + } + } + } +} + +void Preset_Dump::save_file(const char* filename) +{ + pmesg(40, "Preset_Dump::save_file(%s) \n", filename); + // check if file exists and ask for confirmation + struct stat sbuf; + if (stat(filename, &sbuf) == 0 && fl_choice("Overwrite existing file?", + "No", "Overwrite", 0) == 0) + return; + // write + std::ofstream file(filename, std::ofstream::binary | std::ios::trunc); + if (!file.is_open()) + { + fl_message( + "Could not write the file.\nDo you have permission to write?"); + return; + } + update_checksum(); // save a valid dump + file.write((const char*) data, size); + file.close(); + pd->display_status("Program saved to disk."); +} + +void Preset_Dump::move(int new_number) +{ + pmesg(40, "Preset_Dump::move(position: %d)\n", new_number); + if (!data) + return; + number = new_number; + rom_id = 0; + if (new_number < 0) + new_number += 16384; + // preset number + data[7] = new_number % 128; + data[8] = new_number / 128; + // rom id + data[33] = 0; + data[34] = 0; +} + +// recursively copy any parameter range in chunks +void Preset_Dump::copy_layer_parameter_range(int start, int end, int src, + int dst) +{ + // reverse order so instrument rom is set before instrument + if (start < end) + { + int tmp = start; + start = end; + end = tmp; + } + pmesg(40, "Preset_Dump::copy_layer_parameter_range(%d,%d,%d,%d)\n", start, + end, src, dst); + unsigned char m[255]; + m[0] = 0xf0; + m[1] = 0x18; + m[2] = 0x0f; + m[3] = cfg->get_cfg_option(CFG_DEVICE_ID); + m[4] = 0x55; + m[5] = 0x01; + int limit = 0; + if (start - end > 41) + { + // find real ids + int real = 0; + int i; + for (i = start; i >= end; i--) + { + if (get_value(i, src) != -999) + ++real; + if (real == 41) + break; + } + limit = i; + } + else + limit = end; + + int real = -1; + // dont keep undos for copy operations + disable_add_undo = true; + for (int i = start; i >= limit; i--) + { + int v = get_value(i, src); + if (v != -999) + ++real; + else + continue; + int offset = 7 + 4 * real; + set_value(i, v, dst); + if (pwid[i][dst]) + pwid[i][dst]->set_value(v); + if (v < 0) + v += 16384; + m[offset] = i % 128; + m[offset + 1] = i / 128; + m[offset + 2] = v % 128; + m[offset + 3] = v / 128; + if (i == limit) + m[offset + 4] = 0xf7; + } + disable_add_undo = false; + m[6] = (real + 1) * 2; + midi->write_sysex(m, 8 + m[6] * 2); + if (limit != end) + copy_layer_parameter_range(limit + 1, end, src, dst); +} + +void Preset_Dump::copy(int type, int src, int dst) +{ + pmesg(40, "Preset_Dump::copy(%X,%d,%d)\n", type, src, dst); + if (type >= C_LAYER && type <= C_LAYER_PATCHCORD) + { + midi->edit_parameter_value(898, dst); + pd->selected_layer = dst; + } + switch (type) + { + case C_PRESET: + { + midi->copy(C_PRESET, number, dst, 0, 0, rom_id); + // update names and browsers + pd->rom[0]->set_name(PRESET, dst, + pd->rom[rom_id_map[rom_id]]->get_name(PRESET, number)); + if (ui->preset_rom->value() == 0) + ui->preset->load_n(PRESET, 0, dst); + ui->copy_browser->load_n(PRESET, 0, dst); + pd->display_status("Copied."); + } + break; + case C_PRESET_COMMON: + break; + case C_ARP: + { + // note: we cannot copy the arp into the edit buffer + // so we only allow copying if a user preset is selected + if (!pd->preset_copy->get_rom_id()) + { + midi->copy(C_ARP, dst, pd->preset_copy->get_number(), 0, 0, + ui->copy_arp_rom->get_value()); + // wait a bit for the device to update the edit buffer + mysleep(100); + midi->request_preset_dump(-1, 0); + } + pd->display_status("Copied."); + break; + } + case C_FX: + break; + case C_LAYER: + copy_layer_parameter_range(1409, 1992, src, dst); + update_piano(); + update_envelopes(); + pd->display_status("Copied."); + break; + case C_LAYER_COMMON: + copy_layer_parameter_range(1409, 1439, src, dst); + pd->display_status("Copied."); + break; + case C_LAYER_FILTER: + copy_layer_parameter_range(1537, 1539, src, dst); + pd->display_status("Copied."); + break; + case C_LAYER_LFO: + copy_layer_parameter_range(1665, 1674, src, dst); + pd->display_status("Copied."); + break; + case C_LAYER_ENVELOPE: + copy_layer_parameter_range(1793, 1834, src, dst); + update_envelopes(); + pd->display_status("Copied."); + break; + case C_LAYER_PATCHCORD: + copy_layer_parameter_range(1921, 1992, src, dst); + pd->display_status("Copied."); + break; + case C_ARP_PATTERN: + { + int source_rom; + if (ui->preset_editor->arp->visible_r()) + { + src = ui->preset_editor->arp->get_value(); + source_rom + = pd->rom[ui->preset_editor->arp_rom->value()]->get_attribute( + ID); + } + else + { + src = ui->main->arp->get_value(); + source_rom = pd->rom[ui->main->arp_rom->value()]->get_attribute(ID); + } + midi->copy(C_ARP_PATTERN, src, dst, 0, 0, source_rom); + // update names + pd->rom[0]->set_name(ARP, dst, + pd->rom[rom_id_map[source_rom]]->get_name(ARP, src)); + ui->copy_arp_pattern_browser->load_n(ARP, 0, dst); + if (ui->preset_editor->arp_rom->value() == 0) + ui->preset_editor->arp->load_n(ARP, 0, dst); + if (ui->main->arp_rom->value() == 0) + ui->main->arp->load_n(ARP, 0, dst); + pd->display_status("Copied."); + break; + } + case SAVE_PRESET: + { + // update internal files and ui + pd->rom[0]->set_name(PRESET, dst, name); + ui->preset->load_n(PRESET, 0, dst); + if (ui->copy_arp_rom->value() == 0) + ui->copy_browser->load_n(PRESET, 0, dst); + // upload preset + move(dst); + upload(0, cfg->get_cfg_option(CFG_CLOSED_LOOP_UPLOAD)); + set_changed(false); + } + } +} + +void Preset_Dump::add_undo(int id, int value, int layer) +{ + if (disable_add_undo) + return; + pmesg(40, "Preset_Dump::add_undo(%d, %d, %d)\n", id, value, layer); + parameter changed, prev_changed; + // envelopes are special because we change 2 values at once + // and on undo we want to change both back at once + // everything else just doesn't feel right + if ((id > 1793 && id < 1833) && id != 1806 && id != 1819) // envelopes + { + int second_id = 0; + if (id <= 1805 || id >= 1820) + { + if (id % 2 != 0) + id -= 1; + second_id = id + 1; + } + else + { + if (id % 2 == 0) + id -= 1; + second_id = id + 1; + } + // ^^ id is rate, second_id is lvl + if (!undo_s.empty()) + { + prev_changed = undo_s.front(); + if (prev_changed.id == second_id && prev_changed.layer == layer) + return; // dont save all steps + } + // save current values + changed.layer = layer; + // first value + changed.id = id; + changed.value = get_value(id, layer); + undo_s.push_front(changed); + // second value + changed.id = second_id; + changed.value = get_value(second_id, layer); + undo_s.push_front(changed); + } + else + { + // save current value + changed.layer = layer; + changed.id = id; + changed.value = get_value(id, layer); + undo_s.push_front(changed); + } + redo_s.clear(); + ui->redo_b->deactivate(); + ui->undo_b->activate(); +} + +void Preset_Dump::undo() +{ + if (!undo_s.empty()) + { + pmesg(40, "Preset_Dump::undo()\n"); + // 10000 undos max! ") + if (undo_s.size() > 10000) + undo_s.pop_back(); + bool repeat = true; + Undo: + // save current value to redo + parameter p = undo_s.front(); + parameter c; + c.layer = p.layer; + c.id = p.id; + c.value = get_value(p.id, p.layer); + // undo + pd->widget_callback(p.id, p.value, p.layer); + // focus the widget + //((Fl_Widget*)pwid[p.id][p.layer])->take_focus(); + // update stack + undo_s.pop_front(); + redo_s.push_front(c); + if (undo_s.empty()) + ui->undo_b->deactivate(); + else if (repeat && (p.id > 1793 && p.id < 1833) && p.id != 1806 && p.id + != 1819) // envelopes + { + repeat = false; + goto Undo; + } + // update UI + ui->redo_b->activate(); + update_ui_from_xdo(p.id, p.value, p.layer); + } + else + pd->display_status("*** Nothing to Undo."); +} + +void Preset_Dump::redo() +{ + if (!redo_s.empty()) + { + pmesg(40, "Preset_Dump::redo()\n"); + bool repeat = true; + Redo: + // save current value for undo + parameter p = redo_s.front(); + parameter c; + c.layer = p.layer; + c.id = p.id; + c.value = get_value(p.id, p.layer); + undo_s.push_front(c); + // redo + pd->widget_callback(p.id, p.value, p.layer); + // update stack + redo_s.pop_front(); + if (redo_s.empty()) + ui->redo_b->deactivate(); + else if (repeat && (p.id > 1793 && p.id < 1833) && p.id != 1806 && p.id + != 1819) // envelopes + { + repeat = false; + goto Redo; + } + // update UI + ui->undo_b->activate(); + update_ui_from_xdo(p.id, p.value, p.layer); + } + else + pd->display_status("*** Nothing to redo."); +} + +void Preset_Dump::update_ui_from_xdo(int id, int value, int layer) +{ + if (id > 1792 && id < 1835) + update_envelopes(); + else if ((id > 1412 && id < 1425) || id == 1429) + update_piano(); + else + { + pwid_editing = pwid[id][layer]; + int* minimax = pwid_editing->get_minimax(); + ui->value_input->minimum((double) minimax[0]); + ui->value_input->maximum((double) minimax[1]); + pwid[1][0]->set_value(value); + pwid[id][layer]->set_value(value); + ui->forma_out->set_value(id, layer, value); + ui->forma_out->redraw(); + } +} + +// maps Parameter IDs from the device to data position in preset dump +void Preset_Dump::idmap(const int& id, const int& layer, int& id_mapped) const +{ + //pmesg(100, "Preset_Dump::idmap(id: %d, layer: %d, offset)\n", id, layer); + if (!data || !((id >= 899 && id <= 970) || (id >= 1025 && id <= 1043) + || (id >= 1153 && id <= 1168) || (id >= 1281 && id <= 1300) || (id + >= 1409 && id <= 1439) || (id >= 1537 && id <= 1539) || (id >= 1665 + && id <= 1674) || (id >= 1793 && id <= 1834) || (id >= 1921 && id + <= 1992))) + return; + if (!extra_controller && (id >= 967 && id <= 970)) + return; + if (a2k && id == 1043) // a2k has no arp post delay + return; + int pos; + if (id - 970 <= 0) // Preset Common General Edit Parameters + { + pos = id - 899; + if (pos < 16) // name chars + { + id_mapped = DUMP_HEADER_SIZE + 9 + pos; + return; + } + } + + else if (id - 1043 <= 0) // Preset Common Arpeggiator Edit Parameters + pos = id - 1025 + 68 + extra_controller; + + else if (id - 1168 <= 0) // Preset Common Effects Edit Parameters + pos = id - 1153 + 87 + extra_controller - a2k; + + else if (id - 1300 <= 0) // Preset Common Links Edit Parameters + pos = id - 1281 + 103 + extra_controller - a2k; + + // layer parameters start here + else if (id - 1439 <= 0) // Preset Layer General Edit Parameters + pos = id - 1409 + 123 + extra_controller - a2k + layer * 158; + + else if (id - 1539 <= 0) // Preset Layer Filter Edit Parameters + pos = id - 1537 + 154 + extra_controller - a2k + layer * 158; + + else if (id - 1674 <= 0) // Preset Layer LFOs Edit Parameters + pos = id - 1665 + 157 + extra_controller - a2k + layer * 158; + + else if (id - 1834 <= 0) // Preset Layer Envelope Edit Parameters + pos = id - 1793 + 167 + extra_controller - a2k + layer * 158; + + else + // Preset Layer PatchCords Edit Parameters + pos = id - 1921 + 209 + extra_controller - a2k + layer * 158; + + pos = (pos - 16) * 2 + 16; + id_mapped = DUMP_HEADER_SIZE + packet_size * (pos / (packet_size - 11)) + + (pos % (packet_size - 11)) + 9; + if (id_mapped > size - 4) + { + pmesg( + 1, + "*** Preset_Dump::idmap value out of bounds: id %d, layer %d, offset %d\n", + id, layer, id_mapped); + id_mapped = 0; + return; + } + // testing + // pmesg(80, + // "id/layer: %4d/%d value: %2X,%2X %3d pos/offset: %4d/%4d PPL\n", + // id, layer, data[id_mapped], data[id_mapped + 1], + // unibble(data + id_mapped, data + id_mapped + 1), pos, id_mapped); +} + +// updates checksums in the dump +void Preset_Dump::update_checksum() +{ + pmesg(90, "Preset_Dump::update_checksum()\n"); + if (!data) + return; + const static int chunks = (size - DUMP_HEADER_SIZE) / packet_size; + const static int tail = (size - DUMP_HEADER_SIZE) % packet_size - 11; + int offset = DUMP_HEADER_SIZE + 9; + int sum; + unsigned char checksum; + for (int j = 0; j < chunks; j++) + { + sum = 0; + for (int i = 0; i < (packet_size - 11); i++) + sum += data[offset + i]; + checksum = ~sum; + data[offset + packet_size - 11] = checksum % 128; + offset += packet_size; + } + sum = 0; + for (int i = 0; i < tail; i++) + sum += data[offset + i]; + checksum = ~sum; + data[offset + tail] = checksum % 128; +} + +// ################# +// Arp_Dump class +// ################# +Arp_Dump::Arp_Dump(int dump_size, const unsigned char* dump_data) +{ + pmesg(40, "Arp_Dump::Arp_Dump(size: %d, data)\n", dump_size); + size = dump_size; + data = new unsigned char[dump_size]; + memcpy(data, dump_data, dump_size); + number = data[6] + 128 * data[7]; + snprintf((char*) name, 17, "%s ", data + 14); + // tell device that we want to edit this pattern + midi->edit_parameter_value(769, number); + show(); +} + +Arp_Dump::~Arp_Dump() +{ + pmesg(40, "Arp_Dump::~Arp_Dump()\n"); + delete[] data; +} + +int Arp_Dump::get_number() const +{ + pmesg(40, "Arp_Dump::get_number()\n"); + return number; +} + +void Arp_Dump::show() const +{ + pmesg(40, "Arp_Dump::show()\n"); + // fill name field + update_name(name); + int offset; + int velocity; + int duration; + int repeat; + int tmp; + unsigned char* dat = data + 26; + // load step values + for (int i = 0; i < 32; i++) + { + tmp = i * 8; + offset = unibble(dat + tmp, dat + tmp + 1); + velocity = unibble(dat + tmp + 2, dat + tmp + 3); + duration = unibble(dat + tmp + 4, dat + tmp + 5); + repeat = unibble(dat + tmp + 6, dat + tmp + 7); + arp_step[i]->set_values(offset, velocity, duration, repeat); + } + update_sequence_length_information(); + if (!ui->g_arp_edit->visible()) + { + ui->g_arp_edit->show(); + ui->g_main->hide(); + Fl::focus(ui->g_arp_edit); + } +} + +void Arp_Dump::update_sequence_length_information() const +{ + pmesg(40, "Arp_Dump::update_sequence_length_information()\n"); + int tick[19] = + { 6, 8, 9, 12, 16, 18, 24, 32, 36, 48, 64, 72, 96, 128, 144, 192, 256, 288, + 384 }; + int i = 0; + int total = 0; + while (i < 32 && !arp_step[i]->End->value()) + { + if (!arp_step[i]->skip->value()) + total += tick[(int) arp_step[i]->duration->value() - 1] + * (int) arp_step[i]->repeat->value(); + ++i; + } + int beat = total / 48; + int ticks = total % 48; + char buf[8]; + snprintf(buf, 8, "%d:%d", beat, ticks); + ui->pattern_length->value(buf); +} + +int Arp_Dump::get_value(int id, int step) const +{ + pmesg(40, "Arp_Dump::get_value(id: %d, step: %d)\n", id, step); + int offset = (id - 784) * 2 + 26 + step * 8; + int value = unibble(data + offset, data + offset + 1); + if (id == 787) // repeat + value += 1; + return value; +} + +void Arp_Dump::reset_step(int step) const +{ + pmesg(40, "Arp_Dump::reset_step(step: %d)\n", step); + int tmp = step * 8; + unsigned char* dat = data + 26; + int offset = unibble(dat + tmp, dat + tmp + 1); + int velocity = unibble(dat + tmp + 2, dat + tmp + 3); + int duration = unibble(dat + tmp + 4, dat + tmp + 5); + int repeat = unibble(dat + tmp + 6, dat + tmp + 7); + arp_step[step]->set_values(offset, velocity, duration, repeat); + arp_step[step]->op->do_callback(); + arp_step[step]->velocity->do_callback(); + arp_step[step]->duration->do_callback(); + arp_step[step]->repeat->do_callback(); +} + +void Arp_Dump::rename(const char* newname) const +{ + pmesg(40, "Arp_Dump::rename(%s)\n", newname); + unsigned char buf[17]; + snprintf((char*) buf, 17, "%s ", newname); + for (int i = 0; i < 12; i++) + { + if (!isascii(buf[i])) + buf[i] = ' '; + midi->edit_parameter_value(771 + i, buf[i]); + } + update_name(buf); +} + +void Arp_Dump::update_name(const unsigned char* np) const +{ + pmesg(40, "Arp_Dump::update_name(%s)\n", np); + pd->rom[0]->set_name(ARP, number, np); + ui->copy_arp_pattern_browser->load_n(ARP, 0, number); + if (ui->preset_editor->arp_rom->value() == 0) + ui->preset_editor->arp->load_n(ARP, 0, number); + if (ui->main->arp_rom->value() == 0) + ui->main->arp->load_n(ARP, 0, number); + // fill name field + char n[13]; + snprintf(n, 13, "%s", np); + while (n[strlen(n) - 1] == ' ') + n[strlen(n) - 1] = '\0'; + ui->arp_name->value(n); +} + +void Arp_Dump::reset_pattern() const +{ + pmesg(40, "Arp_Dump::reset_pattern()\n"); + midi->write_sysex(data, (size_t) size); + show(); +} + +// ################# +// Setup_Dump class +// ################# +Setup_Dump::Setup_Dump(int dump_size, const unsigned char* dump_data) +{ + pmesg(40, "Setup_Dump::Setup_Dump(size: %d, data)\n", dump_size); + size = dump_size; + (size > 689) ? extra_controller = 4 : extra_controller = 0; + data = 0; + if (dump_data) + { + data = new unsigned char[size]; + memcpy(data, dump_data, size); + setup_dump_info[0] = data[7] * 128 + data[6]; // # general + setup_dump_info[1] = data[9] * 128 + data[8]; // # master + setup_dump_info[2] = data[11] * 128 + data[10]; // # master fx + setup_dump_info[3] = data[13] * 128 + data[12]; // # reserved + setup_dump_info[4] = data[15] * 128 + data[14]; // # non-chan + setup_dump_info[5] = data[17] * 128 + data[16]; // # midi chnls + setup_dump_info[6] = data[19] * 128 + data[18]; // # chnl params + } +} + +Setup_Dump::~Setup_Dump() +{ + pmesg(40, "Setup_Dump::~Setup_Dump()\n"); + delete[] data; +} + +int Setup_Dump::get_value(int id, int channel) const +{ + pmesg(80, "Setup_Dump::get_value(id: %d, ch: %d)\n", id, channel); + int offset = 0; + idmap(id, channel, offset); + if (offset == 0) + return -999; + return unibble(data + offset, data + offset + 1); +} + +int Setup_Dump::get_dump_size() const +{ + pmesg(40, "Setup_Dump::get_dump_size()\n"); + return size; +} + +const unsigned char* Setup_Dump::get_data() const +{ + pmesg(40, "Setup_Dump::get_data()\n"); + return data; +} + +int Setup_Dump::set_value(int id, int value, int channel) +{ + pmesg(40, "Setup_Dump::set_value(id: %d, value: %d, ch: %d)\n", id, value, + channel); + if (id == 388 && data) + { + data[0x4A] = value; + return 0; + } + // update changes in memory + int offset = 0; + idmap(id, channel, offset); + if (offset == 0) + return 0; + if (value < 0) + value += 16384; + // check wether value is the same + if (unibble((const unsigned char*) data + offset, + (const unsigned char*) data + offset + 1) == value) + return 0; + data[offset] = value % 128; + if (id < 142 || id > 157) // for name only one byte per char + data[offset + 1] = value / 128; + return 1; +} + +void Setup_Dump::update_highlight_buttons() +{ + pmesg(40, "Setup_Dump::update_highlight_buttons()\n"); + // used by set color to update the colors of the highlight buttons in the navi bar + pwid[258][0]->set_value(get_value(258)); // fx bypass + pwid[641][0]->set_value(get_value(641)); // master arp +} + +void Setup_Dump::show() const +{ + pmesg(40, "Setup_Dump::show()\n"); + int skip = 0; + if (pd->midi_mode != MULTI) + skip = 140; + // first fill the arp browser + if (pwid[660][0]) + pwid[660][0]->set_value(get_value(660)); + for (int i = 140; i <= 787; i++) + { + // skip fx and browsers + if (pwid[i][0] && (!((i > 512 && i < 529) || i == skip || i == 660))) + pwid[i][0]->set_value(get_value(i)); + } + if (pd->midi_mode == MULTI) + { + if (pd->selected_fx_channel == -1) + show_fx(); + ui->main->mix_out->activate(); + } + else + ui->main->mix_out->deactivate(); +} + +void Setup_Dump::show_fx() const +{ + pmesg(40, "Setup_Dump::show_fx()\n"); + // ui->main->fx->activate(); + for (int i = 513; i < 529; i++) + if (pwid[i][0]) + pwid[i][0]->set_value(get_value(i)); +} + +void Setup_Dump::upload() const +{ + pmesg(40, "Setup_Dump::upload()\n"); + midi->write_sysex(data, size); +} + +// maps Parameter IDs from the device to data position in preset dump +void Setup_Dump::idmap(const int& id, const int& channel, int& id_mapped) const +{ + //pmesg(100, "Setup_Dump::idmap(id: %d, ch: %d, offset)\n", id, channel); + if (!data || !((id >= 130 && id <= 157) || (id >= 257 && id <= 269) || (id + >= 271 && id <= 278) || (id >= 385 && id <= 414) || (id >= 513 + && id <= 528) || (id >= 641 && id <= 661)) || id == 136 || id + == 261 || id == 262 || id == 263 || id == 387 || id == 389 || id + == 390) + return; + if (!extra_controller && (id >= 411 && id <= 414)) + return; + // channel parameters + if (id >= 130 && id <= 138) + id_mapped = 2 * (id - 130) + 36 + 2 + * (setup_dump_info[SDI_GENERAL] + setup_dump_info[SDI_MIDI] + + setup_dump_info[SDI_FX] + + setup_dump_info[SDI_RESERVED] + + setup_dump_info[SDI_NON_CHNL]) + channel * (2 + * setup_dump_info[SDI_CHNL_PARAMS]); + // multimode parameters + else if (id >= 139 && id <= 141) + id_mapped = 2 * (id - 139) + 36 + 2 * (setup_dump_info[SDI_GENERAL] + + setup_dump_info[SDI_MIDI] + setup_dump_info[SDI_FX] + 21); + // name + else if (id >= 142 && id <= 157) + id_mapped = id - 122; + // general parameters + else if (id >= 257 && id <= 278) + { + id_mapped = 2 * (id - 257) + 36; + if (id > 263) + id_mapped -= 6; + } + // midi parameters + else if (id >= 385 && id <= 422) + { + id_mapped = 2 * (id - 385) + 36 + 2 * setup_dump_info[SDI_GENERAL]; + if (id > 390) + id_mapped -= 6; + } + // fx parameters + else if (id >= 513 && id <= 528) + id_mapped = 2 * (id - 513) + 36 + 2 * (setup_dump_info[SDI_GENERAL] + + setup_dump_info[SDI_MIDI]); + // arp parameters + else if (id >= 641 && id <= 661) + id_mapped = 2 * (id - 641) + 36 + 2 * (setup_dump_info[SDI_GENERAL] + + setup_dump_info[SDI_MIDI] + setup_dump_info[SDI_FX]); + else + pmesg(80, "*** Setup_Dump::idmap: Request for unknown ID: %d\n", id); + if (id_mapped > size - 3) + { + pmesg( + 1, + "*** Setup_Dump::idmap value out of bounds: id %d, channel %d, offset %d\n", + id, channel, id_mapped); + id_mapped = 0; + return; + } +} + +// ############### +// ROM class +// ################# +ROM::ROM(int i, int pr, int in) +{ + pmesg(40, "ROM::ROM(%d, %d, %d) \n", i, pr, in); + id = i; + instrument_names = 0; + preset_names = 0; + arp_names = 0; + riff_names = 0; + for (int i = 0; i < 7; i++) + is_saved_already[i] = false; + + const char* rom_name = name(); + ui->preset_rom->add(rom_name); + ui->preset_editor->l1_rom->add(rom_name); + ui->preset_editor->l2_rom->add(rom_name); + // some roms have no arps but we have to add them anyway + // so we the rom indizes are still working correctly. + ui->preset_editor->arp_rom->add(rom_name); + ui->main->arp_rom->add(rom_name); + ui->copy_arp_rom->add(rom_name); + // reset rom choice + if (id != 0) + ui->r_rom_rom->add(rom_name); + + presets = pr; + instruments = in; + riffs = 0; + + if (id == 0) + { + arps = 100; + // device id not yet saved to cfg, request from ui + device_id = (int) ui->device_id->value(); + } + else + { + arps = 0; + const Fl_Menu_Item* item; + item = ui->preset_editor->arp_rom->find_item(rom_name); + const_cast (item)->hide(); + item = ui->main->arp_rom->find_item(rom_name); + const_cast (item)->hide(); + item = ui->copy_arp_rom->find_item(rom_name); + const_cast (item)->hide(); + for (int i = 0; i < 4; i++) + ui->layer_editor[i]->instrument_rom->add(rom_name); + ui->preset_editor->riff_rom->add(rom_name); + ui->main->riff_rom->add(rom_name); + device_id = -1; + } +} + +ROM::~ROM() +{ + pmesg(40, "ROM::~ROM() \n"); + // clear rom choices once + if (id == 0) + { + for (int i = 0; i < 4; i++) + ui->layer_editor[i]->instrument_rom->clear(); + ui->preset_rom->clear(); + ui->preset_editor->arp_rom->clear(); + ui->preset_editor->riff_rom->clear(); + ui->preset_editor->l1_rom->clear(); + ui->preset_editor->l2_rom->clear(); + ui->main->riff_rom->clear(); + ui->main->arp_rom->clear(); + ui->copy_arp_rom->clear(); + } + // save names but only if we successfully initialized + if (pd->midi_mode != -1) + { + const char* path = cfg->get_config_dir(); + char filename[BUF_PATHS]; + // instruments + if (id != 0 && instrument_names && !is_saved_already[INSTRUMENT]) + { + snprintf(filename, BUF_PATHS, "%s/n_ins_%d", path, id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write((char*) instrument_names, instruments * 16); + file.close(); + } + // riffs + if (id != 0 && riff_names && !is_saved_already[RIFF]) + { + snprintf(filename, BUF_PATHS, "%s/n_rff_%d", path, id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write((char*) riff_names, riffs * 16); + file.close(); + } + // presets + if (preset_names && !is_saved_already[PRESET]) + { + if (id == 0) + snprintf(filename, BUF_PATHS, "%s/n_prs_%d_%d", path, id, + device_id); + else + snprintf(filename, BUF_PATHS, "%s/n_prs_%d", path, id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write((char*) preset_names, presets * 16); + file.close(); + } + // arps + if (!is_saved_already[ARP]) + { + if (arp_names) + { + if (id == 0) + snprintf(filename, BUF_PATHS, "%s/n_arp_%d_%d", path, id, + device_id); + else + snprintf(filename, BUF_PATHS, "%s/n_arp_%d", path, id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write((char*) arp_names, arps * 16); + file.close(); + } + else if (id != 0) + { + // save dummy file so we dont get init window on each startup + snprintf(filename, BUF_PATHS, "%s/n_arp_%d", path, id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write("none ", 16); + file.close(); + } + } + + } + delete[] instrument_names; + delete[] preset_names; + delete[] arp_names; + delete[] riff_names; +} + +// returns the number of names to download +int ROM::load_names(int type, int number) +{ + pmesg(40, "ROM(%d)::load_names(type %d, start %d) \n", id, type, number); + if (number == 0 && disk_load_names(type)) + return 0; + int max = 0; + switch (type) + { + case INSTRUMENT: + max = instruments; + break; + case PRESET: + max = presets; + break; + case ARP: + if (id == 0) + max = arps; + else + max = MAX_ARPS; + break; + case RIFF: + max = MAX_RIFFS; + break; + default: + return 0; + } + // for rom arps we need to use arp dumps + if (type == ARP && id != 0 && number < max) + midi->request_arp_dump(number, id); + else if (number < max) + midi->request_name(type, number, id); + if (number == 0) + { + if (type == RIFF) + return 300; + return max; + } + return 0; +} + +int ROM::disk_load_names(int type) +{ + pmesg(40, "ROM::disk_load_names(type: %d) \n", type); + const char* path = cfg->get_config_dir(); + char filename[BUF_PATHS]; + int* number; + unsigned char** data; + switch (type) + { + case INSTRUMENT: + snprintf(filename, BUF_PATHS, "%s/n_ins_%d", path, id); + number = &instruments; + data = &instrument_names; + break; + case PRESET: + if (id == 0) + snprintf(filename, BUF_PATHS, "%s/n_prs_%d_%d", path, id, device_id); + else + snprintf(filename, BUF_PATHS, "%s/n_prs_%d", path, id); + number = &presets; + data = &preset_names; + break; + case ARP: + if (id == 0) + snprintf(filename, BUF_PATHS, "%s/n_arp_%d_%d", path, id, device_id); + else + snprintf(filename, BUF_PATHS, "%s/n_arp_%d", path, id); + number = &arps; + data = &arp_names; + break; + case RIFF: + snprintf(filename, BUF_PATHS, "%s/n_rff_%d", path, id); + number = &riffs; + data = &riff_names; + break; + default: + return 0; + } + std::fstream + file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { + size_t size = file.tellg(); + if (size % 16) + { + file.close(); + return 0; + } + *number = size / 16; + *data = new unsigned char[size]; + file.seekg(0, std::ios::beg); + file.read((char*) *data, size); + file.close(); + if (id != 0 || *number == 1) + is_saved_already[type] = true; + // show this rom in arp selections + if (type == ARP && id != 0 && *number > 1) + { + const char* rom_name = ROM::name(); + const Fl_Menu_Item* item; + item = ui->preset_editor->arp_rom->find_item(rom_name); + const_cast (item)->show(); + item = ui->main->arp_rom->find_item(rom_name); + const_cast (item)->show(); + item = ui->copy_arp_rom->find_item(rom_name); + const_cast (item)->show(); + } + return 1; + } + return 0; +} + +int ROM::set_name(int type, int number, const unsigned char* name) +{ + pmesg(40, "ROM::set_name(type: %d, #: %d, name) (id: %d) \n", type, number, + id); + switch (type) + { + case INSTRUMENT: + if (!instrument_names) + instrument_names = new unsigned char[16 * instruments]; + if (number >= instruments) + { + pmesg( + 1, + "*** ROM::set_name out of bounds: rom: %d type %d, number %d\n", + id, type, number); + return 0; + } + memcpy(instrument_names + 16 * number, name, 16); + break; + case PRESET: + if (!preset_names) + preset_names = new unsigned char[16 * presets]; + if (number >= presets) + { + pmesg( + 1, + "*** ROM::set_name out of bounds: rom: %d type %d, number %d\n", + id, type, number); + return 0; + } + memcpy(preset_names + 16 * number, name, 16); + break; + case ARP: + if (!arp_names) + { + arp_names = new unsigned char[16 * MAX_ARPS]; + memset(arp_names, ' ', 16 * MAX_ARPS); + } + if ((id != 0 && number >= MAX_ARPS) || (id == 0 && number >= arps)) + { + pmesg( + 1, + "*** ROM::set_name out of bounds: rom: %d type %d, number %d\n", + id, type, number); + return 0; + } + if (id != 0) + { + ++arps; + // show this rom in arp selections + if (number == 0) + { + const char* rom_name = ROM::name(); + const Fl_Menu_Item* item; + item = ui->preset_editor->arp_rom->find_item(rom_name); + const_cast (item)->show(); + item = ui->main->arp_rom->find_item(rom_name); + const_cast (item)->show(); + item = ui->copy_arp_rom->find_item(rom_name); + const_cast (item)->show(); + } + } + memcpy(arp_names + 16 * number, name, 12); + break; + case RIFF: + if (!riff_names) + riff_names = new unsigned char[16 * MAX_RIFFS]; + if (number >= MAX_RIFFS) + { + pmesg( + 1, + "*** ROM::set_name out of bounds: rom: %d type %d, number %d\n", + id, type, number); + return 0; + } + ++riffs; + memcpy(riff_names + 16 * number, name, 16); + break; + default: + pmesg(1, + "*** ROM::set_name unknown type: rom: %d type %d, number %d\n", + id, type, number); + pd->display_status("ROM::set_name() Unknown ROM.", true); + return 0; + } + return 1; +} + +const unsigned char* ROM::get_name(int type, int number) const +{ + pmesg(40, "ROM::get_name(type: %d, #: %d) \n", type, number); + switch (type) + { + case INSTRUMENT: + if (!instrument_names || number >= instruments) + { + pmesg( + 1, + "*** ROM::get_name out of bounds: rom: %d type INSTRUMENT, number %d\n", + id, number); + return 0; + } + return instrument_names + 16 * number; + case PRESET: + if (!preset_names || number >= presets) + { + pmesg( + 1, + "*** ROM::get_name out of bounds: rom: %d type PRESET, number %d\n", + id, number); + return 0; + } + return preset_names + 16 * number; + case ARP: + if (!arp_names || number >= arps) + { + pmesg( + 1, + "*** ROM::get_name out of bounds: rom: %d type ARP, number %d\n", + id, number); + return 0; + } + return arp_names + 16 * number; + case RIFF: + if (!riff_names || number >= riffs) + { + pmesg( + 1, + "*** ROM::get_name out of bounds: rom: %d type RIFF, number %d\n", + id, number); + return 0; + } + return riff_names + 16 * number; + default: + pmesg(1, + "*** ROM::get_name unknown type: rom: %d type %d, number %d\n", + id, type, number); + pd->display_status("ROM::get_name() Unknown ROM.", true); + return 0; + } +} + +int ROM::get_attribute(int type) const +{ + pmesg(40, "ROM::get_attribute(type: %d) \n", type); + switch (type) + { + case ID: + return id; + case INSTRUMENT: + return instruments; + case PRESET: + return presets; + case ARP: + return arps; + case RIFF: + return riffs; + default: + return -1; + } +} + +const char* ROM::name() const +{ + pmesg(40, "name(code: %d)\n", id); + switch (id) + { + case 0: + return "User"; + case 2: + return "XTREM"; + case 3: + return "Audity"; + case 4: + return "Composer"; + case 5: + return "Protozoa"; + case 6: + return "B3"; + case 7: + return "XL-1"; + case 8: + return "ZR-76"; + case 9: + return "World Exp."; + case 10: + return "Orch 1"; + case 11: + return "Orch 2"; + case 13: + case 15: + return "Mo'Phatt"; + case 14: + return "XL-2"; + case 16: + return "Ensoniq"; + case 17: + return "PROM1"; + case 18: + return "Vintage"; + case 19: + return "DRUM"; + case 64: + return "Holy Grail"; + case 65: + return "TSCY"; + case 66: + return "Siedlaczek"; + case 67: + return "Beat"; + default: + static char buf[20]; + snprintf(buf, 20, "Unknown (%d)", id); + return buf; + } +} diff --git a/data.H b/data.H new file mode 100644 index 0000000..f172009 --- /dev/null +++ b/data.H @@ -0,0 +1,378 @@ +// $Id$ +#ifndef DATA_H_ +#define DATA_H_ +/** + \defgroup pd_data prodatum Data Classes + @{ +*/ +#include + +#define DUMP_HEADER_SIZE 36 + +/** + * Enum for generic name IDs used by the device + */ +enum +{ + ID, PRESET, INSTRUMENT, ARP, SETUP, DEMO, RIFF +}; + +/** + * Preset Dump class. + * holds data and informations of a preset dump + */ +class Preset_Dump +{ + /// size of the complete dump + int size; + /// size of packets + int packet_size; + /// program/preset number + int number; + /// ROM ID of this program/preset + int rom_id; + /// name of program/preset + unsigned char name[17]; + /// wether this dump contains 4 extra controllers found on p2k modules + int extra_controller; + /// wether we are an audity 2000 dump + int a2k; + /// true if data has been edited + bool data_is_changed; + /// raw dump data + unsigned char* data; + /// undo struct + struct parameter + { + int id; + int value; + int layer; + }; + /// undo stack + std::deque undo_s; + /// redo stack + std::deque redo_s; + /// push undo parameter on stack + void add_undo(int id, int value, int layer); + void update_ui_from_xdo(int id, int value, int layer); + /** + * maps parameter IDs to offset values in the dump + * @param id parameter ID + * @param layer the layer of the parameter (0-3) + * @param id_mapped reference variable for the calculated offset value + */ + void idmap(const int& id, const int& layer, int& id_mapped) const; + /// hands over preset data to the piano widget + void update_piano() const; + /// hands over preset data to the envelope widget + void update_envelopes() const; + /// updates the checksums of the dump + void update_checksum(); + /** + * Copy a given range of parameters from one layer to another. + * works will all ranges (validity checks are being done internally) + * @param start first parameter ID + * @param end last parameter ID + * @param src source layer + * @param dst destination layer + */ + void copy_layer_parameter_range(int start, int end, int src, int dst); + +public: + /** + * CTOR for Preset Dump + * @param dump_size the size of the dump in bytes + * @param dump_data pointer to the dump data + * @param p_size number of bytes in a packet + * @param update wether to automatically update name files and browsers + * from name extracted from the dump + */ + Preset_Dump(int dump_size, const unsigned char* dump_data, int p_size, + bool update = false); + /** + * DTOR just frees the memory + */ + ~Preset_Dump(); + /// return data status + bool is_changed() const; + /// return extra_controller + int get_extra_controller(); + /// undo edit + void undo(); + /// redo edit + void redo(); + /// if true, nothing is pushed on the undo stack + bool disable_add_undo; + /** + * clone this preset dump + * @param dst pointer to destination (will be deleted) + */ + void clone(Preset_Dump* dst) const; + /// + void set_changed(bool); + /// returns the preset name + const char* get_name(); + /// returns the preset number + int get_number() const; + /// returns the ROM ID + int get_rom_id() const; + /** + * get the value of a parameter. + * extract a value for a given (layer-)parameter from the dump + * @param id parameter ID + * @param layer layer of the parameter + * @returns integer value for the parameter + */ + int get_value(int id, int layer = 0) const; + /** + * set the value of a parameter. + * update a given (layer-)parameter to the specified value + * @param id parameter ID + * @param value the new value for the (layer-)parameter + * @param layer layer of the parameter + */ + int set_value(int id, int value, int layer = -2); + /// set category and name + void set_name(const char* val, int type, int position); + void update_highlight_buttons(); + /** + * update UI widgets with the parameter values of this dump. + * this calls \c get_value() for all parameters (except FX parameters) + * and sets the corresponding widget in the UI. + */ + void show(); + /** + * update UI-FX widgets with the parameter values of this dump. + * this calls \c get_value() for all FX parameters + * and sets the corresponding widget in the UI. + */ + void show_fx() const; + /** + * move preset to a new location. + * @param new_number the new location for the preset + */ + void move(int new_number); + /** + * copy various parameters from one layer to another. + * this is also used to save a preset to the device. + * @param type what to copy (preset, fx settings, complete layer, ..) + * @param src the source layer + * @param dst the destination layer + */ + void copy(int type, int src, int dst); + /** + * upload this preset dump to the device. + * this is used to save the preset. it will update the checksums and upload + * the preset in either closed or open loop fashion (depending on what + * has been configured). + * @param packet the packet number to upload + * @param closed wether to use close or open loop style uploads + * @param show wether to show the uploaded dump when + * the upload was successfull + */ + void upload(int packet, int closed = -1, bool show = false); + /// will be used to save the preset to the library + void save_file(const char*); + // get methods needed to clone preset dumps + int get_dump_size() const; + const unsigned char* get_data() const; + int get_p_size() const; +}; + +/** + * Arp Dump class. + * holds data and informations of a arp dump + */ +class Arp_Dump +{ + int size; + int number; + unsigned char name[17]; + unsigned char* data; + void show() const; + void update_name(const unsigned char* np) const; +public: + Arp_Dump(int dump_size, const unsigned char* dump_data); + ~Arp_Dump(); + void update_sequence_length_information() const; + int get_number() const; + int get_value(int id, int step) const; + /// rename arp + void rename(const char* newname) const; + void reset_step(int step) const; + void reset_pattern() const; +}; + +/** + * Setup Dump class. + * holds data and informations of a setup dump + */ +class Setup_Dump +{ + /// size of the complete dump + int size; + /// raw dump data + unsigned char* data; + /// wether this dump contains 4 extra controllers found on p2k modules + int extra_controller; + /** + * maps parameter IDs to offset values in the dump + * @param id parameter ID + * @param channel the channel for the parameter + * @param id_mapped reference variable for the calculated offset value + */ + void idmap(const int& id, const int& channel, int& id_mapped) const; + /** + * Enum for various types of data in the setup dump. + */ + enum + { + SDI_GENERAL, + SDI_MIDI, + SDI_FX, + SDI_RESERVED, + SDI_NON_CHNL, + SDI_CHNLS, + SDI_CHNL_PARAMS + }; + /// array holds vital informations about the current setup + int setup_dump_info[7]; + +public: + /** + * CTOR for Setup Dump + * @param dump_size the size of the dump in bytes + * @param dump_data pointer to the dump data + */ + Setup_Dump(int dump_size, const unsigned char* dump_data); + /** + * DTOR just frees the memory + */ + ~Setup_Dump(); + /** + * get the value of a parameter. + * extract a value for a given setup parameter from the dump + * @param id parameter ID + * @param hannel the channel number for the parameter + * @returns integer value for the parameter + */ + int get_value(int id, int channel = -1) const; + /** + * set the value of a parameter. + * update a given (channel-)parameter to the specified value + * @param id parameter ID + * @param value the new value for the (layer-)parameter + * @param channel parameter channel to update + */ + int set_value(int id, int value, int channel = -1); + void update_highlight_buttons(); + /** + * update UI widgets with the parameter values of this dump. + * this calls \c get_value() for all setup parameters + * and sets the corresponding widget in the UI. + * @param midi_mode the currently active midimode + */ + void show() const; + /** + * update UI FX widgets with master FX settings. + * this calls \c get_value() for all Master FX parameters + * and sets the corresponding widget in the UI. + */ + void show_fx() const; + /** + * uploads the dump to the device to save it. + * currently not used + */ + void upload() const; + // get methods needed to copy setup dumps + int get_dump_size() const; + const unsigned char* get_data() const; +}; + +/** + * Program change map Dump class. + * holds data and informations of a program change map dump + */ +class PC_Dump +{ + +}; + +/** + * ROM class. + * holds data and informations of a ROM module + */ +class ROM +{ + /// rom ID + int id; + /// for user data (programs, arps) we need to know which device we belong to + int device_id; + /// if data (PROGRAM, INSTRUMENT,..) is on disk already, this gets true + bool is_saved_already[7]; + /// number of available instruments in this ROM + int instruments; + /// number of available presets in this ROM + int presets; + /// number of available arps in this ROM + int arps; + /// number of available riffs in this ROM + int riffs; + /// storage pointer to the array of instrument names + unsigned char* instrument_names; + /// storage pointer to the array of preset names + unsigned char* preset_names; + /// storage pointer to the array of arp names + unsigned char* arp_names; + /// storage pointer to the array of riff names + unsigned char* riff_names; + /** + * load a name file from disk. + * @param type of name file (PRESET; INSTRUMENT,..) + * @returns number of names to request if load fails, otherwise 0 + */ + int disk_load_names(int type); + +public: + /** + * CTOR for the ROM class. + * @param id the ROM ID + * @param presets the number of presets the ROM holds + * @param instruments the number of instruments the ROM holds + */ + ROM(int id, int presets = 0, int instruments = 0); + /** + * DTOR of ROM class. + * triggers saving of ROM-name files (if not already saved and ID != 0) + * and frees memory + */ + ~ROM(); + /** + * loads name files or triggers name request commands if loading fails + * @param type of name file (PRESET; INSTRUMENT,..) + * @param number number of name to request + * @returns the number of names to request, or 0 + */ + int load_names(int type, int number); + /** + * set the name of type X with number Z to name Y + * @param type of name (PRESET; INSTRUMENT,..) + * @param number the number of the name + * @param name the name + */ + int set_name(int type, int number, const unsigned char* name); + /// returns an attribute like ROM ID ... + int get_attribute(int type) const; + /// returns the name of this ROM + const char* name() const; + /** + * return the name for type X with number Y + * @param type of name file (PRESET; INSTRUMENT,..) + * @param number the number of the name + * @returns pointer to the name + */ + const unsigned char* get_name(int type, int number = 0) const; +}; + +#endif /*DATA_H_*/ +/** @} */ diff --git a/debug.C b/debug.C new file mode 100644 index 0000000..83b3b52 --- /dev/null +++ b/debug.C @@ -0,0 +1,23 @@ +#include "debug.H" +#include +#include + +extern int msglevel; + +#if defined(NDEBUG) +#else +void pmesg(int level, const char* format, ...) +{ + va_list args; + + if (level>msglevel) + return; + + va_start(args, format); + vfprintf(stderr, format, args); +#ifdef WINDOWS + fflush(stderr); +#endif + va_end(args); +} +#endif diff --git a/debug.H b/debug.H new file mode 100644 index 0000000..294e044 --- /dev/null +++ b/debug.H @@ -0,0 +1,13 @@ +#ifndef DEBUG_H_ +#define DEBUG_H_ +#include + +#if defined(NDEBUG) +#define pmesg(level, format, args...) ((void)0) + +#else +void pmesg(int level, const char *format, ...); + +#endif + +#endif diff --git a/images.H b/images.H new file mode 100644 index 0000000..127f5ce --- /dev/null +++ b/images.H @@ -0,0 +1,1304 @@ +#include +static unsigned char idata_l64_old[] = +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,147,147,0,254,254,254,0,83,83,83,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,0,201,201,201,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,147,147,0,252,252,252,0,85,85,85,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,210,210,210,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,152,152,152,0,248,248,248,0,84,84,84,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,0,206,206,206,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1, +1,1,0,2,2,2,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,151,151,151,0,237,237,237,0,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,11,11,11,0,195,195,195,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,1,0,2,2,2,21,4,4,4,63,4,4,4,107,5,5,5,145,4,4,4,174,4,4,4,192,4,4,4, +201,4,4,4,202,5,5,5,197,5,5,5,183,5,5,5,160,6,6,6,126,5,5,5,84,4,4,4,40,2,2,2,4, +0,0,0,0,0,0,0,0,0,0,0,0,22,22,22,0,39,39,39,0,11,11,11,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,194,194,194,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,3, +3,3,35,4,4,4,110,4,4,4,183,3,3,3,234,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,1,1,1, +255,3,3,3,248,5,5,5,209,6,6,6,144,5,5,5,66,2,2,2,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,0,200,200,200,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,4, +4,4,70,4,4,4,173,2,2,2,244,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,2,2,2,255,5,5,5,209,6,6,6, +115,4,4,4,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12, +12,0,205,205,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,4,4,4,68,4,4,4,190,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,1,1,1,255,5,5,5,228,7,7,7,121,4,4,4,15,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,202,202,202,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,28,5,5,5,162,2,2,2,255,0,0,0,255,0,0,0,255,0,0, +0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,1,1,1,255,7,7,7,214,8,8,8,80,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,4,4,4,83,3,3,3,228,0,0, +0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,3,3,3,255,8,8,8, +151,3,3,3,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,0,206,206,206,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,2,2,0,5,5,5,132,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,1,1,1,255,4,4,4,255,7,7,7,255,14,14,14,255,15,15,15,202,2,2,2,40,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +10,10,10,0,198,198,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,6,5,5,5,162,1,1,1,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,3,3,3,255,8,8,8,255,15,15,15,255,24,24,24,255,32,32,32, +255,37,37,37,255,44,44,44,255,54,54,54,255,45,45,45,228,5,5,5,58,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,194, +194,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,2,2,2,6,4,4,4,172,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,2,2,2,255,10,10,10,255,20, +20,20,255,30,30,30,255,37,37,37,255,46,46,46,255,58,58,58,255,73,73,73,255,91, +91,91,255,110,110,110,255,122,122,122,255,129,129,129,255,140,140,140,255,89, +89,89,237,4,4,4,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,10,10,10,0,199,199,199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,4,4,4,164,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,1,1,1,255,9,9,9,255,23,23, +23,255,41,41,41,255,62,62,62,255,85,85,85,255,109,109,109,255,135,135,135,255, +153,153,153,255,161,161,161,255,166,166,166,255,171,171,171,255,175,175,175,255, +179,179,179,255,177,177,177,255,172,172,172,255,180,180,180,255,104,104,104,234, +0,0,0,49,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9, +9,0,193,193,193,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,1,0,5,5,5,133,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,17,17,17,255,43,43,43,255,79,79,79,255,114,114,114,255,146,146, +146,255,173,173,173,255,194,194,194,255,210,210,210,255,221,221,221,255,229,229, +229,255,234,234,234,255,233,233,233,255,224,224,224,255,217,217,217,255,213,213, +213,255,213,213,213,255,216,216,216,255,213,213,213,255,207,207,207,255,212,212, +212,255,99,99,99,219,0,0,0,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,8,8,8,0,205,205,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,4,4,4,82,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,26,26,26,255,68,68,68,255,175,175,175,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,252,252,252,255,249,249,249,255,248,248,248,255,250,250,250,255,245,245,245, +255,242,242,242,255,234,234,234,255,70,70,70,181,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,207,207,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,28,3,3,3,233,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,11,11,11,255,51,51,51,255, +147,147,147,255,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,221,221,221,255, +28,28,28,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,211, +211,211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,4,4,4, +168,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,2,2,2,255,37,37,37,255,117,117,117,255,244,244,244,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,161,161,161,242,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,12,12,12,0,205,205,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,4,4,4,69,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,23,23,23,255,91,91,91,255, +230,230,230,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,255, +72,72,72,172,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,194,194,194,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,3,4,4,4,199,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,10,10,10,255,67,67,67,255,211,211,211,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,197,197,197,254,6,6,6,61,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,9,9,9,0,206,206,206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,4,4,4,74,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,41,41,41,255,183,183,183, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,82,82,82,177,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,201,201,201,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,4,4,4,183,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,13,13,13,255,49,49,49,255,162,162,162,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,186,186,186,250,2,2,2,45,0,0,0, +0,0,0,0,0,0,0,0,0,11,11,11,0,207,207,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,4,4,40,2,2,2,249,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,7,7,7,255,39,39,39,255,88,88,88,255,143,143,143,255,189, +189,189,255,221,221,221,255,243,243,243,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,250,250,250,255,50,50,50,136,0,0,0, +0,0,0,0,0,0,0,0,0,11,11,11,0,215,215,215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,5,5,5,122,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,1,1,1,255,2,2,2,255,3,3,3,255, +4,4,4,255,5,5,5,255,6,6,6,255,8,8,8,255,14,14,14,255,27,27,27,255,49,49,49, +255,80,80,80,255,123,123,123,255,177,177,177,255,219,219,219,255,246,246,246, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,130,130,130,215,0,0,0,7,0,0,0,0,0,0,0,0,12,12,12,0,207,207, +207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,1,4,4,4,196,0,0,0,255,0,0,0,255,0,0, +0,255,0,0,0,255,0,0,0,255,4,4,4,255,7,7,7,255,9,9,9,255,13,13,13,255,20,20,20, +255,30,30,30,255,35,35,35,255,37,37,37,255,43,43,43,255,56,56,56,255,76,76,76, +255,105,105,105,255,142,142,142,255,182,182,182,255,217,217,217,255,245,245,245, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,202,202,202,254,5,5,5,55,0,0,0,0,0,0,0,0,12,12,12,0,209,209, +209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,31,3,3,3,244,2,2,2,255,7,7,7,255,10, +10,10,255,14,14,14,255,23,23,23,255,34,34,34,255,40,40,40,255,43,43,43,255,51, +51,51,255,66,66,66,255,85,85,85,255,106,106,106,255,135,135,135,255,169,169, +169,255,204,204,204,255,234,234,234,255,254,254,254,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,246,246,255,39,39, +39,118,0,0,0,0,0,0,0,0,12,12,12,0,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,78,16,16,16,255,26,26,26,255,34,34,34,255,37,37,37,255,44,44,44,255, +57,57,57,255,75,75,75,255,91,91,91,255,114,114,114,255,145,145,145,255,185,185, +185,255,218,218,218,255,239,239,239,255,254,254,254,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,88,88,88,173,0,0,0,0,0, +0,0,0,13,13,13,0,218,218,218,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,124,40, +40,40,255,58,58,58,255,73,73,73,255,89,89,89,255,112,112,112,255,146,146,146, +255,176,176,176,255,194,194,194,255,215,215,215,255,239,239,239,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,236,236,236, +255,204,204,204,255,218,218,218,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,135,135,135,214,0,0,0,5,0,0, +0,0,13,13,13,0,212,212,212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,21,21,162,105, +105,105,255,131,131,131,255,151,151,151,255,163,163,163,255,182,182,182,255,209, +209,209,255,225,225,225,255,236,236,236,255,249,249,249,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,252,252,252,255,217, +217,217,255,176,176,176,255,137,137,137,255,101,101,101,255,65,65,65,255,41,41, +41,255,19,19,19,255,60,60,60,255,248,248,248,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,167,167,167,239,0,0,0,25,0, +0,0,0,11,11,11,0,212,212,212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,43,43,43,190, +155,155,155,255,169,169,169,255,182,182,182,255,191,191,191,255,212,212,212,255, +241,241,241,255,253,253,253,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +247,247,247,255,204,204,204,255,158,158,158,255,100,100,100,255,45,45,45,255,6, +6,6,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +193,193,193,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,187,187,187,253,0,0,0,47,0,0,0,0,11,11,11,0,211,211,211,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,3,62,62,62,211,183,183,183,255,196,196,196,255,209, +209,209,255,222,222,222,255,244,244,244,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,176,176,176,255,14,14,14,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,140,140,140,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,196,196,196,255,1,1,1,65,0,0,0,0,10,10, +10,0,190,190,190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,78,78,78,221,211,211,211, +255,224,224,224,255,239,239,239,255,250,250,250,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,155,155,155, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,101,101,101,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,252,252,252,255,185,185,185,255,3,3, +3,75,0,0,0,0,9,9,9,0,192,192,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,89,89,89, +222,239,239,239,255,249,249,249,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,191,191,191,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,68,68,68,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,252,252,252,255,243,243,243,255,228,228,228,255,165, +165,165,255,2,2,2,77,0,0,0,0,12,12,12,0,216,216,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,6,90,90,90,217,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,236,236,236,255,18,18,18,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,86,86,86,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,242,242,242,255,227,227,227,255,215,215,215, +255,202,202,202,255,141,141,141,255,1,1,1,71,0,0,0,0,11,11,11,0,214,214,214,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,81,81,201,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,67,67,67,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +14,14,14,255,58,58,58,255,103,103,103,255,196,196,196,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,238,238,238,255,212, +212,212,255,198,198,198,255,188,188,188,255,176,176,176,255,113,113,113,255,0,0, +0,55,0,0,0,0,12,12,12,0,211,211,211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,60, +60,177,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,146,146,146,255,0,0,0,255,0,0,0,255,0,0,0,255,4,4,4,255, +23,23,23,255,54,54,54,255,108,108,108,255,169,169,169,255,218,218,218,255,248, +248,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,252, +252,252,255,244,244,244,255,232,232,232,255,204,204,204,255,183,183,183,255,174, +174,174,255,164,164,164,255,151,151,151,255,82,82,82,246,0,0,0,34,0,0,0,0,12,12, +12,0,207,207,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,34,34,144,244,244,244, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,244,244,244,255,136,136,136,255,136,136,136,255,177,177,177,255,212,212,212, +255,238,238,238,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,255,242,242,242, +255,226,226,226,255,215,215,215,255,200,200,200,255,170,170,170,255,144,144,144, +255,127,127,127,255,106,106,106,255,85,85,85,255,33,33,33,226,0,0,0,12,0,0,0,0, +13,13,13,0,213,213,213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,102,217,217,217, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,248,248,248,255,221,221,221,255,190,190,190, +255,163,163,163,255,140,140,140,255,113,113,113,255,83,83,83,255,63,63,63,255, +54,54,54,255,45,45,45,255,36,36,36,255,11,11,11,192,0,0,0,0,0,0,0,0,13,13,13,0, +210,210,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,172,172,172,254,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,249,249,249,255,228,228,228,255,200,200, +200,255,172,172,172,255,138,138,138,255,104,104,104,255,80,80,80,255,66,66,66, +255,57,57,57,255,46,46,46,255,36,36,36,255,30,30,30,255,27,27,27,255,19,19,19, +255,11,11,11,255,6,6,6,142,0,0,0,0,0,0,0,0,12,12,12,0,206,206,206,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,12,111,111,111,225,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,245,245,245,255,219,219,219,255,185,185,185,255, +148,148,148,255,115,115,115,255,89,89,89,255,71,71,71,255,61,61,61,255,50,50,50, +255,41,41,41,255,35,35,35,255,31,31,31,255,26,26,26,255,15,15,15,255,7,7,7,255, +4,4,4,255,3,3,3,255,0,0,0,255,1,1,1,255,4,4,4,80,0,0,0,0,0,0,0,0,10,10,10,0, +201,201,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,47,47,164,250,250,250, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,251,251,251,255,225,225,225, +255,191,191,191,255,154,154,154,255,115,115,115,255,82,82,82,255,57,57,57,255, +41,41,41,255,33,33,33,255,29,29,29,255,26,26,26,255,24,24,24,255,19,19,19,255, +12,12,12,255,6,6,6,255,4,4,4,255,2,2,2,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,3,3,3,238,3,3,3,22,0,0,0,0,0,0,0,0,12,12,12,0,208,208, +208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,84,201,201,201,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,253,253,253,255,227,227,227,255,192,192, +192,255,149,149,149,255,94,94,94,255,49,49,49,255,23,23,23,255,9,9,9,255,3,3,3, +255,0,0,0,255,1,1,1,255,1,1,1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,5,5,5,173,1,1,1,0,0,0,0,0,0,0,0,0,10,10,10,0, +206,206,206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,113,113,113,227, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +242,242,242,255,165,165,165,255,115,115,115,255,64,64,64,255,20,20,20,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,1,1,1,255,5,5,5,81,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,209,209,209,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,26,138,236,236,236,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,236,236,236,255,85,85, +85,255,13,13,13,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,4,4,4,218,2,2,2,9,0,0,0,0, +0,0,0,0,0,0,0,0,12,12,12,0,215,215,215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,34,140,140,140,243,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,250,250,250,255,121,121,121,255,37,37,37,255,1,1,1,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,1,1,1,255,5,5,5,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0, +203,203,203,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30, +145,236,236,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,149,149,149,255,50,50,50,255,9,9,9,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,4,4,4,222,2,2,2,12,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,200,200,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,117,117,117,232,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,177,177,177,255,63,63,63,255,22,22, +22,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,1,1,1,255,5,5,5,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10, +10,0,212,212,212,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,7,7,7,100,192,192,192,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +203,203,203,255,78,78,78,255,34,34,34,255,2,2,2,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,5,5,5,183,1,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,200,200,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,37,37,37,176,229,229,229,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,232,232,232,255,102,102,102,255,48,48,48,255,11,11,11, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,3,3,3,236,4,4,4, +34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,0,198,198,198,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +25,68,68,68,221,227,227,227,255,236,236,236,255,239,239,239,255,242,242,242, +255,240,240,240,255,241,241,241,255,244,244,244,255,249,249,249,255,254,254,254, +255,254,254,254,255,252,252,252,255,251,251,251,255,251,251,251,255,250,250,250, +255,246,246,246,255,237,237,237,255,220,220,220,255,186,186,186,255,98,98,98, +255,49,49,49,255,15,15,15,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,2,2,2,255,5,5,5,83,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +12,12,12,0,211,211,211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,78,78,78,241,198,198,198,255,198,198,198, +255,201,201,201,255,203,203,203,255,198,198,198,255,198,198,198,255,201,201,201, +255,208,208,208,255,213,213,213,255,207,207,207,255,190,190,190,255,167,167,167, +255,142,142,142,255,114,114,114,255,85,85,85,255,55,55,55,255,30,30,30,255,15, +15,15,255,5,5,5,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,1,1,1, +255,6,6,6,125,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +13,13,13,0,221,221,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,71,71,71,247,160,160,160,255,162, +162,162,255,164,164,164,255,161,161,161,255,148,148,148,255,133,133,133,255,118, +118,118,255,102,102,102,255,87,87,87,255,68,68,68,255,50,50,50,255,33,33,33,255, +18,18,18,255,6,6,6,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,1,1,1,255,5,5,5,146,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,215,215,215,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,80,50,50,50,244,99,99,99,255,88,88,88,255,75,75,75,255,61,61,61,255, +47,47,47,255,35,35,35,255,25,25,25,255,17,17,17,255,11,11,11,255,6,6,6,255,1,1, +1,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,1,1,1,255,5,5,5,147,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,206,206,206,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,67,10,10,10,229,25,25,25,255,23,23,23,255,17,17,17, +255,13,13,13,255,6,6,6,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,2,2,2,255,6,6,6,128,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,203,203,203,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,2,39,5,5,5,195,2,2,2,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0, +0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,3,3,3,236,6,6,6,89,1,1,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,13,13,13,0,208,208,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,9, +6,6,6,134,3,3,3,249,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,1,1,1,255,5,5,5, +184,4,4,4,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,208,208,208,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,5,5,5,56,6,6,6,185,2,2,2,255,0,0, +0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, +0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,1,1,1,255,4,4,4,222,5,5,5,99,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14, +14,14,0,192,192,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,2,2,2,0,6,6,6,79,6,6,6,190,3,3,3,255,0,0,0,255,0,0,0,255,0,0,0,255, +0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,1,1,1,255,4,4,4,220,5,5,5,118,3,3,3,18,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,195,195,195,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,0,5,5,5,61,7,7,7, +151,5,5,5,224,2,2,2,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, +255,1,1,1,255,3,3,3,241,5,5,5,179,5,5,5,89,3,3,3,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,211,211,211,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,1,0,3,3,3,16,5,5,5,71,6,6,6,135,5,5,5,189,4,4,4,225,3,3,3,247,2,2,2, +255,2,2,2,255,1,1,1,255,1,1,1,255,2,2,2,255,2,2,2,255,2,2,2,251,3,3,3,233,4,4,4, +201,4,4,4,151,4,4,4,89,3,3,3,30,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,212,212,212,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,2,2,2,14,4,4,4,37,5,5,5,60, +7,7,7,85,6,6,6,98,6,6,6,99,7,7,7,90,6,6,6,67,4,4,4,42,2,2,2,19,1,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,72,72,0,127,127,127,0,45,45,45,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,0,200,200,200,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,158,158,158,0,255,255,255,0,89,89,89,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,202,202,202,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,147,147,147,0,251,251,251,0,84,84,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,10,10,10,0,198,198,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,147,147,147,0,254,254,254,0,88,88,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,10,10,10,0,192,192,192,0}; +static Fl_RGB_Image image_l64_old(idata_l64_old, 64, 64, 4, 0); + +static unsigned char idata_l64[] = +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,255,255,255,1,255,255,255,1,255,255,255,1,255,255,255,1,0,0,0,0,255, +255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,1, +255,255,255,2,191,191,191,4,204,204,204,5,182,182,182,7,219,219,219,7,219,219, +219,7,213,213,213,6,204,204,204,5,191,191,191,4,255,255,255,2,255,255,255,1,255, +255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1, +128,128,128,2,191,191,191,4,198,198,198,9,210,210,210,17,202,202,202,29,211,211, +211,41,212,212,212,53,207,207,207,64,208,208,208,71,210,210,210,74,207,207,207, +74,208,208,208,70,210,210,210,62,210,210,210,51,203,203,203,39,206,206,206,26, +221,221,221,15,191,191,191,8,255,255,255,3,255,255,255,1,255,255,255,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,1,255,255,255,1,191,191,191,4,209,209,209,11,206,206,206,26,208,208,208,49, +207,207,207,79,209,209,209,110,210,210,210,137,208,208,208,159,209,209,209,176, +210,210,210,187,209,209,209,194,209,209,209,198,208,208,208,197,209,209,209,193, +210,210,210,185,209,209,209,173,209,209,209,155,209,209,209,132,208,208,208,103, +206,206,206,73,209,209,209,44,209,209,209,22,198,198,198,9,255,255,255,3,255, +255,255,1,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128, +128,128,2,204,204,204,5,207,207,207,16,206,206,206,42,205,205,205,82,209,209, +209,127,209,209,209,168,209,209,209,200,208,208,208,222,207,207,207,235,208,208, +208,243,207,207,207,248,204,204,204,251,204,204,204,252,203,203,203,253,204,204, +204,253,204,204,204,252,206,206,206,250,206,206,206,247,208,208,208,242,207,207, +207,233,208,208,208,218,209,209,209,194,209,209,209,161,210,210,210,118,210,210, +210,73,205,205,205,36,216,216,216,13,191,191,191,4,255,255,255,1,255,255,255,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,255,255,255,1,255,255,255,1,191,191,191,4,207,207,207,16,212,212,212,47, +206,206,206,99,209,209,209,155,209,209,209,200,207,207,207,230,207,207,207,246, +206,206,206,253,200,200,200,255,193,193,193,255,184,184,184,255,175,176,175,255, +167,167,167,255,162,162,162,255,160,160,160,255,159,159,159,255,162,162,162,255, +167,167,167,255,174,175,174,255,183,183,183,255,192,192,192,255,199,199,199,255, +204,204,204,252,208,208,208,243,207,207,207,225,209,209,209,193,209,209,209,145, +206,206,206,89,210,210,210,40,216,216,216,13,191,191,191,4,255,255,255,1,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1, +170,170,170,3,209,209,209,11,208,208,208,38,206,206,206,94,209,209,209,160,208, +208,208,211,207,207,207,240,205,205,205,252,200,200,200,255,186,186,186,255,167, +167,167,255,149,149,149,255,132,132,132,255,119,119,119,255,109,109,109,255,103, +103,103,255,100,100,100,255,97,97,97,255,98,98,97,255,100,100,99,255,103,103, +102,255,108,108,108,255,116,116,116,255,129,129,129,255,145,145,145,255,165,165, +165,255,183,183,183,255,197,197,197,255,205,205,205,251,207,207,207,236,208,208, +208,204,209,209,209,149,206,206,206,83,206,206,206,31,223,223,223,8,255,255,255, +2,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255, +1,204,204,204,5,206,206,206,21,210,210,210,68,208,208,208,142,208,208,208,206, +207,207,207,241,206,206,206,254,195,195,195,255,173,174,173,255,148,148,148,255, +123,123,123,255,103,103,103,255,93,93,92,255,86,87,87,255,83,84,85,255,82,83,86, +255,83,84,88,255,83,84,89,255,83,85,90,255,83,85,90,255,83,85,90,255,83,84,88, +255,82,84,87,255,83,84,86,255,86,87,87,255,92,92,92,255,102,102,102,255,119,119, +119,255,143,143,143,255,171,171,170,255,192,192,192,255,204,204,204,252,209,209, +209,236,208,208,208,196,210,210,210,129,210,210,210,57,207,207,207,16,191,191, +191,4,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128,128,128,2,219,219,219, +7,203,203,203,34,207,207,207,100,208,208,208,179,208,208,208,232,207,207,207, +252,197,197,197,255,172,173,172,255,140,140,140,255,110,110,110,255,93,93,93, +255,84,85,86,255,82,84,87,255,83,86,91,255,84,86,93,255,84,86,94,255,84,87,95, +255,84,87,95,255,84,87,95,255,84,87,95,255,84,87,95,255,84,87,95,255,84,87,95, +255,84,87,95,255,84,86,94,255,84,86,93,255,84,86,92,255,83,84,88,255,83,84,85, +255,91,91,91,255,107,107,106,255,134,134,134,255,167,167,167,255,195,195,195, +255,205,205,205,250,209,209,209,225,206,206,206,167,210,210,210,85,206,206,206, +26,204,204,204,5,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128,128,128,2,227,227,227,9, +205,205,205,46,210,210,210,125,208,208,208,204,207,207,207,245,202,202,202,255, +182,182,182,255,147,147,147,255,110,110,110,255,90,90,90,255,84,85,87,255,83,85, +90,255,84,86,94,255,84,86,95,255,84,87,95,255,85,88,96,255,86,89,97,255,86,90, +98,255,86,90,98,255,87,90,98,255,87,91,99,255,87,91,99,255,87,91,99,255,86,90, +98,255,86,90,98,255,86,89,97,255,85,88,96,255,84,87,96,255,84,87,95,255,84,86, +94,255,84,86,91,255,82,83,86,255,88,88,88,255,106,106,105,255,140,140,140,255, +178,178,178,255,200,200,200,255,208,208,208,240,207,207,207,192,208,208,208,109, +205,205,205,36,182,182,182,7,128,128,128,2,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,2,230,230,230, +10,208,208,208,54,210,210,210,141,207,207,207,218,207,207,207,250,198,198,198, +255,165,165,165,255,124,124,124,255,95,95,94,255,83,84,86,255,84,86,91,255,84, +86,94,255,84,87,95,255,85,88,96,255,86,89,97,255,87,91,99,255,87,91,99,255,87, +91,99,255,87,91,99,255,89,93,101,255,96,99,106,255,98,101,108,255,98,101,108, +255,97,100,107,255,91,94,102,255,87,91,99,255,87,91,99,255,87,91,99,255,87,91, +99,255,86,90,98,255,85,88,96,255,85,87,95,255,84,88,96,255,85,88,94,255,84,85, +88,255,91,92,92,255,118,117,117,255,160,160,160,255,194,194,194,255,206,206, +206,247,208,208,208,207,209,209,209,123,205,205,205,41,191,191,191,8,128,128, +128,2,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128, +128,128,2,204,204,204,10,208,208,208,54,210,210,210,147,207,207,207,224,207,207, +207,253,192,192,192,255,151,151,151,255,109,109,109,255,86,86,86,255,83,84,89, +255,84,86,94,255,84,87,95,255,85,88,96,255,86,90,98,255,87,91,99,255,87,91,99, +255,92,95,103,255,114,117,124,255,143,145,151,255,137,142,154,255,127,132,144, +255,121,125,137,255,119,124,136,255,119,124,136,255,120,125,136,255,125,130,142, +255,134,139,152,255,145,151,165,255,120,123,130,255,96,99,107,255,87,91,100,255, +87,92,100,255,88,92,101,255,88,92,100,255,87,91,100,255,87,91,100,255,86,89,96, +255,84,86,87,255,103,102,102,255,145,145,145,255,186,186,186,255,205,205,205, +250,207,207,207,214,211,211,211,128,205,205,205,41,182,182,182,7,255,255,255,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128,128,128,2,191,191,191,8, +213,213,213,48,209,209,209,144,209,209,209,225,207,207,207,253,189,189,189,255, +144,144,144,255,101,101,100,255,83,84,85,255,84,86,92,255,84,86,95,255,84,87,95, +255,86,90,98,255,87,91,99,255,87,91,99,255,101,104,111,255,143,146,151,255,126, +131,143,255,112,117,128,255,107,113,124,255,108,113,125,255,110,114,126,255,110, +115,127,255,111,116,128,255,111,116,128,255,110,115,127,255,110,114,126,255,108, +114,125,255,108,113,124,255,110,115,126,255,123,128,140,255,144,150,164,255,113, +117,125,255,90,95,105,255,91,96,107,255,91,96,107,255,91,95,105,255,90,94,105, +255,90,94,104,255,85,87,91,255,96,96,95,255,136,136,136,255,182,182,182,255,204, +204,204,251,207,207,207,214,208,208,208,125,205,205,205,36,204,204,204,5,255, +255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,204,204,204,5,207,207,207,37, +210,210,210,130,207,207,207,220,208,208,208,253,189,189,189,255,141,141,141,255, +97,97,96,255,83,84,86,255,84,86,93,255,84,86,95,255,85,88,96,255,87,91,99,255, +87,91,99,255,96,99,107,255,146,149,154,255,119,124,136,255,107,113,124,255,110, +114,126,255,111,116,129,255,112,117,130,255,112,117,130,255,112,117,130,255,112, +117,130,255,112,117,130,255,112,117,130,255,112,117,130,255,112,117,130,255,112, +117,130,255,113,118,132,255,114,120,133,255,114,120,134,255,113,120,133,255,121, +128,141,255,148,155,172,255,115,119,129,255,94,100,113,255,94,100,113,255,93,98, +111,255,92,97,109,255,94,100,113,255,92,96,101,255,91,91,91,255,132,132,132,255, +182,182,182,255,206,206,206,250,208,208,208,207,211,211,211,109,216,216,216,26, +191,191,191,4,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,3,213,213,213, +24,210,210,210,107,207,207,207,209,207,207,207,251,192,192,192,255,144,144,144, +255,97,97,96,255,83,84,87,255,84,86,94,255,84,87,95,255,86,89,97,255,87,91,99, +255,87,91,99,255,118,121,128,255,126,131,143,255,108,113,124,255,110,115,127, +255,112,117,129,255,112,117,130,255,112,117,130,255,112,117,130,255,112,117,130, +255,112,118,131,255,112,118,131,255,112,118,131,255,112,118,131,255,112,118,131, +255,113,119,134,255,116,122,136,255,118,124,140,255,120,127,143,255,122,129,146, +255,122,130,149,255,121,129,148,255,120,128,147,255,134,142,162,255,154,158,167, +255,120,127,137,255,131,137,146,255,143,148,153,255,148,156,159,255,153,163,166, +255,115,121,123,255,90,90,90,255,134,133,133,255,186,186,186,255,205,205,205, +247,209,209,209,192,208,208,208,86,207,207,207,16,255,255,255,2,255,255,255,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +128,128,128,2,216,216,216,13,209,209,209,77,207,207,207,187,208,208,208,247,198, +198,198,255,152,152,152,255,100,100,99,255,83,84,86,255,84,86,94,255,84,87,95, +255,86,90,98,255,87,91,99,255,87,91,99,255,138,140,146,255,115,120,131,255,110, +114,126,255,113,117,129,255,113,118,131,255,113,118,131,255,113,118,132,255,113, +119,132,255,114,119,133,255,114,121,134,255,114,121,134,255,115,121,136,255,115, +121,136,255,117,123,138,255,119,126,143,255,121,129,146,255,123,131,151,255,125, +134,155,255,131,140,160,255,140,148,167,255,152,160,176,255,167,174,186,255,181, +186,194,255,191,194,198,255,204,206,207,255,212,213,213,255,181,181,181,255,176, +176,176,255,174,175,175,255,172,175,174,255,172,174,175,255,118,120,122,255,91, +91,91,255,141,141,141,255,192,192,192,255,207,207,207,240,208,208,208,167,207, +207,207,58,198,198,198,9,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,213,213,213,6,205,205,205,46, +210,210,210,153,207,207,207,236,204,204,204,255,166,166,166,255,108,108,107,255, +83,84,85,255,84,86,93,255,84,87,95,255,86,90,98,255,87,91,99,255,88,91,99,255, +147,149,155,255,112,117,128,255,110,116,128,255,114,119,132,255,114,119,132,255, +114,120,133,255,115,120,133,255,115,122,135,255,116,122,137,255,117,123,138,255, +118,124,139,255,119,125,140,255,119,126,141,255,123,130,146,255,127,135,154,255, +132,141,164,255,142,153,175,255,169,177,190,255,184,189,198,255,196,198,203,255, +205,206,208,255,210,210,210,255,213,212,211,255,212,211,210,255,211,210,210,255, +209,209,208,255,206,206,206,255,219,219,219,255,181,181,181,255,173,174,173,255, +173,174,173,255,174,175,174,255,173,173,173,255,110,112,113,255,97,97,97,255, +155,155,155,255,200,200,200,254,209,209,209,226,210,210,210,130,207,207,207,32, +191,191,191,4,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,255,255,255,2,206,206,206,21,210,210,210,107,207,207,207,214,206, +206,206,254,182,182,182,255,123,123,123,255,86,86,86,255,84,86,92,255,84,87,95, +255,86,89,97,255,87,91,99,255,87,91,99,255,141,144,149,255,114,118,130,255,113, +118,131,255,115,120,133,255,115,120,133,255,115,121,134,255,116,123,137,255,117, +123,138,255,119,125,140,255,120,127,142,255,121,128,144,255,121,128,145,255,121, +128,145,255,121,128,145,255,125,131,148,255,129,137,157,255,136,145,168,255,153, +164,189,255,211,211,212,255,214,213,212,255,212,212,212,255,212,211,211,255,211, +211,211,255,211,211,211,255,211,211,211,255,211,211,211,255,211,211,211,255,210, +210,210,255,208,208,208,255,219,219,219,255,180,180,180,255,173,174,173,255,173, +174,173,255,175,176,175,255,166,167,167,255,96,97,99,255,111,111,111,255,173, +174,173,255,205,205,205,250,207,207,207,198,206,206,206,84,216,216,216,13,128, +128,128,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1, +182,182,182,7,207,207,207,59,208,208,208,174,208,208,208,245,197,197,197,255, +145,145,145,255,94,94,94,255,83,84,89,255,84,86,95,255,85,88,96,255,87,91,99, +255,87,91,99,255,122,125,132,255,118,123,135,255,114,119,132,255,116,121,135, +255,116,121,135,255,117,123,137,255,119,125,140,255,120,126,142,255,121,129,144, +255,123,130,147,255,123,130,147,255,123,130,147,255,123,130,147,255,123,130,147, +255,123,130,147,255,124,130,148,255,128,136,154,255,135,144,166,255,146,157,183, +255,201,205,211,255,215,214,214,255,213,213,213,255,213,213,213,255,213,213,213, +255,213,213,213,255,214,214,214,255,214,214,214,255,214,214,214,255,214,214,214, +255,213,213,213,255,211,211,211,255,213,213,213,255,176,176,176,255,173,174,173, +255,173,174,173,255,177,177,177,255,149,151,152,255,88,89,89,255,133,133,133, +255,191,191,191,255,208,208,208,237,209,209,209,151,211,211,211,41,191,191,191, +4,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,2, +200,200,200,23,211,211,211,115,207,207,207,222,205,205,205,255,172,173,172,255, +110,110,110,255,83,84,86,255,84,86,94,255,85,87,95,255,87,91,99,255,87,91,99, +255,99,103,111,255,128,133,146,255,115,121,134,255,118,124,137,255,118,124,137, +255,120,125,140,255,121,127,142,255,123,130,146,255,125,132,148,255,125,132,149, +255,125,132,149,255,125,132,149,255,125,132,149,255,125,133,149,255,125,133,149, +255,125,133,149,255,125,133,149,255,128,136,154,255,135,144,165,255,142,154,181, +255,193,199,210,255,220,219,219,255,217,217,217,255,217,217,217,255,217,217,217, +255,217,217,217,255,217,217,217,255,217,217,217,255,217,217,217,255,217,217,217, +255,217,217,217,255,216,216,216,255,218,218,218,255,201,201,201,255,173,174,173, +255,173,174,173,255,173,174,173,255,176,176,176,255,118,120,121,255,98,98,98, +255,161,161,161,255,202,202,202,253,207,207,207,206,207,207,207,91,200,200,200, +14,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,213,213, +213,6,208,208,208,54,209,209,209,172,206,206,206,246,195,195,195,255,138,138, +138,255,90,90,90,255,84,86,91,255,84,87,95,255,86,90,98,255,87,91,99,255,87,91, +100,255,149,152,157,255,119,124,137,255,121,126,140,255,121,126,140,255,122,128, +142,255,123,129,145,255,126,134,150,255,127,135,152,255,127,135,152,255,127,135, +152,255,127,135,152,255,129,136,153,255,129,136,154,255,129,136,154,255,129,136, +154,255,130,137,155,255,130,137,155,255,130,138,155,255,135,144,164,255,143,153, +179,255,185,193,209,255,224,224,223,255,221,221,221,255,221,221,221,255,221,221, +221,255,221,221,221,255,221,221,221,255,221,221,221,255,221,221,221,255,221,221, +221,255,221,221,221,255,221,221,221,255,219,219,219,255,226,226,226,255,185,185, +185,255,173,174,173,255,173,174,173,255,176,175,175,255,163,164,165,255,93,94, +95,255,126,126,126,255,187,187,187,255,207,207,207,238,208,208,208,148,208,208, +208,38,255,255,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,207, +207,207,16,207,207,207,100,209,209,209,214,205,205,205,254,173,174,173,255,109, +109,109,255,83,84,86,255,84,86,94,255,85,88,96,255,87,91,99,255,87,91,99,255, +106,110,117,255,129,135,148,255,123,128,142,255,124,129,143,255,125,131,146,255, +127,133,149,255,129,137,154,255,131,138,156,255,131,138,156,255,131,138,156,255, +131,139,156,255,132,140,157,255,133,140,158,255,133,140,159,255,133,141,159,255, +133,141,160,255,134,142,160,255,134,142,160,255,133,141,160,255,136,144,164,255, +144,154,179,255,176,186,208,255,228,228,228,255,227,227,227,255,227,227,227,255, +227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255, +227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255,224,224,224,255, +209,209,209,255,175,175,175,255,173,174,173,255,173,174,173,255,177,177,177,255, +124,126,128,255,98,98,98,255,162,162,162,255,202,202,202,252,207,207,207,196, +205,205,205,77,204,204,204,10,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,170, +170,170,3,205,205,205,36,210,210,210,147,208,208,208,238,199,199,199,255,146, +146,146,255,92,92,92,255,84,86,91,255,85,88,96,255,87,91,99,255,87,91,100,255, +88,92,101,255,144,146,152,255,126,132,146,255,127,133,147,255,127,134,149,255, +130,136,153,255,133,139,156,255,134,142,160,255,134,142,160,255,134,142,160,255, +136,143,160,255,136,144,162,255,137,144,163,255,137,145,164,255,138,145,164,255, +138,146,166,255,138,146,166,255,138,146,166,255,137,145,165,255,138,146,169,255, +143,154,178,255,152,164,192,255,177,188,213,255,226,227,227,255,227,227,227,255, +227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255, +227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255,227,227,227,255, +227,227,227,255,223,224,223,255,186,186,186,255,173,174,173,255,173,174,173,255, +175,176,175,255,161,162,163,255,92,93,93,255,133,133,133,255,193,193,193,255, +208,208,208,227,209,209,209,123,202,202,202,24,128,128,128,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,182,182,182,7,209,209,209,66,209,209,209,187,207,207,207,251, +184,184,184,255,121,121,121,255,83,85,86,255,86,89,96,255,87,91,99,255,89,93, +102,255,89,93,103,255,98,102,111,255,145,152,169,255,134,141,157,255,134,142, +159,255,136,144,162,255,139,147,166,255,143,150,171,255,143,150,171,255,141,150, +170,255,143,151,171,255,143,151,171,255,143,151,171,255,143,152,172,255,142,151, +173,255,142,151,173,255,142,151,175,255,144,154,176,255,154,163,183,255,170,180, +200,255,190,198,217,255,210,216,228,255,219,220,222,255,221,222,223,255,223,223, +223,255,223,223,223,255,223,223,223,255,223,223,223,255,223,223,223,255,223,223, +223,255,223,223,223,255,223,223,223,255,223,223,223,255,223,223,223,255,223,223, +223,255,223,223,223,255,223,223,223,255,225,225,225,255,202,202,202,255,174,174, +174,255,173,174,173,255,173,174,173,255,176,176,176,255,113,115,115,255,107,107, +107,255,176,176,176,255,205,205,205,245,209,209,209,166,212,212,212,47,191,191, +191,4,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,204,204,204,15,207,207,207,100,209, +209,209,215,205,205,205,255,165,165,165,255,102,102,102,255,84,85,90,255,88,92, +101,255,90,94,104,255,91,95,106,255,91,96,107,255,119,123,133,255,146,153,173, +255,145,152,171,255,145,154,174,255,149,158,180,255,154,164,187,255,155,165,190, +255,155,165,190,255,155,166,192,255,156,167,193,255,158,170,198,255,162,175,203, +255,170,182,210,255,181,193,216,255,196,204,223,255,207,209,213,255,213,214,216, +255,217,217,218,255,219,219,219,255,220,220,220,255,220,220,220,255,220,220,219, +255,220,220,219,255,219,219,219,255,219,219,219,255,219,219,219,255,219,219,219, +255,219,219,219,255,219,219,219,255,219,219,219,255,219,219,219,255,219,219,219, +255,219,219,219,255,219,219,219,255,219,219,219,255,219,219,219,255,220,220,220, +255,212,212,212,255,178,178,178,255,173,174,173,255,173,174,173,255,177,177,177, +255,142,145,146,255,92,93,93,255,154,154,154,255,202,202,202,253,209,209,209, +199,206,206,206,78,198,198,198,9,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,208,208, +208,27,209,209,209,134,208,208,208,234,201,201,201,255,146,146,146,255,92,92,92, +255,87,90,97,255,90,94,104,255,93,98,109,255,93,98,110,255,95,100,113,255,138, +142,153,255,154,164,185,255,156,165,188,255,158,169,194,255,162,175,202,255,168, +181,212,255,171,185,216,255,177,191,221,255,192,196,205,255,197,200,208,255,202, +205,211,255,208,210,213,255,212,213,214,255,215,215,215,255,216,216,215,255,216, +216,215,255,216,216,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215, +215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215, +215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215, +215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215,215,215,255,215, +215,215,255,215,215,215,255,214,214,214,255,186,186,186,255,173,174,173,255,173, +174,173,255,174,175,174,255,165,166,166,255,93,94,95,255,133,133,133,255,193, +193,193,255,208,208,208,221,211,211,211,109,210,210,210,17,255,255,255,1,0,0,0, +0,0,0,0,0,170,170,170,3,208,208,208,43,209,209,209,162,208,208,208,244,192, +192,192,255,129,129,128,255,87,88,88,255,90,94,104,255,93,98,109,255,95,101,114, +255,96,102,115,255,99,105,120,255,148,154,166,255,166,178,206,255,176,180,191, +255,181,186,195,255,189,193,201,255,195,198,205,255,201,203,207,255,206,207,209, +255,209,210,210,255,211,211,210,255,211,211,210,255,211,210,210,255,210,210,210, +255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210, +255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210, +255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210, +255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210, +255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210,255,210,210,210, +255,192,192,192,255,173,174,174,255,173,174,174,255,173,174,174,255,175,175,175, +255,106,108,109,255,116,116,116,255,184,184,184,255,208,208,208,235,209,209,209, +138,211,211,211,29,128,128,128,2,0,0,0,0,0,0,0,0,204,204,204,5,209,209,209,61, +208,208,208,184,208,208,208,250,181,181,181,255,117,117,116,255,84,86,88,255,91, +96,108,255,94,100,114,255,99,106,120,255,107,114,127,255,124,131,144,255,173, +177,185,255,192,194,199,255,197,200,202,255,202,204,204,255,205,205,205,255,205, +206,205,255,205,206,205,255,205,205,205,255,204,205,205,255,204,205,205,255,204, +205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204, +205,205,255,204,205,205,255,204,205,205,255,205,205,205,255,205,205,205,255,205, +206,205,255,205,206,205,255,205,206,205,255,204,205,205,255,204,205,205,255,204, +205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204, +205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204,205,205,255,204, +205,205,255,204,205,205,255,205,205,205,255,194,195,195,255,173,174,174,255,173, +174,174,255,173,174,174,255,177,178,178,255,123,125,127,255,102,102,102,255,172, +173,172,255,206,206,206,244,209,209,209,162,208,208,208,43,170,170,170,3,0,0,0, +0,255,255,255,1,191,191,191,8,209,209,209,77,209,209,209,200,206,206,206,253, +172,172,172,255,105,105,104,255,90,93,97,255,118,126,135,255,138,146,152,255, +154,160,163,255,166,169,171,255,176,177,177,255,197,197,196,255,201,201,201,255, +199,200,200,255,199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255, +199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255, +199,199,199,255,199,199,199,255,199,200,199,255,200,201,200,255,201,201,201,255, +199,200,200,255,196,197,198,255,192,193,196,255,186,189,194,255,179,184,192,255, +173,178,189,255,169,176,188,255,194,196,198,255,199,200,199,255,199,199,199,255, +199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255, +199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255,199,199,199,255, +199,200,200,255,193,194,194,255,175,175,175,255,173,174,174,255,173,174,174,255, +177,178,177,255,138,141,142,255,96,96,96,255,162,162,162,255,204,204,204,249, +210,210,210,180,207,207,207,58,204,204,204,5,0,0,0,0,255,255,255,1,209,209,209, +11,207,207,207,91,208,208,208,211,205,205,205,255,163,164,164,255,97,97,96,255, +111,116,119,255,166,176,177,255,174,177,176,255,175,176,176,255,174,175,175,255, +175,177,177,255,190,191,191,255,193,194,194,255,192,194,194,255,192,194,194,255, +192,194,194,255,192,194,194,255,192,194,194,255,192,194,194,255,192,194,194,255, +192,194,194,255,192,194,194,255,192,194,194,255,192,194,194,255,192,193,195,255, +187,190,193,255,179,183,189,255,167,173,180,255,155,161,171,255,146,154,164,255, +142,150,163,255,141,149,162,255,141,149,162,255,141,149,162,255,139,148,161,255, +173,177,183,255,195,196,196,255,192,194,194,255,192,194,194,255,192,194,194,255, +192,194,194,255,192,194,194,255,192,194,194,255,192,194,194,255,192,194,194,255, +192,194,194,255,192,194,194,255,192,194,194,255,193,194,195,255,189,191,191,255, +175,176,177,255,173,174,174,255,173,174,174,255,176,177,177,255,148,151,151,255, +93,94,94,255,152,152,152,255,201,201,201,252,209,209,209,193,208,208,208,70, +182,182,182,7,255,255,255,1,255,255,255,1,219,219,219,14,210,210,210,101,209, +209,209,217,203,203,203,255,157,158,158,255,93,94,94,255,122,127,129,255,175, +178,178,255,172,175,175,255,172,175,175,255,172,175,175,255,174,177,177,255,185, +187,188,255,187,189,190,255,186,189,189,255,186,189,189,255,186,189,189,255,186, +189,189,255,186,189,189,255,186,189,189,255,186,189,189,255,186,189,189,255,186, +189,189,255,186,189,189,255,187,190,190,255,157,166,178,255,137,148,164,255,131, +142,155,255,127,138,152,255,128,139,152,255,129,140,152,255,130,140,153,255,130, +140,153,255,130,140,153,255,130,140,153,255,127,138,151,255,151,159,168,255,189, +191,191,255,186,189,189,255,186,189,189,255,186,189,189,255,186,189,189,255,186, +189,189,255,186,189,189,255,186,189,189,255,186,189,189,255,186,189,189,255,186, +189,189,255,186,189,189,255,187,189,189,255,185,187,187,255,174,177,177,255,173, +175,175,255,173,174,174,255,175,176,176,255,154,156,157,255,92,92,93,255,146, +146,146,255,200,200,200,253,208,208,208,202,207,207,207,80,198,198,198,9,255, +255,255,1,255,255,255,1,207,207,207,16,210,210,210,107,209,209,209,221,203,203, +203,255,154,155,155,255,90,91,91,255,129,133,135,255,176,179,179,255,172,175, +175,255,172,176,176,255,172,176,176,255,172,177,177,255,179,183,183,255,181,185, +185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184, +185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184, +185,255,183,186,186,255,138,148,159,255,117,129,143,255,119,132,146,255,119,132, +146,255,119,132,146,255,119,132,146,255,119,132,146,255,119,132,146,255,119,132, +146,255,119,132,146,255,118,131,145,255,133,145,156,255,181,185,185,255,181,184, +185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184, +185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184,185,255,181,184, +185,255,181,185,185,255,179,183,183,255,173,177,177,255,172,175,175,255,173,175, +175,255,175,176,176,255,156,159,160,255,91,92,92,255,143,142,142,255,198,198, +198,254,209,209,209,206,207,207,207,85,204,204,204,10,255,255,255,1,255,255,255, +1,207,207,207,16,210,210,210,108,208,208,208,222,203,203,203,255,153,154,154, +255,90,91,91,255,130,135,136,255,176,179,179,255,172,176,176,255,171,176,176, +255,171,176,177,255,171,177,177,255,174,180,180,255,175,180,181,255,175,180,181, +255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181, +255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181,255,178,183,183, +255,139,150,159,255,106,122,137,255,109,125,139,255,109,125,139,255,109,125,139, +255,109,125,139,255,109,125,139,255,109,125,139,255,109,125,139,255,109,125,139, +255,108,124,137,255,118,133,148,255,172,178,180,255,176,181,181,255,175,180,181, +255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181, +255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181,255,175,180,181, +255,175,180,180,255,172,176,176,255,172,176,176,255,172,175,175,255,175,176,176, +255,155,158,159,255,90,91,92,255,142,142,142,255,197,197,197,254,209,209,209, +207,208,208,208,86,204,204,204,10,255,255,255,1,255,255,255,1,204,204,204,15, +208,208,208,104,207,207,207,219,202,202,202,255,156,157,157,255,91,92,92,255, +127,132,133,255,176,179,179,255,171,176,176,255,171,177,177,255,171,177,177,255, +170,177,178,255,171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255, +171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255, +171,178,178,255,171,178,178,255,171,178,178,255,173,180,179,255,150,160,166,255, +101,118,134,255,103,120,135,255,103,120,135,255,103,120,135,255,103,120,135,255, +103,120,135,255,102,119,134,255,101,118,134,255,102,119,135,255,105,123,141,255, +123,140,159,255,169,177,179,255,171,178,178,255,171,178,178,255,171,178,178,255, +171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255, +171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255,171,178,178,255, +171,177,177,255,171,176,176,255,172,175,175,255,176,177,177,255,151,155,156,255, +90,91,92,255,144,144,144,255,199,199,199,254,210,210,210,203,208,208,208,82, +198,198,198,9,255,255,255,1,255,255,255,1,213,213,213,12,207,207,207,95,210,210, +210,213,204,204,204,255,161,162,162,255,95,96,96,255,120,125,126,255,176,179, +180,255,171,176,176,255,170,177,177,255,170,178,178,255,170,178,178,255,170,178, +179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178, +179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178, +179,255,170,178,179,255,171,179,179,255,162,173,176,255,104,124,140,255,98,118, +133,255,98,118,134,255,97,117,133,255,97,117,133,255,99,119,134,255,105,125,140, +255,118,138,152,255,135,152,164,255,148,162,173,255,161,173,178,255,170,179,179, +255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179, +255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179,255,170,178,179, +255,170,178,179,255,170,178,178,255,170,178,178,255,170,177,177,255,171,176,177, +255,173,176,176,255,172,178,178,255,139,147,149,255,90,91,91,255,151,151,151, +255,200,200,200,252,209,209,209,196,206,206,206,73,219,219,219,7,255,255,255,1, +255,255,255,1,198,198,198,9,208,208,208,82,209,209,209,204,206,206,206,254,169, +170,170,255,101,103,103,255,110,115,117,255,174,178,179,255,171,177,177,255,170, +178,178,255,170,178,179,255,169,179,179,255,169,179,179,255,169,179,180,255,169, +179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169, +179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169, +179,180,255,169,180,180,255,131,151,165,255,111,135,152,255,119,141,156,255,128, +147,158,255,137,154,162,255,149,164,168,255,162,174,176,255,169,179,180,255,171, +181,181,255,171,181,181,255,170,180,180,255,169,179,180,255,169,179,180,255,169, +179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169, +179,180,255,169,179,180,255,169,179,180,255,169,179,180,255,169,179,179,255,170, +180,179,255,172,180,180,255,173,180,180,255,170,178,178,255,163,172,172,255,146, +157,161,255,114,121,125,255,95,95,95,255,158,158,158,255,203,203,203,250,209, +209,209,184,209,209,209,61,204,204,204,5,0,0,0,0,255,255,255,1,213,213,213,6, +209,209,209,66,209,209,209,189,208,208,208,251,179,180,180,255,111,112,112,255, +99,103,104,255,171,175,176,255,171,177,177,255,170,178,178,255,169,179,179,255, +169,180,180,255,168,180,180,255,168,180,180,255,168,180,181,255,168,180,181,255, +168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255, +168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255, +167,180,181,255,163,177,181,255,168,180,181,255,170,182,182,255,171,183,182,255, +170,182,182,255,169,181,181,255,168,180,181,255,168,180,181,255,168,180,181,255, +168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255,168,180,181,255, +168,180,181,255,168,180,181,255,168,180,181,255,169,181,181,255,170,182,181,255, +170,182,182,255,170,182,181,255,166,179,180,255,159,173,177,255,147,162,168,255, +130,146,154,255,114,131,141,255,104,116,128,255,95,103,115,255,86,90,96,255,103, +103,102,255,169,170,169,255,205,205,205,246,208,208,208,168,212,212,212,47,255, +255,255,3,0,0,0,0,0,0,0,0,255,255,255,3,208,208,208,49,210,210,210,169,208,208, +208,246,190,190,190,255,123,125,125,255,90,93,94,255,162,167,168,255,172,178, +178,255,170,178,178,255,169,179,180,255,168,180,181,255,168,180,181,255,168,181, +181,255,168,181,181,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181, +182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181, +182,255,167,181,182,255,167,181,182,255,167,181,182,255,168,182,182,255,167,181, +182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181, +182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181,182,255,167,181, +182,255,168,182,182,255,168,182,182,255,169,183,183,255,169,183,183,255,167,181, +182,255,162,177,181,255,153,171,178,255,140,161,170,255,125,149,162,255,114,140, +154,255,105,131,148,255,96,118,133,255,92,109,123,255,92,105,118,255,92,102,115, +255,92,98,109,255,86,89,93,255,115,115,114,255,180,180,180,255,208,208,208,238, +209,209,209,145,209,209,209,33,128,128,128,2,0,0,0,0,0,0,0,0,128,128,128,2,207, +207,207,32,209,209,209,143,208,208,208,237,198,198,198,255,141,142,142,255,87, +88,88,255,145,151,152,255,174,179,179,255,170,178,178,255,169,179,180,255,168, +181,181,255,167,181,182,255,167,181,182,255,167,182,182,255,167,182,182,255,167, +182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167, +182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167, +182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167,182,182,255,167, +182,182,255,167,182,182,255,167,182,182,255,168,182,182,255,168,182,182,255,169, +183,183,255,169,183,183,255,167,183,183,255,163,179,182,255,155,173,179,255,145, +166,175,255,132,157,171,255,122,149,166,255,114,144,163,255,107,138,156,255,100, +130,147,255,97,126,141,255,98,124,139,255,96,121,135,255,92,112,124,255,91,107, +119,255,92,103,115,255,91,99,109,255,89,95,104,255,87,88,90,255,129,129,129,255, +191,191,191,255,208,208,208,226,210,210,210,118,217,217,217,20,255,255,255,1,0, +0,0,0,0,0,0,0,255,255,255,1,213,213,213,18,209,209,209,111,209,209,209,222, +203,203,203,255,159,160,160,255,94,95,95,255,120,126,128,255,176,180,180,255, +170,178,178,255,169,179,179,255,168,181,181,255,167,182,182,255,166,182,183,255, +166,182,183,255,166,183,183,255,166,183,183,255,166,183,183,255,166,183,183,255, +166,183,183,255,166,183,183,255,166,183,183,255,166,183,183,255,166,183,183,255, +166,183,183,255,166,183,183,255,166,183,183,255,166,183,183,255,166,183,183,255, +167,183,183,255,167,184,184,255,168,184,184,255,169,185,185,255,167,184,184,255, +162,181,183,255,155,175,181,255,146,169,177,255,134,161,173,255,123,153,168,255, +113,145,163,255,106,139,158,255,102,136,154,255,101,134,152,255,101,134,151,255, +101,133,150,255,98,128,143,255,95,124,137,255,94,121,134,255,93,120,132,255,91, +114,126,255,88,107,117,255,89,102,113,255,89,100,110,255,88,95,104,255,87,91,97, +255,92,93,93,255,148,148,148,255,200,200,200,254,209,209,209,206,208,208,208,87, +209,209,209,11,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,198,198,198,9,208,208,208, +76,208,208,208,197,207,207,207,252,180,181,181,255,113,114,114,255,96,99,101, +255,169,173,174,255,172,178,177,255,169,179,179,255,168,180,181,255,167,182,182, +255,166,183,183,255,166,183,184,255,165,183,184,255,166,183,184,255,165,184,184, +255,165,184,184,255,165,184,184,255,165,184,184,255,165,184,184,255,165,184,184, +255,165,184,184,255,165,184,184,255,165,184,184,255,165,184,184,255,166,184,184, +255,166,185,185,255,163,182,184,255,154,176,181,255,142,167,173,255,128,156,165, +255,114,147,159,255,105,140,155,255,100,135,152,255,98,132,148,255,97,130,146, +255,97,130,145,255,96,129,143,255,96,128,142,255,96,128,141,255,96,128,141,255, +96,128,141,255,94,125,138,255,91,121,133,255,90,118,130,255,90,117,129,255,89, +114,125,255,87,108,118,255,86,102,111,255,87,99,108,255,87,96,104,255,86,92,101, +255,84,87,91,255,105,106,106,255,171,171,170,255,205,205,205,248,209,209,209, +176,205,205,205,56,204,204,204,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,191,191,191,4, +209,209,209,44,209,209,209,160,208,208,208,243,195,195,195,255,138,139,139,255, +86,88,88,255,145,150,152,255,174,179,179,255,170,178,178,255,168,180,180,255, +167,181,182,255,166,183,183,255,165,184,184,255,165,184,185,255,165,184,185,255, +165,184,185,255,165,184,185,255,165,185,185,255,165,185,185,255,165,185,185,255, +165,185,185,255,165,185,185,255,165,185,185,255,165,185,185,255,166,185,185,255, +146,173,180,255,122,155,169,255,108,145,160,255,98,134,149,255,92,126,140,255, +90,123,137,255,91,123,137,255,91,124,137,255,92,124,137,255,91,124,136,255,91, +124,136,255,91,123,135,255,90,123,135,255,90,122,134,255,90,122,134,255,91,123, +135,255,90,121,133,255,88,119,130,255,86,115,126,255,87,115,125,255,87,113,124, +255,85,109,118,255,83,102,111,255,84,98,107,255,85,96,104,255,85,92,99,255,85, +89,96,255,86,87,89,255,128,128,128,255,190,190,190,255,208,208,208,234,210,210, +210,136,204,204,204,30,255,255,255,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, +255,1,206,206,206,21,210,210,210,114,208,208,208,223,204,204,204,255,165,166, +166,255,100,101,101,255,109,113,114,255,174,178,178,255,171,177,177,255,169,179, +179,255,168,180,181,255,166,182,183,255,166,183,184,255,165,184,185,255,165,185, +185,255,164,185,186,255,164,185,186,255,164,185,186,255,164,185,186,255,164,185, +186,255,164,185,186,255,164,185,186,255,164,185,186,255,164,185,186,255,166,187, +187,255,139,169,180,255,102,141,160,255,95,132,147,255,92,125,138,255,92,125, +137,255,92,125,138,255,92,125,137,255,92,125,137,255,91,124,136,255,91,124,136, +255,90,123,135,255,90,123,135,255,89,123,134,255,89,122,134,255,89,122,134,255, +89,121,133,255,87,118,129,255,85,116,125,255,84,113,123,255,85,112,122,255,84, +109,118,255,83,103,112,255,82,98,107,255,84,96,104,255,84,92,100,255,83,89,96, +255,84,86,92,255,97,97,97,255,154,154,154,255,201,201,201,254,207,207,207,208, +210,210,210,90,196,196,196,13,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, +255,255,1,191,191,191,8,209,209,209,66,210,210,210,185,208,208,208,249,190,190, +190,255,129,129,129,255,86,88,89,255,151,156,158,255,175,179,178,255,170,177, +178,255,169,179,180,255,167,181,182,255,166,183,184,255,165,184,185,255,164,185, +186,255,164,186,186,255,164,186,187,255,164,186,187,255,164,186,187,255,164,186, +187,255,164,186,187,255,164,186,187,255,164,186,187,255,164,186,187,255,165,187, +187,255,150,177,183,255,106,147,165,255,98,137,152,255,92,129,142,255,90,125, +137,255,90,125,137,255,90,125,137,255,90,125,136,255,89,125,136,255,89,125,136, +255,88,124,135,255,88,123,135,255,88,123,135,255,88,123,135,255,88,122,134,255, +86,119,130,255,85,117,127,255,84,115,124,255,84,113,122,255,85,111,120,255,83, +105,114,255,83,100,109,255,83,96,104,255,85,94,102,255,83,89,96,255,83,87,95, +255,84,85,87,255,120,120,120,255,182,182,182,255,207,207,207,244,209,209,209, +165,213,213,213,48,204,204,204,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,255,255,255,2,204,204,204,30,209,209,209,132,207,207,207,230,203,203,203, +255,163,164,164,255,99,99,99,255,108,111,113,255,174,177,177,255,171,176,176, +255,170,178,178,255,168,180,180,255,167,182,182,255,166,183,184,255,165,185,185, +255,164,185,186,255,164,186,187,255,163,186,187,255,163,186,187,255,163,187,187, +255,163,187,188,255,163,187,188,255,163,187,188,255,163,187,188,255,164,187,188, +255,156,183,186,255,110,151,168,255,98,140,155,255,93,132,145,255,89,126,138, +255,89,126,137,255,89,126,137,255,88,125,136,255,88,125,136,255,88,124,136,255, +88,124,136,255,88,124,136,255,88,124,136,255,87,123,134,255,86,121,131,255,84, +118,128,255,84,116,125,255,84,114,123,255,85,112,122,255,83,107,116,255,82,101, +109,255,83,97,105,255,84,95,103,255,83,91,99,255,83,87,96,255,83,86,91,255,96, +96,96,255,152,152,152,255,200,200,200,254,208,208,208,218,211,211,211,109,204, +204,204,20,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, +255,255,1,204,204,204,10,210,210,210,73,208,208,208,190,207,207,207,250,192,192, +192,255,134,134,134,255,86,87,88,255,140,144,145,255,176,179,179,255,171,177, +177,255,170,178,178,255,168,180,180,255,167,182,182,255,165,183,184,255,165,185, +185,255,164,186,186,255,163,186,187,255,163,187,188,255,163,187,188,255,163,187, +188,255,163,187,188,255,163,187,188,255,163,187,188,255,163,187,188,255,162,187, +188,255,117,157,173,255,99,143,159,255,94,135,149,255,90,129,141,255,87,125,137, +255,87,125,137,255,87,125,137,255,87,125,137,255,87,125,137,255,87,126,137,255, +87,125,136,255,87,123,134,255,85,121,131,255,84,118,128,255,83,116,126,255,84, +114,123,255,85,112,122,255,84,108,117,255,82,102,110,255,83,98,106,255,84,95, +103,255,84,92,100,255,83,88,96,255,83,87,94,255,86,88,89,255,125,125,124,255, +185,185,185,255,208,208,208,244,210,210,210,170,209,209,209,55,213,213,213,6, +255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,170, +170,170,3,211,211,211,29,209,209,209,127,208,208,208,226,205,205,205,255,173, +174,173,255,112,113,112,255,89,92,93,255,160,163,164,255,175,177,177,255,171, +176,177,255,170,178,178,255,168,180,180,255,167,182,182,255,166,183,184,255,165, +185,185,255,164,186,186,255,163,186,187,255,163,187,188,255,162,187,188,255,162, +188,188,255,162,188,189,255,162,188,189,255,162,188,189,255,165,190,190,255,128, +166,179,255,100,147,164,255,95,140,154,255,91,133,145,255,88,128,140,255,87,126, +138,255,87,126,137,255,87,126,138,255,87,126,136,255,86,124,135,255,85,122,133, +255,84,120,130,255,84,118,127,255,83,116,126,255,84,114,123,255,85,112,122,255, +84,108,117,255,82,102,110,255,83,98,106,255,84,95,103,255,85,93,101,255,83,89, +96,255,83,87,95,255,83,85,88,255,106,106,106,255,163,163,163,255,203,203,203, +254,208,208,208,213,206,206,206,105,204,204,204,20,255,255,255,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,223,223,223,8, +205,205,205,61,209,209,209,173,207,207,207,244,200,200,200,255,155,155,155,255, +97,97,97,255,102,105,107,255,169,171,172,255,174,176,176,255,171,176,176,255, +170,178,178,255,169,179,180,255,168,181,181,255,166,183,183,255,165,184,185,255, +164,185,186,255,163,186,187,255,164,188,188,255,165,189,189,255,165,190,189,255, +164,189,190,255,160,187,189,255,154,183,187,255,127,165,177,255,100,147,164,255, +96,141,154,255,91,134,147,255,88,128,140,255,86,125,135,255,86,125,135,255,85, +124,134,255,85,122,132,255,84,120,130,255,84,119,128,255,83,117,126,255,83,115, +124,255,84,113,123,255,85,111,121,255,84,106,115,255,83,101,110,255,83,97,105, +255,85,95,102,255,86,93,101,255,84,90,97,255,83,87,95,255,83,86,90,255,94,94,95, +255,144,144,144,255,195,195,195,255,208,208,208,237,210,210,210,153,210,210,210, +45,170,170,170,6,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,2,215,215,215,19,206,206,206,98,208, +208,208,205,206,206,206,252,191,191,191,255,138,138,138,255,89,90,90,255,111, +115,117,255,171,173,174,255,174,177,176,255,172,176,176,255,172,178,177,255,171, +180,180,255,171,182,182,255,170,184,184,255,167,185,185,255,163,183,185,255,155, +179,183,255,143,172,178,255,130,164,172,255,117,155,166,255,105,148,161,255,97, +141,155,255,93,135,148,255,90,131,143,255,88,126,137,255,85,123,134,255,84,122, +132,255,84,121,131,255,84,120,131,255,83,119,129,255,84,118,127,255,83,116,126, +255,84,114,124,255,84,113,123,255,85,112,121,255,85,109,118,255,84,104,113,255, +83,100,108,255,84,96,105,255,85,94,102,255,86,93,101,255,84,90,97,255,84,87,95, +255,84,86,92,255,88,89,90,255,129,129,129,255,184,184,184,255,206,206,206,248, +208,208,208,189,209,209,209,78,216,216,216,13,128,128,128,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,204, +204,204,5,211,211,211,35,210,210,210,131,207,207,207,224,205,205,205,254,183, +183,183,255,130,130,130,255,87,88,88,255,113,117,119,255,161,170,172,255,165, +173,175,255,164,172,173,255,157,166,169,255,144,157,163,255,129,148,155,255,116, +140,150,255,106,135,147,255,101,132,147,255,96,129,144,255,92,126,141,255,91, +124,138,255,89,123,135,255,87,122,133,255,85,120,130,255,84,118,127,255,84,117, +126,255,84,118,127,255,84,117,126,255,83,117,126,255,83,116,125,255,84,115,125, +255,84,114,123,255,85,112,122,255,85,111,121,255,85,109,119,255,85,106,115,255, +84,101,110,255,84,98,106,255,84,95,103,255,85,94,101,255,86,92,100,255,84,89, +97,255,83,87,95,255,84,86,93,255,87,88,89,255,121,121,121,255,175,176,175,255, +204,204,204,252,209,209,209,212,209,209,209,111,204,204,204,25,255,255,255,3, +255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,128,128,128,2,223,223,223,8,208,208,208,54,209,209,209, +156,207,207,207,234,204,204,204,255,178,178,178,255,126,126,126,255,87,88,88, +255,101,106,109,255,112,120,129,255,103,112,123,255,97,108,121,255,95,106,119, +255,92,104,117,255,91,105,117,255,91,108,120,255,91,110,122,255,91,113,125,255, +90,114,126,255,89,115,126,255,87,114,125,255,86,113,122,255,85,112,122,255,85, +112,122,255,85,112,122,255,85,112,122,255,85,112,122,255,85,112,121,255,85,111, +121,255,86,111,120,255,86,109,119,255,86,107,117,255,85,104,113,255,85,100,109, +255,84,98,106,255,84,95,104,255,85,94,102,255,86,93,101,255,85,91,99,255,83,88, +95,255,84,87,95,255,84,86,92,255,86,87,88,255,119,119,118,255,172,172,172,255, +203,203,203,254,208,208,208,224,210,210,210,136,210,210,210,40,213,213,213,6, +255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,2,196,196,196,13,207, +207,207,69,209,209,209,171,207,207,207,238,203,203,203,255,178,178,178,255,129, +129,129,255,91,91,91,255,82,83,88,255,89,94,104,255,91,96,107,255,92,98,109,255, +92,99,110,255,91,100,110,255,89,99,110,255,88,100,110,255,87,100,110,255,86, +101,111,255,86,102,111,255,86,104,112,255,85,105,115,255,86,106,116,255,86,107, +117,255,86,107,117,255,86,107,117,255,86,107,117,255,86,106,116,255,86,105,115, +255,86,104,113,255,86,101,110,255,85,99,108,255,85,97,105,255,84,95,103,255,85, +94,101,255,86,93,101,255,86,92,99,255,85,89,97,255,84,88,95,255,84,87,95,255, +83,85,90,255,88,89,89,255,121,121,121,255,171,171,170,255,202,202,202,254,208, +208,208,230,210,210,210,152,208,208,208,54,198,198,198,9,128,128,128,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,2,210,210,210,17, +206,206,206,78,210,210,210,175,208,208,208,238,204,204,204,255,181,181,181,255, +137,137,137,255,98,98,98,255,83,85,86,255,86,90,97,255,88,92,101,255,88,93,101, +255,89,94,103,255,88,94,103,255,87,94,102,255,85,93,102,255,85,94,102,255,85,94, +103,255,85,96,105,255,85,96,105,255,85,98,106,255,86,99,108,255,86,99,108,255, +86,99,108,255,86,98,108,255,85,98,106,255,85,97,105,255,86,96,104,255,85,94, +103,255,85,94,102,255,86,93,101,255,86,92,100,255,86,92,100,255,86,90,97,255,84, +88,95,255,84,87,95,255,84,86,94,255,83,85,88,255,94,94,94,255,128,128,128,255, +175,176,175,255,203,203,203,254,208,208,208,230,210,210,210,158,206,206,206,62, +191,191,191,12,255,255,255,2,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,255,255,255,1,170,170,170,3,213,213,213,18,209,209,209,78,209,209,209, +171,209,209,209,234,205,205,205,254,189,189,189,255,151,151,151,255,110,110,110, +255,87,87,87,255,83,85,89,255,85,88,96,255,85,89,97,255,85,89,96,255,86,90,98, +255,86,91,99,255,86,92,100,255,86,92,100,255,86,93,101,255,86,93,102,255,86,93, +102,255,85,93,102,255,85,93,102,255,85,93,102,255,86,93,102,255,86,93,102,255, +86,93,101,255,86,92,100,255,86,92,100,255,86,92,100,255,87,91,99,255,86,90,97, +255,85,89,96,255,84,87,95,255,84,86,94,255,84,86,91,255,86,87,88,255,103,103, +103,255,143,143,143,255,184,184,184,255,204,204,204,253,208,208,208,226,209,209, +209,154,210,210,210,62,216,216,216,13,255,255,255,2,255,255,255,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,170,170,170,3,210, +210,210,17,208,208,208,70,210,210,210,158,207,207,207,225,206,206,206,252,198, +198,198,255,169,169,168,255,129,129,129,255,99,99,98,255,85,86,86,255,83,85,89, +255,84,86,93,255,84,87,95,255,84,87,95,255,85,89,96,255,86,90,97,255,86,90,98, +255,87,91,99,255,87,91,99,255,87,92,100,255,87,92,100,255,87,92,100,255,86,92, +100,255,87,91,99,255,87,91,99,255,86,90,98,255,86,90,97,255,85,89,96,255,84,87, +95,255,84,87,95,255,84,86,94,255,83,86,91,255,84,85,87,255,95,95,95,255,123, +123,122,255,162,162,162,255,194,194,194,255,206,206,206,249,208,208,208,215,209, +209,209,140,205,205,205,56,213,213,213,12,255,255,255,2,255,255,255,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1, +255,255,255,2,216,216,216,13,209,209,209,55,209,209,209,134,208,208,208,207,208, +208,208,244,204,204,204,255,188,188,188,255,157,157,157,255,123,123,122,255,98, +98,98,255,86,87,87,255,82,84,87,255,84,86,91,255,84,86,94,255,84,86,95,255,84, +87,95,255,84,87,95,255,85,87,96,255,85,88,96,255,85,88,96,255,85,88,96,255,85, +88,96,255,85,87,96,255,84,87,96,255,84,87,95,255,84,86,95,255,84,86,94,255,84, +86,93,255,83,84,89,255,85,86,87,255,95,95,95,255,117,117,117,255,150,150,150, +255,183,183,183,255,201,201,201,255,207,207,207,240,208,208,208,195,209,209,209, +117,208,208,208,43,227,227,227,9,255,255,255,2,255,255,255,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1, +255,255,255,1,255,255,255,2,198,198,198,9,207,207,207,37,207,207,207,101,209, +209,209,176,208,208,208,228,208,208,208,250,202,202,202,255,184,184,184,255,157, +157,157,255,129,129,129,255,107,107,106,255,94,94,94,255,86,87,88,255,83,85,87, +255,83,84,89,255,83,86,91,255,84,86,92,255,84,86,93,255,84,86,93,255,84,86,93, +255,84,86,93,255,84,86,92,255,84,86,91,255,83,84,89,255,83,84,87,255,86,87,88, +255,92,92,92,255,103,103,103,255,125,125,125,255,152,152,152,255,180,180,180, +255,199,199,199,255,207,207,207,248,209,209,209,220,208,208,208,162,208,208,208, +86,209,209,209,28,213,213,213,6,255,255,255,2,255,255,255,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,255,255,255,1,128,128,128,2,204,204,204,5,217,217,217,20,207,207, +207,64,210,210,210,130,209,209,209,193,208,208,208,232,207,207,207,250,203,203, +203,255,191,191,191,255,171,171,170,255,149,149,149,255,130,130,130,255,115,115, +115,255,103,103,102,255,96,96,96,255,92,92,92,255,88,89,89,255,87,88,88,255,87, +88,88,255,88,89,89,255,92,92,92,255,95,95,95,255,103,103,102,255,113,113,113, +255,128,128,127,255,146,146,146,255,167,167,167,255,188,188,188,255,200,200,200, +255,207,207,207,248,208,208,208,226,207,207,207,182,211,211,211,116,206,206,206, +52,204,204,204,15,191,191,191,4,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,2,198,198,198,9,206,206, +206,31,209,209,209,77,210,210,210,136,209,209,209,189,207,207,207,225,208,208, +208,244,205,205,205,253,201,201,201,255,192,192,192,255,180,180,180,255,169,169, +168,255,157,157,157,255,147,147,147,255,140,140,140,255,136,136,136,255,136,136, +136,255,140,140,140,255,147,147,147,255,155,155,155,255,167,167,167,255,179,179, +179,255,190,190,190,255,199,199,199,255,205,205,205,252,208,208,208,241,207,207, +207,219,210,210,210,180,210,210,210,124,209,209,209,66,204,204,204,25,182,182, +182,7,255,255,255,2,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,170,170,170,3,209,209,209, +11,207,207,207,32,208,208,208,70,210,210,210,118,210,210,210,164,209,209,209, +200,208,208,208,224,208,208,208,239,208,208,208,248,205,205,205,252,202,202,202, +254,200,200,200,255,198,198,198,255,197,197,197,255,196,196,196,255,198,198,198, +255,199,199,199,255,202,202,202,254,206,206,206,251,207,207,207,246,208,208,208, +237,209,209,209,221,208,208,208,195,209,209,209,156,208,208,208,109,209,209,209, +61,216,216,216,26,223,223,223,8,255,255,255,2,255,255,255,1,255,255,255,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,1,170,170,170,3,198,198,198,9,209, +209,209,22,206,206,206,47,207,207,207,80,209,209,209,116,210,210,210,148,210, +210,210,174,209,209,209,194,209,209,209,209,208,208,208,219,209,209,209,225,208, +208,208,228,209,209,209,227,209,209,209,224,209,209,209,217,208,208,208,207,209, +209,209,192,210,210,210,170,209,209,209,143,211,211,211,109,207,207,207,74,206, +206,206,42,201,201,201,19,219,219,219,7,255,255,255,2,255,255,255,1,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,128, +128,128,2,191,191,191,4,204,204,204,10,204,204,204,20,204,204,204,35,207,207, +207,53,208,208,208,71,209,209,209,89,206,206,206,104,210,210,210,114,210,210, +210,119,212,212,212,118,210,210,210,113,210,210,210,101,208,208,208,86,207,207, +207,69,204,204,204,50,207,207,207,32,213,213,213,18,223,223,223,8,255,255,255,3, +255,255,255,1,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255, +255,255,1,255,255,255,2,191,191,191,4,219,219,219,7,209,209,209,11,204,204,204, +15,213,213,213,18,217,217,217,20,204,204,204,20,198,198,198,18,219,219,219,14, +204,204,204,10,213,213,213,6,191,191,191,4,128,128,128,2,255,255,255,1,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,255,255,255,1,255,255,255,1,255,255,255,1,255,255,255,1, +255,255,255,1,255,255,255,1,255,255,255,1,255,255,255,1,255,255,255,1,255,255, +255,1,255,255,255,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static Fl_RGB_Image image_l64(idata_l64, 64, 64, 4, 0); diff --git a/include/.gitignore b/include/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/include/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/midi.C b/midi.C new file mode 100644 index 0000000..0b6b37b --- /dev/null +++ b/midi.C @@ -0,0 +1,1299 @@ +// This file is part of prodatum. +// Copyright 2011 Jan Eidtmann +// +// prodatum 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 3 of the License, or +// (at your option) any later version. +// +// prodatum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with prodatum. If not, see . + +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "ringbuffer.H" +#include "midi.H" +#include "pd.H" +#include "ui.H" +#include "cfg.H" + +extern PD* pd; +extern PD_UI* ui; +extern Cfg* cfg; + +#include "debug.H" + +/** + * midi core implementation (sender/receiver/decoder). + * this is where all MIDI bytes (outgoing and incoming) pass through. + * this thread should never lock + * in the linux version a pipe is used to notify \c process_midi_in + * for new messages. + */ +static void process_midi(PtTimestamp, void*); +static bool timer_running = false; +/*! \fn process_midi_in + * connects the MIDI receiver with the main thread. + * all incoming MIDI messages are passed to this function via the + * read buffer. runs in the main thread. + * in the linux version this gets notified by \c process_midi if a new message + * is available. on windows and mac this is a timeout function, repeated + * until we close our MIDI ports + */ +#ifndef WINDOWS +static void process_midi_in(int fd, void*); +static int p[2]; +#else +static void process_midi_in(void*); +#endif + +/** + * updates some MIDI engine informations that are shown in the UI + */ +static int overflows = 0; +static PmError pmerror = pmNoError; + +static PortMidiStream *port_in; +static PortMidiStream *port_out; +static PortMidiStream *port_thru; // controller port (eg keyboard) +static bool thru_active; +static bool midi_active; +static bool process_midi_exit_flag; +static jack_ringbuffer_t *read_buffer; +static jack_ringbuffer_t *write_buffer; +static int midi_device_id; +static bool seed_randomizer = true; +static bool requested = false; +static int requested_names = 0; +// used by watchdog in PD +timeval tv_incoming; +bool time_incoming_midi = false; +bool automap; +// set in cfg +extern int request_delay; + +static void process_midi(PtTimestamp, void*) +{ + if (!midi_active) + { + if (!jack_ringbuffer_read_space(write_buffer)) + { + process_midi_exit_flag = true; + return; + } + } + PmEvent ev; + static unsigned char event[4]; // 3 midi bytes, one byte to distinguish device (0) and controller (1) events + static int data, shift; + // we only want to put full sysex messages in our ringbuffer + // these are the buffers to store sysex chunks locally + static unsigned char local_read_buffer[SYSEX_MESSAGE_BUFFER]; + static unsigned char local_write_buffer[SYSEX_MESSAGE_BUFFER]; + static size_t position = 0; + static bool receiving_sysex = false; + static bool result_out = false; + do + { + // check if theres something from the device and write it to the read_buffer + while (midi_active && Pm_Poll(port_in)) + { + pmerror = (PmError) Pm_Read(port_in, &ev, 1); + if (pmerror < 0) + { + receiving_sysex = false; + break; + } + // got 4 bytes + for (shift = 0; shift <= 24; shift += 8) + { + // byte for byte inspection + data = (ev.message >> shift) & 0xFF; + if (data == MIDI_SYSEX) + { + receiving_sysex = false; + // filter sysex + // e-mu proteus + if (((ev.message >> 8) & 0xFF) == 0x18 && ((ev.message + >> 16) & 0xFF) == 0x0F && ((ev.message >> 24) + & 0xFF) == midi_device_id) + receiving_sysex = true; + // universal sysex + else if (((ev.message >> 8) & 0xFF) == 0x7E) + receiving_sysex = true; + position = 0; + } + // check for truncated sysex + if (receiving_sysex && (((data & 0x80) == 0 || data == 0xF7) + || position == 0)) + { + // copy data + if (position < SYSEX_MESSAGE_BUFFER) + { + local_read_buffer[position] = data; + ++position; + // hand over a complete sysex message to the main thread + if (data == MIDI_EOX) + { + if (jack_ringbuffer_write_space(read_buffer) + >= position) + { + jack_ringbuffer_write(read_buffer, + local_read_buffer, position); +#ifndef WINDOWS + if (!write(p[1], " ", 1) == 1) + pmesg(1, "*** Could not write into pipe!\n"); +#endif + if (time_incoming_midi) + gettimeofday(&tv_incoming, 0); + } + else + overflows |= 1; + receiving_sysex = false; + break; + } + } + else + { + ++position; + if (data == MIDI_EOX) + { + pmesg( + 1, + "*** SYSEX_MESSAGE_BUFFER (%d) too small (%d) for reader\n", + SYSEX_MESSAGE_BUFFER, position); + overflows |= 2; + receiving_sysex = false; + break; + } + } + } + // voice message + else if (shift == 0 && data >= 0x80 && data <= 0xEF) + { + receiving_sysex = false; + if (jack_ringbuffer_write_space(read_buffer) >= 4) + { + event[0] = Pm_MessageStatus(ev.message); + event[1] = Pm_MessageData1(ev.message); + event[2] = Pm_MessageData2(ev.message); + event[3] = 0; + jack_ringbuffer_write(read_buffer, event, 4); +#ifndef WINDOWS + if (!write(p[1], " ", 1) == 1) + pmesg(1, "*** Could not write into pipe!\n"); +#endif + } + break; // dont loop through the other bytes + } + else + { + // can be no realtime message here (which could have been inserted + // into a sysex stream) as we filter those + receiving_sysex = false; + break; + } + } + } + + // check if theres something from the controller + if (thru_active) + { + if (Pm_Poll(port_thru)) + { + pmerror = (PmError) Pm_Read(port_thru, &ev, 1); + if (!(pmerror < 0)) // no error + { + event[0] = Pm_MessageStatus(ev.message); + // voice messages + if (event[0] >= 0x80 && event[0] <= 0xEF) + { + // automap + if (automap && pd->midi_mode != OMNI) + event[0] = (event[0] & ~0xf) + | (pd->selected_channel & 0xff); + event[1] = Pm_MessageData1(ev.message); + event[2] = Pm_MessageData2(ev.message); + event[3] = 1; + // write to ringbuffer for internal processing + if (jack_ringbuffer_write_space(read_buffer) >= 4) + { + jack_ringbuffer_write(read_buffer, event, 4); +#ifndef WINDOWS + if (!write(p[1], " ", 1) == 1) + pmesg(1, "*** Could not write into pipe!\n"); +#endif + } + ev.message = Pm_Message(event[0], event[1], event[2]); + } + // forward message + pmerror = (PmError) Pm_Write(port_out, &ev, 1); + } + } + } + + // check if theres some MIDI to write on the bus + result_out = false; + if (jack_ringbuffer_read(write_buffer, &local_write_buffer[0], 1) == 1) + { + result_out = true; + if (local_write_buffer[0] == MIDI_SYSEX) + { + int i = 0; + do + { + jack_ringbuffer_read(write_buffer, + local_write_buffer + ++i, 1); + } while (local_write_buffer[i] != MIDI_EOX); + pmerror = Pm_WriteSysEx(port_out, 0, local_write_buffer); + } + else + { + if (jack_ringbuffer_read(write_buffer, event + 1, 2) == 2) + { + ev.message = Pm_Message(local_write_buffer[0], event[1], + event[2]); + pmerror = Pm_Write(port_out, &ev, 1); + } + } + } + } while (result_out); // repeat until all our queued sysex has been written +} + +static void show_error(void) +{ + pmesg(40, "show_error()\n"); + static char buf[256]; + if (pmerror == -10000) + Pm_GetHostErrorText(buf, 256); + else if (pmerror < 0) + snprintf(buf, 256, "%s", Pm_GetErrorText(pmerror)); + else if (overflows & 2) // internal buffer overflows + snprintf(buf, 256, "ERROR: SysEx message too large!\nSkipping message."); + else if (overflows & 1) // read buffer overflows + sysex lost + snprintf(buf, 256, + "Warning: SysEx incoming too fast! Message(s) lost!\n"); + pmerror = pmNoError; + overflows = 0; + fl_message("%s", buf); +} + +#ifndef WINDOWS +static void process_midi_in(int fd, void*) +#else +static void process_midi_in(void*) +#endif +{ + static unsigned long count = 0; + static unsigned long count_events = 0; + unsigned char poll = 0; + if (pmerror < 0 || overflows) + show_error(); + while (midi_active && jack_ringbuffer_peek(read_buffer, &poll, 1)) + { +#ifndef WINDOWS + char buf; + if (!read(fd, &buf, 1) == 1) // this is fatal but very unlikely + { + pmesg(1, "*** Could not read from pipe!\n"); + pd->display_status("*** Could not read from pipe!", true); + } +#endif + if (poll == MIDI_SYSEX) + { + unsigned char sysex[SYSEX_MESSAGE_BUFFER]; + int len = -1; + do + { + jack_ringbuffer_read(read_buffer, sysex + ++len, 1); + } while (sysex[len] != MIDI_EOX); + ++len; + // log sysex messages + ++count; + if (ui->log_sysex_in->value()) + { + char* buf = new char[2 * len + 17]; + int n = snprintf(buf, 15, "\nIS.%lu ", count); + for (int i = 0; i < len; i++) + sprintf(n + buf + 2 * i, "%02X", sysex[i]); + ui->logbuf->append(buf); + delete[] buf; + ui->log->insert_position(ui->logbuf->length()); + if (!ui->scroll_lock->value()) + ui->log->show_insert_position(); + } + // e-mu sysex + if (sysex[1] == 0x18) + { + switch (sysex[5]) + { + case 0x70: // error + pd->incoming_ERROR(sysex[7] * 128 + sysex[6], + sysex[9] * 128 + sysex[8]); + break; + + case 0x7f: // ACK + pd->incoming_ACK(sysex[7] * 128 + sysex[6]); + break; + + case 0x7e: // NAK + pd->incoming_NAK(sysex[7] * 128 + sysex[6]); + break; + + case 0x7c: // WAIT + pd->incoming_WAIT(); + Pt_Sleep(request_delay); + break; + + case 0x7b: // EOF + pd->incoming_EOF(); + break; + + case 0x7d: // CANCEL + pd->incoming_CANCEL(); + break; + + case 0x09: // hardware configuration + if (requested) + { + requested = false; + pd->incoming_hardware_config(sysex, len); + } + break; + + case 0x0b: // generic name + if (requested_names > 0) + { + --requested_names; + pd->incoming_generic_name(sysex); + } + break; + + case 0x1c: // setup dumps + if (requested) + { + requested = false; + pd->incoming_setup_dump(sysex, len); + } + break; + + case 0x18: // arp pattern dump + pd->incoming_arp_dump(sysex, len); + break; + + // case 0x16: // program change/preset map dump + // pd->incoming_pc_dump(sysex, len); + // break; + + case 0x10: // preset dumps + if (requested) + switch (sysex[6]) + { + case 0x01: // dump header (closed) + case 0x03: // dump header (open) + pd->incoming_preset_dump(sysex, len); + break; + case 0x02: // dump data (closed) + case 0x04: // dump data (open) + pd->incoming_preset_dump(sysex, len); + if (len < 253) // last packet + requested = false; + break; + } + break; + case 0x40: // remote front panel control command + break; + + default: + pd->display_status("Received unrecognized sysex.", true); + pmesg(10, + "process_midi_in: received unrecognized message:\n"); + for (int i = 0; i < len; i++) + pmesg(10, "%X ", sysex[i]); + pmesg(10, "\n"); + } + } + // universal sysex + else if (sysex[1] == 0x7e) + { + pmesg(90, + "process_midi_in: received MIDI standard universal message: "); + // device inquiry + if (sysex[3] == 0x06 && sysex[4] == 0x02 && sysex[5] == 0x18) + { + if (requested) + { + pmesg(90, "device inquiry response\n"); + requested = false; + pd->incoming_inquiry_data(sysex, len); + } + } + } + else + { + pd->display_status("Received data from another planet.", true); + pmesg(10, + "process_midi_in: received data from another planet!!!:\n"); + for (int i = 0; i < len; i++) + pmesg(40, "%X ", sysex[i]); + pmesg(10, "\n"); + } + } // if (poll == MIDI_SYSEX) + + else + { + unsigned char event[4]; + jack_ringbuffer_read(read_buffer, event, 4); + if (event[3] == 0) // device event + { + switch (event[0] >> 4) + { + case 0x8: // note off + ui->piano->activate_key(-1, event[1]); + ui->main->minipiano->activate_key(-1, event[1]); + ui->global_minipiano->activate_key(-1, event[1]); + break; + case 0x9: // note-on + if (event[2] == 0) + { + ui->piano->activate_key(-1, event[1]); + ui->main->minipiano->activate_key(-1, event[1]); + ui->global_minipiano->activate_key(-1, event[1]); + } + else + { + ui->piano->activate_key(1, event[1]); + ui->main->minipiano->activate_key(1, event[1]); + ui->global_minipiano->activate_key(1, event[1]); + } + break; + case 0xb: // controller event + { + if (pd->cc_to_ctrl.find(event[1]) != pd->cc_to_ctrl.end()) + { + int controller = pd->cc_to_ctrl[event[1]]; + if (controller <= 12) + // sliders + ((Fl_Slider*) ui->main->ctrl_x[controller])->value( + (double) event[2]); + else + // footswitches + ((Fl_Button*) ui->main->ctrl_x[controller])->value( + event[2] > 63 ? 1 : 0); + } + else if (event[1] == 1) // modwhl + ui->modwheel->value((double) event[2]); + else if (event[1] == 7) // channel volume + pwid[131][0]->set_value(event[2]); + else if (event[1] == 10) // channel pan + pwid[132][0]->set_value(event[2]); + } + break; + case 0xe: // pitchwheel + { + int v = event[2]; + v <<= 7; + v |= event[1]; + ui->pitchwheel->value((double) v); + } + break; + default: + pd->display_status("Received unused MIDI event."); + pmesg(10, + "process_device_event: unused event: %X, %X, %X\n", + event[0], event[1], event[2]); + } + } + else // controller event + { + switch (event[0] >> 4) + { + case 0x8: // note off + ui->piano->activate_key(-3, event[1]); + ui->main->minipiano->activate_key(-3, event[1]); + ui->global_minipiano->activate_key(-3, event[1]); + break; + case 0x9: // note-on + if (event[2] == 0) + { + ui->piano->activate_key(-2, event[1]); + ui->main->minipiano->activate_key(-2, event[1]); + ui->global_minipiano->activate_key(-2, event[1]); + } + else + { + ui->piano->activate_key(2, event[1]); + ui->main->minipiano->activate_key(2, event[1]); + ui->global_minipiano->activate_key(2, event[1]); + } + break; + case 0xb: // controller event + { + if (pd->cc_to_ctrl.find(event[1]) != pd->cc_to_ctrl.end()) + { + int controller = pd->cc_to_ctrl[event[1]]; + if (controller <= 12) + // sliders + ((Fl_Slider*) ui->main->ctrl_x[controller])->value( + (double) event[2]); + else + // footswitches + ((Fl_Button*) ui->main->ctrl_x[controller])->value( + event[2] > 63 ? 1 : 0); + } + else if (event[1] == 1) // modwhl + ui->modwheel->value((double) event[2]); + else if (event[1] == 7) // channel volume + pwid[131][0]->set_value(event[2]); + else if (event[1] == 10) // channel pan + pwid[132][0]->set_value(event[2]); + } + break; + case 0xe: // pitchwheel + { + int v = event[2]; + v <<= 7; + v |= event[1]; + ui->pitchwheel->value((double) v); + } + break; + default: + pd->display_status("Received unused MIDI event."); + pmesg( + 10, + "process_controller_event: unused event: %X, %X, %X\n", + event[0], event[1], event[2]); + } + } + // log midi events + ++count_events; + if (ui->log_events_in->value()) + { + char buf[28]; + snprintf(buf, 28, "\nIE.%lu %02X%02X%02X", count_events, + event[0], event[1], event[2]); + ui->logbuf->append(buf); + ui->log->insert_position(ui->logbuf->length()); + if (!ui->scroll_lock->value()) + ui->log->show_insert_position(); + } + } + } +#ifdef WINDOWS + if (timer_running) + Fl::repeat_timeout(.01, process_midi_in); +#endif +} + +// ######################################## +// midi connection class member definitions +// ######################################## +MIDI::MIDI() +{ + pmesg(40, "MIDI::MIDI()\n"); + midi_device_id = cfg->get_cfg_option(CFG_DEVICE_ID); + // initialize (global) variables and buffers + timer_running = false; + midi_active = false; + thru_active = false; + process_midi_exit_flag = false; + port_in = 0; + port_out = 0; + port_thru = 0; + selected_port_out = -1; + selected_port_in = -1; + selected_port_thru = -1; + read_buffer = jack_ringbuffer_create(RING_READ_BUFFER_SIZE); + jack_ringbuffer_mlock(read_buffer); + write_buffer = jack_ringbuffer_create(RING_WRITE_BUFFER_SIZE); + jack_ringbuffer_mlock(write_buffer); +#ifndef WINDOWS + if (pipe(p) == -1) + { + pmesg(10, "*** Could not open pipe\n%s", strerror(errno)); + fl_alert("Could not open pipe\n%s", strerror(errno)); + throw 1; + } + // int flags; + // flags = fcntl(p[0], F_GETFL, 0); + // fcntl(p[0], F_SETFL, flags | O_NONBLOCK); + // flags = fcntl(p[1], F_GETFL, 0); + // fcntl(p[1], F_SETFL, flags | O_NONBLOCK); +#endif + populate_ports(); +} + +MIDI::~MIDI() +{ + pmesg(40, "MIDI::~MIDI()\n"); + ui->b_auto_detect->deactivate(); + stop_timer(); + if (selected_port_in != -1) + Pm_Close(port_in); + if (selected_port_out != -1) + Pm_Close(port_out); + if (selected_port_thru != -1) + Pm_Close(port_thru); + Pm_Terminate(); + // free buffers + jack_ringbuffer_free(read_buffer); + jack_ringbuffer_free(write_buffer); +} + +void MIDI::nibble(int value, unsigned char& lsb, unsigned char& msb) const +{ + if (value < 0) + value += 16384; + msb = value / 128; + lsb = value % 128; +} + +// get available system midi ports +void MIDI::populate_ports() +{ + pmesg(40, "MIDI::populate_ports()\n"); + ui->midi_outs->clear(); + ui->midi_ins->clear(); + ui->midi_ctrl->clear(); + ports_out.clear(); + ports_in.clear(); + for (int i = 0; i < Pm_CountDevices(); i++) + { + const PmDeviceInfo *info = Pm_GetDeviceInfo(i); + pmesg(40, "%s %s ", info->interf, info->name); + if (info->output) + { + pmesg(40, "Out\n"); + ui->midi_outs->add("foo"); + ui->midi_outs->replace(ui->midi_outs->size() - 2, info->name); + ports_out.push_back(i); + pd->display_status(info->name); + Fl::wait(); + } + else + { + ui->midi_ins->add("foo"); + ui->midi_ins->replace(ui->midi_ins->size() - 2, info->name); + ui->midi_ctrl->add("foo"); + ui->midi_ctrl->replace(ui->midi_ctrl->size() - 2, info->name); + ports_in.push_back(i); + pd->display_status(info->name); + Fl::wait(); + pmesg(40, "In\n"); + } + } +} + +void MIDI::set_device_id(int id) +{ + pmesg(40, "MIDI::set_device_id(%d)\n", id); + midi_device_id = id; +} + +// start realtime receiver +int MIDI::start_timer() +{ + if (timer_running) + return 1; + pmesg(40, "MIDI::start_timer()\n"); + // initialize timout or filedescriptors for IPC +#ifndef WINDOWS + Fl::add_fd(p[0], process_midi_in); +#else + Fl::add_timeout(.1, process_midi_in); +#endif + // start timer, clean up if we couldnt + if (Pt_Start(1, &process_midi, 0) < 0) + { +#ifndef WINDOWS + Fl::remove_fd(p[0]); + close(p[0]); + close(p[1]); +#else + Fl::remove_timeout(process_midi_in, 0); +#endif + pd->display_status("*** Could not start MIDI timer.", true); + return 0; + } + timer_running = true; + return 1; +} + +// stop realtime receiver +void MIDI::stop_timer() +{ + if (!timer_running) + return; + pmesg(40, "MIDI::stop_timer()\n"); + process_midi_exit_flag = false; + thru_active = false; + midi_active = false; + while (!process_midi_exit_flag) + Fl::wait(.1); + Pt_Stop(); +#ifndef WINDOWS + Fl::remove_fd(p[0]); + close(p[0]); + close(p[1]); +#else + Fl::remove_timeout(process_midi_in, 0); +#endif + timer_running = false; +} + +int MIDI::connect_out(int port) +{ + pmesg(40, "MIDI::connect_out(port: %d)\n", port); + if (port < 0 || port >= (int) ports_out.size()) + return 0; + if (midi_active) + { + ui->b_auto_detect->deactivate(); + process_midi_exit_flag = false; + thru_active = false; + midi_active = false; + while (!process_midi_exit_flag) + Fl::wait(.1); + } + if (!start_timer()) + return 0; + pmerror = Pm_Initialize(); // start portmidi + if (pmerror < 0) + { + show_error(); + return 0; + } + if (selected_port_out != -1) + { + pmerror = Pm_Close(port_out); + if (pmerror < 0) + { + show_error(); + return 0; + } + } + if (selected_port_out == port) + { + selected_port_out = -1; + return 0; + } + // device ID validation + try + { + ports_out.at(port); + } catch (...) + { + return 0; + } + pmerror = Pm_OpenOutput(&port_out, ports_out.at(port), NULL, 0, NULL, NULL, + 0); // open the port + if (pmerror < 0) + { + show_error(); + return 0; + } + selected_port_out = port; + if (selected_port_in != -1) + { + midi_active = true; + ui->b_auto_detect->activate(); + request_device_inquiry(); + } + if (selected_port_thru != -1) + thru_active = true; + return 1; +} + +int MIDI::connect_in(int port) +{ + pmesg(40, "MIDI::connect_in(port: %d)\n", port); + if (port < 0 || port >= (int) ports_in.size()) + return 0; + if (port == selected_port_thru) + { + fl_message("In-port must be different from Ctrl-port."); + return 0; + } + if (midi_active) + { + ui->b_auto_detect->deactivate(); + process_midi_exit_flag = false; + midi_active = false; + while (!process_midi_exit_flag) + Fl::wait(.1); + } + if (!start_timer()) + return 0; + pmerror = Pm_Initialize(); // start portmidi + if (pmerror < 0) + { + show_error(); + return 0; + } + if (selected_port_in != -1) + { + pmerror = Pm_Close(port_in); + if (pmerror < 0) + { + show_error(); + return 0; + } + } + if (selected_port_in == port) + { + selected_port_in = -1; + return 0; + } + // device ID validation + try + { + ports_in.at(port); + } catch (...) + { + return 0; + } + pmerror = Pm_OpenInput(&port_in, ports_in.at(port), NULL, 512, NULL, NULL); + if (pmerror < 0) + { + show_error(); + return 0; + } + // filter messages we dont process + pmerror = Pm_SetFilter( + port_in, + PM_FILT_SYSTEMCOMMON | PM_FILT_ACTIVE | PM_FILT_CLOCK + | PM_FILT_PLAY | PM_FILT_TICK | PM_FILT_FD | PM_FILT_RESET + | PM_FILT_AFTERTOUCH | PM_FILT_PROGRAM | PM_FILT_PITCHBEND); + if (pmerror < 0) + { + show_error(); + return 0; + } + selected_port_in = port; + if (selected_port_out != -1) + { + midi_active = true; + ui->b_auto_detect->activate(); + request_device_inquiry(); + } + return 1; +} + +// connect midi thru +int MIDI::connect_thru(int port) +{ + pmesg(40, "MIDI::connect_thru(port: %d)\n", port); + if (port < 0 || port >= (int) ports_in.size()) + return 0; + if (port == selected_port_in) + { + fl_message("Ctrl-port must be different from In-port"); + return 0; + } + if (thru_active) + { + thru_active = false; + mysleep(20); + } + if (!start_timer()) + return 0; + pmerror = Pm_Initialize(); // start portmidi + if (pmerror < 0) + { + show_error(); + return 0; + } + if (selected_port_thru != -1) + { + pmerror = Pm_Close(port_thru); + if (pmerror < 0) + { + show_error(); + return 0; + } + } + if (selected_port_thru == port) + { + selected_port_thru = -1; + return 0; + } + // device ID validation + try + { + ports_in.at(port); + } catch (...) + { + return 0; + } + pmerror + = Pm_OpenInput(&port_thru, ports_in.at(port), NULL, 512, NULL, NULL); + if (pmerror < 0) + { + show_error(); + return 0; + } + // filter messages we dont process + pmerror = Pm_SetFilter(port_thru, PM_FILT_REALTIME | PM_FILT_SYSTEMCOMMON); + if (pmerror < 0) + { + show_error(); + return 0; + } + selected_port_thru = port; + if (selected_port_out != -1) + { + cfg->get_cfg_option(CFG_AUTOMAP) ? automap = true : automap = false; + thru_active = true; + } + set_control_channel_filter(cfg->get_cfg_option(CFG_CONTROL_CHANNEL)); + return 1; +} + +void MIDI::set_control_channel_filter(int channel) +{ + pmesg(40, "MIDI::set_control_channel_filter(%d)\n", channel); + cfg->set_cfg_option(CFG_CONTROL_CHANNEL, channel); + if (channel == 16) + pmerror = Pm_SetChannelMask( + port_thru, + Pm_Channel(0) | Pm_Channel(1) | Pm_Channel(2) | Pm_Channel(3) + | Pm_Channel(4) | Pm_Channel(5) | Pm_Channel(6) + | Pm_Channel(7) | Pm_Channel(8) | Pm_Channel(9) + | Pm_Channel(10) | Pm_Channel(11) | Pm_Channel(12) + | Pm_Channel(13) | Pm_Channel(14) | Pm_Channel(15)); + else + pmerror = Pm_SetChannelMask(port_thru, Pm_Channel(channel)); + if (pmerror < 0) + show_error(); +} + +void MIDI::set_channel_filter(int channel) +{ + pmesg(40, "MIDI::set_channel_filter(%d)\n", channel); + pmerror = Pm_SetChannelMask(port_in, Pm_Channel(channel)); + if (pmerror < 0) + show_error(); +} + +void MIDI::write_sysex(const unsigned char* sysex, size_t len) const +{ + pmesg(40, "MIDI::write_sysex(data, len: %d)\n", len); + // dont use if (!midi_active) here because we wanna be able to send + // everything important (eg the setup_init) before the midi thread goes void + static unsigned long count = 0; + if (len > SYSEX_MESSAGE_BUFFER) + { + pmesg(1, "*** SYSEX_MESSAGE_BUFFER (%d) too small (%d) for writer\n", + SYSEX_MESSAGE_BUFFER, len); + overflows |= 2; +#ifndef WINDOWS + show_error(); +#endif + return; + } + while (jack_ringbuffer_write_space(write_buffer) < len) + Fl::wait(.1); + jack_ringbuffer_write(write_buffer, sysex, len); + // log sysex messages + ++count; + if (ui->log_sysex_out->value()) + { + char* buf = new char[2 * len + 17]; + int n = snprintf(buf, 15, "\nOS.%lu ", count); + for (int i = 0; i < len; i++) + sprintf(n + buf + 2 * i, "%02X", sysex[i]); + ui->logbuf->append(buf); + delete[] buf; + ui->log->insert_position(ui->logbuf->length()); + if (!ui->scroll_lock->value()) + ui->log->show_insert_position(); + } +} + +void MIDI::write_event(int status, int value1, int value2, int channel) const +{ + pmesg(40, "MIDI::write_event(%X, %X, %X, %d)\n", status, value1, value2, + channel); + static unsigned long count = 0; + if (!midi_active) + return; + if (channel == -1) + channel = pd->selected_channel; + unsigned char stat = ((status & ~0xf) | channel) & 0xff; + const unsigned char msg[] = + { stat, value1 & 0xff, value2 & 0xff }; + while (jack_ringbuffer_write_space(write_buffer) < 3) + { + pd->display_status("Throttling upload...", true); + Fl::wait(.1); + } + jack_ringbuffer_write(write_buffer, msg, 3); + // log midi events + ++count; + if (ui->log_events_out->value()) + { + char buf[29]; + snprintf(buf, 29, "\nOE.%lu %02X%02X%02X", count, stat, value1, value2); + ui->logbuf->append(buf); + ui->log->insert_position(ui->logbuf->length()); + if (!ui->scroll_lock->value()) + ui->log->show_insert_position(); + } +} + +void MIDI::ack(int packet) const +{ + pmesg(40, "MIDI::ack(packet: %d) \n", packet); + uchar ack[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x7f, packet % 128, packet / 128, + 0xf7 }; + write_sysex(ack, 9); +} +void MIDI::nak(int packet) const +{ + pmesg(40, "MIDI::nak(packet: %d) \n", packet); + uchar nak[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x7e, packet % 128, packet / 128, + 0xf7 }; + write_sysex(nak, 9); +} +void MIDI::cancel() const +{ + pmesg(40, "MIDI::cancel() \n"); + uchar cancel[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x7d, 0xf7 }; + write_sysex(cancel, 7); +} +void MIDI::wait() const +{ + pmesg(40, "MIDI::wait() \n"); + uchar wait[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x7c, 0xf7 }; + write_sysex(wait, 7); +} +void MIDI::eof() const +{ + pmesg(40, "MIDI::eof() \n"); + uchar endof[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x7b, 0xf7 }; + write_sysex(endof, 7); +} + +void MIDI::request_device_inquiry(int id) const +{ + pmesg(40, "MIDI::request_device_inquiry(%d) \n", id); + if (!midi_active) + return; + int check_id = id; + if (check_id == -1) + check_id = midi_device_id; + uchar request[] = + { 0xf0, 0x7e, check_id, 0x06, 0x01, 0xf7 }; + write_sysex(request, 6); + requested = true; +} + +void MIDI::request_hardware_config() const +{ + pmesg(40, "MIDI::request_hardware_config() \n"); + if (requested) + return; + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x0a, 0xf7 }; + write_sysex(request, 7); + requested = true; +} + +void MIDI::request_preset_dump(int preset, int rom_id) const +{ + pmesg(40, "MIDI::request_preset_dump(preset: %d, rom: %d) \n", preset, + rom_id); + if (requested) + return; + if (preset < 0) + preset += 16384; + else + seed_randomizer = true; + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x11, cfg->get_cfg_option( + CFG_CLOSED_LOOP_DOWNLOAD) ? 0x02 : 0x04, preset % 128, + preset / 128, rom_id % 128, rom_id / 128, 0xf7 }; + pd->loading(); + write_sysex(request, 12); + requested = true; +} + +void MIDI::request_setup_dump() const +{ + pmesg(40, "MIDI::request_setup_dump() \n"); + if (requested || !midi_active) + return; + // now we know that we have initialzed we don't accept any more name data + requested_names = 0; + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x1d, 0xf7 }; + write_sysex(request, 7); + requested = true; +} + +void MIDI::request_arp_dump(int number, int rom_id) const +{ + if (!midi_active) + return; + pmesg(40, "MIDI::request_arp_dump(#: %d, rom: %d)\n", number, rom_id); + if (number < 0) + number += 16384; + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x19, number % 128, number / 128, + rom_id % 128, rom_id / 128, 0xf7 }; + write_sysex(request, 11); +} + +void MIDI::request_name(int type, int number, int rom_id) const +{ + if (!midi_active) + return; + pmesg(40, "MIDI::request_name(type: %d, #: %d, rom_id: %d)\n", type, + number, rom_id); + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x0c, type, number % 128, number + / 128, rom_id % 128, rom_id / 128, 0xf7 }; + write_sysex(request, 12); + requested_names++; +} + +void MIDI::edit_parameter_value(int id, int value) const +{ + if (!midi_active) + return; + pmesg(40, "MIDI::edit_parameter_value(id: %d, value: %d) \n", id, value); + static unsigned char plsb, pmsb, vlsb, vmsb; + nibble(id, plsb, pmsb); + nibble(value, vlsb, vmsb); + uchar request[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x01, 0x02, plsb, pmsb, vlsb, + vmsb, 0xf7 }; + write_sysex(request, 12); + // display request message in menu + static char buf[25]; + for (size_t i = 0; i < 12; i++) + sprintf(buf + 2 * i, "%02X", request[i]); + buf[24] = '\0'; + pd->display_status(buf); +} + +void MIDI::master_volume(int volume) const +{ + if (!midi_active) + return; + pmesg(40, "MIDI::master_volume() \n"); + uchar master_vol[] = + { 0xf0, 0x7f, midi_device_id, 0x04, 0x01, volume % 128, volume + / 128, 0xf7 }; + write_sysex(master_vol, 8); +} + +void MIDI::copy(int cmd, int src, int dst, int src_l, int dst_l, int rom_id) const +{ + if (!midi_active) + return; + pmesg( + 40, + "MIDI::copy(cmd: %X, src: %d, src_l: %d, dst: %d, dst_l: %d, rom: %d)\n", + cmd, src, src_l, dst, dst_l, rom_id); + if (dst < 0) + dst += 16384; + if (src < 0) + src += 16384; + // layer dependent + if (cmd > 0x24 && cmd < 0x2b) + { + uchar copy[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, cmd, src % 128, src / 128, + src_l, 0, dst % 128, dst / 128, dst_l, 0, rom_id % 128, rom_id + / 128, 0xf7 }; + write_sysex(copy, 17); + } + // layer independent + else + { + if (cmd == 0x2c) // copy setup + { + uchar copy[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, cmd, src % 128, + src / 128, dst % 128, dst / 128, 0xf7 }; + write_sysex(copy, 11); + // set device id to our chosen device id + // so it will respond to our requests + edit_parameter_value(388, midi_device_id); + // set sysex delay to our chosen setting + edit_parameter_value(405, request_delay); + } + else + { + uchar copy[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, cmd, src % 128, + src / 128, dst % 128, dst / 128, rom_id % 128, + rom_id / 128, 0xf7 }; + write_sysex(copy, 13); + } + } +} + +void MIDI::audit() const +{ + if (!midi_active) + return; + pmesg(40, "MIDI::audit()\n"); + // open session + uchar os[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x40, 0x10, 0xf7 }; + write_sysex(os, 8); + uchar press[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x40, 0x20, 0x04, 0x0, + 0x01, 0xf7 }; + write_sysex(press, 11); + uchar cs[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x40, 0x11, 0xf7 }; + write_sysex(cs, 8); +} + +void MIDI::randomize() const +{ + pmesg(40, "MIDI::randomize()\n"); + if (seed_randomizer) + { +#ifdef WINDOWS + srand(time(0)); + int byte1 = rand() % 16384; + int byte2 = rand() % 16384; +#else + srandom(time(0)); + int byte1 = random() % 16384; + int byte2 = random() % 16384; +#endif + uchar seedr[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x72, 0x7f, 0x7f, 0, 0, byte1 + % 128, byte1 / 128, byte2 % 128, byte2 / 128, 0xf7 }; + write_sysex(seedr, 15); + seed_randomizer = false; + } + uchar randomize[] = + { 0xf0, 0x18, 0x0f, midi_device_id, 0x55, 0x71, 0x7f, 0x7f, 0, 0, 0xf7 }; + write_sysex(randomize, 11); + + request_preset_dump(-1, 0); +} diff --git a/midi.H b/midi.H new file mode 100644 index 0000000..a75fa92 --- /dev/null +++ b/midi.H @@ -0,0 +1,190 @@ +// $Id$ +#ifndef MIDI_H_ +#define MIDI_H_ +/** + \defgroup pd_midi prodatum MIDI I/O + @{ +*/ +#include +#include +#include +#include +//#include "ringbuffer.H" + +#define MIDI_SYSEX 0xf0 +#define MIDI_EOX 0xf7 +#define NOTE_OFF 0x80 +#define NOTE_ON 0x90 + +#ifdef WINDOWS +# include +# define mysleep(x) Sleep(x) +#else +# include +# define mysleep(x) usleep(x * 1000) +#endif + +/** + * prodatum MIDI class. + * opens and closes MIDI ports, starts and stops the MIDI sender/receiver, + * allocates buffers for reading and writing MIDI data, populates the UI + * with available MIDI ports and offers many methods to send all kinds of + * sysex commands and MIDI events + */ +class MIDI +{ + /// vector for available readable MIDI ports + std::vector ports_in; + /// vector for writable MIDI ports + std::vector ports_out; + /// opened writable MIDI port + int selected_port_out; + /// opened readable MIDI port + int selected_port_in; + /// opened controller MIDI port + int selected_port_thru; + /// method to start the MIDI sender/receiver + int start_timer(); + /// method to stop the MIDI sender/receiver + void stop_timer(); + /** + * nibblelize an integer value + * creates two nibble bytes from an integer for MIDI transmission + * @param value the integer value to nibblelize + * @param lsb reference to the lsb value + * @param msb reference to the msb value + */ + void nibble(int value, unsigned char& lsb, unsigned char& msb) const; + +public: + /** + * CTOR for the MIDI class + * populates available MIDI ports to the UI and allocates storage for + * the ringbuffers, initializes default values + */ + MIDI(); + /** + * CTOR for the MIDI class + * frees allocated ringbuffers, closes all opened MIDI ports and stops + * the MIDI sender/receiver + */ + ~MIDI(); + /// populates the UI with available system MIDI ports + void populate_ports(); + /// allows for switching the device ID on the fly + void set_device_id(int id); + /// sets the incoming channel filter for the control port + void set_control_channel_filter(int channel); + /// sets the incoming channel filter + void set_channel_filter(int channel); + /** + * opens writable MIDI port, starts MIDI timer if not running yet. + * @param out the MIDI port to open + */ + int connect_out(int out); + /** + * opens readable MIDI port, starts MIDI timer if not running yet. + * @param in the MIDI port to open + */ + int connect_in(int in); + /** + * opens readable MIDI controller port, starts MIDI timer if not running yet. + * @param thru the MIDI port to open + */ + int connect_thru(int thru); + /** + * puts a sysex message into the write buffer. + * @param sysex the sysex data + * @param size the size of the message in bytes + */ + void write_sysex(const unsigned char* sysex, size_t size) const; + /** + * puts a MIDI event into the write buffer + * @param status MIDI status byte + * @param value1 first MIDI data byte + * @param value2 second MIDI data byte + * @param channel the channel to send the event on + */ + void write_event(int status, int value1, int value2, int channel = -1) const; + /** + * send an acknowledgement for a packet. + * @param packet the packet to acknowledge + */ + void ack(int packet) const; + /** + * send an negative acknowledgement for a packet. + * @param packet the packet to negative acknowledge + */ + void nak(int packet) const; + /// sends a cancel command + void cancel() const; + /// send WAIT command + void wait() const; + /// sends a EOF command + void eof() const; + /// sends a device inquiry + void request_device_inquiry(int id = -1) const; + /** + * sends a preset dump request. + * @param preset the preset number + * @param rom_id the ROM ID of the preset + */ + void request_preset_dump(int preset, int rom_id) const; + /// sends a setup dump request + void request_setup_dump() const; + // /// sends an FX dump request + // void request_fx_dump(int preset, int rom_id) const; + /// sends an arp dump request + void request_arp_dump(int number, int rom_id) const; + /** + * sends a parameter value request + * @param id the parameter ID + * @param channel the channel of the parameter + */ + //void request_parameter_value(int id, int channel = -1) const; + /** + * sends a generic name request. + * @param type the type of name (PRESET, INSTRUMENT, ..) + * @param number the items number + * @param rom_ID the ROM ID of the item + */ + void request_name(int type, int number, int rom_ID) const; + /** + * sends a parameter value edit command. + * @param id the parameter ID + * @param value the new value for the parameter + */ + void edit_parameter_value(int id, int value) const; + /** + * renames an item on the device. + * @param type the type of the item to rename (PRESET or ARP) + * @param number the number of the item to rename + * @param name the new name + */ + //void rename(int type, int number, const unsigned char* name) const; + /// sends a hardware configuration request + void request_hardware_config() const; + /** + * sets the master volume of the device + * @param volume the new volume + */ + void master_volume(int volume) const; + /** + * sends a copy command. + * @param cmd the type of copy command (copy preset/arp, patchcords, layer,..) + * @param src the source program + * @param dst the destination program + * @param src_l the source layer + * @param dst_l the destination layer + * @param rom_id the ROM ID of the source + */ + void copy(int cmd, int src, int dst, int src_l = 0, int dst_l = 0, + int rom_id = 0) const; + /// toggles audition on the device + void audit() const; + /// sends a randomize preset command + void randomize() const; +}; + +#endif /*MIDI_H_*/ +/** @} */ diff --git a/pd.C b/pd.C new file mode 100644 index 0000000..1ae91c3 --- /dev/null +++ b/pd.C @@ -0,0 +1,2201 @@ +// This file is part of prodatum. +// Copyright 2011 Jan Eidtmann +// +// prodatum 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 3 of the License, or +// (at your option) any later version. +// +// prodatum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with prodatum. If not, see . + +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +//#include +#include +#include +#include + +#include "pd.H" +#include "midi.H" +#include "ui.H" +#include "cfg.H" +#include "threads.H" + +#include "debug.H" + +static bool init_complete; +static int init_timeout; + +extern PD* pd; +extern MIDI* midi; +extern PD_UI* ui; +extern Cfg* cfg; +extern bool time_incoming_midi; +static int init_progress; +extern timeval tv_incoming; +extern FilterMap FM[51]; +// set in cfg +extern int request_delay; + +/** + * maps ROM ID's to an index in our rom array + * @see ROM() + */ +std::map rom_id_map; + +PD::PD() +{ + pmesg(40, "PD::PD() \n"); + setup_names = 0; + user_presets = 0; + roms = 0; + preset = 0; + preset_copy = 0; + preset_library = 0; + setup = 0; + setup_copy = 0; + setup_init = 0; + arp = 0; + selected_channel = -1; + selected_layer = -2; + selected_fx_channel = -2; + selected_multisetup = -2; + midi_mode = -1; + randomizing = false; + cc_changed = false; + nak_count = 0; + for (int i = 0; i < 4; i++) + { + mute_volume[i] = -100; + is_solo[i] = 0; + } + for (int i = 0; i < 5; i++) + rom[i] = 0; +} + +PD::~PD() +{ + pmesg(40, "PD::~PD() \n"); + for (int i = 0; i < 4; i++) // unmute eventually muted voices + mute(0, i); + // save setup_names + save_setup_names(cfg->get_cfg_option(CFG_DEVICE_ID)); + for (int i = 0; i <= roms; i++) + delete rom[i]; + if (preset) + delete preset; + if (preset_copy) + delete preset_copy; + if (preset_library) + delete preset_library; + if (setup) + delete setup; + if (setup_copy) + delete setup_copy; + if (setup_init) + delete setup_init; + if (setup_names) + delete[] setup_names; +} +/** + * watchdog to track initialization. + * returns when initialization is finished (no more data has been received + * since \c init_timeout) + * we need this because the number of riffs available on a rom + * cannot be requested + */ +static void *init_watchdog(void*) +{ + timeval tv_last_sleep; + timeval tv_sub; + gettimeofday(&tv_incoming, 0); + ++tv_incoming.tv_sec; + while (time_incoming_midi) + { + gettimeofday(&tv_last_sleep, 0); + mysleep (100); + tv_sub.tv_sec = tv_incoming.tv_sec - tv_last_sleep.tv_sec; + tv_sub.tv_usec = tv_incoming.tv_usec - tv_last_sleep.tv_usec; + if (tv_sub.tv_usec < 0) + { + --tv_sub.tv_sec; + tv_sub.tv_usec += 1000000; + } + //pmesg(90, "wd time: %d\n", tv_sub.tv_sec * 1000000 + tv_sub.tv_usec); + if ((tv_sub.tv_sec * 1000000 + tv_sub.tv_usec) < init_timeout) + time_incoming_midi = false; + } + return 0; +} + +/** + * updates UI at initialization and triggers setup dump request when done. + * also triggers setup name downloads + */ +static void wait_for_init(void*) +{ + pmesg(40, "wait_for_init() \n"); + static char buf[30]; + if (init_complete && !time_incoming_midi) + { + // might have been canceled + if (ui->init->shown()) + { + // wait a bit, might loading a setup here which + // makes the device ignore all requests + mysleep (25); + // load setup + pd->load_setup(); + ui->init->hide(); + } + Fl::remove_timeout(wait_for_init, 0); + } + else + { + // might have been canceled + if (ui->init->shown()) + { + if (!time_incoming_midi) + ui->init_progress->value((float) init_progress); + else + { + snprintf(buf, 30, "Loading RIFF/ARP names: %d", init_progress); + ui->init_progress->label(buf); + } + Fl::repeat_timeout(.1, wait_for_init); + } + else + Fl::remove_timeout(wait_for_init, 0); + } +} + +/** + * displays text in the status bar for one second + */ +static void check_loading(void*) +{ + pmesg(40, "check_loading() \n"); + if (ui->loading_w->shown()) + ui->loading_w->hide(); + Fl::remove_timeout(check_loading, 0); +} + +void PD::loading() +{ + pmesg(40, "PD::loading() \n"); + Fl::remove_timeout(check_loading, 0); + ui->loading_w->free_position(); + ui->loading_w->show(); + Fl::add_timeout(4. + 8 * ((float) request_delay / 1000.), check_loading, 0); +} + +/** + * displays text in the status bar for 2 seconds + */ +static bool launch = true; +static void status(void* p) +{ + pmesg(80, "status() \n"); + static char message[40]; + if ((char*) p) + { + strncpy(message, (char*) p, 40); + ui->status->label(message); + if (launch) + Fl::repeat_timeout(1.5, status); + else + Fl::repeat_timeout(.8, status); // dont display system message too long + } + else + { + launch = true; + if (!pd->status_message.empty()) + { + strncpy(message, pd->status_message.back().c_str(), 40); + pd->status_message.clear(); // delete old messages + ui->status->label(message); + Fl::repeat_timeout(1.5, status); + return; + } + ui->status->label(0); + Fl::remove_timeout(status, 0); + } +} + +// currently spasce for ~30 characters max! +void PD::display_status(const char* message, bool top) +{ + pmesg(40, "PD::display_status(%s, %s) \n", message, top ? "true" : "false"); + if (top) // important stuff + { + if (!launch) + status_message.push_back(message); + else + { + launch = false; + Fl::remove_timeout(status, 0); + Fl::add_timeout(0, status, (void*) message); + } + } + else + { + if (launch) + { + Fl::remove_timeout(status, 0); + Fl::add_timeout(0, status, (void*) message); + } + else + status_message.push_back(message); + } +} + +void PD::init_arp_riff_names() +{ + pmesg(40, "PD::init_arp_riff_names() \n"); + time_incoming_midi = true; + init_complete = true; + names_to_download = 0; + for (int j = 1; j <= roms; j++) + { + if (member_code != AUDITY) + names_to_download += rom[j]->load_names(RIFF, 0); + names_to_download += rom[j]->load_names(ARP, 0); + } + if (names_to_download) + { + ui->init_progress->value((float) names_to_download); + init_progress = 0; + // launch init watchdog + Fl_Thread watchdog_t; + fl_create_thread(watchdog_t, init_watchdog, 0); + } + else + time_incoming_midi = false; +} + +void PD::widget_callback(int id, int value, int layer) +{ + pmesg(40, "PD::widget_callback(%d, %d, %d) \n", id, value, layer); + if (!setup) + return; + // browser returns -1 when user clicked on empty space + if (value == -1 && (id == 278 || id == 643 || id == 897 || id == 928 || id + == 1027 || id == 1409)) + { + int current = 0; + // reselect the previous selection for them + switch (id) + { + case (278): // master riff + current = setup->get_value(id); + break; + case (643): // master arp + current = setup->get_value(id); + break; + case 897: // preset + current = setup->get_value(130, selected_channel); + break; + case 1409: // intrument + current = preset->get_value(id, layer); + break; + default: // arp/riff + current = preset->get_value(id); + } + if (layer == -2) + pwid[id][0]->set_value(current); + else + pwid[id][layer]->set_value(current); + return; + } + // channel changed + if (id == 129) + { + if (ui->b_copy_p->value()) + { + ui->b_copy_p->value(0); + ui->b_copy_p->do_callback(); + } + else if (ui->b_save_p->value()) + { + ui->b_save_p->value(0); + ui->b_save_p->do_callback(); + } + selected_channel = value; + // select multimode channel (to make pan and channel related controls work) + midi->edit_parameter_value(id, selected_channel); + // select basic channel (to get the edit buffer of the channels preset below) + midi->edit_parameter_value(139, selected_channel); + // update midi input filter + midi->set_channel_filter(selected_channel); + // request preset data + selected_preset_rom = setup->get_value(138, selected_channel); + selected_preset = setup->get_value(130, selected_channel); + ui->preset_rom->set_value(selected_preset_rom); + ui->preset->set_value(selected_preset); + midi->request_preset_dump(-1, 0); + // FX channel + if (midi_mode != MULTI) + pwid[140][0]->set_value(selected_channel); + // multimode channel specific (update channel controls (pan etc)) + for (int i = 131; i < 138; i++) + if (pwid[i][0]) + pwid[i][0]->set_value(setup->get_value(i, selected_channel)); + ui->global_minipiano->reset_active_keys(); + ui->main->minipiano->reset_active_keys(); + ui->piano->reset_active_keys(); + return; + } + if (id == 897) // preset_select (this is effectively id 130 (MULTIMODE_PRESET)) + { + // do nothing if the preset didn't change + if (setup->set_value(130, value, selected_channel)) + { + selected_preset = value; + midi->write_event(0xb0, 0, selected_preset_rom, selected_channel); + midi->write_event(0xb0, 32, selected_preset / 128, selected_channel); + midi->write_event(0xc0, selected_preset % 128, 0, selected_channel); + midi->request_preset_dump(-1, 0); + } + return; + } + // select editing layer + if (layer != selected_layer && layer != -2 && !ui->eall) + { + selected_layer = layer; + midi->edit_parameter_value(898, selected_layer); + } + // volume, honor mute state ") + if (id == 1410 && mute_volume[selected_layer] != -100) + { + mute_volume[selected_layer] = value; + return; + } + // update changes locally + int ret = 0; + if (id > 898) + { + if (ui->eall) + for (int i = 0; i < 4; i++) + ret |= preset->set_value(id, value, i); + else + ret = preset->set_value(id, value, selected_layer); + } + else + ret = setup->set_value(id, value, selected_channel); + // update changes remotely but only if we really changed something + if (ret == 1) + midi->edit_parameter_value(id, value); + else + return; + + // id's which have deps and need further updates below + switch (id) + { + case 135: // channel enable + if (value == 0) + { + ui->main->minipiano->reset_active_keys(); + ui->global_minipiano->reset_active_keys(); + ui->piano->reset_active_keys(); + } + return; + case 138: // preset rom select + selected_preset_rom = value; + midi->write_event(0xb0, 0, selected_preset_rom, selected_channel); + midi->write_event(0xb0, 32, selected_preset / 128, selected_channel); + midi->write_event(0xc0, selected_preset % 128, 0, selected_channel); + midi->request_preset_dump(-1, 0); + return; + case 140: // FX channel + selected_fx_channel = value; + if (midi_mode != MULTI || selected_fx_channel != -1) + preset->show_fx(); + else + setup->show_fx(); + return; + case 385: // MIDI Mode + if (value != MULTI) + { + if (midi_mode == MULTI) + { + pwid[140][0]->set_value(selected_channel); + preset->show_fx(); + ui->main->mix_out->deactivate(); + for (int i = 0; i < 4; i++) + ui->main->layer_strip[i]->mix_out->activate(); + } + midi_mode = value; + } + else // multimode + { + midi_mode = value; + pwid[140][0]->set_value(selected_fx_channel); + if (selected_fx_channel != -1) + preset->show_fx(); + else + setup->show_fx(); + ui->main->mix_out->get_value(); + ui->main->mix_out->activate(); + } + return; + case 1537: // Filter type + for (int i = 0; i <= 50; i++) + if (FM[i].value == value) + { + Fl_Tooltip::exit((Fl_Widget*) pwid[id][layer]); + ui->main->layer_strip[layer]->filter->tooltip(FM[i].info); + break; + } + return; + case 513: // fx types + case 520: + case 1153: + case 1160: + update_fx_values(id, value); + return; + } + // controller mapping changed + if ((id > 390 && id < 402) || (id > 405 && id < 410)) + update_control_map(); + // update cc controler values when we change initial amounts + else if ((id > 914 && id < 928) && id != 923) + ((Fl_Slider*) ui->main->ctrl_x[(id > 922) ? id - 915 : id - 914])->value( + (double) value); +} + +void PD::update_cc_sliders() +{ + pmesg(40, "PD::update_cc_sliders() \n"); + if (!preset) + return; + ui->main->b_store->deactivate(); + cc_changed = false; + int tmp = preset->get_value(915); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[1])->value((double) tmp); + tmp = preset->get_value(916); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[2])->value((double) tmp); + tmp = preset->get_value(917); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[3])->value((double) tmp); + tmp = preset->get_value(918); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[4])->value((double) tmp); + tmp = preset->get_value(919); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[5])->value((double) tmp); + tmp = preset->get_value(920); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[6])->value((double) tmp); + tmp = preset->get_value(921); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[7])->value((double) tmp); + tmp = preset->get_value(922); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[8])->value((double) tmp); + tmp = preset->get_value(924); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[9])->value((double) tmp); + tmp = preset->get_value(925); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[10])->value((double) tmp); + tmp = preset->get_value(926); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[11])->value((double) tmp); + tmp = preset->get_value(927); + if (tmp != -1) + ((Fl_Slider*) ui->main->ctrl_x[12])->value((double) tmp); +} + +void PD::update_control_map() +{ + pmesg(40, "PD::update_control_map() \n"); + // cc to controller + cc_to_ctrl.clear(); + cc_to_ctrl[setup->get_value(391)] = 1; + cc_to_ctrl[setup->get_value(392)] = 2; + cc_to_ctrl[setup->get_value(393)] = 3; + cc_to_ctrl[setup->get_value(394)] = 4; + cc_to_ctrl[setup->get_value(395)] = 5; + cc_to_ctrl[setup->get_value(396)] = 6; + cc_to_ctrl[setup->get_value(397)] = 7; + cc_to_ctrl[setup->get_value(398)] = 8; + cc_to_ctrl[setup->get_value(406)] = 9; + cc_to_ctrl[setup->get_value(407)] = 10; + cc_to_ctrl[setup->get_value(408)] = 11; + cc_to_ctrl[setup->get_value(409)] = 12; + // fottswitches + cc_to_ctrl[setup->get_value(399)] = 13; + cc_to_ctrl[setup->get_value(400)] = 14; + cc_to_ctrl[setup->get_value(401)] = 15; + // vice versa + ctrl_to_cc.clear(); + ctrl_to_cc[1] = setup->get_value(391); + ctrl_to_cc[2] = setup->get_value(392); + ctrl_to_cc[3] = setup->get_value(393); + ctrl_to_cc[4] = setup->get_value(394); + ctrl_to_cc[5] = setup->get_value(395); + ctrl_to_cc[6] = setup->get_value(396); + ctrl_to_cc[7] = setup->get_value(397); + ctrl_to_cc[8] = setup->get_value(398); + ctrl_to_cc[9] = setup->get_value(406); + ctrl_to_cc[10] = setup->get_value(407); + ctrl_to_cc[11] = setup->get_value(408); + ctrl_to_cc[12] = setup->get_value(409); + // footswitches + ctrl_to_cc[13] = setup->get_value(399); + ctrl_to_cc[14] = setup->get_value(400); + ctrl_to_cc[15] = setup->get_value(401); +} + +void PD::cc_callback(int controller, int value) +{ + pmesg(40, "PD::cc_callback(%d, %d) \n", controller, value); + midi->write_event(0xb0, ctrl_to_cc[controller], value, selected_channel); + if (!cc_changed) + { + ui->main->b_store->activate(); + cc_changed = true; + } +} + +void PD::store_play_as_initial() +{ + if (!preset) + return; + pmesg(40, "PD::store_play_as_initial() \n"); + ui->main->b_store->deactivate(); + cc_changed = false; + widget_callback(915, (int) ((Fl_Slider*) ui->main->ctrl_x[1])->value()); + widget_callback(916, (int) ((Fl_Slider*) ui->main->ctrl_x[2])->value()); + widget_callback(917, (int) ((Fl_Slider*) ui->main->ctrl_x[3])->value()); + widget_callback(918, (int) ((Fl_Slider*) ui->main->ctrl_x[4])->value()); + widget_callback(919, (int) ((Fl_Slider*) ui->main->ctrl_x[5])->value()); + widget_callback(920, (int) ((Fl_Slider*) ui->main->ctrl_x[6])->value()); + widget_callback(921, (int) ((Fl_Slider*) ui->main->ctrl_x[7])->value()); + widget_callback(922, (int) ((Fl_Slider*) ui->main->ctrl_x[8])->value()); + widget_callback(924, (int) ((Fl_Slider*) ui->main->ctrl_x[9])->value()); + widget_callback(925, (int) ((Fl_Slider*) ui->main->ctrl_x[10])->value()); + widget_callback(926, (int) ((Fl_Slider*) ui->main->ctrl_x[11])->value()); + widget_callback(927, (int) ((Fl_Slider*) ui->main->ctrl_x[12])->value()); + for (int i = 915; i < 928; i++) + if (pwid[i][0] && i != 923) + pwid[i][0]->set_value(preset->get_value(i)); +} + +// if autoconnection is enabled but the device is not powered +// we end up with an unconnected main window. to show the open +// dialog instead we use this timeout (in connect below) +static void check_connection(void* p) +{ + pmesg(40, "check_connection() \n"); + if (*(int*) p == 0 && !ui->init->shown()) + ui->open_device->show(); + Fl::remove_timeout(check_connection); +} + +#ifdef DEBUG +void _test_s(int n) +{ + pmesg(40, "_test_s(%d)\n", n); + int skip = 0; + // first fill the arp browser + if (pwid[660][0]) + pwid[660][0]->set_value(n); + for (int i = 140; i <= 787; i++) + { + // skip fx and browsers + if (pwid[i][0] && (!((i > 512 && i < 529) || i == skip || i == 660))) + pwid[i][0]->set_value(n); + } + // show fx + for (int i = 513; i < 529; i++) + if (pwid[i][0]) + pwid[i][0]->set_value(n); +} +void _test_p(int n) +{ + pmesg(40, "_test_p(%d)\n", n); + char buf[30]; + snprintf(buf, 30, "%d", n); + ui->main->preset_name->copy_label((char*) buf); + ui->n_n_m->copy_label(buf); + ui->n_name_m->value(buf); + ui->n_cat_m->value((const char*) buf); + // first we wanna load the names into the browsers + // so they are available for selection + for (int j = 0; j < 4; j++) + if (pwid[1439][j]) // instruments + pwid[1439][j]->set_value(n); + if (pwid[929][0]) // riffs + pwid[929][0]->set_value(n); + if (pwid[1042][0]) // arp + pwid[1042][0]->set_value(n); + if (pwid[1299][0]) // link 1 + pwid[1299][0]->set_value(n); + if (pwid[1300][0]) // link 2 + pwid[1300][0]->set_value(n); + + for (int i = 915; i <= 1300; i++) // preset params + + { + if ((i > 1152 && i < 1169) || i == 929) // skip fx & riff rom + continue; + if (pwid[i][0]) + pwid[i][0]->set_value(n); + } + for (int i = 1409; i <= 1992; i++) // layer params + + { + // skip roms + if (i == 1439 || i == 1042 || i == 1299 || i == 1300) + continue; + for (int j = 0; j < 4; j++) + if (pwid[i][j]) + pwid[i][j]->set_value(n); + } + //update_piano(); + int id = 1413; + for (int m = 0; m < 3; m++) // modes + for (int i = 0; i < 4; i++) // layers + ui->piano->set_range_values(m, i, n, n, n, n); + // arp ranges + ui->piano->set_range_values(0, 4, n, 0, n, 0); + ui->piano->set_range_values(0, 5, n, 0, n, 0); + // link ranges + ui->piano->set_range_values(0, 6, n, 0, n, 0); + ui->piano->set_range_values(0, 7, n, 0, n, 0); + // transpose + ui->piano->set_transpose(n, n, n, n); + //update_envelopes(); + static int stages[12]; + id = 1793; + for (int l = 0; l < 4; l++) // for all 4 layers + + { + for (int m = 0; m < 3; m++) // for all three envelopes + + { + for (int i = 0; i < 6; i++) + { + *(stages + i * 2) = n; + *(stages + i * 2 + 1) = n; + } + ui->layer_editor[l]->envelope_editor->set_data(m, stages, n, n); + } + } + // show_fx() + for (int i = 1153; i < 1169; i++) + if (pwid[i][0]) + pwid[i][0]->set_value(n); +} +void test() +{ + for (int i = -1; i <= 256; i++) + { + _test_p(i); + _test_s(i); + Fl::wait(.05); + } +} +#endif // DEBUG +void PD::connect() +{ +#ifdef DEBUG + test(); + return; +#endif + pmesg(40, "PD::connect() \n"); + if (!cfg->get_cfg_option(CFG_AUTOCONNECT)) + ui->open_device->show(); + int p_out = cfg->get_cfg_option(CFG_MIDI_OUT); + int p_in = cfg->get_cfg_option(CFG_MIDI_IN); + int p_thru = cfg->get_cfg_option(CFG_MIDI_THRU); + device_code = 0; + if (p_out != -1) + { + if (midi->connect_out(p_out)) + { + ui->midi_outs->label(ui->midi_outs->text(p_out)); + ui->midi_outs->value(p_out); + } + else + { + p_out = -1; + display_status("*** Failed to open Out-Port.", true); + } + } + if (p_in != -1) + { + if (midi->connect_in(p_in)) + { + ui->midi_ins->label(ui->midi_ins->text(p_in)); + ui->midi_ins->value(p_in); + } + else + { + p_in = -1; + display_status("*** Failed to open In-Port.", true); + } + } + if (p_thru != -1) + { + if (midi->connect_thru(p_thru)) + { + ui->midi_ctrl->label(ui->midi_ctrl->text(p_thru)); + ui->midi_ctrl->value(p_thru); + } + else + { + p_thru = -1; + //fl_message("Failed to open Ctrl-Port"); + display_status("*** Failed to open Ctrl-Port.", true); + } + } + if (p_out == -1 || p_in == -1) + ui->open_device->show(); + else + Fl::add_timeout(.5, check_connection, (void*) &device_code); +} + +void PD::initialize() +{ + pmesg(40, "PD::initialize() \n"); + for (int i = 0; i < 5; i++) + for (int j = 0; j < 7; j++) + name_counter[i][j] = 0; + // reset patchcord source widgets (for MNOP controllers) + for (int i = 0; i < 4; i++) + ui->layer_editor[i]->patchcords->uninitialize_sources(); + ui->preset_editor->patchcords->uninitialize_sources(); + // load names + names_to_download = 0; + // check for preset, instrument and arp files + for (int j = 0; j <= roms; j++) + { + names_to_download += rom[j]->load_names(PRESET, 0); + if (j == 0) // rom arp quantity unknown + names_to_download += rom[j]->load_names(ARP, 0); + if (j == 0) + continue; + names_to_download += rom[j]->load_names(INSTRUMENT, 0); + } + if (names_to_download) + ui->init_progress->label("Loading ROM data"); + // check for setup file + if (!names_to_download && load_setup_names(0, true)) + { + ui->init_progress->label("Loading Setup names"); + names_to_download = load_setup_names(0, false); + } + // check for riff files + if (!names_to_download) + init_arp_riff_names(); + if (names_to_download) + { + init_progress = 0; + ui->init_progress->maximum((float) names_to_download); + ui->init->show(); + ui->connect->deactivate(); + // set timeout level + init_timeout = -1000000; + midi_mode = -1; // if this gets != -1 we are finished (used by ~ROM()) + Fl::add_timeout(.1, wait_for_init); + } + else + { + init_complete = true; + // all names here, load setup + load_setup(); + } +} + +// callback for cancel button on init +void PD::cancel_init() +{ + pmesg(40, "PD::cancel_init() \n"); + midi->cancel(); + if (setup_init) + { + setup_init->upload(); + delete setup_init; + setup_init = 0; + } + names_to_download = -1; + init_complete = true; + time_incoming_midi = false; + delete midi; + midi = new MIDI(); + ui->midi_outs->label("Select..."); + ui->midi_ins->label("Select..."); + ui->midi_ctrl->label("Select... (optional)"); + ui->device_info->label(0); + int selection; + selection = cfg->get_cfg_option(CFG_MIDI_OUT); + if (selection != -1) + { + ui->midi_outs->value(selection); + ui->midi_outs->do_callback(); + } + selection = cfg->get_cfg_option(CFG_MIDI_IN); + if (selection != -1) + { + ui->midi_ins->value(selection); + ui->midi_ins->do_callback(); + } + selection = cfg->get_cfg_option(CFG_MIDI_THRU); + if (selection != -1) + { + ui->midi_ctrl->value(selection); + ui->midi_ctrl->do_callback(); + } + ui->init->hide(); + ui->open_device->show(); +} + +//void PD::start_stopwatch() +//{ +// gettimeofday(&tv_start, 0); +//} +// +//void PD::stop_stopwatch() +//{ +// gettimeofday(&tv_stop, 0); +// timeval tv_sub; +// tv_sub.tv_sec = tv_stop.tv_sec - tv_start.tv_sec; +// tv_sub.tv_usec = tv_stop.tv_usec - tv_start.tv_usec; +// if (tv_sub.tv_usec < 0) +// { +// --tv_sub.tv_sec; +// tv_sub.tv_usec += 1000000; +// } +// char message[20]; +// snprintf(message, 20, "%ld", tv_sub.tv_usec + tv_sub.tv_sec * 1000000); +// ui->main->stopwatch->value(message); +//} + +void PD::create_device_info() +{ + pmesg(40, "PD::create_device_info()\n"); + // if we cancelled initialisation of roms, return here + if (!rom[1]) + return; + char buf[512]; + snprintf(buf, 512, "%s (%s) with %d ROM%s", get_name(member_code), os_rev, + roms, (roms > 1 || roms == 0) ? "s:" : ":"); + std::string info; + info += buf; + if (roms == 0) + { + snprintf(buf, 512, "\nNo ROM installed"); + info += buf; + } + else + { + for (int i = 1; i <= roms; i++) + { + snprintf(buf, 512, "\n - %s: %d sam, %d prg", rom[i]->name(), + rom[i]->get_attribute(INSTRUMENT), + rom[i]->get_attribute(PRESET)); + info += buf; + } + } + ui->device_info->copy_label(info.data()); + pmesg(40, "%s\n", info.data()); + // TODO: warn about outdated OS + // if (member_code != AUDITY && strncmp(os_rev, "2.26", 4) != 0) + // fl_message( + // "Your OS (%s) is out of date!\nPlease get and install the latest OS (2.26) from\n" + // "http://www.emu.com/support/ to ensure smooth operation.", + // os_rev); +} + +// device infos +void PD::incoming_inquiry_data(const unsigned char* data, int len) +{ + pmesg(40, "PD::incoming_inquiry_data(data, %d) \n", len); + display_status("Received device inquiry."); + device_code = data[7] * 128 + data[6]; + if (device_code == 516) + { + member_code = data[9] * 128 + data[8]; + snprintf(os_rev, 5, "%c%c%c%c", data[10], data[11], data[12], data[13]); + if ((int) ui->device_id->value() != (int) data[2]) + { + midi->set_device_id((int) data[2]); + ui->device_id->value((double) data[2]); + ui->r_user_id->value((double) data[2]); + } + midi->request_hardware_config(); + switch (member_code) + { + case AUDITY: + ui->main->b_audit->hide(); + ui->m_audit->hide(); + ui->main->g_riff->deactivate(); + ui->preset_editor->g_riff->deactivate(); + ui->main->post_d->hide(); + ui->main->pre_d->label("Delay"); + ui->preset_editor->post_d->hide(); + ui->preset_editor->pre_d->label("Delay"); + break; + default: + ui->main->b_audit->show(); + ui->m_audit->show(); + ui->main->g_riff->activate(); + ui->preset_editor->g_riff->activate(); + ui->main->post_d->show(); + ui->main->pre_d->label("Pre D"); + ui->preset_editor->post_d->show(); + ui->preset_editor->pre_d->label("Pre D"); + } + } +} + +void PD::incoming_hardware_config(const unsigned char* data, int len) +{ + pmesg(40, "PD::incoming_hardware_config(data, %d) \n", len); + init_complete = false; + display_status("Received device configuration."); + user_presets = data[8] * 128 + data[7]; + roms = data[9]; + rom_id_map.clear(); + rom_id_map[0] = 0; + // save possible previous setup names + save_setup_names(cfg->get_cfg_option(CFG_DEVICE_ID)); + // init roms + // make sure to delete all roms, not just those for this device + // (we might have been connected to a device with more roms before! + delete rom[0]; + rom[0] = new ROM(0, user_presets); + for (int j = 1; j < 5; j++) + { + delete rom[j]; + if (j > roms) + continue; + int idx = 11 + (j - 1) * 6; + rom[j] = new ROM(data[idx + 1] * 128 + data[idx], + data[idx + 3] * 128 + data[idx + 2], + data[idx + 5] * 128 + data[idx + 4]); + rom_id_map[data[idx + 1] * 128 + data[idx]] = j; + } + create_device_info(); + // sysex delay is saved with the multisetup + // set sysex delay to our chosen setting + midi->edit_parameter_value(405, request_delay); + if (roms != 0) + { + ui->connect->activate(); + if (!ui->open_device->shown()) + //initialize(); + midi->request_setup_dump(); + } + else + ui->open_device->show(); +} + +void PD::incoming_setup_dump(const unsigned char* data, int len) +{ + pmesg(40, "PD::incoming_setup_dump(data, %d) \n", len); + display_status("Received setup dump."); + selected_multisetup = data[0x4A]; // needed to select it in the multisetup choice + if (!init_complete) + { + // cache currently used setup for later upload + setup_init = new Setup_Dump(len, data); + initialize(); + return; + } + if (setup) + { + delete setup; + delete setup_copy; + } + setup = new Setup_Dump(len, data); + setup_copy = new Setup_Dump(len, data); + load_setup(); +} + +void PD::load_setup() +{ + pmesg(40, "PD::load_setup() \n"); + display_status("Loading setup..."); + if (setup_init) + { + setup = new Setup_Dump(setup_init->get_dump_size(), + setup_init->get_data()); + setup_copy = new Setup_Dump(setup_init->get_dump_size(), + setup_init->get_data()); + if (ui->init->shown()) + setup->upload(); // re-load previously used setup + delete setup_init; + setup_init = 0; + } + if (!setup) // might have been called before the device sent the dump + return; + midi_mode = setup->get_value(385); + selected_fx_channel = setup->get_value(140); + + // select first entry in the reset rom choice + ui->r_rom_rom->value(0); + + // load names into the copy browser + ui->copy_arp_rom->set_value(0); + ui->copy_arp_pattern_browser->load_n(ARP, 0); + + // multisetups + ui->multisetups->select(selected_multisetup + 1); + ui->multisetups->activate(); + char n[17]; + snprintf(n, 17, "%s", setup_names + 16 * selected_multisetup); + while (n[strlen(n) - 1] == ' ') + n[strlen(n) - 1] = '\0'; + ui->s_name->value(n); + // show setup + setup->show(); + // select basic channel on startup + pwid[129][0]->set_value(setup->get_value(139)); + ui->main->channel_select->do_callback(); + // get realtime controller assignments + update_control_map(); +} + +void PD::incoming_preset_dump(const unsigned char* data, int len) +{ + pmesg(40, "PD::incoming_preset_dump(data, %d) \n", len); + //static int packets; + static unsigned char dump[1615]; + static int dump_pos = 0; + static int packet_size = 0; + static bool closed_loop; + static int number; + if (dump_pos + len > 1615) + { + fl_message("Preset dump larger than expected!\nPlease report!"); + return; + } + // preset dump header + if (data[6] == 0x01 && dump_pos == 0) // closed loop (requires ACKs) + { + //pmesg(40, "PD::incoming_preset_dump(len: %d) header (closed)\n", len); + midi->ack(0); + closed_loop = true; + dump_pos = len; + ui->progress->value((float) dump_pos); + number = data[7] + 128 * data[8]; + if (number >= 8192) + number -= 16384; + memcpy(dump, data, len); + } + else if (data[6] == 0x03 && dump_pos == 0) // open loop + { + //pmesg(40, "PD::incoming_preset_dump(len: %d) header (open)\n", len); + closed_loop = false; + dump_pos = len; + ui->progress->value((float) dump_pos); + number = data[7] + 128 * data[8]; + if (number >= 8192) + number -= 16384; + memcpy(dump, data, len); + } + // preset dump data message + else + { + // didn't receive a header + if (!dump_pos) + return; + ui->progress->value((float) dump_pos); + if (closed_loop) + { + //pmesg(40, "PD::incoming_preset_dump(len: %d) data (closed)\n", len); + // calculate checksum + int sum = 0; + for (int i = 9; i < len - 2; i++) + sum += data[i]; + unsigned char checksum = ~sum; + // compare checksums + if (checksum % 128 != data[len - 2]) + midi->nak(data[8] * 128 + data[7]); + else + { + midi->ack(data[8] * 128 + data[7]); + memcpy(dump + dump_pos, data, len); + dump_pos += len; + if (len < 253) // last packet + { + delete preset; + if (randomizing) + { + preset = new Preset_Dump(dump_pos, dump, packet_size); + preset->set_changed(true); + randomizing = false; + } + else + preset = new Preset_Dump(dump_pos, dump, packet_size, + true); + // store a copy + delete preset_copy; + preset_copy = new Preset_Dump(dump_pos, dump, packet_size); + dump_pos = 0; + } + else + packet_size = len; + } + } + else + { + //pmesg(40, "PD::incoming_preset_dump(len: %d) data (open)\n", len); + memcpy(dump + dump_pos, data, len); + dump_pos += len; + if (len < 253) // last packet + { + delete preset; + if (randomizing) + { + preset = new Preset_Dump(dump_pos, dump, packet_size); + preset->set_changed(true); + randomizing = false; + } + else + preset = new Preset_Dump(dump_pos, dump, packet_size, true); + // store a copy + delete preset_copy; + preset_copy = new Preset_Dump(dump_pos, dump, packet_size); + dump_pos = 0; + } + else + packet_size = len; + } + } + if (dump_pos == 0) + { + ui->progress->value(1600.); + show_preset(); + display_status("Edit buffer loaded."); + // only activate preset selection if program + // change is enabled for the channel + if (setup && setup->get_value(137, selected_channel)) + ui->g_preset->activate(); + else + ui->g_preset->deactivate(); + // hide loading window + ui->loading_w->hide(); + } +} + +void PD::show_preset(bool lib) +{ + pmesg(40, "PD::show_preset(%s) \n", lib ? "library" : "preset"); + // update ui controls + ui->set_eall(0); + if (lib) + { + preset_library->show(); + return; + } + preset->show(); + if (ui->piano_w->shown()) + ui->piano->redraw(); + update_cc_sliders(); + ui->undo_b->deactivate(); + ui->redo_b->deactivate(); + // clear solo/mute buttons + for (int i = 0; i < 4; i++) + { + is_solo[i] = 0; + ui->solo_b[i]->value(0); + ui->main->layer_strip[i]->solo_b->value(0); + mute_volume[i] = -100; + ui->mute_b[i]->value(0); + ui->main->layer_strip[i]->mute_b->value(0); + } +} + +void PD::incoming_arp_dump(const unsigned char* data, int len) +{ + pmesg(40, "PD::incoming_arp_dump(data, %d)\n", len); + // on init we are only interested in the names + if (names_to_download == -1) + return; + if (time_incoming_midi) // init + { + if (data[14] < 32) // not ascii + return; + // some roms dont have arpeggios and return "(not instld)" + if (strncmp((const char*) data + 14, "(not", 4) == 0) + return; + int number = data[6] + 128 * data[7]; + if (number > MAX_ARPS) + { + pmesg( + 10, + "PD::incoming_arp_dump(len: %d) *** returning: MAX_ARPS reached\n", + len); + return; + } + int rom_id = data[len - 3] + 128 * data[len - 2]; + if (rom_id_map.find(rom_id) != rom_id_map.end()) + { + pmesg(90, "PD::incoming_arp_dump(len:%d) (#:%d-%d)\n ", len, + number, data[len - 3] + 128 * data[len - 2]); + rom[rom_id_map[rom_id]]->load_names(ARP, number + 1); + rom[rom_id_map[rom_id]]->set_name(ARP, number, data + 14); + ++init_progress; + } + } + else // this is a dump we like to edit ") + { + delete arp; + arp = new Arp_Dump(len, data); + display_status("Arp dump loaded."); + } +} + +//void PD::incoming_pc_dump(const unsigned char* data, int len) +//{ +// pmesg(40, "PD::incoming_pc_dump(len: %d) \n", len); +//} + +void PD::incoming_generic_name(const unsigned char* data) +{ + if (names_to_download == -1) + return; + // received a name of type PRESET(=1) with an identifier of 17 + // Hopefully this fixes incomplete initializations + unsigned char type = data[6] % 0xF; + if (type < PRESET || type > RIFF) + { + pmesg(1, "*** unknown name type %d\n", type); + display_status("*** Received unknown name type.", true); + cancel_init(); + return; + } + int rom_id; + if (rom_id_map.find(data[9] + 128 * data[10]) != rom_id_map.end()) + rom_id = rom_id_map[data[9] + 128 * data[10]]; + else + { + pmesg(1, "*** ROM %d does not exist\n", data[9] + 128 * data[10]); + display_status("*** Received unknown name type.", true); + cancel_init(); + return; + } + int number = data[7] + 128 * data[8]; + pmesg(40, "PD::incoming_generic_name(data) (#:%d-%d, type:%d)\n", number, + data[9] + 128 * data[10], type); + // number of riffs unknown + if (type == RIFF) + if (number > MAX_RIFFS || (data[11] == 'f' && data[12] == 'f') + || data[11] < 32) + return; + if (type == SETUP) + { + if (number != name_counter[rom_id][type]) + { + display_status("*** Received bogus name.", true); + cancel_init(); + return; + } + set_setup_name(number, data + 11); + ++init_progress; + ++name_counter[rom_id][type]; + --names_to_download; + if (names_to_download) + load_setup_names(name_counter[rom_id][type], false); + else + { + load_setup_names(name_counter[rom_id][type], false); // setup 63 (not a bug!) + init_arp_riff_names(); + } + } + else // load next (chunk of) name(s) + { + if (number != name_counter[rom_id][type] || !rom[rom_id]->set_name( + type, number, data + 11)) + { + display_status("*** Received bogus name.", true); + cancel_init(); + return; + } + ++init_progress; + ++name_counter[rom_id][type]; + --names_to_download; + if (names_to_download) + rom[rom_id]->load_names(type, name_counter[rom_id][type]); + else + { + names_to_download = load_setup_names(0, true); + if (names_to_download) + { + ui->init_progress->label("Loading Setup names"); + ui->init_progress->maximum(64.); + ui->init_progress->value(0.); + init_progress = 0; + load_setup_names(0, false); + } + else + init_arp_riff_names(); + } + } +} + +void PD::incoming_ERROR(int cmd, int sub) +{ + pmesg(40, "PD::incoming_ERROR(cmd: %X, subcmd: %X) \n", cmd, sub); + display_status("Received ERROR."); + +} + +void PD::incoming_ACK(int packet) +{ + pmesg(40, "PD::incoming_ACK(packet: %d) \n", packet); + display_status("Received ACK."); + if (preset_library) + preset_library->upload(++packet); + else if (preset) + preset->upload(++packet); + nak_count = 0; +} + +void PD::incoming_NAK(int packet) +{ + pmesg(40, "PD:incoming_NAK:(packet: %d) \n", packet); + display_status("Received NAK. Retrying..."); + if (preset && nak_count < 3) + { + preset->upload(packet); + ++nak_count; + } + else + fl_message("Closed Loop Upload failed!\nData is currupt."); +} + +void PD::incoming_CANCEL() +{ + pmesg(40, "PD::incoming_CANCEL() \n"); + display_status("Received CANCEL."); +} + +void PD::incoming_WAIT() +{ + pmesg(40, "PD::incoming_WAIT() \n"); + display_status("Received WAIT."); +} + +void PD::incoming_EOF() +{ + pmesg(40, "PD::incoming_EOF() \n"); +} + +void PD::start_over() +{ + pmesg(40, "PD::start_over() \n"); + if (!preset || !preset_copy || !preset->is_changed() || dismiss(false) != 1) + return; + // select a different basic channel (erases edit buffer) + midi->edit_parameter_value(139, (selected_channel + 1) % 15); + midi->edit_parameter_value(139, selected_channel); + preset_copy->clone(preset); + preset->set_changed(false); + show_preset(); +} + +void PD::randomize() +{ + pmesg(40, "PD::randomize() \n"); + if (!setup) + { + pd->display_status("*** Must be connected."); + return; + } + if (!(cfg->get_cfg_option(CFG_CONFIRM_RAND) && !fl_choice( + "Randomize preset?", "Cancel", "Randomize", 0))) + { + ui->set_eall(0); + randomizing = true; + midi->randomize(); + } +} + +int PD::load_export(const char* filename, bool library) //, bool keep) +{ + pmesg(40, "PD::load_export(%s) \n", filename); + if (!setup) + { + pd->display_status("*** Must be connected."); + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + return 0; + } + if (!filename) // user hit cancel + { + if (preset_library) // with loaded audit preset + { + // delete preset_library and upload our preset back to the edit buffer + delete preset_library; + preset_library = 0; + preset->upload(0, cfg->get_cfg_option(CFG_CLOSED_LOOP_UPLOAD)); + show_preset(); + display_status("Canceled import, Program reloaded."); + } + return 1; + } + // if (library && keep) + // { + // // user chose preset, keep it, show it + // delete preset; + // delete preset_copy; + // preset = new Preset_Dump(preset_library->get_dump_size(), + // preset_library->get_data(), preset_library->get_p_size()); + // preset_copy = new Preset_Dump(preset_library->get_dump_size(), + // preset_library->get_data(), preset_library->get_p_size()); + // preset->set_changed(true); + // show_preset(); + // display_status("Program imported."); + // //pd->display_status("Import successful."); + // delete preset_library; + // preset_library = 0; + // return 1; + // } + // open the file +#ifdef __linux + int offset = 0; + while (strncmp(filename + offset, "/", 1) != 0) + ++offset; + char n[BUF_PATHS]; + snprintf(n, BUF_PATHS, "%s", filename + offset); + while (n[strlen(n) - 1] == '\n' || n[strlen(n) - 1] == '\r' || n[strlen(n) + - 1] == ' ') + n[strlen(n) - 1] = '\0'; + std::ifstream file(n, std::ifstream::binary); +#else + std::ifstream file(filename, std::ifstream::binary); +#endif + if (!file.is_open()) + { + fl_message("Could not open the file. Do you have read permissions?\n" + "Note: You can only drop a single file."); + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + return 0; + } + // check and load file + int size; + file.seekg(0, std::ios::end); + size = file.tellg(); + file.seekg(0, std::ios::beg); + if (size < 1605 || size > 1615) + { + pd->display_status("*** File format unsupported."); + file.close(); + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + return 0; + } + unsigned char* sysex = new unsigned char[size]; + file.read((char*) sysex, size); + file.close(); + if (!(sysex[0] == 0xf0 && sysex[1] == 0x18 && sysex[2] == 0x0f && sysex[4] + == 0x55 && sysex[size - 1] == 0xf7)) + { + pd->display_status("*** File format unsupported."); + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + delete[] sysex; + return 0; + } + // find packet size + int pos = DUMP_HEADER_SIZE; // start after the header + while (++pos < size) // calculate packet size + if (sysex[pos] == 0xf7) + break; + if (0 != test_checksum(sysex, size, pos - DUMP_HEADER_SIZE + 1)) + { + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + delete[] sysex; + return 0; + } + // load presets + if (!library) // "this is not a library preview" aka import this! + { + if (preset_library) + { + delete preset_library; + preset_library = 0; + } + if (preset) + { + delete preset; + delete preset_copy; + } + preset = new Preset_Dump(size, sysex, pos - DUMP_HEADER_SIZE + 1); + preset_copy = new Preset_Dump(size, sysex, pos - DUMP_HEADER_SIZE + 1); + // set edited + preset->set_changed(true); + // upload to edit buffer + preset->move(-1); + preset->upload(0, cfg->get_cfg_option(CFG_CLOSED_LOOP_UPLOAD)); + show_preset(); + } + else // upload preset from library for audition + { + if (preset_library) + delete preset_library; + preset_library = new Preset_Dump(size, sysex, + pos - DUMP_HEADER_SIZE + 1); + preset_library->move(-1); + preset_library->upload(0, cfg->get_cfg_option(CFG_CLOSED_LOOP_UPLOAD)); + pd->show_preset(true); // true = show preset_library instead of preset + display_status("Program loaded for audition."); + } + delete[] sysex; + return 1; +} + +int PD::test_checksum(const unsigned char* data, int size, int packet_size) +{ + pmesg(40, "PD::test_checksum(data, %d, %d) \n", size, packet_size); + const int chunks = (size - DUMP_HEADER_SIZE) / packet_size; + const int tail = (size - DUMP_HEADER_SIZE) % packet_size - 11; + int offset = DUMP_HEADER_SIZE + 9; + int sum; + unsigned char checksum; + int errors = 0; + for (int j = 0; j < chunks; j++) + { + sum = 0; + for (int i = 0; i < (packet_size - 11); i++) + sum += data[offset + i]; + checksum = ~sum; + if (data[offset + packet_size - 11] != checksum % 128) + ++errors; + offset += packet_size; + } + sum = 0; + for (int i = 0; i < tail; i++) + sum += data[offset + i]; + checksum = ~sum; + if (data[offset + tail] != checksum % 128) + ++errors; + sum = 0; + if (errors) + sum = fl_choice("Checksum test failed! Import anyway?\n" + "Note: This may crash prodatum.", "Import", "No", 0); + return sum; +} + +// for testing so we can add missing names +const char* PD::get_name(int code) const +{ + pmesg(40, "PD::get_name(code: %d)\n", code); + switch (code) + { + case 0x02: + return "Audity 2000"; + case 0x03: + return "Proteus 2000"; + case 0x04: + return "B-3"; + case 0x05: + return "XL-1"; + case 0x06: + return "Virtuoso 2000"; + case 0x07: + return "Mo'Phatt"; + case 0x08: + return "B-3 Turbo"; + case 0x09: + return "XL-1 Turbo"; + case 0x0a: + return "Mo'Phatt Turbo"; + case 0x0b: + return "Planet Earth"; + case 0x0c: + return "Planet Earth Turbo"; + case 0x0d: + return "XL-7"; + case 0x0e: + return "MP-7"; + case 0x0f: + return "Proteus 2500"; + case 0x10: + return "Orbit 3"; + case 0x11: + return "PK-6"; + case 0x12: + return "XK-6"; + case 0x13: + return "MK-6"; + case 0x14: + return "Halo"; + case 0x15: + return "Proteus 1000"; + case 0x16: + return "Vintage Pro"; + case 0x17: + return "Vintage Keys"; + case 0x18: + return "PX-7"; + default: + static char buf[20]; + snprintf(buf, 20, "Unknown (%X)", code); + return buf; + } +} + +void PD::mute(int state, int layer) +{ + pmesg(40, "PD::mute(%d, %d)\n", state, layer); + if (!preset) + return; + if (state) + { + if (mute_volume[layer] == -100) + { + int tmp = preset->get_value(1410, layer); + midi->edit_parameter_value(898, layer); + selected_layer = layer; + midi->edit_parameter_value(1410, -96); + mute_volume[layer] = tmp; + if (is_solo[layer]) + solo(0, layer); + ui->mute_b[layer]->value(1); + ui->main->layer_strip[layer]->mute_b->value(1); + } + } + else if (mute_volume[layer] != -100) + { + int tmp = mute_volume[layer]; + if (!is_solo[layer]) + for (int i = 0; i < 4; i++) + { + is_solo[i] = 0; + ui->solo_b[i]->value(0); + ui->main->layer_strip[i]->solo_b->value(0); + } + mute_volume[layer] = -100; + midi->edit_parameter_value(898, layer); + selected_layer = layer; + midi->edit_parameter_value(1410, tmp); + ui->mute_b[layer]->value(0); + ui->main->layer_strip[layer]->mute_b->value(0); + } + if (ui->eall) + { + midi->edit_parameter_value(898, -1); + selected_layer = 0; + } +} + +void PD::solo(int state, int layer) +{ + pmesg(40, "PD::solo(%d, %d)\n", state, layer); + if (state) + { + is_solo[layer] = 1; + ui->solo_b[layer]->value(1); + ui->main->layer_strip[layer]->solo_b->value(1); + for (int i = 0; i < 4; i++) + { + if (layer == i) + { + mute(0, i); + continue; + } + if (is_solo[i]) + { + is_solo[i] = 0; + ui->solo_b[i]->value(0); + ui->main->layer_strip[i]->solo_b->value(0); + } + mute(1, i); + } + } + else if (is_solo[layer]) + { + is_solo[layer] = 0; + ui->solo_b[layer]->value(0); + ui->main->layer_strip[layer]->solo_b->value(0); + if (mute_volume[layer] == -100) + for (int i = 0; i < 4; i++) + mute(0, i); + } +} + +void PD::save_setup(int dst, const char* newname) +{ + pmesg(40, "PD::save_setup(%d, %s) \n", dst, newname); + if (!setup) + { + ui->do_save->activate(); + return; + } + if (dst == selected_multisetup) + { + fl_message("Target must be different from currently\nselected setup."); + ui->do_save->activate(); + return; + } + selected_multisetup = dst; + char name[17]; + snprintf(name, 17, "%s ", newname); + bool updated = false; + for (int i = 0; i < 16; i++) + if (!isascii(name[i])) + { + name[i] = ' '; + updated = true; + } + // update text input + if (updated) + { + char n[17]; + snprintf(n, 17, "%s", name); + while (n[strlen(n) - 1] == ' ') + n[strlen(n) - 1] = '\0'; + ui->s_name->value(n); + } + // update device + for (int i = 0; i < 16; i++) + { + midi->edit_parameter_value(142 + i, name[i]); + setup->set_value(142 + i, name[i]); + } + midi->copy(C_SETUP, -1, dst); + // update memory + setup->set_value(388, dst); + set_setup_name(dst, (const unsigned char*) name); + // update setup choice + char n[21]; + snprintf(n, 21, "%02d: %s", dst, name); + ui->multisetups->text(dst + 1, n); + ui->multisetups->select(dst + 1); + ui->multisetups->redraw(); + ui->do_save->activate(); +} + +void PD::save_setup_names(int device_id) +{ + pmesg(40, "PD::save_setup_names(%d) \n", device_id); + if (midi_mode != -1 && setup_names) + { + char filename[BUF_PATHS]; + snprintf(filename, BUF_PATHS, "%s/n_set_%d", cfg->get_config_dir(), + device_id); + std::fstream file(filename, + std::ios::out | std::ios::binary | std::ios::trunc); + file.write((char*) setup_names, 1024); + file.close(); + } +} + +int PD::load_setup_names(int start, bool from_disk_only) +{ + pmesg(40, "PD::load_setup_names(%d)\n", start); + // try to load from disk + if (from_disk_only) + { + if (setup_names) + { + delete[] setup_names; + setup_names = 0; + } + char filename[BUF_PATHS]; + snprintf(filename, BUF_PATHS, "%s/n_set_%d", cfg->get_config_dir(), + cfg->get_cfg_option(CFG_DEVICE_ID)); + std::fstream file(filename, + std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { + size_t size = file.tellg(); + if (size != 1024) + { + file.close(); + return 63; + } + setup_names = new unsigned char[1024]; + file.seekg(0, std::ios::beg); + file.read((char*) setup_names, 1024); + file.close(); + ui->multisetups->clear(); + char buf[21]; + for (int i = 0; i < 64; i++) + { + snprintf(buf, 21, "%02d: %s", i, setup_names + i * 16); + ui->multisetups->add(buf); + // if (i != 62) + // ui->multisetup_dst->add(buf); + } + return 0; + } + return 63; + } + // midi load setup names + if (start < 63) + { + midi->copy(C_SETUP, start, -1); + midi->request_name(SETUP, start, 0); + } + else // last setup name + { + // load first setup + midi->copy(C_SETUP, 0, -1); + set_setup_name(63, (unsigned char*) "Factory Setup "); + ui->multisetups->clear(); + char buf[21]; + for (int i = 0; i < 64; i++) + { + snprintf(buf, 21, "%02d: %s", i, setup_names + i * 16); + ui->multisetups->add(buf); + // if (i != 63) + // ui->multisetup_dst->add(buf); + } + } + return 63; +} + +void PD::set_setup_name(int number, const unsigned char* name) +{ + pmesg(40, "PD::set_setup_name(%d, %s) \n", number, name); + if (!setup_names) + setup_names = new unsigned char[1024]; + memcpy(setup_names + 16 * number, name, 16); + //pmesg(1, "setup number = %D\n", number); +} + +void PD::update_fx_values(int id, int value) const +{ + pmesg(40, "PD::update_fx_values(%d, %d) \n", id, value); + if (id == 513 || id == 1153) // fxa + { + int decay = 0; + int damp = 0; + switch (value) + { + case 1: + decay = 40; + damp = 96; + break; + case 2: + decay = 44; + damp = 64; + break; + case 3: + case 34: + decay = 48; + damp = 96; + break; + case 4: + decay = 56; + damp = 64; + break; + case 5: + decay = 56; + damp = 80; + break; + case 6: + decay = 56; + damp = 64; + break; + case 7: + decay = 56; + damp = 120; + break; + case 8: + decay = 36; + damp = 120; + break; + case 9: + case 10: + case 11: + case 12: + decay = 24; + damp = 64; + break; + case 13: + case 14: + case 15: + case 16: + case 17: + decay = 48; + damp = 64; + break; + case 18: + decay = 40; + damp = 64; + break; + case 19: + decay = 37; + damp = 120; + break; + case 20: + decay = 60; + damp = 120; + break; + case 21: + decay = 30; + damp = 120; + break; + case 22: + decay = 45; + damp = 120; + break; + case 23: + decay = 48; + damp = 0; + break; + case 24: + decay = 72; + damp = 0; + break; + case 25: + decay = 80; + damp = 0; + break; + case 26: + case 33: + decay = 64; + damp = 96; + break; + case 27: + decay = 32; + damp = 96; + break; + case 28: + decay = 0; + damp = 0; + break; + case 29: + decay = 0; + damp = 96; + break; + case 30: + decay = 0; + damp = 64; + break; + case 31: + case 32: + decay = 60; + damp = 120; + break; + case 35: + decay = 80; + damp = 0; + break; + case 36: + decay = 64; + damp = 120; + break; + case 37: + decay = 60; + damp = 8; + break; + case 38: + decay = 60; + damp = 104; + break; + case 39: + decay = 40; + damp = 104; + break; + case 40: + decay = 48; + damp = 112; + break; + case 41: + decay = 52; + damp = 112; + break; + case 42: + decay = 40; + damp = 80; + break; + case 43: + decay = 32; + damp = 56; + break; + case 44: + decay = 56; + damp = 32; + break; + + } + ui->fxa_decay->value((double) decay); + ui->fxa_damp->value((double) damp); + if (id == 513) + { + setup->set_value(514, decay); + setup->set_value(515, damp); + } + else + { + preset->disable_add_undo = true; + preset->set_value(1154, decay); + preset->set_value(1155, damp); + preset->disable_add_undo = false; + } + } + else if (id == 520 || id == 1160) // fxb + { + int feedback = 0; + int lfo = 0; + int delay = 0; + switch (value) + { + case 1: + lfo = 3; + break; + case 2: + feedback = 4; + lfo = 11; + break; + case 3: + feedback = 8; + lfo = 4; + break; + case 4: + feedback = 16; + lfo = 11; + break; + case 5: + feedback = 64; + lfo = 2; + break; + case 8: + feedback = 88; + lfo = 3; + break; + case 9: + feedback = 64; + lfo = 1; + break; + case 10: + feedback = 64; + lfo = 6; + break; + case 11: + feedback = 104; + lfo = 5; + break; + case 12: + feedback = 72; + lfo = 2; + break; + case 13: + feedback = 16; + lfo = 24; + break; + case 14: + feedback = 112; + lfo = 1; + break; + case 15: + feedback = 16; + lfo = 4; + break; + case 16: + feedback = 48; + lfo = 24; + break; + case 17: + feedback = 64; + lfo = 9; + break; + case 18: + feedback = 32; + delay = 50; + break; + case 19: + feedback = 32; + delay = 60; + break; + case 20: + case 21: + feedback = 32; + delay = 80; + break; + case 22: + feedback = 16; + lfo = 9; + delay = 40; + break; + case 23: + feedback = 24; + lfo = 24; + delay = 24; + break; + case 24: + feedback = 24; + lfo = 3; + delay = 50; + break; + case 25: + case 26: + feedback = 32; + delay = 100; + break; + case 27: + lfo = 70; + break; + case 28: + feedback = 100; + break; + case 29: + feedback = 70; + lfo = 1; + break; + case 30: + feedback = 90; + lfo = 6; + break; + case 31: + feedback = 20; + lfo = 4; + break; + } + ui->fxb_feedback->value((double) feedback); + ui->fxb_lfo_rate->value((double) lfo); + ui->fxb_delay->value((double) delay); + if (id == 513) + { + setup->set_value(521, feedback); + setup->set_value(522, lfo); + setup->set_value(523, delay); + } + else + { + preset->disable_add_undo = true; + preset->set_value(1161, feedback); + preset->set_value(1162, lfo); + preset->set_value(1163, delay); + preset->disable_add_undo = false; + } + } +} diff --git a/pd.H b/pd.H new file mode 100644 index 0000000..3cdd6ff --- /dev/null +++ b/pd.H @@ -0,0 +1,297 @@ +// $Id$ +#ifndef PD_H_ +#define PD_H_ +/** + \defgroup pd_pd prodatum CPU + @{ +*/ +#include +#include +#include +#include + +#include "data.H" + +/** + * Enum for the various copy commands of the device + */ +enum +{ + C_PRESET = 0x20, + C_PRESET_COMMON, + C_ARP, + C_FX, + C_PRESET_LINK, + C_LAYER, + C_LAYER_COMMON, + C_LAYER_FILTER, + C_LAYER_LFO, + C_LAYER_ENVELOPE, + C_LAYER_PATCHCORD, + C_ARP_PATTERN, + C_SETUP, + SAVE_PRESET +}; + +/** + * Enum for the three MIDI modes + */ +enum +{ + OMNI, POLY, MULTI +}; + +enum +{ + AUDITY = 2 +}; + +/** + * prodatum's control class. + * Evaluates incoming sysex messages and holds data objects like preset and + * setup dumps and ROM informations. + * @see ROM() + * @see Preset_Dump() + * @see Setup_Dump() + * @see FX_Dump() + */ +class PD +{ + /// device code of opened device + int device_code; + /// member code of opened device + int member_code; + /// OS revision string for opened device + char os_rev[5]; + /// number of available user presets in this device + int user_presets; + /// pointer for setup names + unsigned char* setup_names; + /// number of installed ROMs in the opened device + int roms; + /// temporary storage for volume changes of muted voices + int mute_volume[4]; + /// keeps track of solo'ed voices + int is_solo[4]; + /// currently selected setup number + int selected_multisetup; + /// keeps track of incoming name request replies, so we can make sure + /// to re-request missing names + int name_counter[5][7]; + int names_to_download; + int nak_count; + bool randomizing; + Setup_Dump* setup_init; + /// creates device infoormations for an detected device + void create_device_info(); + /// sets realtime controllers to initial values + void update_cc_sliders(); + bool cc_changed; + /// updates internal controller mappings on controller assignment changes + void update_control_map(); + /** + * saves setup names to a file + * @param device_id the device id of the device that these setup names + * belong to + */ + void save_setup_names(int device_id); + /** + * initialize a setup name + * @param number setup number + * @param name the name + */ + void set_setup_name(int number, const unsigned char* name); + /** + * get a devices name + * @param the device code + * @returns the device name + */ + const char* get_name(int code) const; + /** + * updates fx paramaters depending on the fx algorithm + * @param id (master/preset)fxa/fxb + * @param value fx type + */ + void update_fx_values(int id, int value) const; + int test_checksum(const unsigned char* data, int size, int packet_size); +public: + /// CTOR initializes variables + PD(); + /// DTOR frees memory and saves setup names + ~PD(); + // these are used everywhere, so we just make them public! ;) + /// currently selected MIDI channel + int selected_channel; + int selected_preset; + int selected_preset_rom; + /// currently active MIDI mode + int midi_mode; + /// currently selected layer + int selected_layer; + /// currently selected FX channel + int selected_fx_channel; + /** + * UI -> Device/Data controller. + * Receives user widget input and forwards commands to the device. + * Updates internal state. + * @param id the parameter ID + * @param value the parameter value + * @param layer the layer number for the parameter (-2 for layer independent + * parameters) + */ + void widget_callback(int id, int value, int layer = -2); + /** + * UI CC -> device controller + * Receives controller inputs from the UI and forwards them + * to the device. + * @param controller the controller number + * @param value the controller value + */ + void cc_callback(int controller, int value); + /// stores current controller settings as initial amounts + void store_play_as_initial(); + /// maps controller values to CC widget numbers (device -> UI) + std::map cc_to_ctrl; + /// maps CC widget numbers to actual controller values (UI -> device) + std::map ctrl_to_cc; + /** + * request a setup name from the device or load a setup name file + * @param start the number of the setup to request + * @param from_disk_only wether we should try to only load a setup name + * file and skip the device request if the load fails + */ + int load_setup_names(int start, bool from_disk_only); + /** + * local copy of the currently loaded setup on the device + * @see Setup_Dump() + */ + Setup_Dump* setup; + /** + * copy of the currently loaded setup. + * the copy is not editable and is used to reset controller values + * to their initial amount ("right-click" feature) + * @see Setup_Dump() + */ + const Setup_Dump* setup_copy; + /** + * local copy of the currently selected program/preset + * @see Preset_Dump() + */ + Preset_Dump* preset; + /** + * copy of the currently loaded program/preset. + * the copy is not editable and is used to reset controller values + * to their initial amount ("right-click" feature) + * @see Preset_Dump() + */ + const Preset_Dump* preset_copy; + /** + * preset data that has been loaded from the library. + * unused yet + * @see Preset_Dump() + */ + Preset_Dump* preset_library; + /** + * array of ROM()s for the currently opened device. + * @see ROM() + */ + ROM* rom[5]; + /** + * user edit arp dump + */ + Arp_Dump* arp; + /** + * tries to open a device with pre-configured values. + * if autoconnect is enabled and MIDI ports have been configured, + * this method tries to open the device on those ports. shows the + * "Open device..." dialog if it fails to do so + */ + void connect(); + /** + * initializes all ROM's and requests a setup dump when finished. + * triggers the loading of all names for the currently opened device. + * these may be saved already and loaded from disk, if not, name requests + * will be send out and a watchdog is launched to track the requests. + * once all names have been loaded (one way or the other), a setup dump + * is requested + */ + void initialize(); + void init_arp_riff_names(); + void loading(); + std::vector status_message; + void display_status(const char* message, bool top = false); + /** + * saves current setup dump to the device. + * @param dst the slot to save to (0-62) + * @param newname the name for the multisetup + */ + void save_setup(int dst, const char* newname); + /** + * cancel initialization process and clean up the mess + */ + void cancel_init(); + /** + * set tv_start + * @see tv_start + */ + //void start_stopwatch(); + /** + * set tv_stop and update the UI + * @see tv_stop + */ + //void stop_stopwatch(); + /// handles incoming device inuqiry sysex message + void incoming_inquiry_data(const unsigned char* data, int len); + /// handles incoming hardware config sysex message + void incoming_hardware_config(const unsigned char* data, int len); + /// handles incoming setup dump sysex message + void incoming_setup_dump(const unsigned char* data, int len); + void load_setup(); + /// handles incoming preset dump sysex message + void incoming_preset_dump(const unsigned char* data, int len); + /// handles incoming arp dump sysex message + void incoming_arp_dump(const unsigned char* data, int len); + /// handles incoming program change map dump sysex message + //void incoming_pc_dump(const unsigned char* data, int len); + /// handles incoming generic name sysex message + void incoming_generic_name(const unsigned char* data); + /// handles incoming parameter value sysex message + // void incoming_parameter_value(int parameter, int value); + /// handles incoming ERROR sysex message + void incoming_ERROR(int cmd, int sub); + /// handles incoming ACK sysex message + void incoming_ACK(int packet); + /// handles incoming NAK sysex message + void incoming_NAK(int packet); + /// handles incoming CANCEL sysex message + void incoming_CANCEL(); + /// handles incoming WAIT sysex message + void incoming_WAIT(); + /// handles incoming EOF sysex message + void incoming_EOF(); + /** + * reset all edited values to initial. + * resets all parameter values to the program/preset default values + * and updates the UI + */ + void start_over(); + void randomize(); + /// load an exported program + int load_export(const char*, bool library = false); //, bool keep = false); + void show_preset(bool lib = false); + /** + * mute/unmute a layer + * @param state wether to mute or unmute + * @param layer the voice to mute/unmute + */ + void mute(int state, int layer); + /** + * solo/unsolo a layer + * @param state wether to solo or unsolo + * @param layer the voice to solo/unsolo + */ + void solo(int state, int layer); +}; + +#endif /* PD_H_ */ +/** @} */ diff --git a/prodatum.C b/prodatum.C new file mode 100644 index 0000000..5f19a07 --- /dev/null +++ b/prodatum.C @@ -0,0 +1,1293 @@ +// prodatum: E-MU Proteus family remote and preset editor +// Copyright 2011 Jan Eidtmann +// +// 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 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#ifdef WINDOWS +#include +#else +#include +#endif + +#include "ui.H" +#include "midi.H" +#include "pd.H" +#include "cfg.H" + +#include "debug.H" + +static void load_data(); + +PD_UI* ui; +MIDI* midi; +PD* pd; +Cfg* cfg; + +extern unsigned char colors[5]; +extern FilterMap FM[51]; +extern const char* rates[25]; +extern PD_Arp_Step* arp_step[32]; + +// default message level +int msglevel = 1; +// default config +static char config[32]; +static int auto_connect = 1; +static bool use_system_colors = false; + +// for fltk 1.3 +//#ifdef OSX +//static void mac_about(void* p) +//{ +// ui->about->show(); +//} +// +//static void mac_drop_on_icon(const char* p) +//{ +// pmesg(1, "mac_drop_on_icon(%s) \n", p); +// pd->load_export(p, false); +//} +//#endif + +//// delete name files +void reset(int user_data, int rom_data) +{ + if (!cfg || (user_data == -1 && rom_data == -1)) + { + ui->reset_w->hide(); + ui->b_reset->activate(); + pd->display_status("Formatting harddrive... just kidding."); + return; + } + pmesg(40, "reset(%d, %d)\n", user_data, rom_data); + // stop MIDI + delete midi; + midi = 0; + // delete ROMS + delete pd; + pd = 0; + // delete files + dirent **files; + int num_files = fl_filename_list(cfg->get_config_dir(), &files); + char buf[BUF_PATHS]; + int f_size = 20; + char f[f_size]; + int deleted = 0; + if (user_data >= 0) + { + if (user_data == 127) // delete all user data + snprintf(f, f_size, "n_???_0_*"); + else + snprintf(f, f_size, "n_???_0_%d", user_data); + for (int i = 0; i < num_files; i++) + { + if (fl_filename_match(files[i]->d_name, f)) + { + snprintf(buf, BUF_PATHS, "%s/%s", cfg->get_config_dir(), + files[i]->d_name); + pmesg(50, " - - deleting %s ... ", buf); +#ifdef WINDOWS + if (_unlink(buf)) +#else + if (unlink(buf)) +#endif + { + fl_message("Could not delete\n%s", buf); + pmesg(50, " failed!\n", buf); + } + else + { + pmesg(50, " success!\n", buf); + ++deleted; + } + } + } + } + if (rom_data >= 1) + { + if (rom_data == 1) // delete all rom data + snprintf(f, f_size, "n_???_[123456789]*"); + else + snprintf(f, f_size, "n_???_%d", rom_data); + for (int i = 0; i < num_files; i++) + { + if (fl_filename_match(files[i]->d_name, f)) + { + snprintf(buf, BUF_PATHS, "%s/%s", cfg->get_config_dir(), + files[i]->d_name); + pmesg(50, " - - deleting %s! ... ", buf); +#ifdef WINDOWS + if (_unlink(buf)) +#else + if (unlink(buf)) +#endif + { + fl_message("Could not delete\n%s", buf); + pmesg(50, " failed!\n", buf); + } + else + { + pmesg(50, " success!\n", buf); + ++deleted; + } + } + } + } + // clean up + for (int i = num_files; i > 0;) + free((void*) (files[--i])); + free((void*) files); + // reload + midi = new MIDI(); + pd = new PD(); + ui->reset_w->hide(); + ui->b_reset->activate(); + fl_message("Deleted %d files from\n%s", deleted, cfg->get_config_dir()); + // select previous + ui->midi_outs->label("Select..."); + ui->midi_ins->label("Select..."); + ui->midi_ctrl->label("Select... (optional)"); + ui->open_device->show(); + int selection; + selection = cfg->get_cfg_option(CFG_MIDI_OUT); + if (selection != -1) + { + ui->midi_outs->value(selection); + ui->midi_outs->do_callback(); + } + selection = cfg->get_cfg_option(CFG_MIDI_IN); + if (selection != -1) + { + ui->midi_ins->value(selection); + ui->midi_ins->do_callback(); + } + selection = cfg->get_cfg_option(CFG_MIDI_THRU); + if (selection != -1) + { + ui->midi_ctrl->value(selection); + ui->midi_ctrl->do_callback(); + } +} + +/** + * command line option parser + */ +int options(int argc, char **argv, int &i) +{ + if (argv[i][1] == 'm') + { + if (i + 1 >= argc) + return 0; + msglevel = atoi(argv[i + 1]); + if (msglevel < 0) + msglevel = 0; + else if (msglevel > MAX_MSGLEVEL) + msglevel = MAX_MSGLEVEL; + i += 2; + return 2; + } + if (argv[i][1] == 'a') + { + auto_connect = 0; + i++; + return 1; + } + if (argv[i][1] == 'c') + { + if (i + 1 >= argc) + return 0; + snprintf(config, 32, "%s", argv[i + 1]); + i += 2; + return 2; + } + if (argv[i][1] == 'y') + { + use_system_colors = true; + i++; + return 1; + } + // ignore color settings + return 0; +} + +int main(int argc, char *argv[]) +{ + snprintf(config, 32, "cfg.txt"); + Fl::scheme("gleam"); + // command line options + int i = 1; + if (!Fl::args(argc, argv, i, options)) + { + printf("%s options:\n" + " -c file\tConfig file to use (default: cfg.txt)\n" + " -m n \tset default Messagelevel (min/max/default: 0/%d/%d)\n" + " -a \tdo not open device at startup\n" + " -y \tuse system colors/colors specified below\n" + "FLTK options:\n" + "%s\n", PACKAGE_NAME, MAX_MSGLEVEL, msglevel, Fl::help); + return 1; + } + ui = 0; + midi = 0; + pd = 0; + cfg = 0; + // for fltk 1.3 + //#ifdef OSX + // fl_mac_set_about((Fl_Callback*) mac_about, 0); + // fl_open_callback( mac_drop_on_icon); + //#endif + // load config + try + { + cfg = new Cfg((const char*) config, auto_connect); + } catch (int e) + { + if (e == 1) // couldnt create config dir + return -1; + } + // load some data + load_data(); + // create controller + pd = new PD(); + // create user interface + ui = new PD_UI(); + ui->status->label("Welcome! Populating MIDI ports..."); + ui->main_window->show(argc, argv); + if (!use_system_colors) + ui->set_color(CURRENT, 0); + Fl::wait(); + try + { + midi = new MIDI(); + } catch (int e) + { + if (e == 1) // couldnt create pipe + return -2; + } + pd->display_status("...success! Have fun!"); + pd->connect(); + pmesg(40, "Fl::run()\n"); + return Fl::run(); +} + +/** + * set global debuglevel + */ +void PD_UI::set_msglevel(int level) +{ + switch (level) + { + case 0: // error + msglevel = 1; + break; + case 1: + msglevel = 40; + break; + case 2: + msglevel = 90; + break; + } +} + +void PD_UI::initialize() +{ + pmesg(40, "PD_UI::initialize()\n"); + // UI INIT + // midi options + device_id->value(cfg->get_cfg_option(CFG_DEVICE_ID)); + r_user_id->value(cfg->get_cfg_option(CFG_DEVICE_ID)); + cfg->get_cfg_option(CFG_AUTOCONNECT) ? autoconnect->set() + : autoconnect->clear(); + midi_ctrl_ch->value(cfg->get_cfg_option(CFG_CONTROL_CHANNEL)); + midi_automap->value(cfg->get_cfg_option(CFG_AUTOMAP)); + speed->value(cfg->get_cfg_option(CFG_SPEED)); + + // preferences + confirm->value(cfg->get_cfg_option(CFG_CONFIRM_EXIT)); + confirm_rand->value(cfg->get_cfg_option(CFG_CONFIRM_RAND)); + confirm_dismiss->value(cfg->get_cfg_option(CFG_CONFIRM_DISMISS)); + ((Fl_Button*) g_knobmode->child(cfg->get_cfg_option(CFG_KNOBMODE)))->setonly(); + cfg->get_cfg_option(CFG_CLOSED_LOOP_UPLOAD) ? closed_loop_upload->set() + : closed_loop_upload->clear(); + cfg->get_cfg_option(CFG_CLOSED_LOOP_DOWNLOAD) ? closed_loop_download->set() + : closed_loop_download->clear(); + export_dir->value(cfg->get_export_dir()); + c_aaudit->value(cfg->get_cfg_option(CFG_AUDIT_IMPORT)); + + // UI misc + if (cfg->get_cfg_option(CFG_TOOLTIPS)) + { + tooltips->set(); + Fl_Tooltip::enable(); + } + else + { + tooltips->clear(); + Fl_Tooltip::disable(); + } + if (cfg->get_cfg_option(CFG_DRLS)) + { + drls->value(1); + value_input->when(FL_WHEN_ENTER_KEY); + } + else + { + drls->value(0); + value_input->when(FL_WHEN_CHANGED); + } + progress->minimum(.0); + progress->maximum(1600.); + progress->value(1600.); + init_progress->minimum(.0); + init_progress->maximum(1.); + syncview = cfg->get_cfg_option(CFG_SYNCVIEW); + selected_step = -1; + eall = false; + arp_name_changed = false; + selected = 5; + filter_tmp = 0; + select(0); + fc = 0; + + // log + logbuf = new Fl_Text_Buffer(LOG_BUFFER_SIZE); + log->buffer(logbuf); + log_sysex_out->value(cfg->get_cfg_option(CFG_LOG_SYSEX_OUT)); + log_sysex_in->value(cfg->get_cfg_option(CFG_LOG_SYSEX_IN)); + log_events_out->value(cfg->get_cfg_option(CFG_LOG_EVENTS_OUT)); + log_events_in->value(cfg->get_cfg_option(CFG_LOG_EVENTS_IN)); + + create_about(); + Fl::add_handler(handler); + + main_window->free_position(); + main_window->size(cfg->get_cfg_option(CFG_WINDOW_WIDTH), + cfg->get_cfg_option(CFG_WINDOW_HEIGHT)); + Fl::focus(selector); +} + +void PD_UI::set_export_path() +{ + pmesg(40, "PD_UI::set_export_path()\n"); + // create filechooser + // enum { SINGLE = 0, MULTI = 1, CREATE = 2, DIRECTORY = 4 }; + fc = new Fl_File_Chooser(cfg->get_export_dir(), 0, 4, + "Change Export Directory"); + fc->preview(0); + fc->ok_label("Select"); + fc->show(); + while (fc->shown()) + Fl::wait(); + if (fc->value()) + { + cfg->set_export_dir(fc->value()); + ui->export_dir->value(fc->value()); + } + delete fc; + fc = 0; +} + +static bool audit_on = false; +static void audit(void* p) +{ + pmesg(40, "audit()\n"); + // actual request + if (pd->load_export((char*) p, true)) + { + while (ui->loading_w->shown()) // wait for closed loop uploads + Fl::wait(.1); + audit_on = true; // these two should be made atomic but we are lazy + midi->audit(); + } +} + +// callback for import browser to load preset for preview +void fcp_cb(Fl_File_Chooser* fc, void*) +{ + pmesg(40, "fcp_cb(fc*)\n"); + if (!fc->fileList->changed()) + return; + Fl::remove_timeout(audit, 0); + if (audit_on) + { + audit_on = false; // these two should be made atomic but we are lazy + midi->audit(); + } + if (!fc->shown()) + return; + // wait a bit before loading the preset to prevent lots of uploads + // when we scroll the list + Fl::add_timeout(0.4, audit, (void*) fc->value()); +} + +void PD_UI::file_program(int save_load) +{ + pmesg(40, "PD_UI::file_program(%d) \n", save_load); + if (save_load == 0 && !pd->preset) + { + pd->display_status("*** Nothing to export."); + return; + } + if (save_load == 1 && !pd->setup) + { + pd->display_status("*** Must be connected."); + return; + } + if (save_load == 2) // quick export + { + if (!pd->preset) + { + pd->display_status("*** Nothing to export."); + return; + } + char path[BUF_PATHS]; + snprintf(path, BUF_PATHS, "%s%s.syx", cfg->get_export_dir(), + pd->preset->get_name()); + pd->preset->save_file((const char*) path); + return; + } + // create filechooser + fc + = new Fl_File_Chooser(cfg->get_export_dir(), "Sysex Files (*.syx)", + 2, 0); + fc->preview(0); + if (save_load == 0) // export + + { + fc->label("Export Program"); + fc->ok_label("Export"); + } + else // import + + { + fc->label("Import Program"); + fc->ok_label("Import"); + // connect preview callback only if enabled + if (cfg->get_cfg_option(CFG_AUDIT_IMPORT)) + fc->callback(fcp_cb); + } + fc->show(); + while (fc->shown()) + Fl::wait(); + Fl::remove_timeout(audit, 0); // cancel audition + if (audit_on) + { + midi->audit(); + audit_on = false; + } + // pass path to a data method + if (fc->value()) // we got a candidate! + { + if (save_load == 0) + pd->preset->save_file(fc->value()); + else + { + // try to keep preset_library, making it the current preset + // if (cfg->get_cfg_option(CFG_AUDIT_IMPORT)) + // pd->load_export(fc->value(), true, true); + // else + pd->load_export(fc->value()); + } + } + else + // cancelled import + pd->load_export(0, true); + // clean up + delete fc; + fc = 0; +} + +/** + * "view"/layer selector of the main window. + * hides/shows widgets depending on the selection + * @param l the view/layer to show + */ +void PD_UI::select(int l) +{ + pmesg(40, "PD_UI::select(%d)\n", l); + static int prev; + if (g_arp_edit->visible()) + { + g_arp_edit->hide(); + g_main->show(); + if (l == selected) + return; + } + if (l == selected) + { + if (l == 5 && b_links->value()) + { + b_links->value(0); + b_links->do_callback(); + return; + } + if (l == 0) + { + if (b_master->value()) + { + b_master->value(0); + b_master->do_callback(); + return; + } + } + l = prev; + } + ((Fl_Button*) selector->child(l))->setonly(); + prev = selected; + if (l == 5) + { + preset_editor->show(); + g_pfx->show(); + if (prev > 0) + layer_editor[prev - 1]->hide(); + else + { + if (b_master->value()) + g_multisetups->hide(); + main->hide(); + } + } + else if (l == 0) + { + main->show(); + if (b_master->value()) + { + g_multisetups->show(); + g_pfx->hide(); + } + else + { + g_pfx->show(); + g_multisetups->hide(); + } + if (prev < 5 && prev > 0) + layer_editor[prev - 1]->hide(); + else + preset_editor->hide(); + } + else + { + layer_editor[l - 1]->show(); + if (prev == 0) + { + main->hide(); + if (b_master->value()) + g_multisetups->hide(); + else + g_pfx->hide(); + } + else if (prev == 5) + { + preset_editor->hide(); + g_pfx->hide(); + } + else + layer_editor[prev - 1]->hide(); + } + selected = l; +} + +/** + * gets selected view/layer + * @return selected view/layer + */ +int PD_UI::get_selected() +{ + return selected; +} + +void PD_Arp_Step::init(int s) +{ + pmesg(80, "PD_Arp_Step::init(%d)\n", s); + step = s; + op->set_step(s); + offset->set_step(s); + velocity->set_id(785, s); + duration->set_id(786, s); + repeat->set_id(787, s); + arp_step[s] = this; + char buf[3]; + snprintf(buf, 3, "%d", s + 1); + offset->copy_label(buf); +} + +void PD_Arp_Step::edit_value(int id, int value) +{ + pmesg(40, "PD_Arp_Step::edit_value(%d, %d)\n", id, value); + if (ui->selected_step != step) + { + midi->edit_parameter_value(770, step); + ui->selected_step = step; + } + midi->edit_parameter_value(id, value); + if (id != 785) + pd->arp->update_sequence_length_information(); +} + +void PD_Arp_Step::set_values(int off, int vel, int dur, int rep) +{ + pmesg(40, "PD_Arp_Step::set_values(%d, %d, %d, %d)\n", off, vel, dur, rep); + if (off > -49) + { + if (off < 49) + { + offset->value((double) off); + ((Fl_Button*) op->child(4))->setonly(); + op->c = 4; + op->p = 0; + } + } + else + { + if (off > -53) + { + off += 52; + ((Fl_Button*) op->child(off))->setonly(); + op->c = off; + op->p = 4; + offset->value((double) 0); + } + } + velocity->value((double) vel); + duration->value((double) dur); + repeat->value((double) rep + 1); +} + +void PD_UI::edit_arp_x(int x) +{ + pmesg(40, "PD_UI::edit_arp_x(%d)\n", x); + if (x == 0 || x == -1) // preset arp + { + if (pd->arp && pd->arp->get_number() == ui->preset_editor->arp->value() + - 1) + { + ui->g_arp_edit->show(); + ui->g_main->hide(); + Fl::focus(ui->g_arp_edit); + } + else + midi->request_arp_dump(ui->preset_editor->arp->value() - 1, 0); + } + else if (x == 1) // master arp + { + if (pd->arp && pd->arp->get_number() == ui->main->arp->value() - 1) + { + ui->g_arp_edit->show(); + ui->g_main->hide(); + Fl::focus(ui->g_arp_edit); + } + else + midi->request_arp_dump(ui->main->arp->value() - 1, 0); + } +} + +void PD_UI::set_color(int type, int value) +{ + pmesg(40, "PD_UI::set_color(%d, %d)\n", type, value); + switch (type) + { + case BG: + colors[type] = value; + cfg->set_cfg_option(CFG_BG, value); + break; + case BG2: + colors[type] = value; + cfg->set_cfg_option(CFG_BG2, value); + break; + case RR: + colors[type] = value; + cfg->set_cfg_option(CFG_RR, value); + break; + case GG: + colors[type] = value; + cfg->set_cfg_option(CFG_GG, value); + break; + case BB: + colors[type] = value; + cfg->set_cfg_option(CFG_BB, value); + break; + case KNOBS: + if (value == 1) + shiny_knobs = true; + else + shiny_knobs = false; + cfg->set_cfg_option(CFG_SHINY_KNOBS, value); + break; + case DEFAULT: + colors[BG] = cfg->getset_default(CFG_BG); + colors[BG2] = cfg->getset_default(CFG_BG2); + colors[RR] = cfg->getset_default(CFG_RR); + colors[GG] = cfg->getset_default(CFG_GG); + colors[BB] = cfg->getset_default(CFG_BB); + (cfg->getset_default(CFG_SHINY_KNOBS)) ? shiny_knobs = true + : shiny_knobs = false; + c_bg->value(colors[BG]); + c_bg2->value(colors[BG2]); + c_rr->value(colors[RR]); + c_gg->value(colors[GG]); + c_bb->value(colors[BB]); + c_cbg->value(cfg->getset_default(CFG_COLORED_BG)); + c_sk->value((int) shiny_knobs); + break; + case CURRENT: + colors[BG] = cfg->get_cfg_option(CFG_BG); + colors[BG2] = cfg->get_cfg_option(CFG_BG2); + colors[RR] = cfg->get_cfg_option(CFG_RR); + colors[GG] = cfg->get_cfg_option(CFG_GG); + colors[BB] = cfg->get_cfg_option(CFG_BB); + c_cbg->value(cfg->get_cfg_option(CFG_COLORED_BG)); + (cfg->get_cfg_option(CFG_SHINY_KNOBS)) ? shiny_knobs = true + : shiny_knobs = false; + c_sk->value(shiny_knobs ? 1 : 0); + c_bg->value(colors[BG]); + c_bg2->value(colors[BG2]); + c_rr->value(colors[RR]); + c_gg->value(colors[GG]); + c_bb->value(colors[BB]); + break; + default: + break; + } + // Background2 + Fl::set_color(FL_BACKGROUND2_COLOR, colors[BG2], colors[BG2], colors[BG2]); + if (!cfg->get_cfg_option(CFG_COLORED_BG)) + { + // Background + Fl::set_color(FL_BACKGROUND_COLOR, colors[BG], colors[BG], colors[BG]); + // Selection + Fl::set_color(FL_SELECTION_COLOR, colors[RR], colors[GG], colors[BB]); + // inactive + //if (colors[BG2] > colors[BG]) + Fl::set_color(FL_INACTIVE_COLOR, + fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .7f)); + // else + // Fl::set_color(FL_INACTIVE_COLOR, fl_color_average( + // FL_BACKGROUND2_COLOR, FL_WHITE, .75f)); + } + else // colored background + + { + // Background + Fl::set_color(FL_BACKGROUND_COLOR, colors[RR], colors[GG], colors[BB]); + // Selection + Fl::set_color(FL_SELECTION_COLOR, colors[BG], colors[BG], colors[BG]); + // inactive + int luma = (colors[RR] + colors[RR] + colors[BB] + colors[GG] + + colors[GG] + colors[GG]) / 6; + if (luma > 128) + Fl::set_color(FL_INACTIVE_COLOR, + fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .75f)); + else + Fl::set_color(FL_INACTIVE_COLOR, + fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .75f)); + } + // Text + Fl::set_color(FL_FOREGROUND_COLOR, colors[BG2], colors[BG2], colors[BG2]); + // Tooltips + Fl_Tooltip::textcolor(FL_BACKGROUND_COLOR); + Fl_Tooltip::color(FL_BACKGROUND2_COLOR); + Fl::reload_scheme(); + // update highlight buttons + if (pd && pd->preset) + pd->preset->update_highlight_buttons(); + if (pd && pd->setup) + pd->setup->update_highlight_buttons(); +} + +/** + * switches edit-all-alyers on and off + * @param v if 0, switch edit all layer off, else on + */ +void PD_UI::set_eall(int v) +{ + pmesg(40, "PD_UI::set_eall(%d)\n", v); + if (v && !eall) + { + pd->widget_callback(269, 1); // enable edit all layers + midi->edit_parameter_value(898, -1); // select all layers + pd->selected_layer = 0; + // update UI + //ui->select(0); + m_voice2->hide(); + m_voice3->hide(); + m_voice4->hide(); + ((Fl_Button*) selector->array()[2])->deactivate(); + ((Fl_Button*) selector->array()[3])->deactivate(); + ((Fl_Button*) selector->array()[4])->deactivate(); + for (int i = 1; i < 4; i++) + { + mute_b[i]->deactivate(); + solo_b[i]->deactivate(); + } + main->layer_strip[0]->copy->deactivate(); + main->layer_strip[1]->deactivate(); + main->layer_strip[2]->deactivate(); + main->layer_strip[3]->deactivate(); + layer_editor[0]->copy_env->deactivate(); + layer_editor[0]->copy_lfo->deactivate(); + layer_editor[0]->copy_pc->deactivate(); + layer_editor[1]->deactivate(); + layer_editor[2]->deactivate(); + layer_editor[3]->deactivate(); + // disconnect and reset value in-/output + pwid_editing = 0; + ui->value_input->minimum(0.); + ui->value_input->maximum(0.); + ui->value_input->value(0.); + ui->forma_out->set_value(915, 0, 0); // just anything + b_eall->set(); + if (!m_eall->value()) + m_eall->set(); + if (piano_w->shown()) + piano->redraw(); + eall = true; + pd->display_status("Edit All Layers enabled."); + } + if (!v && eall) + { + pd->widget_callback(269, 0); + midi->edit_parameter_value(898, 0); + m_voice2->show(); + m_voice3->show(); + m_voice4->show(); + ((Fl_Button*) selector->array()[2])->activate(); + ((Fl_Button*) selector->array()[3])->activate(); + ((Fl_Button*) selector->array()[4])->activate(); + for (int i = 1; i < 4; i++) + { + mute_b[i]->activate(); + solo_b[i]->activate(); + } + main->layer_strip[0]->copy->activate(); + main->layer_strip[1]->activate(); + main->layer_strip[2]->activate(); + main->layer_strip[3]->activate(); + layer_editor[0]->copy_env->activate(); + layer_editor[0]->copy_lfo->activate(); + layer_editor[0]->copy_pc->activate(); + layer_editor[1]->activate(); + layer_editor[2]->activate(); + layer_editor[3]->activate(); + b_eall->clear(); + m_eall->clear(); + eall = false; + pd->display_status("Edit All Layers disabled."); + } +} + +/** + * sets various details for the layer copy window and shows it + * @param type what to copy (patchcords, layer, lfos...) + * @param src_layer source layer + * @see copy_layer + */ +void PD_UI::show_copy_layer(int type, int src_layer) +{ + pmesg(40, "PD_UI::show_copy_layer(%d, %d)\n", type, src_layer); + if (!pd->preset) + return; + // reset buttons + for (int i = 0; i < layer_dst->children(); i++) + { + ((Fl_Button*) layer_dst->array()[i])->activate(); + ((Fl_Button*) layer_dst->array()[i])->value(0); + } + // deactivate src layer + ((Fl_Button*) layer_dst->array()[src_layer])->deactivate(); + switch (type) + { + case C_LAYER: + copy_layer->label("Copy Voice"); + break; + case C_LAYER_COMMON: + copy_layer->label("Copy Voice Common"); + break; + case C_LAYER_FILTER: + copy_layer->label("Copy Filter"); + break; + case C_LAYER_LFO: + copy_layer->label("Copy LFO's"); + break; + case C_LAYER_ENVELOPE: + copy_layer->label("Copy Envelopes"); + break; + case C_LAYER_PATCHCORD: + copy_layer->label("Copy Patchcords"); + break; + default: + return; + } + copy_type = type; + copy_src = src_layer; + copy_layer->show(); + pd->display_status("Hint: [ESC] closes windows."); +} + +/** + * sets various details for the copy window and shows it + * @param type what to copy (preset, arp, ..) + * @see copy_preset + */ +void PD_UI::show_copy_preset(int type) +{ + pmesg(40, "PD_UI::show_copy_preset(%d)\n", type); + if (!pd->preset) + { + pd->display_status("*** Nothing to save or copy."); + return; + } + switch (type) + { + case SAVE_PRESET: + copy_preset->label("Save Program"); + g_copy_preset->label("TARGET"); + copy_arp_rom->set_value(0); + copy_browser->set_id(type); + g_copy_preset->show(); + Fl::focus(copy_browser); + g_copy_arp_pattern->hide(); + copy_arp_rom->deactivate(); + break; + case C_PRESET: + copy_preset->label("Copy Program"); + g_copy_preset->label("TARGET"); + copy_arp_rom->set_value(0); + copy_browser->set_id(type); + g_copy_preset->show(); + Fl::focus(copy_browser); + g_copy_arp_pattern->hide(); + copy_arp_rom->deactivate(); + break; + case C_ARP: + copy_preset->label("Copy Arp Settings"); + g_copy_preset->label("SOURCE"); + copy_browser->set_id(type); + g_copy_preset->show(); + Fl::focus(copy_browser); + g_copy_arp_pattern->hide(); + copy_arp_rom->activate(); + break; + case C_ARP_PATTERN: + copy_preset->label("Copy Arp Pattern"); + copy_arp_pattern_browser->set_id(type); + g_copy_arp_pattern->show(); + Fl::focus(copy_arp_pattern_browser); + g_copy_preset->hide(); + break; + } + copy_preset->show(); + pd->display_status("Hint: [ESC] closes windows."); +} + +/** + * initializes voice strips. + * sets id and layer information for all widgets in the voice strips + * @param l layer number of this strip (0-3) + */ +void PD_UI::create_about() +{ + pmesg(40, "PD_UI::create_about()\n"); + const char* OS; +#if defined(OSX) + OS = "Mac OS X"; +#elif defined(WINDOWS) + OS = "Microsoft Windows"; +#else + OS = "GNU/Linux"; +#endif + char buf[512]; + snprintf(buf, 512, "%s\nfor %s", PACKAGE_STRING, OS); + about_text->copy_label(buf); +} + +void PD_Layer_Strip::init(int l) +{ + pmesg(80, "PD_Layer_Strip::init(%d)\n", l); + // initialize layer strips + layer = l; + layer_solo->set_id(1437, layer); + layer_group->set_id(1438, layer); + cutoff->set_id(1538, layer); + emphasis->set_id(1539, layer); + filter->set_id(1537, layer); + for (int i = 0; i <= 50; i++) + FM[i]._index = filter->add(FM[i].name); + coarse->set_id(1425, layer); + fine->set_id(1426, layer); + chorus->set_id(1427, layer); + width->set_id(1428, layer); + offset->set_id(1436, layer); + delay->set_id(1435, layer); + glide->set_id(1432, layer); + glide_curve->set_id(1433, layer); + pan->set_id(1411, layer); + bend->set_id(1431, layer); + volume->set_id(1410, layer); + mix_out->set_id(1412, layer); + non_t->set_id(1430, layer); + // loop->set_id(1434, layer); +} + +/** + * initializes the layer editors + * sets id and layer informations for all widgets contained in the layer editor + * @param l layer of this editor (0-3) + */ +void PD_Layer_Editor::init(int l) +{ + pmesg(80, "PD_Layer_Editor::init(%d)\n", l); + layer = l; + instrument_rom->set_id(1439, l); + instrument->set_id(1409, l); + envelope_editor->set_layer(l); + lfo1_waveform->set_id(1666, l); + lfo1_rate->set_id(1665, l); + lfo1_delay->set_id(1667, l); + lfo1_variation->set_id(1668, l); + lfo1_sync->set_id(1669, l); + lfo2_waveform->set_id(1671, l); + lfo2_rate->set_id(1670, l); + lfo2_delay->set_id(1672, l); + lfo2_variation->set_id(1673, l); + lfo2_sync->set_id(1674, l); + patchcords->init(l); +} + +/** + * create about text. + * creates the text that is shown in the about dialog window + * @see about + */ +/** + * loads various data that needs to be initialized early + */ +static void load_data() +{ + pmesg(40, "load_data()\n"); + // information + rates[0] = "8/1 octal whole"; + rates[1] = "4/1d dotted quad whole"; + rates[2] = "8/1t octal whole triplet"; + rates[3] = "4/1 quad whole"; + rates[4] = "2/1d dotted double whole"; + rates[5] = "4/1t quad whole triplet"; + rates[6] = "2/1 double whole"; + rates[7] = "1/1d dotted whole"; + rates[8] = "2/1t double triplet"; + rates[9] = "1/1 whole note"; + rates[10] = "1/2d dotted half"; + rates[11] = "1/1t whole triplet"; + rates[12] = "1/2 half"; + rates[13] = "1/4d dotted quarter"; + rates[14] = "1/2t half triplet"; + rates[15] = "1/4 quarter"; + rates[16] = "1/8d dotted 8th"; + rates[17] = "1/4t quarter triplet"; + rates[18] = "1/8 8th"; + rates[19] = "1/16d dotted 16th"; + rates[20] = "1/8t 8th triplet"; + rates[21] = "1/16 16th"; + rates[22] = "1/32d dotted 32th"; + rates[23] = "1/16t 16th triplet"; + rates[24] = "1/32 32nd"; + // initialize filter map + FM[0].value = 127; + FM[0].name = "Off"; + FM[0].info = "Unfiltered sound"; + FM[1].value = 138; + FM[1].name = "FuzziFace 12 DST"; + FM[1].info + = "Nasty clipped distortion.\nQ functions as mid-frequency tone\ncontrol."; + FM[2].value = 162; + FM[2].name = "EarBender 12 WAH"; + FM[2].info + = "Midway between wah & vowel.\nStrong mid-boost.\nNasty at high Q settings."; + FM[3].value = 163; + FM[3].name = "KlangKling 12 SFX"; + FM[3].info = "Ringing Flange filter.\nQ \"tunes\" the ring frequency."; + FM[4].value = 1; + FM[4].name = "Lowpass/Smooth 2 LPF"; + FM[4].info + = "Typical OB type low-pass filter\nwith a shallow 12 dB/octave slope."; + FM[5].value = 0; + FM[5].name = "Lowpass/Classic 4 LPF"; + FM[5].info + = "4-pole low-pass filter,\nthe standard filter on classic\nanalog synths.\n24 dB/octave rolloff."; + FM[6].value = 2; + FM[6].name = "Lowpass/Steeper 6 LPF"; + FM[6].info + = "6-pole low-pass filter which has a\nsteeper slope than a 4-pole low-\npass filter.\n36 dB/octave rolloff!"; + FM[7].value = 132; + FM[7].name = "Lowpass/MegaSweepz 12 LPF"; + FM[7].info = "\"Loud\" LPF with a hard Q.\nTweeters beware!"; + FM[8].value = 133; + FM[8].name = "Lowpass/EarlyRizer 12 LPF"; + FM[8].info = "Classic analog sweeping\nwith hot Q and Lo-end."; + FM[9].value = 136; + FM[9].name = "Lowpass/KlubKlassi 12 LPF"; + FM[9].info + = "Responsive low-pass filter sweep\nwith a wide spectrum of Q sounds."; + FM[10].value = 137; + FM[10].name = "Lowpass/BassBox-303 12 LPF"; + FM[10].info = "Pumped up lows with\nTB-like squelchy Q factor."; + FM[11].value = 134; + FM[11].name = "Lowpass/Millennium 12 LPF"; + FM[11].info + = "Aggressive low-pass filter.\nQ gives you a variety of\nspiky tonal peaks."; + FM[12].value = 8; + FM[12].name = "Highpass/Shallow 2 HPF"; + FM[12].info = "2-pole high-pass filter.\n12 dB/octave slope."; + FM[13].value = 9; + FM[13].name = "Highpass/Deeper 4 HPF"; + FM[13].info + = "Classic 4-pole high-pass filter.\nCutoff sweep progressively cuts\n4th Order High-pass."; + FM[14].value = 16; + FM[14].name = "Bandpass/Band-pass1 2 BPF"; + FM[14].info + = "Band-pass filter with 6 dB/octave\nrolloff on either side of the\npassband and Q control."; + FM[15].value = 17; + FM[15].name = "Bandpass/Band-pass2 4 BPF"; + FM[15].info + = "Band-pass filter with 12 dB/octave\nrolloff on either side of the\npassband and Q control."; + FM[16].value = 18; + FM[16].name = "Bandpass/ContraBand 6 BPF"; + FM[16].info + = "A novel band-pass filter where the\nfrequency peaks and dips midway\nin the frequency range."; + FM[17].value = 32; + FM[17].name = "EQ/Swept1>oct 6 EQ+"; + FM[17].info + = "Parametric filter with 24 dB of\nboost or cut and a one octave\nbandwidth."; + FM[18].value = 33; + FM[18].name = "EQ/Swept2>1oct 6 EQ+"; + FM[18].info + = "Parametric filter with 24 dB of\nboost or cut. The bandwidth of the\nfilter is two octaves wide at the\nlow end of the audio spectrum,\ngradually changing to one octave\nwide at the upper end of the\nspectrum."; + FM[19].value = 34; + FM[19].name = "EQ/Swept3>1oct 6 EQ+"; + FM[19].info + = "Parametric filter with 24 dB of\nboost or cut. The bandwidth of the\nfilter is three octaves wide at the\nlow end of the audio spectrum,\ngradually changing to one octave\nwide at the upper end of the\nspectrum."; + FM[20].value = 140; + FM[20].name = "EQ/TB-OrNot-TB 12 EQ+"; + FM[20].info = "Great Bassline \"Processor.\""; + FM[21].value = 142; + FM[21].name = "EQ/RolandBass 12 EQ+"; + FM[21].info = "Constant bass boost\nwith mid-tone Q control."; + FM[22].value = 147; + FM[22].name = "EQ/BassTracer 12 EQ+"; + FM[22].info + = "Low Q boosts bass.\nTry sawtooth or square waveform\nwith Q set to 115."; + FM[23].value = 148; + FM[23].name = "EQ/RogueHertz 12 EQ+"; + FM[23].info + = "Bass with mid-range boost and\nsmooth Q. Sweep cutoff with Q at\n127."; + FM[24].value = 146; + FM[24].name = "EQ/DJAlkaline 12 EQ+"; + FM[24].info = "Band accentuating filter,\nQ shifts \"ring\" frequency."; + FM[25].value = 131; + FM[25].name = "EQ/AceOfBass 12 EQ+"; + FM[25].info = "Bass-boost to bass-cut morph."; + FM[26].value = 149; + FM[26].name = "EQ/RazorBlades 12 EQ-"; + FM[26].info + = "Cuts a series of frequency bands.\nQ selects different bands."; + FM[27].value = 150; + FM[27].name = "EQ/RadioCraze 12 EQ-"; + FM[27].info = "Band limited for a cheap\nradio-like EQ."; + FM[28].value = 64; + FM[28].name = "Phaser/PhazeShift1 6 PHA"; + FM[28].info + = "Recreates a comb filter effect\ntypical of phase shifters. Freq.\n moves position of notches.\nQ varies the depth of the notches."; + FM[29].value = 65; + FM[29].name = "Phaser/PhazeShift2 6 PHA"; + FM[29].info + = "Comb filter with slightly different\nnotch frequency moving the\nfrequency of notches. Q varies\nthe depth of the notches."; + FM[30].value = 66; + FM[30].name = "Phaser/BlissBlatz 6 PHA"; + FM[30].info = "Bat phaser from the Emulator 4."; + FM[31].value = 154; + FM[31].name = "Phaser/FreakShifta 12 PHA"; + FM[31].info = "Phasey movement.\nTry major 6 interval\nand maximum Q."; + FM[32].value = 155; + FM[32].name = "Phaser/CruzPusher 12 PHA"; + FM[32].info = "Accentuates harmonics at high Q.\nTry with a sawtooth LFO."; + FM[33].value = 72; + FM[33].name = "Flanger/FlangerLite 6 FLG"; + FM[33].info + = "Contains three notches.\nFrequency moves frequency and\nspacing of notches.\nQ increases flanging depth."; + FM[34].value = 156; + FM[34].name = "Flanger/AngelzHairz 12 FLG"; + FM[34].info + = "Smooth sweep flanger.\nGood with vox waves.\neg. I094, Q = 60."; + FM[35].value = 157; + FM[35].name = "Flanger/DreamWeava 12 FLG"; + FM[35].info + = "Directional Flanger.\nPoles shift down at low Q\nand up at high Q."; + FM[36].value = 80; + FM[36].name = "Vowel/Aah-Ay-Eeh 6 VOW"; + FM[36].info + = "Vowel formant filter which sweeps\nfrom \"Ah\" sound, through \"Ay\"\nsound to \"Ee\" sound at maximum\nfrequency setting. Q varies the\napparent size of the mouth\ncavity."; + FM[37].value = 81; + FM[37].name = "Vowel/Ooh-To-Aah 6 VOW"; + FM[37].info + = "Vowel formant filter which sweeps\nfrom \"Oo\" sound, through \"Oh\"\nsound to \"Ah\" sound at maximum\nfrequency setting. Q varies the\napparent size of mouth\ncavity."; + FM[38].value = 141; + FM[38].name = "Vowel/Ooh-To-Eee 12 VOW"; + FM[38].info = "Oooh to Eeee formant morph."; + FM[39].value = 143; + FM[39].name = "Vowel/MultiQVox 12 VOW"; + FM[39].info = "Multi-Formant,\nMap Q To velocity."; + FM[40].value = 144; + FM[40].name = "Vowel/TalkingHedz 12 VOW"; + FM[40].info = "\"Oui\" morphing filter.\nQ adds peaks."; + FM[41].value = 151; + FM[41].name = "Vowel/Eeh-To-Aah 12 VOW"; + FM[41].info + = "\"E\" to \"Ah\" formant movement.\nQ accentuates \"peakiness.\""; + FM[42].value = 152; + FM[42].name = "Vowel/UbuOrator 12 VOW"; + FM[42].info = "Aah-Uuh vowel with no Q.\nRaise Q for throaty vocals."; + FM[43].value = 153; + FM[43].name = "Vowel/DeepBouche 12 VOW"; + FM[43].info = "French vowels!\n\"Ou-Est\" vowel at low Q."; + FM[44].value = 135; + FM[44].name = "Resonance/MeatyGizmo 12 REZ"; + FM[44].info = "Filter inverts at mid-Q."; + FM[45].value = 139; + FM[45].name = "Resonance/DeadRinger 12 REZ"; + FM[45].info = "Permanent \"Ringy\" Q response.\nMany Q variations."; + FM[46].value = 145; + FM[46].name = "Resonance/ZommPeaks 12 REZ"; + FM[46].info = "High resonance nasal filter."; + FM[47].value = 158; + FM[47].name = "Resonance/AcidRavage 12 REZ"; + FM[47].info + = "Great analog Q response.\nWide tonal range.\nTry with a sawtooth LFO."; + FM[48].value = 159; + FM[48].name = "Resonance/BassOMatic 12 REZ"; + FM[48].info + = "Low boost for basslines.\nQ goes to distortion at\nthe maximum level."; + FM[49].value = 160; + FM[49].name = "Resonance/LucifersQ 12 REZ"; + FM[49].info = "Violent mid Q filter!\nTake care with Q values 40-90."; + FM[50].value = 161; + FM[50].name = "Resonance/ToothComb 12 REZ"; + FM[50].info + = "Highly resonant harmonic peaks\nshift in unison.\nTry mid Q."; +} diff --git a/prodatum.fl b/prodatum.fl new file mode 100644 index 0000000..df809c4 --- /dev/null +++ b/prodatum.fl @@ -0,0 +1,4523 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0110 +header_name {ui.H} +code_name {ui.C} +comment {/** + \\defgroup pd_ui prodatum User Interface + @\{ +*/} {in_source in_header +} + +decl {\#include "widgets.H"} {public global +} + +declblock {\#ifdef HAVE_CONFIG_H} {after {\#endif} +} { + decl {\#include } {} +} + +decl {\#include } {public global +} + +decl {\#include } {public global +} + +decl {\#include } {public global +} + +decl {\#include "images.H"} {} + +decl {\#include "midi.H"} {} + +decl {\#include "pd.H"} {} + +decl {\#include "cfg.H"} {} + +decl {\#include "debug.H"} {} + +decl {extern MIDI* midi;} {} + +decl {extern PD* pd;} {} + +decl {extern Cfg* cfg;} {} + +decl {extern PD_UI* ui;} {} + +decl {extern int automap;} {} + +decl {extern void reset(int udata, int rdata);} {} + +decl {char filter_tooltip[512];} {} + +widget_class PD_Arp_Step { + xywh {422 50 40 279} type Double hide position_relative +} { + decl {void init(int s);} {public + } + decl {void set_values(int off, int vel, int dur, int rep);} {public + } + decl {int step;} {} + decl {void edit_value(int id, int value);} {} + Fl_Group op { + callback {int val; +for (val = 0; val < 5; val++) +if (((Fl_Button*) o->array()[val])->value()) +break; + +if (val == o->c) + val = o->p; + +o->p = o->c; +o->c = val; + +((Fl_Button*) o->child(val))->setonly(); +if (val == 4) // note +edit_value(784, (int) offset->value()); +else +edit_value(784, val - 52);} + xywh {0 0 40 90} labeltype NO_LABEL labelsize 10 labelcolor 7 align 0 when 0 + class Step_Type + } { + Fl_Button End { + label End + callback {((Group*)o->parent())->do_callback();} + tooltip {End: This command signals the end of the pattern. Any steps programmed after the step containing the End command are ignored.} xywh {0 0 40 17} type Radio down_box UP_BOX color 7 selection_color 81 labelsize 10 labelcolor 49 align 80 when 6 + } + Fl_Button skip { + label Skip + callback {((Group*)o->parent())->do_callback();} + tooltip {Skip: This command simply removes the step from the pattern. The Skip feature makes it easy to remove an unwanted step without rearranging the entire pattern. You'll be happy to know that the velocity, duration and repeat parameters are remembered if you decide to put the step back later.} xywh {0 18 40 17} type Radio down_box UP_BOX color 7 selection_color 94 labelsize 10 labelcolor 49 align 80 when 6 + } + Fl_Button {} { + label Rest + callback {((Group*)o->parent())->do_callback();} + tooltip {Rest: Instead of playing a note, you can define the step as a Rest. The Duration parameter specifies the length of the rest. Rests can be tied together to form longer rests.} xywh {0 36 40 17} type Radio down_box UP_BOX color 7 selection_color 200 labelsize 10 labelcolor 49 align 80 when 6 + } + Fl_Button {} { + label Tie + callback {((Group*)o->parent())->do_callback();} + tooltip {Tie: This function extends the duration of notes beyond the values given in the duration field by "tying" notes together. You can tie together any number of consecutive steps. IMPORTANT: The Gate function in the arpeggiator MUST be set to 100% when using the tie function, otherwise the tied note is retriggered instead of extended.} xywh {0 54 40 17} type Radio down_box UP_BOX color 7 selection_color 179 labelsize 10 labelcolor 49 align 80 when 6 + } + Fl_Button key { + label Key + callback {((Group*)o->parent())->do_callback();} + tooltip {Key: Play a note} xywh {0 72 40 17} type Radio down_box UP_BOX color 7 selection_color 100 labelsize 10 labelcolor 49 align 80 when 6 + } + } + Fl_Value_Output duration { + callback {edit_value(786, (int) o->value());} + tooltip {Duration: Sets the length of time for the current step, defined as a note value, based on the Master Tempo.} xywh {0 91 40 17} box UP_BOX selection_color 15 labeltype NO_LABEL labelsize 10 align 0 when 4 minimum 1 maximum 19 step 1 textfont 4 textsize 12 + class Step_Value + } + Fl_Value_Output repeat { + callback {edit_value(787, (int) o->value() - 1);} + tooltip {Repeat: Each step can be played from 1 to 32 times.} xywh {0 110 40 17} box UP_BOX selection_color 15 labeltype NO_LABEL labelsize 10 align 0 when 4 minimum 1 maximum 32 step 1 textfont 4 textsize 12 + class Step_Value + } + Fl_Value_Output velocity { + callback {edit_value(785, (int) o->value());} + tooltip {Velocity: Each note in the pattern plays using either a preset velocity value (from 1 through 127), or using the actual velocity of the played note (0).} xywh {0 129 40 17} box UP_BOX selection_color 15 labeltype NO_LABEL labelsize 10 align 0 when 4 maximum 127 step 1 textfont 4 textsize 12 + class Step_Value + } + Fl_Value_Slider offset { + callback {if (key->value()) edit_value(784, (int) o->value());} + tooltip {Key Offset: Offset from the original note played (semitones).} xywh {0 148 40 131} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 80 when 4 minimum 48 maximum -48 step 1 textfont 4 textsize 12 + class Step_Offset + } +} + +widget_class PD_Preset_Patchcords { + xywh {322 151 826 132} type Double hide position_relative +} { + Function {uninitialize_sources()} {return_type void + } { + code {s1->uninitialize(); + s2->uninitialize(); + s3->uninitialize(); + s4->uninitialize(); + s5->uninitialize(); + s6->uninitialize(); + s7->uninitialize(); + s8->uninitialize(); + s9->uninitialize(); + s10->uninitialize(); + s11->uninitialize(); + s12->uninitialize();} {} + } + Fl_Box {} { + label {1-4} + xywh {1 2 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {5-8} + xywh {276 2 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {9-12} + xywh {551 2 274 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Choice s1 {open + tooltip {Patch Source} xywh {2 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(931);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {118 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(932);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {234 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(933);} + class Value_Output + } + Fl_Choice s2 {open + tooltip {Patch Source} xywh {2 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(934);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {118 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(935);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {234 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(936);} + class Value_Output + } + Fl_Choice s3 {open + tooltip {Patch Source} xywh {2 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(937);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {118 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(938);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {234 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(939);} + class Value_Output + } + Fl_Choice s4 {open + tooltip {Patch Source} xywh {2 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(940);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {118 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(941);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {234 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(942);} + class Value_Output + } + Fl_Choice s5 {open + tooltip {Patch Source} xywh {277 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(943);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {393 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(944);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {509 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(945);} + class Value_Output + } + Fl_Choice s6 {open + tooltip {Patch Source} xywh {277 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(946);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {393 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(947);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {509 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(948);} + class Value_Output + } + Fl_Choice s7 {open + tooltip {Patch Source} xywh {277 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(949);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {393 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(950);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {509 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(951);} + class Value_Output + } + Fl_Choice s8 {open + tooltip {Patch Source} xywh {277 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(952);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {393 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(953);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {509 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(954);} + class Value_Output + } + Fl_Choice s9 {open + tooltip {Patch Source} xywh {552 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(955);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {668 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(956);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {784 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(957);} + class Value_Output + } + Fl_Choice s10 {open + tooltip {Patch Source} xywh {552 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(958);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {668 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(959);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {784 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(960);} + class Value_Output + } + Fl_Choice s11 {open + tooltip {Patch Source} xywh {552 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(961);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {668 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(962);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {784 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(963);} + class Value_Output + } + Fl_Choice s12 {open + tooltip {Patch Source} xywh {552 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(964);} + class PCS_Choice + } {} + Fl_Choice {} {open + tooltip {Patch Destination} xywh {668 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + code0 {o->set_id(965);} + class PPCD_Choice + } {} + Fl_Value_Output {} { + tooltip {Modulation Amount} xywh {784 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + code0 {o->set_id(966);} + class Value_Output + } +} + +widget_class PD_Layer_Patchcords { + xywh {335 230 826 264} type Double labelcolor 7 hide position_relative +} { + Function {init(int l)} {return_type void + } { + code {s1->set_id(1921, l); + s2->set_id(1924, l); + s3->set_id(1927, l); + s4->set_id(1930, l); + s5->set_id(1933, l); + s6->set_id(1936, l); + s7->set_id(1939, l); + s8->set_id(1942, l); + s9->set_id(1945, l); + s10->set_id(1948, l); + s11->set_id(1951, l); + s12->set_id(1954, l); + s13->set_id(1957, l); + s14->set_id(1960, l); + s15->set_id(1963, l); + s16->set_id(1966, l); + s17->set_id(1969, l); + s18->set_id(1972, l); + s19->set_id(1975, l); + s20->set_id(1978, l); + s21->set_id(1981, l); + s22->set_id(1984, l); + s23->set_id(1987, l); + s24->set_id(1990, l); + d1->set_id(1922, l); + d2->set_id(1925, l); + d3->set_id(1928, l); + d4->set_id(1931, l); + d5->set_id(1934, l); + d6->set_id(1937, l); + d7->set_id(1940, l); + d8->set_id(1943, l); + d9->set_id(1946, l); + d10->set_id(1949, l); + d11->set_id(1952, l); + d12->set_id(1955, l); + d13->set_id(1958, l); + d14->set_id(1961, l); + d15->set_id(1964, l); + d16->set_id(1967, l); + d17->set_id(1970, l); + d18->set_id(1973, l); + d19->set_id(1976, l); + d20->set_id(1979, l); + d21->set_id(1982, l); + d22->set_id(1985, l); + d23->set_id(1988, l); + d24->set_id(1991, l); + a1->set_id(1923, l); + a2->set_id(1926, l); + a3->set_id(1929, l); + a4->set_id(1932, l); + a5->set_id(1935, l); + a6->set_id(1938, l); + a7->set_id(1941, l); + a8->set_id(1944, l); + a9->set_id(1947, l); + a10->set_id(1950, l); + a11->set_id(1953, l); + a12->set_id(1956, l); + a13->set_id(1959, l); + a14->set_id(1962, l); + a15->set_id(1965, l); + a16->set_id(1968, l); + a17->set_id(1971, l); + a18->set_id(1974, l); + a19->set_id(1977, l); + a20->set_id(1980, l); + a21->set_id(1983, l); + a22->set_id(1986, l); + a23->set_id(1989, l); + a24->set_id(1992, l);} {} + } + Function {uninitialize_sources()} {return_type void + } { + code {s1->uninitialize(); + s2->uninitialize(); + s3->uninitialize(); + s4->uninitialize(); + s5->uninitialize(); + s6->uninitialize(); + s7->uninitialize(); + s8->uninitialize(); + s9->uninitialize(); + s10->uninitialize(); + s11->uninitialize(); + s12->uninitialize(); + s13->uninitialize(); + s14->uninitialize(); + s15->uninitialize(); + s16->uninitialize(); + s17->uninitialize(); + s18->uninitialize(); + s19->uninitialize(); + s20->uninitialize(); + s21->uninitialize(); + s22->uninitialize(); + s23->uninitialize(); + s24->uninitialize();} {} + } + Fl_Choice s1 {open + tooltip {Patch Source} xywh {2 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d1 {open + tooltip {Patch Destination} xywh {118 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a1 { + tooltip {Modulation Amount} xywh {234 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s2 {open + tooltip {Patch Source} xywh {2 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d2 {open + tooltip {Patch Destination} xywh {118 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a2 { + tooltip {Modulation Amount} xywh {234 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s3 {open + tooltip {Patch Source} xywh {2 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d3 {open + tooltip {Patch Destination} xywh {118 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a3 { + tooltip {Modulation Amount} xywh {234 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s4 {open + tooltip {Patch Source} xywh {2 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d4 {open + tooltip {Patch Destination} xywh {118 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a4 { + tooltip {Modulation Amount} xywh {234 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s5 {open + tooltip {Patch Source} xywh {277 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d5 {open + tooltip {Patch Destination} xywh {393 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a5 { + tooltip {Modulation Amount} xywh {509 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s6 {open + tooltip {Patch Source} xywh {277 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d6 {open + tooltip {Patch Destination} xywh {393 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a6 { + tooltip {Modulation Amount} xywh {509 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s7 {open + tooltip {Patch Source} xywh {277 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d7 {open + tooltip {Patch Destination} xywh {393 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a7 { + tooltip {Modulation Amount} xywh {509 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s8 {open + tooltip {Patch Source} xywh {277 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d8 {open + tooltip {Patch Destination} xywh {393 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a8 { + tooltip {Modulation Amount} xywh {509 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s9 {open + tooltip {Patch Source} xywh {552 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d9 {open + tooltip {Patch Destination} xywh {668 28 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a9 { + tooltip {Modulation Amount} xywh {784 28 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s10 {open + tooltip {Patch Source} xywh {552 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d10 {open + tooltip {Patch Destination} xywh {668 53 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a10 { + tooltip {Modulation Amount} xywh {784 53 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s11 {open + tooltip {Patch Source} xywh {552 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d11 {open + tooltip {Patch Destination} xywh {668 78 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a11 { + tooltip {Modulation Amount} xywh {784 78 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s12 {open + tooltip {Patch Source} xywh {552 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d12 {open + tooltip {Patch Destination} xywh {668 103 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a12 { + tooltip {Modulation Amount} xywh {784 103 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s13 {open + tooltip {Patch Source} xywh {2 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d13 {open + tooltip {Patch Destination} xywh {118 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a13 { + tooltip {Modulation Amount} xywh {234 160 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s14 {open + tooltip {Patch Source} xywh {2 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d14 {open + tooltip {Patch Destination} xywh {118 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a14 { + tooltip {Modulation Amount} xywh {234 185 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s15 {open + tooltip {Patch Source} xywh {2 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d15 {open + tooltip {Patch Destination} xywh {118 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a15 { + tooltip {Modulation Amount} xywh {234 210 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s16 {open + tooltip {Patch Source} xywh {2 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d16 {open + tooltip {Patch Destination} xywh {118 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a16 { + tooltip {Modulation Amount} xywh {234 235 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s17 {open + tooltip {Patch Source} xywh {277 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d17 {open + tooltip {Patch Destination} xywh {393 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a17 { + tooltip {Modulation Amount} xywh {509 160 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s18 {open + tooltip {Patch Source} xywh {277 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d18 {open + tooltip {Patch Destination} xywh {393 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a18 { + tooltip {Modulation Amount} xywh {509 185 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s19 {open + tooltip {Patch Source} xywh {277 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d19 {open + tooltip {Patch Destination} xywh {393 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a19 { + tooltip {Modulation Amount} xywh {509 210 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s20 {open + tooltip {Patch Source} xywh {277 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d20 {open + tooltip {Patch Destination} xywh {393 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a20 { + tooltip {Modulation Amount} xywh {509 235 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s21 {open + tooltip {Patch Source} xywh {552 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d21 {open + tooltip {Patch Destination} xywh {668 160 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a21 { + tooltip {Modulation Amount} xywh {784 160 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s22 {open + tooltip {Patch Source} xywh {552 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d22 {open + tooltip {Patch Destination} xywh {668 185 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a22 { + tooltip {Modulation Amount} xywh {784 185 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s23 {open + tooltip {Patch Source} xywh {552 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d23 {open + tooltip {Patch Destination} xywh {668 210 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a23 { + tooltip {Modulation Amount} xywh {784 210 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Choice s24 {open + tooltip {Patch Source} xywh {552 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCS_Choice + } {} + Fl_Choice d24 {open + tooltip {Patch Destination} xywh {668 235 115 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 12 labelcolor 15 align 0 textsize 13 + class PCD_Choice + } {} + Fl_Value_Output a24 { + tooltip {Modulation Amount} xywh {784 235 41 21} box FLAT_BOX selection_color 15 labeltype NO_LABEL labelsize 12 align 0 minimum -100 maximum 100 step 1 textsize 13 + class Value_Output + } + Fl_Box {} { + label {1-4} + xywh {1 2 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {5-8} + xywh {276 2 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {9-12} + xywh {551 2 274 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {13-16} + xywh {1 134 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {17-20} + xywh {276 134 275 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } + Fl_Box {} { + label {21-24} + xywh {551 134 274 20} box THIN_UP_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 20 + } +} + +widget_class PD_Layer_Strip { + xywh {347 50 100 542} type Double hide position_relative +} { + decl {void init(int layer);} {public + } + decl {int layer;} {} + Fl_Button instrument { + label { :None} + callback {ui->select(layer + 1);} + xywh {3 3 94 20} down_box UP_BOX color 7 selection_color 15 labelfont 5 labelsize 12 labelcolor 49 align 84 + } + Fl_Dial coarse { + label Coarse + private tooltip {Coarse tune (±36 semitones)} xywh {7 23 40 40} color 7 labelsize 10 minimum -36 maximum 36 step 1 + class Fl_Knob + } + Fl_Button {} { + label {-} + callback {if (o->value()) +{ +int val = coarse->value(); +if (val == -36) return; +val -= 12; +if (val < -36) val = -36; +coarse->value(val); +coarse->do_callback(); +}} + tooltip {Tune octave down} xywh {1 63 26 15} box NO_BOX labelfont 4 labelsize 9 align 20 when 1 + class Fixed_Button + } + Fl_Button {} { + label {+} + callback {if (o->value()) +{ +int val = coarse->value(); +if (val == 36) return; +val += 12; +if (val > 36) val = 36; +coarse->value(val); +coarse->do_callback(); +}} + tooltip {Tune octave up} xywh {28 63 26 15} box NO_BOX labelfont 4 labelsize 9 align 24 when 1 + class Fixed_Button + } + Fl_Dial fine { + label Fine + private tooltip {Fine tune (±1 semitone by 1/64 semitone intervals (1.56 cents))} xywh {53 23 40 40} color 7 labelsize 10 minimum -63 maximum 63 step 1 + class Fl_Knob + } + Fl_Dial offset { + label {S.Offset} + private tooltip {Sample Start Offset: higher values move the Sample Start Point further into the sample toward the end} xywh {7 76 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial delay { + label {S.Delay} + private tooltip {Sample Start Delay: defines the time between when you hit a key (note-on) and the onset of the current layer's note and the start of the envelopes (if applicable)} xywh {53 76 40 40} color 7 labelsize 10 minimum -25 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial chorus { + label Chorus + private tooltip {Chorus (detuning amount 1-100%)} xywh {7 129 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial width { + label Width + private tooltip {Chorus width (stereo spreading 0-100%)} xywh {53 129 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Choice filter {open + tooltip {Filter Type. Allows you to choose the type of filter for the layer} xywh {3 183 94 20} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textfont 4 textsize 12 + class Choice + } {} + Fl_Group filter_knobs {open + xywh {7 203 87 53} + } { + Fl_Dial cutoff { + label Cutoff + private tooltip {Control various elements of the filter depending on the type of filter used} xywh {7 203 40 40} color 7 labelsize 10 maximum 255 step 1 + class Fl_Knob + } + Fl_Dial emphasis { + label Res + private tooltip {Control various elements of the filter depending on the type of filter used} xywh {53 203 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + } + Fl_Dial glide { + label Glide + private tooltip {Glide Rate: defines the time it takes to glide to the new pitch (the larger the value, the slower the glide rate) The glide rate value range is from 0 through 32.738 seconds (zero means off)} xywh {7 256 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial glide_curve { + label {G.Curve} + private tooltip {Glide Curve: describes how the glide accelerates as it slides between notes. Because of the ear's non-linear response to pitch, a linear glide sounds slow at the beginning and speeds up toward the end. Exponential curves actually sound smoother and more linear. Eight exponential curves are provided} xywh {52 256 40 40} color 7 labelsize 10 maximum 8 step 1 + class Fl_Knob + } + Fl_Dial pan { + label Pan + private tooltip {Stereo panorama} xywh {7 310 40 40} color 7 labelsize 10 minimum -64 maximum 63 step 1 + class Fl_Knob + } + Fl_Dial bend { + label {Bend R.} + private tooltip {Pitch-Bend Range: 0 to ±12 semitones or Master (-1)} xywh {52 310 40 40} color 7 labelsize 10 minimum -1 maximum 12 step 1 + class Fl_Knob + } + Fl_Box {} { + xywh {8 402 7 5} box BORDER_BOX color 7 labeltype NO_LABEL labelsize 10 labelcolor 7 when 0 deactivate + } + Fl_Box {} { + xywh {40 402 7 5} box BORDER_BOX color 7 labeltype NO_LABEL labelsize 10 labelcolor 7 when 0 deactivate + } + Fl_Slider volume { + label dB + tooltip {Voice volume} xywh {15 365 25 129} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 1.19102e+06 maximum 0 step 1 + class Slider + } + Fl_Button mute_b { + label M + callback {pd->mute(o->value(), layer);} + tooltip {Mute Voice} xywh {49 366 19 17} type Toggle down_box UP_BOX color 7 selection_color 81 labelfont 1 labelsize 10 labelcolor 49 when 1 + class Fixed_Button + } + Fl_Button solo_b { + label S + callback {pd->solo(o->value(), layer);} + tooltip {Solo Voice} xywh {76 366 19 17} type Toggle down_box UP_BOX color 7 selection_color 134 labelfont 1 labelsize 10 labelcolor 49 when 1 + class Fixed_Button + } + Fl_Button copy { + label COPY + callback {ui->show_copy_layer(C_LAYER, layer);} + tooltip {Copy voice} xywh {52 477 40 17} selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Button non_t { + label NTP + tooltip {Turns keyboard transposition On or Off. With Nontranspose the keyboard will not control the pitch of the instrument. This is a useful function for drones, attack "chiffs" or other sound effects which you may not want to track the keyboard} xywh {52 385 40 17} type Toggle down_box UP_BOX selection_color 140 labelsize 10 labelcolor 15 + class Button + } + Fl_Group mix_out { + tooltip {Layer Submix, FX Send} xywh {52 404 41 71} color 52 labeltype NO_LABEL labelsize 10 labelcolor 7 align 0 + class Group + } { + Fl_Button {} { + label 1 + callback {((Group*)o->parent())->do_callback();} + xywh {57 404 30 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 + } + Fl_Button {} { + label 2 + callback {((Group*)o->parent())->do_callback();} + xywh {57 422 30 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 + } + Fl_Button {} { + label 3 + callback {((Group*)o->parent())->do_callback();} + xywh {57 440 30 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 + } + Fl_Button {} { + label 4 + callback {((Group*)o->parent())->do_callback();} + xywh {57 458 30 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 + } + } + Fl_Choice layer_solo {open + tooltip {Solo Mode: provides the playing action of a monophonic instrument such as a lead synthesizer by preventing more than one note from sounding at once} xywh {3 498 94 20} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->add("off");o->add("multi trigger");o->add("melody last");} + code1 {o->add("melody low");o->add("melody high");o->add("synth last");} + code2 {o->add("synth low");o->add("synth high");o->add("fingered glide");} + class Choice + } {} + Fl_Choice layer_group {open + tooltip {Assign Group: use this parameter to assign a certain number of channels to each layer. By assigning all voices in the preset to assign groups, important parts are protected from being "stolen" by more recently played keys. Or you can assign a voice, such as an open high hat, to a mono channel so it is cancelled by a closed high hat on the same mono channel. Layers rotate within their assigned "bin" of channels, not interfering with other bins} xywh {3 520 94 20} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->add("poly all"); o->add("poly 16 A"); o->add("poly 16 B"); o->add("poly 8 A"); o->add("poly 8 B"); o->add("poly 8 C");} + code1 {o->add("poly 8 D"); o->add("poly 4 A"); o->add("poly 4 B"); o->add("poly 4 C"); o->add("poly 4 D"); o->add("poly 2 A");} + code2 {o->add("poly 2 B"); o->add("poly 2 C"); o->add("poly 2 D"); o->add("mono A"); o->add("mono B"); o->add("mono C");} + code3 {o->add("mono D"); o->add("mono E"); o->add("mono F"); o->add("mono G"); o->add("mono H"); o->add("mono I");} + class Choice + } {} +} + +widget_class PD_Layer_Editor { + xywh {344 207 833 569} type Double box BORDER_BOX hide position_relative +} { + decl {void init(int l);} {public + } + decl {int layer;} {} + Fl_Group {} { + label INSTRUMENT open + xywh {4 23 196 244} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice instrument_rom {open + xywh {14 29 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + class ROM_Choice + } {} + Fl_Browser instrument { + xywh {14 55 176 181} type Hold when 1 textfont 4 textsize 12 textcolor 49 + class Browser + } + Fl_Input instrument_filter { + label {F } + callback {instrument->set_filter(o->value());} + xywh {30 241 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {instrument_filter->value(0); +instrument_filter->do_callback();} + xywh {164 241 26 20} box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + Fl_Button copy_env { + label COPY + callback {ui->show_copy_layer(C_LAYER_ENVELOPE, layer);} + tooltip {Copy envelopes to voice...} xywh {208 6 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Group {} { + label ENVELOPES open + xywh {208 23 417 244} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Box envelope_editor { + xywh {209 24 415 242} box FLAT_BOX labeltype NO_LABEL + class Envelope_Editor + } + } + Fl_Button copy_lfo { + label COPY + callback {ui->show_copy_layer(C_LAYER_LFO, layer);} + tooltip {Copy LFO's to voice...} xywh {634 86 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Group {} { + label {LFO'S} open + xywh {634 103 196 164} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice lfo1_waveform {open + tooltip {LFO Shape} xywh {644 108 176 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 10 labelcolor 15 align 0 textsize 13 + code1 {o->add("Random");o->add("Triangle");o->add("Sine");o->add("Sawtooth");o->add("Square");o->add("33% Pulse");o->add("25% Pulse");o->add("16% Pulse");o->add("12% Pulse");o->add("Pat: Octaves");o->add("Pat: Fifth+Octave");o->add("Pat: Sus4Trip");o->add("Pat: Neener");o->add("Sine 1,2");o->add("Sine 1,3,5");o->add("Sine+Noise");o->add("Hemi-quaver");} + class Choice + } {} + Fl_Dial lfo1_rate { + label Rate + tooltip {LFO Rate: the LFO speed in absolute frequency rate values (0.08 Hz to 18.14 Hz) or tempo-based note values} xywh {644 132 40 40} color 7 labelsize 10 minimum -25 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial lfo1_delay { + label Delay + tooltip {LFO Delay: defines the amount of time between hitting a key on the controller and the onset of the LFO modulation} xywh {689 132 40 40} color 7 labelsize 10 minimum -25 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial lfo1_variation { + label Variation + tooltip {LFO Variation: sets the amount of random variation of the LFO each time you press a key on the controller (Variation is disabled when a Tempo-Based LFO is selected)} xywh {734 132 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Button lfo1_sync { + label Sync + tooltip {LFO Sync: specifies whether the LFO is synchronized to a key stroke or is Free Running. Key Sync starts the LFO wave at the beginning of its cycle each time you press a key on the controller. In Free Run mode, the LFO wave begins at a random point in its cycle each time you press a key on the controller} xywh {779 136 41 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 179 labelsize 10 labelcolor 49 + class Button + } + Fl_Choice lfo2_waveform {open + tooltip {LFO Shape} xywh {644 187 176 21} down_box BORDER_BOX labeltype NO_LABEL labelsize 10 labelcolor 15 align 0 textsize 13 + code1 {o->add("Random");o->add("Triangle");o->add("Sine");o->add("Sawtooth");o->add("Square");o->add("33% Pulse");o->add("25% Pulse");o->add("16% Pulse");o->add("12% Pulse");o->add("Pat: Octaves");o->add("Pat: Fifth+Octave");o->add("Pat: Sus4Trip");o->add("Pat: Neener");o->add("Sine 1,2");o->add("Sine 1,3,5");o->add("Sine+Noise");o->add("Hemi-quaver");} + class Choice + } {} + Fl_Dial lfo2_rate { + label Rate + tooltip {LFO Rate: the LFO speed in absolute frequency rate values (0.08 Hz to 18.14 Hz) or tempo-based note values} xywh {644 211 40 40} color 7 labelsize 10 minimum -25 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial lfo2_delay { + label Delay + tooltip {LFO Delay: defines the amount of time between hitting a key on the controller and the onset of the LFO modulation} xywh {689 211 40 40} color 7 labelsize 10 minimum -25 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial lfo2_variation { + label Variation + tooltip {LFO Variation: sets the amount of random variation of the LFO each time you press a key on the controller (Variation is disabled when a Tempo-Based LFO is selected)} xywh {734 211 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Button lfo2_sync { + label Sync + tooltip {LFO Sync: specifies whether the LFO is synchronized to a key stroke or is Free Running. Key Sync starts the LFO wave at the beginning of its cycle each time you press a key on the controller. In Free Run mode, the LFO wave begins at a random point in its cycle each time you press a key on the controller} xywh {779 215 41 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 179 labelsize 10 labelcolor 49 + class Button + } + Fl_Box {} { + label 1 + xywh {779 159 41 18} labelfont 1 labelsize 15 labelcolor 15 + } + Fl_Box {} { + label 2 + xywh {779 238 41 18} labelfont 1 labelsize 15 labelcolor 15 + } + } + Fl_Button copy_pc { + label COPY + callback {ui->show_copy_layer(C_LAYER_PATCHCORD, layer);} + tooltip {Copy patchcords to voice...} xywh {4 284 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Box patchcords { + label PATCHCORDS + xywh {4 301 826 264} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + class PD_Layer_Patchcords + } +} + +widget_class PD_Preset_Editor { + xywh {285 127 833 569} type Double box BORDER_BOX hide position_relative +} { + Fl_Group g_riff { + label RIFF open + xywh {4 23 196 376} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice riff_rom {open + xywh {14 29 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(929);} + class ROM_Choice + } {} + Fl_Browser riff { + xywh {14 55 176 313} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(928);} + class Browser + } + Fl_Input riff_filter { + label {F } + callback {riff->set_filter(o->value());} + xywh {30 373 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {riff_filter->value(0); +riff_filter->do_callback();} + xywh {164 373 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + Fl_Group program {open + xywh {208 1 417 398} + } { + Fl_Button copy_arp_b { + label {COPY FROM} + callback {ui->show_copy_preset(C_ARP);} + tooltip {Copy arpeggiator settings from another program. Note: this is permanent (it overwrites program arpeggiator settings)} xywh {208 7 86 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 deactivate + } + Fl_Group {} { + label ARPEGGIATOR open + xywh {208 23 417 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Button {} { + label Sync + tooltip {Sync. The Sync parameter defines when a note is played in relation to when the key is pressed. When On, the note sounds the instant a key is pressed (Key Sync). When Off, the note does not sound until the next occurrence of the selected note value (Quantized)} xywh {234 33 48 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 179 labelsize 10 + code0 {o->set_id(1033);} + class Button + } + Fl_Group {} { + label Mode + tooltip {Arpeggiator Mode. The Mode parameter determines the direction or pattern mode of the arpeggiated notes} xywh {224 67 68 143} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(1026);} + class Group + } { + Fl_Button {} { + label Up + callback {((Group*)o->parent())->do_callback();} + xywh {224 67 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Down + callback {((Group*)o->parent())->do_callback();} + xywh {224 85 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {Up-Down} + callback {((Group*)o->parent())->do_callback();} + xywh {224 103 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Fwd + callback {((Group*)o->parent())->do_callback();} + xywh {224 121 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Bkw + callback {((Group*)o->parent())->do_callback();} + xywh {224 139 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {Fwd-Bkw} + callback {((Group*)o->parent())->do_callback();} + xywh {224 157 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Random + callback {((Group*)o->parent())->do_callback();} + xywh {224 175 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Pattern + callback {((Group*)o->parent())->do_callback();} + xywh {224 193 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Group g_pattern_speed { + label {Pattern Speed} + xywh {220 230 76 89} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(1041);} + class Group + } { + Fl_Button {} { + label 4x + callback {((Group*)o->parent())->do_callback();} + xywh {234 230 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label 2x + callback {((Group*)o->parent())->do_callback();} + xywh {234 248 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label 1x + callback {((Group*)o->parent())->do_callback();} + xywh {234 266 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {1/2x} + callback {((Group*)o->parent())->do_callback();} + xywh {234 284 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {1/4x} + callback {((Group*)o->parent())->do_callback();} + xywh {234 302 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Dial note { + label Note + tooltip {Note Value. The Note Value determines the duration of each note played. This parameter is used in non-pattern mode only} xywh {312 28 40 40} color 7 labelsize 10 minimum 1 maximum 19 step 1 value 1 + code0 {o->set_id(1028);} + class Fl_Knob + } + Fl_Dial {} { + label Gate + tooltip {Gate Time. The Gate Time parameter works together with the Note Value parameter. Just as Note Value defines the length of a note, the Gate Time sets the percentage of the Note Value time played} xywh {357 28 40 40} color 7 labelsize 10 maximum 100 step 1 + code0 {o->set_id(1030);} + class Fl_Knob + } + Fl_Dial {} { + label Velocity + tooltip {Note Velocity. The Velocity parameter determines the velocity at which each note arpeggiates. Velocity can be defined by the velocity value specified (from 1 through 127), or by the actual velocity of the played note (0)} xywh {312 82 40 40} color 7 labelsize 10 maximum 127 step 1 + code0 {o->set_id(1029);} + class Fl_Knob + } + Fl_Dial {} { + label Duration + tooltip {Duration. This parameter defines how long the arpeggiator plays before stopping. The Duration is specified in note values. Therefore if an arpeggio were running at a 16th Note Value and the Duration were set to a whole note, the arpeggiator would play 16 steps before stopping. After the duration has elapsed, the arpeggiator remains inactive until the key is released. If Duration is set to Off, the arpeggio repeats as long as the notes are held (Infinite Duration)} xywh {357 82 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(1035);} + class Fl_Knob + } + Fl_Dial pre_d { + label {Pre D} + tooltip {Pre-Delay. The Pre-Delay value determines how long the arpeggiator is delayed before becoming active after the first "note-on". During the pre-delay period, notes are played normally (as if the arpeggiator was off). After the pre-delay period has elapsed, the arpeggiator kicks in. Once you release all the keys on the controller, the pre-delay starts over with the next note-on. In combination with the Duration parameter, Pre-Delay lets you change the arpeggio patterns to create many more variations} xywh {312 138 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(1034);} + class Fl_Knob + } + Fl_Dial post_d { + label {Post D} + tooltip {Post-Delay. This parameter is only relevant when both the "Duration" and "Recycle" parameters are not in the "Off" state. The Post-Delay value determines how long the arpeggiator is delayed after the Duration period. During the post-delay period, notes are played normally (as if the arpeggiator was off). After the post-delay period has elapsed, the arpeggiator either jumps to the beginning of the Pre-Delay period or to the beginning of the Duration period depending on the Recycle setting} xywh {357 138 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(1043);} + class Fl_Knob + } + Fl_Dial {} { + label Count + tooltip {Extension Count. The Extension Count parameter specifies how many times the Extension Interval is carried out. With an Extension Count of 0, the arpeggio plays only the notes pressed. With an Extension Count of 1, the arpeggio plays the notes pressed, then plays the same notes (in the same order), transposed by the Extension Interval amount. The cycle is then repeated} xywh {312 192 40 40} color 7 labelsize 10 maximum 15 step 1 + code0 {o->set_id(1031);} + class Fl_Knob + } + Fl_Dial {} { + label Interval + tooltip {Extension Interval. The Extension Interval specifies the additional intervals played when you press a key. For example, suppose you played C2 with an Interval of 7 (a Major 5th), Up mode, and an Extension Count of 2. The arpeggio alternates between C2 and G2} xywh {357 192 40 40} color 7 labelsize 10 minimum 1 maximum 16 step 1 value 1 + code0 {o->set_id(1032);} + class Fl_Knob + } + Fl_Group {} { + label Recylce + tooltip {Recycle. This parameter works together with the Duration and Pre/Post Delay parameters. When these are enabled without one of the Recycle options turned on, the pattern or arpeggio normally stops. With Recycle On, the arpeggio instantly resets the pattern to the beginning of the Pre-Delay period after the duration value has elapsed and repeats the pattern or arpeggio. Another option called "On-No Pre-Delay" bypasses the predelay period} xywh {330 266 50 53} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(1036);} + class Group + } { + Fl_Button {} { + label Off + callback {((Group*)o->parent())->do_callback();} + xywh {330 266 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label On + callback {((Group*)o->parent())->do_callback();} + xywh {330 284 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {No-Pre} + callback {((Group*)o->parent())->do_callback();} + xywh {330 302 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Button {} { + label Active + tooltip {Arpeggiator On/Off} xywh {437 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 78 labelsize 10 + code0 {o->set_id(1025);} + class Button + } + Fl_Button {} { + label Thru + tooltip {Keyboard Thru. When enabled, merges the notes not arpeggiated with the arpeggiated notes. This gives the effect of two parts playing at once} xywh {492 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + code0 {o->set_id(1037);} + class Button + } + Fl_Button {} { + label Latch + tooltip {Latch. With Latch mode On, any notes you play remain on until you press them again. Latched notes can be halted by turning Latch off in this screen, or by turning off the Arpeggiator} xywh {547 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + code0 {o->set_id(1038);} + class Button + } + Fl_Button {} { + label COPY + callback {ui->show_copy_preset(C_ARP_PATTERN);} + tooltip {Copy pattern...} xywh {419 58 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Button edit_arp { + label EDIT + callback {if (pd->arp && pd->arp->get_number() == arp->value()-1) +{ +ui->g_arp_edit->show(); +ui->g_main->hide(); +Fl::focus(ui->g_arp_edit); +} +else +midi->request_arp_dump(arp->value()-1, 0);} + tooltip {Edit Arpeggiator pattern} xywh {575 58 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 deactivate + class Fixed_Button + } + Fl_Group g_pattern { + label PATTERN open + xywh {419 75 196 244} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice arp_rom {open + xywh {429 81 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(1042);} + class ROM_Choice + } {} + Fl_Browser arp { + xywh {429 107 176 181} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(1027);} + class Browser + } + Fl_Input arp_filter { + label {F } + callback {arp->set_filter(o->value());} + xywh {445 293 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {arp_filter->value(0); +arp_filter->do_callback();} + xywh {579 293 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + } + Fl_Choice {} { + label {Keyboard Tuning} + tooltip {Keyboard Tuning. The Keyboard Tuning parameter selects which tuning is used by the current preset. The User Tuning tables are defined in the Master section} xywh {208 346 196 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(923);} + code1 {o->add("Equal Temperament"); o->add("Just C"); o->add("Just C2"); o->add("Just C minor"); o->add("Just C3"); o->add("Valloti"); o->add("19-tone"); o->add("Gamelan"); o->add("Werkmeister III"); o->add("Kirnberger"); o->add("Scarlatti"); o->add("Repeating Octave");} + class Choice + } {} + Fl_Group {} { + label {Tempo Offset} open + tooltip {This function allows you to double or halve the Master Tempo as it applies to this preset} xywh {466 346 76 53} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(930);} + class Group + } { + Fl_Button {} { + label halve + callback {((Group*)o->parent())->do_callback();} + xywh {470 346 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label current + callback {((Group*)o->parent())->do_callback();} + xywh {470 364 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label double + callback {((Group*)o->parent())->do_callback();} + xywh {470 382 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + } + Fl_Group links {open + xywh {210 1 414 396} hide + } { + Fl_Group {} { + label {LINK 1} open + xywh {216 23 196 374} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice l1_rom {open + xywh {226 29 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(1299);} + class ROM_Choice + } {} + Fl_Browser l1 { + xywh {226 55 176 204} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(1281);} + class Browser + } + Fl_Input l1_filter { + label {F } + callback {l1->set_filter(o->value());} + xywh {242 264 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {l1_filter->value(0); +l1_filter->do_callback();} + xywh {376 264 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + Fl_Group g_link1 { + xywh {226 286 176 106} + } { + Fl_Dial {} { + label Pan + tooltip {Program Stereo Panorama} xywh {236 286 40 40} color 7 selection_color 39 labelsize 10 minimum -64 maximum 63 step 1 + code0 {o->set_id(1283);} + class Fl_Knob + } + Fl_Dial {} { + label Volume + tooltip {Program Volume} xywh {236 339 40 40} color 7 selection_color 39 labelsize 10 minimum -96 maximum 10 step 1 + code0 {o->set_id(1282);} + class Fl_Knob + } + Fl_Dial {} { + label Transpose + tooltip {Program Transpose} xywh {294 286 40 40} color 7 selection_color 39 labelsize 10 minimum -127 maximum 127 step 1 + code0 {o->set_id(1284);} + class Fl_Knob + } + Fl_Dial {} { + label Delay + tooltip {Program Delay} xywh {294 339 40 40} color 7 selection_color 39 labelsize 10 minimum -25 maximum 127 step 1 + code0 {o->set_id(1285);} + class Fl_Knob + } + Fl_Dial {} { + label {Velo-Low} + tooltip {Velocity Low} xywh {352 286 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 + code0 {o->set_id(1288);} + class Fl_Knob + } + Fl_Dial {} { + label {Velo-High} + tooltip {Velocity High} xywh {352 339 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 value 127 + code0 {o->set_id(1289);} + class Fl_Knob + } + } + } + Fl_Group {} { + label {LINK 2} open + xywh {422 23 196 374} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice l2_rom {open + xywh {432 29 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(1300);} + class ROM_Choice + } {} + Fl_Browser l2 { + xywh {432 55 176 204} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(1290);} + class Browser + } + Fl_Input l2_filter { + label {F } + callback {l2->set_filter(o->value());} + xywh {448 264 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {l2_filter->value(0); +l2_filter->do_callback();} + xywh {582 264 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + Fl_Group g_link2 { + xywh {432 286 176 106} + } { + Fl_Dial {} { + label Pan + tooltip {Program Stereo Panorama} xywh {442 286 40 40} color 7 selection_color 39 labelsize 10 minimum -64 maximum 63 step 1 + code0 {o->set_id(1292);} + class Fl_Knob + } + Fl_Dial {} { + label Volume + tooltip {Program Volume} xywh {442 339 40 40} color 7 selection_color 39 labelsize 10 minimum -96 maximum 10 step 1 + code0 {o->set_id(1291);} + class Fl_Knob + } + Fl_Dial {} { + label Transpose + tooltip {Program Transpose} xywh {500 286 40 40} color 7 selection_color 39 labelsize 10 minimum -127 maximum 127 step 1 + code0 {o->set_id(1293);} + class Fl_Knob + } + Fl_Dial {} { + label Delay + tooltip {Program Delay} xywh {500 339 40 40} color 7 selection_color 39 labelsize 10 minimum -25 maximum 127 step 1 + code0 {o->set_id(1294);} + class Fl_Knob + } + Fl_Dial {} { + label {Velo-Low} + tooltip {Velocity Low} xywh {558 286 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 + code0 {o->set_id(1297);} + class Fl_Knob + } + Fl_Dial {} { + label {Velo-High} + tooltip {Velocity High} xywh {558 339 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 value 127 + code0 {o->set_id(1298);} + class Fl_Knob + } + } + } + } + Fl_Box patchcords { + label PATCHCORDS + xywh {4 433 826 132} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + class PD_Preset_Patchcords + } +} + +widget_class PD_Main { + xywh {344 150 833 569} type Double box BORDER_BOX hide position_relative +} { + decl {PD_Layer_Strip* layer_strip[4];} {public + } + decl {Fl_Widget* ctrl_x[16];} {public + } + Fl_Group {} { + label main + xywh {0 0 834 574} labeltype NO_LABEL align 0 + } { + Fl_Group {} { + label {PROGRAM/CHANNEL} + xywh {4 23 200 225} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Button preset_name { + callback {ui->select(5);} + tooltip {Program name} xywh {7 26 190 20} down_box UP_BOX color 7 selection_color 15 labelfont 5 labelsize 12 labelcolor 49 align 84 + } + Fl_Group channel_select { + tooltip {Select preset by channel or activate channel in omni and poly-mode.} xywh {4 23 196 73} labeltype NO_LABEL labelfont 1 labelcolor 15 when 0 + code0 {o->set_id(129);} + class Group + } { + Fl_Button {} { + label 1 + callback {((Group*)o->parent())->do_callback();} + xywh {7 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 2 + callback {((Group*)o->parent())->do_callback();} + xywh {31 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 3 + callback {((Group*)o->parent())->do_callback();} + xywh {55 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 4 + callback {((Group*)o->parent())->do_callback();} + xywh {79 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 5 + callback {((Group*)o->parent())->do_callback();} + xywh {103 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 6 + callback {((Group*)o->parent())->do_callback();} + xywh {127 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 7 + callback {((Group*)o->parent())->do_callback();} + xywh {151 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 8 + callback {((Group*)o->parent())->do_callback();} + xywh {175 48 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 9 + callback {((Group*)o->parent())->do_callback();} + xywh {7 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 10 + callback {((Group*)o->parent())->do_callback();} + xywh {31 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 11 + callback {((Group*)o->parent())->do_callback();} + xywh {55 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 12 + callback {((Group*)o->parent())->do_callback();} + xywh {79 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 13 + callback {((Group*)o->parent())->do_callback();} + xywh {103 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 14 + callback {((Group*)o->parent())->do_callback();} + xywh {127 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 15 + callback {((Group*)o->parent())->do_callback();} + xywh {151 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + Fl_Button {} { + label 16 + callback {((Group*)o->parent())->do_callback();} + xywh {175 72 22 22} type Radio down_box UP_BOX selection_color 15 labelsize 12 align 64 + } + } + Fl_Dial {} { + label Pan + tooltip {Channel Stereo Panorama} xywh {10 97 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 value 64 + code0 {o->set_id(132);} + class Fl_Knob + } + Fl_Dial {} { + label Volume + tooltip {Channel Volume} xywh {10 151 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 value 100 + code0 {o->set_id(131);} + class Fl_Knob + } + Fl_Button b_audit { + label {A&UDIT} + callback {if (o->value()) +ui->m_audit->set(); +else +ui->m_audit->clear(); + +midi->audit();} + tooltip {Toggle audition} xywh {56 103 65 20} type Toggle down_box UP_BOX selection_color 73 labelsize 12 labelcolor 15 align 80 when 1 + } + Fl_Button channel_enable { + label {C&HANNEL ENABLE} + tooltip {Multimode channel enable} xywh {56 129 65 30} type Toggle down_box UP_BOX shortcut 0x68 selection_color 59 labelsize 10 labelcolor 15 align 208 + code0 {o->set_id(135);} + class Button + } + Fl_Button {} { + label {PROGRAM &CHANGE} + tooltip {Receive Program Change} xywh {56 165 65 30} type Toggle down_box UP_BOX shortcut 0x63 selection_color 138 labelsize 10 labelcolor 15 align 208 + code0 {o->set_id(137);} + class Button + } + Fl_Group g_main_arp { + label Arp + xywh {126 111 33 71} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(134);} + class Group + } { + Fl_Button {} { + label OFF + callback {((Group*)o->parent())->do_callback();} + tooltip {Arpeggiator OFF (no matter what, where, when, who and why)} xywh {126 111 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label ON + callback {((Group*)o->parent())->do_callback();} + tooltip {Arpeggiator ON (uses program settings, overrides Active state)} xywh {126 129 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label P + callback {((Group*)o->parent())->do_callback();} + tooltip {Use program arpeggiator settings} xywh {126 147 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label M + callback {((Group*)o->parent())->do_callback();} + tooltip {Use master arpeggiator settings} xywh {126 165 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + } + Fl_Button main_edit_arp { + label EDIT + callback {ui->edit_arp_x(g_main_arp->get_value());} + tooltip {Edit assigned arpeggiator pattern (only enabled if it is a User pattern)} xywh {126 183 33 17} selection_color 15 labelsize 10 labelcolor 15 align 16 deactivate + class Fixed_Button + } + Fl_Group mix_out { + label Mix + tooltip {Mix (only effective in Multimode): Effects Sends and Sub-Out setup for selected MIDI channel. "P" means that the Effects Send is programmed for each voice (in the voice strips to the right), all other settings (1,2,3,4) will send all the voices of the preset selected on this channel to that FX send bus. "2" and "3" are also used to route sounds to the Sub 1 and 2 outputs on the back panel.} xywh {163 111 33 89} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(133);} + class Group + } { + Fl_Button {} { + label P + callback {((Group*)o->parent())->do_callback();} + xywh {163 111 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label 1 + callback {((Group*)o->parent())->do_callback();} + xywh {163 129 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label 2 + callback {((Group*)o->parent())->do_callback();} + xywh {163 147 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label 3 + callback {((Group*)o->parent())->do_callback();} + xywh {163 165 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + Fl_Button {} { + label 4 + callback {((Group*)o->parent())->do_callback();} + xywh {163 183 33 17} type Radio down_box UP_BOX selection_color 15 labelsize 10 align 80 + } + } + Fl_Box minipiano { + xywh {5 203 198 44} box FLAT_BOX labeltype NO_LABEL + class MiniPiano + } + } + Fl_Group controller { + xywh {4 257 196 308} + } { + Fl_Button {} { + label PLAY + callback {if(o->value()) +{ + ctrl_play->show(); + ctrl_initial->hide(); + //b_store->activate(); +} +else // initial controller amounts +{ + ctrl_initial->show(); + ctrl_play->hide(); + //b_store->deactivate(); +}} + tooltip {PLAY: Sliders send and receive CC values instead of acting as editors for initial controller amount values} xywh {4 257 40 17} type Toggle down_box UP_BOX value 1 selection_color 78 labelsize 10 labelcolor 15 align 80 + } + Fl_Button b_store { + label SET + callback {pd->store_play_as_initial();} + tooltip {Copy controller settings to initial controller amounts} xywh {160 257 40 17} down_box UP_BOX color 7 selection_color 15 labelsize 10 labelcolor 49 align 80 deactivate + } + Fl_Group {} { + label CONTROLLER + xywh {4 274 196 291} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Group ctrl_initial { + tooltip {Initial Controller Amounts} xywh {10 277 185 285} hide + } { + Fl_Slider {} { + label A + xywh {10 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(915);} + class Slider + } + Fl_Slider {} { + label B + xywh {42 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(916);} + class Slider + } + Fl_Slider {} { + label C + xywh {74 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(917);} + class Slider + } + Fl_Slider {} { + label D + xywh {105 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(918);} + class Slider + } + Fl_Slider {} { + label E + xywh {137 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(919);} + class Slider + } + Fl_Slider {} { + label F + xywh {169 278 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(920);} + class Slider + } + Fl_Slider {} { + label G + xywh {10 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(921);} + class Slider + } + Fl_Slider {} { + label H + xywh {42 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(922);} + class Slider + } + Fl_Slider {} { + label I + xywh {74 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(924);} + class Slider + } + Fl_Slider {} { + label J + xywh {105 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(925);} + class Slider + } + Fl_Slider {} { + label K + xywh {137 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(926);} + class Slider + } + Fl_Slider {} { + label L + xywh {169 421 25 141} box THIN_DOWN_BOX selection_color 7 labelfont 1 labelsize 10 labelcolor 49 align 64 minimum 127 maximum -1 step 1 + code0 {o->set_id(927);} + class Slider + } + } + Fl_Group ctrl_play { + tooltip {CC Controller} xywh {10 275 185 287} labelcolor 15 + } { + Fl_Slider {} { + label A + callback {pd->cc_callback(1, (int) o->value());} + xywh {10 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[1] = o;} + class Slider + } + Fl_Slider {} { + label B + callback {pd->cc_callback(2, (int) o->value());} + xywh {42 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[2] = o;} + class Slider + } + Fl_Slider {} { + label C + callback {pd->cc_callback(3, (int) o->value());} + xywh {74 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[3] = o;} + class Slider + } + Fl_Slider {} { + label D + callback {pd->cc_callback(4, (int) o->value());} + xywh {105 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[4] = o;} + class Slider + } + Fl_Slider {} { + label E + callback {pd->cc_callback(5, (int) o->value());} + xywh {137 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[5] = o;} + class Slider + } + Fl_Slider {} { + label F + callback {pd->cc_callback(6, (int) o->value());} + xywh {169 278 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[6] = o;} + class Slider + } + Fl_Slider {} { + label G + callback {pd->cc_callback(7, (int) o->value());} + xywh {10 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[7] = o;} + class Slider + } + Fl_Slider {} { + label H + callback {pd->cc_callback(8, (int) o->value());} + xywh {42 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[8] = o;} + class Slider + } + Fl_Slider {} { + label I + callback {pd->cc_callback(9, (int) o->value());} + xywh {74 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[9] = o;} + class Slider + } + Fl_Slider {} { + label J + callback {pd->cc_callback(10, (int) o->value());} + xywh {105 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[10] = o;} + class Slider + } + Fl_Slider {} { + label K + callback {pd->cc_callback(11, (int) o->value());} + xywh {137 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[11] = o;} + class Slider + } + Fl_Slider {} { + label L + callback {pd->cc_callback(12, (int) o->value());} + xywh {169 421 25 141} box THIN_DOWN_BOX labelfont 1 labelsize 10 align 64 minimum 127 maximum 0 step 1 + code0 {ctrl_x[12] = o;} + class Slider + } + } + } + } + Fl_Group controller_assign { + label {CONTROLLER ASSIGN} + xywh {4 274 196 291} box THIN_DOWN_BOX labelfont 1 labelcolor 15 hide + } { + Fl_Group {} { + label REALTIME open + xywh {4 303 196 118} labelfont 1 labelcolor 15 + } { + Fl_Spinner {} { + label A + xywh {10 309 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(391);} + class Spinner + } + Fl_Spinner {} { + label B + xywh {32 334 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 value 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(392);} + class Spinner + } + Fl_Spinner {} { + label C + xywh {67 309 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(393);} + class Spinner + } + Fl_Spinner {} { + label D + xywh {89 334 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(394);} + class Spinner + } + Fl_Spinner {} { + label E + xywh {124 309 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(395);} + class Spinner + } + Fl_Spinner {} { + label F + xywh {146 334 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(396);} + class Spinner + } + Fl_Spinner {} { + label G + xywh {10 366 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(397);} + class Spinner + } + Fl_Spinner {} { + label H + xywh {32 391 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(398);} + class Spinner + } + Fl_Spinner {} { + label I + xywh {67 366 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(406);} + class Spinner + } + Fl_Spinner {} { + label J + xywh {89 391 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(407);} + class Spinner + } + Fl_Spinner {} { + label K + xywh {124 366 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(408);} + class Spinner + } + Fl_Spinner {} { + label L + xywh {146 391 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 maximum 95 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(409);} + class Spinner + } + } + Fl_Group {} { + label FOOTSWITCH open + xywh {4 446 196 37} labelfont 1 labelcolor 15 + } { + Fl_Spinner fs1 { + label 1 + xywh {21 452 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 minimum 64 maximum 95 value 64 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(399);} + class Spinner + } + Fl_Spinner fs2 { + label 2 + xywh {78 452 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 minimum 64 maximum 95 value 64 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(400);} + class Spinner + } + Fl_Spinner fs3 { + label 3 + xywh {135 452 40 20} box FLAT_BOX color 7 selection_color 15 labelsize 10 labelcolor 15 align 8 minimum 64 maximum 95 value 64 textfont 4 textsize 13 textcolor 49 + code0 {o->set_id(401);} + class Spinner + } + } + } + Fl_Group mixer { + xywh {208 0 421 569} + } { + Fl_Box {} { + label {VOICE 1} + xywh {208 23 100 542} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + code0 {o->init(0);} + code1 {layer_strip[0] = o;} + class PD_Layer_Strip + } + Fl_Box {} { + label {VOICE 2} + xywh {314 23 100 542} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + code0 {o->init(1);} + code1 {layer_strip[1] = o;} + class PD_Layer_Strip + } + Fl_Box {} { + label {VOICE 3} + xywh {420 23 100 542} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + code0 {o->init(2);} + code1 {layer_strip[2] = o;} + class PD_Layer_Strip + } + Fl_Box {} { + label {VOICE 4} + xywh {526 23 100 542} box THIN_DOWN_BOX labelfont 1 labelcolor 15 align 1 + code0 {o->init(3);} + code1 {layer_strip[3] = o;} + class PD_Layer_Strip + } + } + Fl_Group master {open + xywh {204 0 425 569} hide + } { + Fl_Group {} { + label {MASTER ARPEGGIATOR} open + xywh {208 23 417 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Button {} { + label Sync + tooltip {Sync. The Sync parameter defines when a note is played in relation to when the key is pressed. When On, the note sounds the instant a key is pressed (Key Sync). When Off, the note does not sound until the next occurrence of the selected note value (Quantized)} xywh {234 33 48 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 179 labelsize 10 + code0 {o->set_id(649);} + class Button + } + Fl_Group {} { + label Mode + tooltip {Arpeggiator Mode. The Mode parameter determines the direction or pattern mode of the arpeggiated notes} xywh {224 67 68 143} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(642);} + class Group + } { + Fl_Button {} { + label Up + callback {((Group*)o->parent())->do_callback();} + xywh {224 67 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Down + callback {((Group*)o->parent())->do_callback();} + xywh {224 85 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {Up-Down} + callback {((Group*)o->parent())->do_callback();} + xywh {224 103 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Fwd + callback {((Group*)o->parent())->do_callback();} + xywh {224 121 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Bkw + callback {((Group*)o->parent())->do_callback();} + xywh {224 139 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {Fwd-Bkw} + callback {((Group*)o->parent())->do_callback();} + xywh {224 157 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Random + callback {((Group*)o->parent())->do_callback();} + xywh {224 175 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label Pattern + callback {((Group*)o->parent())->do_callback();} + xywh {224 193 68 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Group g_pattern_speed { + label {Pattern Speed} + xywh {220 230 76 89} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(659);} + class Group + } { + Fl_Button {} { + label 4x + callback {((Group*)o->parent())->do_callback();} + xywh {234 230 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label 2x + callback {((Group*)o->parent())->do_callback();} + xywh {234 248 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label 1x + callback {((Group*)o->parent())->do_callback();} + xywh {234 266 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {1/2x} + callback {((Group*)o->parent())->do_callback();} + xywh {234 284 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {1/4x} + callback {((Group*)o->parent())->do_callback();} + xywh {234 302 48 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Dial note { + label Note + tooltip {Note Value. The Note Value determines the duration of each note played. This parameter is used in non-pattern mode only} xywh {312 28 40 40} color 7 labelsize 10 minimum 1 maximum 19 step 1 value 1 + code0 {o->set_id(644);} + class Fl_Knob + } + Fl_Dial {} { + label Gate + tooltip {Gate Time. The Gate Time parameter works together with the Note Value parameter. Just as Note Value defines the length of a note, the Gate Time sets the percentage of the Note Value time played} xywh {357 28 40 40} color 7 labelsize 10 maximum 100 step 1 + code0 {o->set_id(646);} + class Fl_Knob + } + Fl_Dial {} { + label Velocity + tooltip {Note Velocity. The Velocity parameter determines the velocity at which each note arpeggiates. Velocity can be defined by the velocity value specified (from 1 through 127), or by the actual velocity of the played note (0)} xywh {312 82 40 40} color 7 labelsize 10 maximum 127 step 1 + code0 {o->set_id(645);} + class Fl_Knob + } + Fl_Dial {} { + label Duration + tooltip {Duration. This parameter defines how long the arpeggiator plays before stopping. The Duration is specified in note values. Therefore if an arpeggio were running at a 16th Note Value and the Duration were set to a whole note, the arpeggiator would play 16 steps before stopping. After the duration has elapsed, the arpeggiator remains inactive until the key is released. If Duration is set to Off, the arpeggio repeats as long as the notes are held (Infinite Duration)} xywh {357 82 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(651);} + class Fl_Knob + } + Fl_Dial pre_d { + label {Pre D} + tooltip {Pre-Delay. The Pre-Delay value determines how long the arpeggiator is delayed before becoming active after the first "note-on". During the pre-delay period, notes are played normally (as if the arpeggiator was off). After the pre-delay period has elapsed, the arpeggiator kicks in. Once you release all the keys on the controller, the pre-delay starts over with the next note-on. In combination with the Duration parameter, Pre-Delay lets you change the arpeggio patterns to create many more variations} xywh {312 138 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(650);} + class Fl_Knob + } + Fl_Dial post_d { + label {Post D} + tooltip {Post-Delay. This parameter is only relevant when both the "Duration" and "Recycle" parameters are not in the "Off" state. The Post-Delay value determines how long the arpeggiator is delayed after the Duration period. During the post-delay period, notes are played normally (as if the arpeggiator was off). After the post-delay period has elapsed, the arpeggiator either jumps to the beginning of the Pre-Delay period or to the beginning of the Duration period depending on the Recycle setting} xywh {357 138 40 40} color 7 labelsize 10 maximum 19 step 1 + code0 {o->set_id(661);} + class Fl_Knob + } + Fl_Dial {} { + label Count + tooltip {Extension Count. The Extension Count parameter specifies how many times the Extension Interval is carried out. With an Extension Count of 0, the arpeggio plays only the notes pressed. With an Extension Count of 1, the arpeggio plays the notes pressed, then plays the same notes (in the same order), transposed by the Extension Interval amount. The cycle is then repeated} xywh {312 192 40 40} color 7 labelsize 10 maximum 15 step 1 + code0 {o->set_id(647);} + class Fl_Knob + } + Fl_Dial {} { + label Interval + tooltip {Extension Interval. The Extension Interval specifies the additional intervals played when you press a key. For example, suppose you played C2 with an Interval of 7 (a Major 5th), Up mode, and an Extension Count of 2. The arpeggio alternates between C2 and G2} xywh {357 192 40 40} color 7 labelsize 10 minimum 1 maximum 16 step 1 value 1 + code0 {o->set_id(648);} + class Fl_Knob + } + Fl_Group {} { + label Recylce + tooltip {Recycle. This parameter works together with the Duration and Pre/Post Delay parameters. When these are enabled without one of the Recycle options turned on, the pattern or arpeggio normally stops. With Recycle On, the arpeggio instantly resets the pattern to the beginning of the Pre-Delay period after the duration value has elapsed and repeats the pattern or arpeggio. Another option called "On-No Pre-Delay" bypasses the predelay period} xywh {330 266 50 53} labelsize 10 labelcolor 15 when 0 + code0 {o->set_id(652);} + class Group + } { + Fl_Button {} { + label Off + callback {((Group*)o->parent())->do_callback();} + xywh {330 266 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label On + callback {((Group*)o->parent())->do_callback();} + xywh {330 284 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + Fl_Button {} { + label {No-Pre} + callback {((Group*)o->parent())->do_callback();} + xywh {330 302 50 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + class Button + } + } + Fl_Button {} { + label Active + tooltip {Arpeggiator On/Off} xywh {437 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 78 labelsize 10 + code0 {o->set_id(641);} + class Button + } + Fl_Button {} { + label Thru + tooltip {Keyboard Thru. When enabled, merges the notes not arpeggiated with the arpeggiated notes. This gives the effect of two parts playing at once} xywh {492 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + code0 {o->set_id(653);} + class Button + } + Fl_Button {} { + label Latch + tooltip {Latch. With Latch mode On, any notes you play remain on until you press them again. Latched notes can be halted by turning Latch off in this screen, or by turning off the Arpeggiator} xywh {547 33 50 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 + code0 {o->set_id(654);} + class Button + } + Fl_Button {} { + label COPY + callback {ui->show_copy_preset(C_ARP_PATTERN);} + tooltip {Paste Arpeggiator pattern} xywh {419 58 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 + } + Fl_Button edit_arp { + label EDIT + callback {if (pd->arp && pd->arp->get_number() == arp->value()-1) +{ +ui->g_arp_edit->show(); +ui->g_main->hide(); +Fl::focus(ui->g_arp_edit); +} +else +midi->request_arp_dump(arp->value()-1, 0);} + tooltip {Edit Arpeggiator pattern} xywh {575 58 40 17} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 deactivate + class Fixed_Button + } + Fl_Group g_pattern { + label PATTERN + xywh {419 75 196 244} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice arp_rom {open + xywh {429 81 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(660);} + class ROM_Choice + } {} + Fl_Browser arp { + xywh {429 107 176 181} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(643);} + class Browser + } + Fl_Input arp_filter { + label {F } + callback {arp->set_filter(o->value());} + xywh {445 293 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {arp_filter->value(0); +arp_filter->do_callback();} + xywh {579 293 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + } + Fl_Group g_riff { + label {MASTER RIFF} open + xywh {208 350 196 214} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice riff_rom {open + xywh {218 356 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(277);} + class ROM_Choice + } {} + Fl_Browser riff { + xywh {218 382 176 151} type Hold when 1 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(278);} + class Browser + } + Fl_Input riff_filter { + label {F } + callback {riff->set_filter(o->value());} + xywh {234 538 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {riff_filter->value(0); +riff_filter->do_callback();} + xywh {368 538 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + Fl_Group {} { + label {TEMPO CONTROL} + xywh {415 350 210 41} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice {} { + label Channel open + tooltip {Tempo Control Channel. Determines which channel receives tempo controller values} xywh {425 366 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(141);} + code1 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");} + class Choice + } {} + Fl_Choice {} { + label {Ctrl Up} open + tooltip {Allows a MIDI controller to change the Master Tempo. You can assign any controller number from 1-31, mono key pressure, or the pitch wheel to change the Global Tempo. MIDI Controller values are added to the Base Tempo with a range of ±64. When the controller is set to "Off" the tempo returns to its original setting. This control has no effect when using an external clock} xywh {490 366 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(402);} + code1 {o->add("Off");o->add("MNP");o->add("PW");} + code2 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");o->add("17");o->add("18");o->add("19");o->add("20");o->add("21");o->add("22");o->add("23");o->add("24");o->add("25");o->add("26");o->add("27");o->add("28");o->add("29");o->add("30");o->add("31");} + class Choice + } {} + Fl_Choice {} { + label {Ctrl Down} open + tooltip {Allows a MIDI controller to change the Master Tempo. You can assign any controller number from 1-31, mono key pressure, or the pitch wheel to change the Global Tempo. MIDI Controller values are added to the Base Tempo with a range of ±64. When the controller is set to "Off" the tempo returns to its original setting. This control has no effect when using an external clock} xywh {555 366 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(403);} + code1 {o->add("Off");o->add("MNP");o->add("PW");} + code2 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");o->add("17");o->add("18");o->add("19");o->add("20");o->add("21");o->add("22");o->add("23");o->add("24");o->add("25");o->add("26");o->add("27");o->add("28");o->add("29");o->add("30");o->add("31");} + class Choice + } {} + } + Fl_Group {} { + label SUPERBEATS + xywh {415 425 210 41} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice {} { + label Mode open + tooltip {BEATS Mode. Off: BEATS mode off --- On: BEATS mode on. The Riff assigned in the preset is used --- Preset: BEATS mode is turned on ONLY if the Riff assigned in the preset is a "BTS" riff --- Master: BEATS mode on. The Master Riff is used} xywh {425 441 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(271);} + code1 {o->add("Off");o->add("On");o->add("Preset");o->add("Master");} + class Choice + } {} + Fl_Choice {} { + label Channel open + tooltip {Selects the MIDI channel on which BEATS play} xywh {490 441 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(272);} + code1 {o->add("Basic");} + code2 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");} + code3 {o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");} + class Choice + } {} + Fl_Choice {} { + label {Trigger Ch} open + tooltip {Selects the MIDI channel on which Trigger Keys will be active} xywh {555 441 60 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(273);} + code1 {o->add("Basic");} + code2 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");} + code3 {o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");} + class Choice + } {} + } + Fl_Group {} { + label GENERAL open + xywh {415 496 210 68} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice {} { + label {MIDI Song Start} + tooltip {This function enables or disables MIDI Song Start for the Arpeggiator and Riffs. The MIDI Song Start option restarts the arpeggiator and/or Riff (BEAT) to the beginning when a MIDI Song Start command is received. This is useful for synchronizing arpeggios and BEATS when recording into, or playing along with a sequencer} xywh {425 512 90 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(658);} + code1 {o->add("Off");o->add("Arps");o->add("Riffs");o->add("Both");} + class Choice + } {} + Fl_Button {} { + label {MODE CHANGE} + tooltip {MIDI Mode Change. Specifies whether mode changes made through an external MIDI controller are accepted or ignored} xywh {425 539 190 20} type Toggle down_box DOWN_BOX selection_color 138 labelsize 10 + code0 {o->set_id(386);} + class Button + } + } + } + Fl_Group {} { + label MASTER + xywh {634 433 196 132} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Counter {} { + label BPM + tooltip {Master Clock. The Master Clock controls SuperBEATS, arpeggiators, synchronizes the LFOs when in tempo-based mode, controls the times of tempo-based envelopes, and can be used as a modulation source in the PatchCords section. Values range from 1 through 300 BPM or you can select "0" to use an external MIDI clock source} xywh {735 484 85 20} box THIN_UP_BOX selection_color 49 labelsize 10 labelcolor 15 align 1 minimum 0 maximum 300 step 1 textfont 4 textcolor 49 + code0 {o->set_id(257);} + class Counter + } + Fl_Choice {} { + label {MIDI Mode} open + tooltip {MIDI Mode. Omni: Responds to note information on all MIDI channels and plays the preset currently displayed in the main screen - Poly: Responds only to note information received on the currently selected MIDI channel and plays that channel's associated preset - Multi: Responds to data on any combination of MIDI channels and plays the specific preset associated with each of the MIDI channels. You must select multi mode for multitimbral operation} xywh {645 484 80 21} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->add("Omni");o->add("Poly");o->add("Multi");} + code1 {o->set_id(385);} + class Choice + } {} + Fl_Choice {} { + label {Velocity Curve} open + tooltip {Velocity Curve. Modifies incoming velocity data by a velocity curve in order to provide different types of dynamics in response to your playing, or to better adapt to a MIDI controller} xywh {644 448 85 21} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->add("linear");o->add("compress");o->add("emphasize medium");o->add("expand");o->add("expand ++");o->add("shift up");o->add("shift up ++");o->add("shift up +");o->add("shift up, emphasize mid");o->add("extreme compression");o->add("extreme compression with lows");o->add("extreme compression, no lows");o->add("extreme compression, no lows 2");o->add("extreme expansion");} + code1 {o->set_id(265);} + class Choice + } {} + Fl_Dial {} { + label Volume + callback {midi->master_volume((int) o->value());} + tooltip {Master Volume} xywh {640 510 40 40} color 7 selection_color 39 labelsize 10 maximum 127 step 1 value 100 + class Fl_Knob + } + Fl_Dial {} { + label {Transp.} + tooltip {Master Transpose. Transposes the key of all presets, in semitone intervals. The transpose range is ± 24 semitones} xywh {688 510 40 40} color 7 selection_color 39 labelsize 10 minimum -24 maximum 24 step 1 + code0 {o->set_id(259);} + class Fl_Knob + } + Fl_Dial {} { + label Tune + tooltip {Master Tune (cents). Adjusts the fine tuning of all presets so that you can tune your device to other instruments. The master tuning range is ± 1 semitone in 1/64th semitone increments} xywh {737 510 40 40} color 7 selection_color 39 labelsize 10 minimum -63 maximum 63 step 1 + code0 {o->set_id(260);} + class Fl_Knob + } + Fl_Dial {} { + label {Bend R.} + tooltip {Bend Range. Sets the range of the pitch wheel. This affects only presets that have their individual Pitch Bend range set to Master. The maximum pitch bend range is ±12 semitones or one octave in each direction} xywh {786 510 40 40} color 7 selection_color 39 labelsize 10 maximum 12 step 1 value 2 + code0 {o->set_id(264);} + class Fl_Knob + } + Fl_Choice {} { + label {MIDI Transmit} open + tooltip {Enables or disables transmission of Riff/Arp note data over MIDI} xywh {740 448 80 20} down_box BORDER_BOX labelsize 10 labelcolor 15 align 5 textsize 13 + code0 {o->set_id(657);} + code1 {o->add("Off");o->add("Arps");o->add("Riffs");o->add("Both");} + class Choice + } {} + } + } +} + +decl {PD_Arp_Step* arp_step[32];} {global +} + +class PD_UI {open +} { + decl {Fl_File_Chooser* fc;} {} + decl {Fl_Button* mute_b[4];} {public + } + decl {Fl_Button* solo_b[4];} {public + } + decl {Fl_Text_Buffer* logbuf;} {public + } + decl {Fl_Double_Window* layer_editor_windows[4];} {public + } + decl {Fl_Menu_Item* layer_editor_menu_items[4];} { + callback {if (dismiss(true) == 2) +return; +if (!(confirm->value() && !fl_choice("Exit prodatum?", "Cancel", "Exit", 0))) +delete this;} public + } + decl {PD_Layer_Editor* layer_editor[4];} {public + } + decl {bool eall;} {public + } + decl {int syncview;} {public + } + decl {int selected_step;} {public + } + decl {int selected;} {} + decl {int copy_type;} {} + decl {int copy_src;} {} + decl {char* filter_tmp;} {} + decl {bool arp_name_changed;} {} + decl {void set_msglevel(int level);} {} + decl {bool shiny_knobs;} {public + } + decl {void initialize();} {} + decl {void set_export_path();} {} + decl {void file_program(int)} {} + decl {void select(int l);} {public + } + decl {int get_selected();} {public + } + decl {void edit_arp_x(int x);} {public + } + decl {void set_color(int type, int value);} {public + } + decl {void set_eall(int v);} {public + } + decl {void show_copy_layer(int type, int layer);} {public + } + decl {void show_copy_preset(int type);} {public + } + decl {void create_about();} { + callback {if (dismiss(true) == 2) +return; +if (!(confirm->value() && !fl_choice("Exit prodatum?", "Cancel", "Exit", 0))) +delete this;} public + } + Function {PD_UI()} { + callback {if (dismiss(true) == 2) +return; +if (!(confirm->value() && !fl_choice("Exit prodatum?", "Cancel", "Exit", 0))) +delete this;} open + } { + code {Fl::visual(FL_DOUBLE|FL_RGB); + // filter tooltip + snprintf(filter_tooltip, 512, + "* matches any sequence of 0 or more characters.\\n" + "? matches any single character.\\n" + "[set] matches any character in the set.\\n" + "[^set] or [!set] matches any character not in the set.\\n" + "{X|Y|Z} or {X,Y,Z} matches any one of the subexpressions literally.\\n" + "\\\\x quotes the character x so it has no special meaning.\\n" + "x all other characters must be matched exactly.\\n" + "NOTE: Your query is automatically expanded to '*query*' to mimic prodatum's original filter behaviour.");} {} + Fl_Window main_window { + callback {if (pd->preset && pd->preset->is_changed()) +{ + if (dismiss(true) == 1) + delete this; + return; +} +if (confirm->value() && fl_choice("Exit prodatum?", "Cancel", "Exit", 0) != 1) + return; +delete this;} + xywh {301 157 843 615} type Double hide resizable + code0 {o->label(PACKAGE_STRING);} + class Double_Window size_range {674 492 843 615} + } { + Fl_Group {} { + label name + xywh {1 1 841 23} labeltype NO_LABEL + } { + Fl_Box {} { + label resizable + xywh {642 21 1 1} labeltype NO_LABEL resizable + } + Fl_Box {} { + xywh {1 1 772 19} box FLAT_BOX color 7 labelfont 5 labelsize 12 labelcolor 49 align 24 + } + Fl_Box n_n_m { + label {RR.PPP.B} + xywh {645 1 61 17} color 7 labelfont 5 labelsize 12 labelcolor 49 align 26 + } + Fl_Input n_cat_m { + label {:} + callback {if (pd->preset) +pd->preset->set_name(o->value(), 0, o->position());} + tooltip {Program category (3 characters max.)} xywh {716 1 27 19} box FLAT_BOX labelfont 5 labelsize 12 labelcolor 49 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(3);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->value("cat");} + class Input + } + Fl_Input n_name_m { + label {:} + callback {if (pd->preset) +pd->preset->set_name(o->value(), 1, o->position());} + tooltip {Program name (12 characters max.) [CTRL+N to focus]} xywh {752 1 90 19} box FLAT_BOX labelfont 5 labelsize 12 labelcolor 49 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(12);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->value("Program Name");} + class Input + } + } + Fl_Group {} { + label menu open + xywh {1 1 420 23} labeltype NO_LABEL + } { + Fl_Box {} { + label resizeable + xywh {418 21 1 1} labeltype NO_LABEL resizable + } + Fl_Menu_Bar {} {open + xywh {1 1 231 19} box FLAT_BOX color 7 labelcolor 49 textcolor 49 + code0 {o->global();} + } { + Submenu {} { + label File + xywh {5 5 70 21} + } { + MenuItem {} { + label {&Open device...} + callback {if (open_device->shown() && open_device->visible()) +open_device->hide(); +else +open_device->show();} + xywh {10 10 36 21} shortcut 0x6f + } + MenuItem {} { + label {&Save...} + callback {show_copy_preset(SAVE_PRESET);} + tooltip {Save the edit buffer} xywh {5 5 36 21} shortcut 0x40073 + } + MenuItem {} { + label {Save (quick)} + callback {if (pd->preset) +pd->preset->copy(SAVE_PRESET, -1, pd->selected_preset); +else +pd->display_status("*** Nothing to save.");} + tooltip {Save the edit buffer to the current selected preset slot} xywh {5 5 36 21} shortcut 0x50073 + } + MenuItem {} { + label {Export...} + callback {file_program(0);} + tooltip {Saves the edit buffer to a file} xywh {5 5 29 19} shortcut 0x50078 + } + MenuItem {} { + label {Export (quick)} + callback {file_program(2);} + tooltip {Saves the edit buffer to a file into the directory where prodatum was started from without asking for a filename (the preset name is used)..} xywh {5 5 29 19} shortcut 0x40078 + } + MenuItem {} { + label {Import...} + callback {file_program(1);} + tooltip {Loads a program from a file into the edit buffer.} xywh {5 5 29 19} shortcut 0x40069 + } + MenuItem {} { + label {Reset...} + callback {reset_w->show();} + xywh {5 5 29 19} + } + MenuItem {} { + label Exit + callback {main_window->do_callback();} + xywh {5 5 36 21} shortcut 0xff1b + } + } + Submenu {} { + label Edit + xywh {5 5 70 21} + } { + MenuItem {} { + label Undo + callback {if (pd->preset) pd->preset->undo(); +else pd->display_status("*** Nothing to Undo.");} + xywh {5 5 36 21} shortcut 0x4007a + } + MenuItem {} { + label Redo + callback {if (pd->preset) pd->preset->redo(); +else pd->display_status("*** Nothing to Redo.");} + xywh {15 15 36 21} shortcut 0x5007a + } + MenuItem {} { + label {Start Over} + callback {pd->start_over();} + tooltip {Clear the edit buffer, start from the beginning} xywh {15 15 36 21} shortcut 0x40075 + } + MenuItem {} { + label {Copy...} + callback {show_copy_preset(C_PRESET);} + xywh {15 15 36 21} shortcut 0x40063 + } + MenuItem rand_m { + label {&Randomize} + callback {pd->randomize();} + xywh {5 5 36 21} shortcut 0x40072 + } + MenuItem m_audit { + label {A&udit} + callback {if (m_audit->value()) +{ +ui->main->b_audit->value(1); +ui->main->b_audit->do_callback(); +pd->display_status("Audit: ON"); +} +else +{ +ui->main->b_audit->value(0); +ui->main->b_audit->do_callback(); +pd->display_status("Audit: OFF"); +}} + xywh {5 5 30 20} type Toggle shortcut 0x75 labelcolor 49 + } + MenuItem m_eall { + label {&Edit All} + callback {eall ? set_eall(0) : set_eall(1); +if (!eall && pd->preset) +{ + pd->preset->show(); + if (piano_w->shown()) + piano->redraw(); +}} + xywh {5 5 36 21} type Toggle shortcut 0x65 labelcolor 49 + } + MenuItem m_bypass { + label {F&X Bypass} + callback {if (m_bypass->value()) +{ +ui->b_bypass->value(1); +ui->b_bypass->do_callback(); +pd->display_status("FX bypass: ON"); +} +else +{ +ui->b_bypass->value(0); +ui->b_bypass->do_callback(); +pd->display_status("FX bypass: OFF"); +}} + xywh {5 5 30 20} type Toggle shortcut 0x78 labelcolor 49 + } + MenuItem {} { + label {&Preferences...} + callback {if (preferences->shown() && preferences->visible()) +preferences->hide(); +else +preferences->show();} + xywh {10 10 36 21} shortcut 0x70 + } + } + Submenu {} { + label Window open + xywh {5 5 70 21} + } { + MenuItem {} { + label {M&ain} + callback {((Fl_Button*) selector->child(0))->setonly(); +selector->do_callback();} + xywh {15 15 30 20} shortcut 0x61 + } + MenuItem {} { + label {Main - Maste&r} + callback {if (b_master->value()) +b_master->value(0); +else +b_master->value(1); + +b_master->do_callback(); +Fl::focus(b_master);} + xywh {25 25 30 20} shortcut 0x72 + } + MenuItem {} { + label {Voice &1} + callback {((Fl_Button*) selector->child(1))->setonly(); +selector->do_callback();} + xywh {15 15 30 20} shortcut 0x31 + } + MenuItem m_voice2 { + label {Voice &2} + callback {((Fl_Button*) selector->child(2))->setonly(); +selector->do_callback();} + xywh {25 25 30 20} shortcut 0x32 + } + MenuItem m_voice3 { + label {Voice &3} + callback {((Fl_Button*) selector->child(3))->setonly(); +selector->do_callback();} + xywh {35 35 30 20} shortcut 0x33 + } + MenuItem m_voice4 { + label {Voice &4} + callback {((Fl_Button*) selector->child(4))->setonly(); +selector->do_callback();} + xywh {45 45 30 20} shortcut 0x34 + } + MenuItem {} { + label {Pro&gram} + callback {((Fl_Button*) selector->child(5))->setonly(); +selector->do_callback();} + xywh {5 5 30 20} shortcut 0x67 + } + MenuItem {} { + label {Program - &Links} + callback {if (b_links->value()) +b_links->value(0); +else +b_links->value(1); + +b_links->do_callback(); +Fl::focus(b_links);} + xywh {15 15 30 20} shortcut 0x6c + } + MenuItem {} { + label {&Keyboard} + callback {if (piano_w->shown() && piano_w->visible()) +piano_w->hide(); +else{ +piano_w->show(); +pd->display_status("Hint: [ESC] closes windows.");}} + xywh {5 5 36 21} shortcut 0x6b + } + MenuItem {} { + label {&Message Log} + callback {if (log_w->shown() && log_w->visible()) +log_w->hide(); +else +log_w->show();} + xywh {5 5 36 21} shortcut 0x6d + } + } + Submenu {} { + label MIDI + xywh {5 5 70 21} + } { + MenuItem {} { + label {All Notes Off} + callback {midi->write_event(0xb0, 0x7b, 0); + +global_minipiano->reset_active_keys(); +main->minipiano->reset_active_keys(); +piano->reset_active_keys();} + xywh {0 0 29 19} + } + MenuItem {} { + label {All Notes Off (All Channels)} + callback {for (int i = 0; i < 16; i++) +midi->write_event(0xb0, 0x7b, 0, i); + +global_minipiano->reset_active_keys(); +main->minipiano->reset_active_keys(); +piano->reset_active_keys();} + xywh {0 0 29 19} + } + MenuItem {} { + label {All Sound Off} + callback {midi->write_event(0xb0, 0x78, 0); + +global_minipiano->reset_active_keys(); +main->minipiano->reset_active_keys(); +piano->reset_active_keys();} + xywh {0 0 29 19} + } + MenuItem {} { + label {All Sound Off (All Channels)} + callback {for (int i = 0; i < 16; i++) +midi->write_event(0xb0, 0x78, 0, i); + +global_minipiano->reset_active_keys(); +main->minipiano->reset_active_keys(); +piano->reset_active_keys();} + xywh {0 0 29 19} + } + MenuItem {} { + label {Kill Stale Sound (last resort)} + callback {for (int i = 0; i < 128; i++) +midi->write_event(NOTE_ON, i, 1); +for (int i = 0; i < 128; i++) +midi->write_event(NOTE_OFF, i, 0); + +global_minipiano->reset_active_keys(); +main->minipiano->reset_active_keys(); +piano->reset_active_keys();} + xywh {0 0 29 19} + } + MenuItem {} { + label {Reset All Controllers} + callback {midi->write_event(0xb0, 0x79, 0); + +pitchwheel->value(8192); +modwheel->value(0); +b_fs1->clear(); +b_fs2->clear(); +b_fs3->clear();} + xywh {0 0 29 19} + } + MenuItem {} { + label {Reset All Controllers (All Channels)} + callback {for (int i = 0; i < 16; i++) +midi->write_event(0xb0, 0x79, 0, i); + +pitchwheel->value(8192); +modwheel->value(0); +b_fs1->clear(); +b_fs2->clear(); +b_fs3->clear();} + xywh {0 0 29 19} + } + } + Submenu {} { + label Help open + xywh {5 5 70 21} + } { + MenuItem tooltips { + label {Toolt&ips} + callback {if (tooltips->value()) +{ +Fl_Tooltip::enable(); +cfg->set_cfg_option(CFG_TOOLTIPS, 1); +pd->display_status("Tooltips enabled."); +} +else +{ +Fl_Tooltip::disable(); +cfg->set_cfg_option(CFG_TOOLTIPS, 0); +pd->display_status("Tooltips disabled."); +}} + xywh {5 5 36 21} type Toggle shortcut 0x69 labelcolor 49 + } + MenuItem {} { + label {Hints...} + callback {fl_open_uri("http://prodatum.sf.net/doc/hints.html");} + xywh {5 5 36 21} shortcut 0xffbe + } + MenuItem {} { + label {Visit website...} + callback {fl_open_uri("http://prodatum.sf.net/");} + xywh {5 5 36 21} shortcut 0xffbf + } + MenuItem {} { + label {About...} + callback {if (about->shown() && about->visible()) +about->hide(); +else +about->show();} + xywh {5 5 36 21} shortcut 0xffc0 + } + } + } + } + Fl_Group {} { + label status + xywh {280 1 283 23} labeltype NO_LABEL + } { + Fl_Box {} { + label resizeable + xywh {421 21 1 1} labeltype NO_LABEL resizable + } + Fl_Box status { + label {((broadcast))} + xywh {281 1 281 17} box FLAT_BOX color 7 labelfont 5 labelsize 12 labelcolor 49 align 18 + } + } + Fl_Group g_main {open + xywh {0 19 843 596} + } { + Fl_Group selector { + callback {for (int i = 0; i < o->children(); i++) +if (((Fl_Button*) o->array()[i])->value()) +{ + select(i); + Fl::focus(o->array()[i]); + break; +}} + xywh {56 19 754 24} when 0 + } { + Fl_Button {} { + label {M&AIN} + callback {((Group*)o->parent())->do_callback();} + xywh {56 26 101 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button {} { + label {VOICE &1} + callback {((Group*)o->parent())->do_callback();} + xywh {233 26 60 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button {} { + label {VOICE &2} + callback {((Group*)o->parent())->do_callback();} + xywh {339 26 60 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button {} { + label {VOICE &3} + callback {((Group*)o->parent())->do_callback();} + xywh {445 26 60 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button {} { + label {VOICE &4} + callback {((Group*)o->parent())->do_callback();} + xywh {551 26 60 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button b_program { + label {PRO&GRAM} + callback {((Group*)o->parent())->do_callback();} + xywh {686 26 102 17} type Radio box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelsize 10 when 6 + } + Fl_Button {} { + label M + callback {pd->mute(o->value(), 0);} + tooltip {Mute Voice} xywh {213 26 19 17} type Toggle down_box UP_BOX shortcut 0x40031 color 7 selection_color 81 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {mute_b[0] = o;} + class Fixed_Button + } + Fl_Button {} { + label S + callback {pd->solo(o->value(), 0);} + tooltip {Solo Voice} xywh {294 26 19 17} type Toggle down_box UP_BOX shortcut 0x80031 color 7 selection_color 134 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {solo_b[0] = o;} + class Fixed_Button + } + Fl_Button {} { + label M + callback {pd->mute(o->value(), 1);} + tooltip {Mute Voice} xywh {319 26 19 17} type Toggle down_box UP_BOX shortcut 0x40032 color 7 selection_color 81 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {mute_b[1] = o;} + class Fixed_Button + } + Fl_Button {} { + label S + callback {pd->solo(o->value(), 1);} + tooltip {Solo Voice} xywh {400 26 19 17} type Toggle down_box UP_BOX shortcut 0x80032 color 7 selection_color 134 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {solo_b[1] = o;} + class Fixed_Button + } + Fl_Button {} { + label M + callback {pd->mute(o->value(), 2);} + tooltip {Mute Voice} xywh {425 26 19 17} type Toggle down_box UP_BOX shortcut 0x40033 color 7 selection_color 81 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {mute_b[2] = o;} + class Fixed_Button + } + Fl_Button {} { + label S + callback {pd->solo(o->value(), 2);} + tooltip {Solo Voice} xywh {506 26 19 17} type Toggle down_box UP_BOX shortcut 0x80033 color 7 selection_color 134 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {solo_b[2] = o;} + class Fixed_Button + } + Fl_Button {} { + label M + callback {pd->mute(o->value(), 3);} + tooltip {Mute Voice} xywh {531 26 19 17} type Toggle down_box UP_BOX shortcut 0x40034 color 7 selection_color 81 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {mute_b[3] = o;} + class Fixed_Button + } + Fl_Button {} { + label S + callback {pd->solo(o->value(), 3);} + tooltip {Solo Voice} xywh {612 26 19 17} type Toggle down_box UP_BOX shortcut 0x80034 color 7 selection_color 134 labelfont 1 labelsize 10 labelcolor 49 when 1 + code0 {solo_b[3] = o;} + class Fixed_Button + } + } + Fl_Button b_master { + label {Maste&r} + callback {if (o->value()) +{ +if (get_selected() != 0) + select(0); +main->master->show(); +main->mixer->hide(); +g_multisetups->show(); +g_pfx->hide(); +main->controller_assign->show(); +main->controller->hide(); +} +else +{ +if (get_selected() != 0) +{ + select(0); + o->value(1); + return; +} +main->mixer->show(); +main->master->hide(); +g_pfx->show(); +g_multisetups->hide(); +main->controller->show(); +main->controller_assign->hide(); +}} + tooltip Master xywh {158 26 46 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelfont 1 labelsize 10 + } + Fl_Button b_pfx { + label {P/&FX} + callback {if (g_effects->visible()) +{ +g_preset->show(); +g_effects->hide(); +} +else +{ +g_preset->hide(); +g_effects->show(); +}} + tooltip Links xywh {639 26 46 17} box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelfont 1 labelsize 10 + } + Fl_Button b_links { + label {&Links} + callback {if (o->value()) +{ +if (get_selected() != 5) + select(5); +preset_editor->links->show(); +preset_editor->program->hide(); +} +else +{ +if (get_selected() != 5) +{ + select(5); + o->value(1); + return; +} +preset_editor->program->show(); +preset_editor->links->hide(); +}} + tooltip Links xywh {789 26 46 17} type Toggle box THIN_UP_BOX down_box THIN_UP_BOX selection_color 15 labelfont 1 labelsize 10 + } + Fl_Box main { + xywh {5 43 833 567} labeltype NO_LABEL + class PD_Main + } + Fl_Box v1 { + xywh {5 43 833 567} labeltype NO_LABEL hide + code1 {layer_editor[0] = o;} + code2 {o->init(0);} + class PD_Layer_Editor + } + Fl_Box v2 { + xywh {5 43 833 567} labeltype NO_LABEL hide + code1 {layer_editor[1] = o;} + code2 {o->init(1);} + class PD_Layer_Editor + } + Fl_Box v3 { + xywh {5 43 833 567} labeltype NO_LABEL hide + code1 {layer_editor[2] = o;} + code2 {o->init(2);} + class PD_Layer_Editor + } + Fl_Box v4 { + xywh {5 43 833 567} labeltype NO_LABEL hide + code1 {layer_editor[3] = o;} + code2 {o->init(3);} + class PD_Layer_Editor + } + Fl_Box preset_editor { + xywh {5 43 833 567} labeltype NO_LABEL + class PD_Preset_Editor + } + Fl_Button {} { + label MP + callback {if (g_value->visible()) +{g_value->hide();g_minipiano->show();} +else +{g_minipiano->hide();g_value->show();}} + tooltip {Toggle MiniPiano} xywh {639 49 28 17} type Toggle down_box UP_BOX shortcut 0x6e selection_color 7 labelsize 10 labelcolor 15 + } + Fl_Group g_value { + label {VALUE OUT/ INPUT} + xywh {639 66 196 56} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Value_Output forma_out { + tooltip {Formatted value display} xywh {642 69 190 20} box UP_BOX color 7 selection_color 15 labeltype NO_LABEL labelsize 12 labelcolor 7 align 0 textfont 5 textsize 12 textcolor 49 + class Formatted_Output + } + Fl_Button undo_b { + label {@<-} + callback {if (pd->preset) pd->preset->undo();} + tooltip {Undo program parameter change} xywh {642 91 28 28} color 7 selection_color 78 labelfont 4 labelsize 18 labelcolor 49 deactivate + } + Fl_Button redo_b { + label {@->} + callback {if (pd->preset) pd->preset->redo();} + tooltip {Redo program parameter change} xywh {672 91 28 28} color 7 selection_color 78 labelfont 4 labelsize 18 labelcolor 49 deactivate + } + Fl_Value_Input value_input { + tooltip {Manually edit value of last edited parameter (with the keyboard, by dragging left/right or the mousewheel) [CTRL+E to focus]} xywh {703 91 68 28} box UP_BOX color 49 labeltype NO_LABEL labelsize 12 align 0 when 8 maximum 0 step 1 textfont 5 textsize 20 + code0 {o->set_id(1, 0);} + class Value_Input + } + Fl_Button drls { + label {&DR} + callback {if (o->value()) +{ +value_input->when(FL_WHEN_ENTER_KEY); +cfg->set_cfg_option(CFG_DRLS, 1); +} +else +{ +value_input->when(FL_WHEN_CHANGED); +cfg->set_cfg_option(CFG_DRLS, 0); +}} + tooltip {When to actually commit the value of the Value display. Enabled: commit on mousebutton release or when you press enter. Disabled: commit all value changes.} xywh {774 91 28 28} type Toggle down_box UP_BOX shortcut 0x64 value 1 color 7 selection_color 78 labelsize 12 labelcolor 49 align 80 + } + Fl_Button b_eall { + label {&Eall} + callback {set_eall(o->value()); +if (!o->value() && pd->preset) +if (!eall && pd->preset) +{ + pd->preset->show(); + if (piano_w->shown()) + piano->redraw(); +}} + tooltip {Edit All Layers} xywh {804 91 28 28} type Toggle down_box UP_BOX color 7 selection_color 78 labelsize 12 labelcolor 49 align 16 + } + } + Fl_Group g_minipiano { + label MINIPIANO + xywh {639 66 196 56} box THIN_DOWN_BOX labelfont 1 labelcolor 15 hide + } { + Fl_Box global_minipiano { + xywh {640 67 194 54} box FLAT_BOX labeltype NO_LABEL + class MiniPiano + } + } + Fl_Group g_pfx {open + xywh {639 129 196 321} labeltype NO_LABEL align 0 + } { + Fl_Group g_effects { + label EFFECTS + tooltip {Effects section (it is disabled when the selected channel and the selected FX channel differ)} xywh {639 146 196 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 hide + } { + Fl_Choice fx_channel {open + tooltip {FX Control Channel. When in multi mode, you can set this to "0" which applies the Master menu effects settings to all 16 MIDI channels. If you want more control, you can choose a channel which applies the effects settings of the preset on the specified channel to all the other channels. Changing the preset on the specified channel changes the effect. If you are in Omni or Poly modes this parameter is disabled} xywh {649 151 82 21} down_box BORDER_BOX labeltype NO_LABEL align 0 textsize 13 + code0 {o->set_id(140);} + code1 {o->add("Master");} + code2 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");} + code3 {o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");} + class Choice + } {} + Fl_Button b_bypass { + label {F&X BYPASS} + tooltip {When bypassed, the effects are turned Off on a global scale. This includes Effects programmed in the preset} xywh {742 151 82 21} type Toggle down_box UP_BOX selection_color 81 labelsize 10 align 80 + code0 {o->set_id(258);} + class Button + } + Fl_Group fx { + xywh {644 176 185 274} + } { + Fl_Choice fxa {open + tooltip {Selects the type of effect A} xywh {649 178 175 21} down_box BORDER_BOX align 2 textsize 13 + class Choice + } {} + Fl_Group g_fxa { + xywh {644 200 185 114} + } { + Fl_Box {} { + label FXA + xywh {649 213 40 24} labelfont 1 labelsize 15 labelcolor 15 + } + Fl_Dial fxa_decay { + label Decay + tooltip {Decay sets the length of time it takes an effect to fade out. When setting up reverb effects, Decay controls the room size and the reflectivity of the room. For larger room sizes and greater reflectivity, set the Decay value higher. When setting up delay effects, the Decay parameter controls how many echoes are produced or how long the echoes last. The greater the value, the more echoes and longer lengths of time} xywh {694 204 40 40} color 7 labelsize 10 maximum 90 step 1 + class Fl_Knob + } + Fl_Dial fxa_damp { + label Damp + tooltip {High Frequency Damping. High Frequency energy tends to fade away first as a sound is dissipated in a room. the HF Damping parameter adjusts the amount of damping applied to the signal's high frequency elements which, in turn, changes the characteristics of the room. Rooms with smooth, hard surfaces are more reflective and have less high frequency damping. Rooms filled with sound absorbing materials, such as curtains or people, have more high frequency damping} xywh {739 204 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial fxa_ba { + label {B >> A} + tooltip {The output of effects processor B can be routed into effects processor A. This connects the effects in series instead of their normal parallel configuration} xywh {784 204 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial fxa_send1 { + label {Send 1} + tooltip {Send 1 amount} xywh {649 257 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxa_send2 { + label {Send 2} + tooltip {Send 2 amount} xywh {694 257 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxa_send3 { + label {Send 3} + tooltip {Send 3 amount} xywh {739 257 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxa_send4 { + label {Send 4} + tooltip {Send 4 amount} xywh {784 257 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + } + Fl_Choice fxb {open + tooltip {Selects the type of effect B} xywh {649 316 175 21} down_box BORDER_BOX align 2 textsize 13 + class Choice + } {} + Fl_Group g_fxb { + xywh {644 338 185 112} + } { + Fl_Box {} { + label FXB + xywh {649 351 40 24} labelfont 1 labelsize 15 labelcolor 15 + } + Fl_Dial fxb_feedback { + label Feedback + tooltip {The Chorus and Flange effects have a controllable feedback loop after the delay element. Feeding back a small amount of the signal intensifies the effect by creating multiple cancellations or images. Higher feedback values increase the amount of the Feedback loop} xywh {694 342 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial fxb_lfo_rate { + label LFO + tooltip {Both Chorus and Flange effects use a Low Frequency Oscillator (LFO) to animate the effect. LFO applied to a chorus effect creates the slight changes necessary for a realistic choral effect. Applied to a flanger effect, the LFO moves the comb filter notches and adds animation to the sound} xywh {739 342 40 40} color 7 labelsize 10 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial fxb_delay { + label Delay + tooltip {Flanging, chorus and echoes are all based on a delay line where the signal is delayed by some time period and then mixed back with the unaltered signal. This parameter specifies the how much time passes before you hear the delayed signal. On some effects, this value cannot be changed. The Delay value range is from 0ms to 635ms} xywh {784 342 40 40} color 7 labelsize 10 minimum -12 maximum 127 step 1 + class Fl_Knob + } + Fl_Dial fxb_send1 { + label {Send 1} + tooltip {Send 1 amount} xywh {649 395 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxb_send2 { + label {Send 2} + tooltip {Send 2 amount} xywh {694 395 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxb_send3 { + label {Send 3} + tooltip {Send 2 amount} xywh {739 395 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + Fl_Dial fxb_send4 { + label {Send 4} + tooltip {Send 4 amount} xywh {784 395 40 40} color 7 labelsize 10 maximum 100 step 1 + class Fl_Knob + } + } + } + } + Fl_Group g_preset {open + xywh {639 129 196 321} labeltype NO_LABEL align 0 deactivate + } { + Fl_Button b_copy_p { + label COPY + callback {//ui->show_copy_preset(c_preset); +if (o->value()) +{ +if (b_save_p->value()) + b_save_p->value(0); +// load user list and deactivate rom choice +if (pd->selected_preset_rom != 0) + preset_rom->set_value(0); +preset_rom->deactivate(); +g_program->label("TARGET"); +// save filter string +if (!filter_tmp) + { + filter_tmp = new char[preset_filter->size()+1]; + strcpy(filter_tmp, preset_filter->value()); + preset_filter->value(0); + preset_filter->do_callback(); + } +Fl::focus(preset); +} +else +{ +preset_rom->set_value(pd->selected_preset_rom); +preset_rom->activate(); +preset->select(pd->selected_preset + 1); +preset_filter->value(filter_tmp); +preset_filter->do_callback(); +delete filter_tmp; +filter_tmp = 0; +g_program->label("PROGRAM"); +Fl::focus(preset); +}} + tooltip {Copy Program (You will need to select a target below. This copies the already saved version of the selected program and NOT the edit buffer. Use "SAVE" to save the edit buffer). Backspace cancels.} xywh {639 129 40 17} type Toggle down_box UP_BOX selection_color 81 labelsize 10 labelcolor 15 + } + Fl_Button b_save_p { + label SAVE + callback {//ui->show_copy_preset(s_preset); +if (o->value()) +{ +if (b_copy_p->value()) + b_copy_p->value(0); +pd->display_status("Hint: Give me a name over there --->"); +// load user list and deactivate rom choice +if (pd->selected_preset_rom != 0) + preset_rom->set_value(0); +preset_rom->deactivate(); +g_program->label("TARGET"); +// save filter string +if (!filter_tmp) + { + filter_tmp = new char[preset_filter->size()+1]; + strcpy(filter_tmp, preset_filter->value()); + preset_filter->value(0); + preset_filter->do_callback(); + } +Fl::focus(preset); +} +else +{ +preset_rom->set_value(pd->selected_preset_rom); +preset_rom->activate(); +preset->select(pd->selected_preset + 1); +preset_filter->value(filter_tmp); +preset_filter->do_callback(); +delete filter_tmp; +filter_tmp = 0; +g_program->label("PROGRAM"); +Fl::focus(preset); +}} + tooltip {Save the edit buffer (You will need to select a target below). Backspace cancels.} xywh {795 129 40 17} type Toggle down_box UP_BOX selection_color 81 labelsize 10 labelcolor 15 + } + Fl_Group g_program { + label PROGRAM open + xywh {639 146 196 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice preset_rom {open + xywh {649 152 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 + code0 {o->set_id(138);} + class ROM_Choice + } {} + Fl_Browser preset { + tooltip {Select a program to load for editing or, if either "COPY" or "SAVE" is active, double-click/Enter/Space target to copy/save (hold SHIFT to copy/save and return to preset selection mode).} xywh {649 178 176 241} type Hold when 4 textfont 4 textsize 12 textcolor 49 + code0 {o->set_id(897);} + class Browser + } + Fl_Input preset_filter { + label {F } + callback {preset->set_filter(o->value());} + xywh {665 424 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + code2 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {preset_filter->value(0); +preset_filter->do_callback();} + xywh {799 424 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 10 labelcolor 49 + } + } + } + } + Fl_Group g_multisetups { + label MULTISETUP open + xywh {639 146 196 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 hide + } { + Fl_Browser multisetups { + callback {o->deactivate(); +midi->copy(C_SETUP, o->value() - 1, -1); +midi->request_setup_dump();} + xywh {649 152 176 226} type Hold when 0 textfont 4 textsize 12 textcolor 49 deactivate + } + Fl_Input s_name { + label {Save as} + tooltip {MultiSetup name (16 characters max.)} xywh {649 395 176 20} box UP_BOX labelsize 10 labelcolor 15 align 5 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(16);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + class Input + } + Fl_Button do_save { + label {Save @returnarrow} + callback {o->deactivate(); +pd->save_setup(multisetups->value() - 1, s_name->value());} + tooltip {Save MultiSetup} xywh {649 424 60 20} box THIN_UP_BOX shortcut 0xff0d selection_color 15 labelsize 12 + } + Fl_Button {} { + label Load + callback {multisetups->do_callback();} + tooltip {Save MultiSetup} xywh {765 424 60 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + } + } + Fl_Group g_arp_edit { + xywh {0 20 843 595} box FLAT_BOX hide + } { + Fl_Box {} { + xywh {10 30 40 279} labeltype NO_LABEL + code0 {o->init(0);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {53 30 40 279} labeltype NO_LABEL + code0 {o->init(1);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {96 30 40 279} labeltype NO_LABEL + code0 {o->init(2);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {139 30 40 279} labeltype NO_LABEL + code0 {o->init(3);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {182 30 40 279} labeltype NO_LABEL + code0 {o->init(4);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {225 30 40 279} labeltype NO_LABEL + code0 {o->init(5);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {268 30 40 279} labeltype NO_LABEL + code0 {o->init(6);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {311 30 40 279} labeltype NO_LABEL + code0 {o->init(7);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {354 30 40 279} labeltype NO_LABEL + code0 {o->init(8);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {397 30 40 279} labeltype NO_LABEL + code0 {o->init(9);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {440 30 40 279} labeltype NO_LABEL + code0 {o->init(10);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {483 30 40 279} labeltype NO_LABEL + code0 {o->init(11);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {526 30 40 279} labeltype NO_LABEL + code0 {o->init(12);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {569 30 40 279} labeltype NO_LABEL + code0 {o->init(13);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {612 30 40 279} labeltype NO_LABEL + code0 {o->init(14);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {655 30 40 279} labeltype NO_LABEL + code0 {o->init(15);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {10 325 40 279} labeltype NO_LABEL + code0 {o->init(16);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {53 325 40 279} labeltype NO_LABEL + code0 {o->init(17);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {96 325 40 279} labeltype NO_LABEL + code0 {o->init(18);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {139 325 40 279} labeltype NO_LABEL + code0 {o->init(19);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {182 325 40 279} labeltype NO_LABEL + code0 {o->init(20);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {225 325 40 279} labeltype NO_LABEL + code0 {o->init(21);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {268 325 40 279} labeltype NO_LABEL + code0 {o->init(22);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {311 325 40 279} labeltype NO_LABEL + code0 {o->init(23);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {354 325 40 279} labeltype NO_LABEL + code0 {o->init(24);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {397 325 40 279} labeltype NO_LABEL + code0 {o->init(25);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {440 325 40 279} labeltype NO_LABEL + code0 {o->init(26);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {483 325 40 279} labeltype NO_LABEL + code0 {o->init(27);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {526 325 40 279} labeltype NO_LABEL + code0 {o->init(28);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {569 325 40 279} labeltype NO_LABEL + code0 {o->init(29);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {612 325 40 279} labeltype NO_LABEL + code0 {o->init(30);} + class PD_Arp_Step + } + Fl_Box {} { + xywh {655 325 40 279} labeltype NO_LABEL + code0 {o->init(31);} + class PD_Arp_Step + } + Fl_Input arp_name { + label NAME + callback {arp_name_changed = true;} + tooltip {Arpeggiator pattern name} xywh {705 554 127 20} box UP_BOX labelfont 1 labelsize 10 labelcolor 15 align 5 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->maximum_size(12);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + class Input + } + Fl_Button {} { + label {Close @returnarrow} + callback {if (arp_name_changed && pd->arp) pd->arp->rename(arp_name->value()); +arp_name_changed = false; +g_main->show(); +g_arp_edit->hide(); +Fl::focus(g_main);} + tooltip {Keep settings and return} xywh {705 584 68 20} box THIN_UP_BOX shortcut 0xff0d selection_color 15 labelsize 12 + } + Fl_Button {} { + label Reset + callback {if (pd->arp) pd->arp->reset_pattern(); +arp_name_changed = false;} + tooltip {Undo all changes} xywh {781 584 51 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + Fl_Box {} { + label OP + xywh {698 30 1 90} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label TIME + xywh {698 123 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label REPEAT + xywh {698 141 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label VELOCITY + xywh {698 159 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label {PITCH | OFFSET} + xywh {698 179 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label OP + xywh {698 325 1 90} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label TIME + xywh {698 418 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label REPEAT + xywh {698 436 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label VELOCITY + xywh {698 454 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Box {} { + label {PITCH | OFFSET} + xywh {698 474 1 16} box BORDER_BOX color 7 labelfont 1 labelsize 10 labelcolor 15 align 8 + } + Fl_Output pattern_length { + label {BEATS:TICKS} + tooltip {Pattern length (48 Ticks/Beat)} xywh {705 280 127 30} box FLAT_BOX color 49 labelfont 1 labelsize 10 labelcolor 15 align 5 textfont 4 textsize 24 + } + } + Fl_Box {} { + xywh {1 1 841 66} labeltype NO_LABEL when 0 + class DND_Box + } + } + Fl_Window init { + label Initializing + callback {;} + xywh {680 68 290 147} type Double box BORDER_BOX hide modal + } { + Fl_Box {} { + xywh {1 1 104 43} box FLAT_BOX color 7 labeltype NO_LABEL labelfont 1 labelcolor 49 align 26 + } + Fl_Box {} { + label {Please wait. This may take a few minutes.} + xywh {105 1 184 43} box FLAT_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 154 + } + Fl_Box {} { + xywh {5 0 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Progress init_progress { + label {Loading ROM data} + xywh {10 74 270 26} box THIN_DOWN_BOX color 49 selection_color 15 labelsize 13 + } + Fl_Button {} { + label Cancel + callback {init_progress->value(0.); +init_progress->label("Waiting for MIDI queue to exit..."); +init_progress->redraw(); +pd->cancel_init();} + xywh {220 117 60 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + } + Fl_Window open_device { + label {Open Device} + xywh {544 73 355 414} type Double box BORDER_BOX labelcolor 15 hide modal + } { + Fl_Box {} { + label {Open Device} + xywh {1 1 353 43} box FLAT_BOX color 7 labelfont 1 labelcolor 49 align 26 + } + Fl_Box {} { + xywh {5 0 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Box {} { + label {Out Port} + xywh {17 78 56 20} labelsize 12 labelcolor 15 align 24 + } + Fl_Menu_Button midi_outs { + label {Select...} + callback {connect->deactivate(); +device_info->label(0); +if (midi->connect_out(o->value())) +{ +o->label(o->text(o->value())); +} +else +{ +o->label("Select..."); +}} open + tooltip {OUT: Select the MIDI port that is connected to MIDI IN of your device.} xywh {74 78 211 20} box THIN_UP_BOX down_box THIN_UP_BOX labelsize 12 align 84 textsize 13 + } {} + Fl_Box {} { + label {In Port} + xywh {17 106 56 20} labelsize 12 labelcolor 15 align 24 + } + Fl_Menu_Button midi_ins { + label {Select...} + callback {connect->deactivate(); +device_info->label(0); +if (midi->connect_in(o->value())) +{ +o->label(o->text(o->value())); +} +else +{ +o->label("Select..."); +}} open + tooltip {IN: Select the MIDI port that is connected to MIDI OUT of your device.} xywh {74 106 211 20} box THIN_UP_BOX down_box THIN_UP_BOX labelsize 12 align 84 textsize 13 + } {} + Fl_Box {} { + label {Device ID} + xywh {17 134 56 20} labelsize 12 labelcolor 15 align 24 + } + Fl_Spinner device_id { + callback {connect->deactivate(); +device_info->label(0); +midi->set_device_id(o->value()); +midi->request_device_inquiry(); +r_user_id->value(o->value());} + tooltip {ID: Must be unique for every device you intend to use prodatum with (you can set the ID in the Master Menu of your device)!} xywh {74 134 55 20} color 7 selection_color 15 labeltype NO_LABEL labelfont 2 labelsize 12 labelcolor 15 align 0 when 1 minimum 0 maximum 126 value 0 textfont 4 textsize 13 textcolor 49 + } + Fl_Button b_auto_detect { + label {Auto-Detect} + callback {connect->deactivate(); +device_info->label(0); +midi->request_device_inquiry(127);} + xywh {140 134 80 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 11 labelcolor 49 deactivate + } + Fl_Choice speed { + label {Op. Level} + callback {cfg->set_cfg_option(CFG_SPEED, o->value());} open + tooltip {Operation Level: Lower settings will work better if your computer or your MIDI device is very slow.} xywh {74 162 110 20} down_box BORDER_BOX labelsize 12 labelcolor 15 textsize 13 + code0 {o->add("Fast");o->add("Slower");o->add("Turtle");} + } {} + Fl_Box {} { + label {Ctrl Port} + xywh {20 198 53 20} labelsize 12 labelcolor 15 align 24 + } + Fl_Menu_Button midi_ctrl { + label {Select... (optional)} + callback {if (midi->connect_thru(o->value())) +{ +cfg->set_cfg_option(CFG_MIDI_THRU, o->value()); +o->label(o->text(o->value())); +} +else +{ +cfg->set_cfg_option(CFG_MIDI_THRU, -1); +o->label("Select... (optional)"); +}} open + tooltip {Control: Select the MIDI port that your controller is connected to (select again to disconnect).} xywh {74 198 211 20} box THIN_UP_BOX down_box THIN_UP_BOX labelsize 12 align 84 textsize 13 + } {} + Fl_Choice midi_ctrl_ch { + label {Ctrl Chnl} + callback {midi->set_control_channel_filter(o->value());} open + tooltip {Control Channel: Data to the control port will only be accepted for the selected channel(s).} xywh {74 228 55 20} down_box BORDER_BOX labelsize 12 labelcolor 15 textsize 13 + code0 {o->add("1");o->add("2");o->add("3");o->add("4");o->add("5");o->add("6");o->add("7");o->add("8");o->add("9");o->add("10");o->add("11");o->add("12");o->add("13");o->add("14");o->add("15");o->add("16");o->add("All");} + } {} + Fl_Check_Button midi_automap { + label {Map to Basic Channel} + callback {automap = o->value(); +cfg->set_cfg_option(CFG_AUTOMAP, o->value());} + tooltip {When enabled voice messages from the controller will always leave prodatum on the channel that is selected in prodatum. This is helpful when your controller does not allow you to change the MIDI channel or if you do not want to switch channels on the controller all the time.} xywh {140 228 162 20} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Button {} { + label Update + callback {connect->deactivate(); +device_info->label(0); +midi->request_device_inquiry(device_id->value());} + tooltip {Request device information.} xywh {15 294 54 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 11 labelcolor 49 + } + Fl_Box {} { + label {Device Info} + xywh {74 264 267 20} color 7 labelsize 12 labelcolor 15 align 132 + } + Fl_Box device_info { + tooltip {Shows device information for the selected device (updates automatically on every port or ID change).} xywh {74 264 267 85} box THIN_DOWN_BOX color 7 selection_color 15 labelcolor 49 align 213 + } + Fl_Check_Button autoconnect { + label {Open at startup} + callback {cfg->set_cfg_option(CFG_AUTOCONNECT, o->value());} + tooltip {Wether you want prodatum to automatically connect to your device at startup.} xywh {84 354 123 20} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Button b_rescan { + label {Populate Ports} + callback {midi_outs->label("Select..."); +midi_ins->label("Select..."); +midi_ctrl->label("Select... (optional)"); +delete midi; +midi = new MIDI(); +// select previous +int selection; +selection = cfg->get_cfg_option(CFG_MIDI_OUT); +if (selection != -1) +{ +midi_outs->value(selection); +midi_outs->do_callback();} +selection = cfg->get_cfg_option(CFG_MIDI_IN); +if (selection != -1) +{ +midi_ins->value(selection); +midi_ins->do_callback();} +selection = cfg->get_cfg_option(CFG_MIDI_THRU); +if (selection != -1) +{ +midi_ctrl->value(selection); +midi_ctrl->do_callback();}} + tooltip {Populate (newly) available MIDI ports.} xywh {74 384 90 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 11 labelcolor 49 + } + Fl_Button connect { + label {Open @returnarrow} + callback {open_device->hide(); +cfg->set_cfg_option(CFG_MIDI_OUT, midi_outs->value()); +cfg->set_cfg_option(CFG_MIDI_IN, midi_ins->value()); +cfg->set_cfg_option(CFG_DEVICE_ID, device_id->value()); +midi->request_setup_dump();} + xywh {212 384 64 20} box THIN_UP_BOX shortcut 0xff0d selection_color 15 labelsize 12 deactivate + } + Fl_Button {} { + label Close + callback {open_device->hide();} + xywh {281 384 60 20} box THIN_UP_BOX shortcut 0x6f selection_color 15 labelsize 12 + } + } + Fl_Window preferences { + label Preferences + callback {b_close_prefs->do_callback();} + xywh {382 320 617 338} type Double box UP_BOX labelsize 11 hide modal + } { + Fl_Box {} { + label Preferences + xywh {1 1 615 43} box FLAT_BOX color 7 labelfont 1 labelcolor 49 align 26 + } + Fl_Box {} { + xywh {5 0 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Box {} { + label Confirm + xywh {10 90 124 70} labelfont 1 labelcolor 15 align 5 + } + Fl_Check_Button confirm { + label Exit + callback {cfg->set_cfg_option(CFG_CONFIRM_EXIT, o->value());} + tooltip {Wether to show a confirmation dialog on exit} xywh {20 97 46 15} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Check_Button confirm_dismiss { + label Dismiss + callback {cfg->set_cfg_option(CFG_CONFIRM_DISMISS, o->value());} + tooltip {Wether to show a confirmation dialog for dismiss} xywh {20 116 72 15} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Check_Button confirm_rand { + label Randomize + callback {cfg->set_cfg_option(CFG_CONFIRM_RAND, o->value());} + tooltip {Wether to show a confirmation dialog for randomize} xywh {20 135 94 15} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Group g_knobmode { + label {Knob job..} + callback {int i; +for (i = 0; i < o->children(); i++) +if (((Fl_Button*) o->array()[i])->value()) +break; +((Fl_Button*) o->child(i))->setonly(); +cfg->set_cfg_option(CFG_KNOBMODE, i);} + tooltip {Choose how knobs should behave when you drag them} xywh {140 90 124 70} labelfont 1 labelcolor 15 align 5 + } { + Fl_Check_Button {} { + label {..radially} + callback {((Group*)o->parent())->do_callback();} + xywh {155 97 77 15} type Radio down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Check_Button {} { + label {..horizontally} + callback {((Group*)o->parent())->do_callback();} + xywh {155 116 103 15} type Radio down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Check_Button {} { + label {..vertically} + callback {((Group*)o->parent())->do_callback();} + xywh {155 135 87 15} type Radio down_box DOWN_BOX value 1 selection_color 49 + } + } + Fl_Box {} { + label {Import and Export} + xywh {10 185 290 61} labelfont 1 labelcolor 15 align 133 + } + Fl_Output export_dir { + tooltip {The default export directory is where quick exports are saved to and is the start location for all im-/export browsers.} xywh {20 192 275 20} box UP_BOX labelsize 10 labelcolor 15 align 0 when 0 textfont 5 textsize 12 textcolor 49 + } + Fl_Button {} { + label Change + callback {set_export_path();} + tooltip {This button starts the "browse for a nice export directory" quest!} xywh {20 218 60 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 11 labelcolor 49 + } + Fl_Check_Button c_aaudit { + label {Audit Imports} + callback {cfg->set_cfg_option(CFG_AUDIT_IMPORT, o->value());} + tooltip {Audit programs selected in the import browser?} xywh {90 222 107 15} down_box DOWN_BOX selection_color 49 + } + Fl_Box {} { + label {MIDI Performance} + xywh {10 274 290 51} labelfont 1 labelcolor 15 align 5 + } + Fl_Check_Button closed_loop_download { + label {Closed Loop Preset Download (Slower)} + callback {cfg->set_cfg_option(CFG_CLOSED_LOOP_DOWNLOAD, o->value());} + tooltip {Closed loop downloads require prodatum to acknowledge each packet using handshake messages. Advantage: a checksum is used to validate each packet. Disadvantage: it's slower. (Default: disabled, use open loop downloads)} xywh {20 281 269 15} down_box DOWN_BOX selection_color 49 + } + Fl_Check_Button closed_loop_upload { + label {Closed Loop Preset Upload (Slower)} + callback {cfg->set_cfg_option(CFG_CLOSED_LOOP_UPLOAD, o->value());} + tooltip {Closed loop uploads require the device to acknowledge each packet using handshake messages. Advantage: a checksum is used to validate each packet. Disadvantage: it's slower. (Default: disabled, use open loop uploads)} xywh {20 300 251 15} down_box DOWN_BOX selection_color 49 + } + Fl_Box {} { + label Colors + xywh {320 90 290 146} labelfont 1 labelcolor 15 align 5 + } + Fl_Check_Button c_cbg { + label {Colored Background} + callback {cfg->set_cfg_option(CFG_COLORED_BG, o->value()); +set_color(-1, 0);} + tooltip {Use color C as background} xywh {400 204 154 15} down_box DOWN_BOX selection_color 49 + } + Fl_Check_Button c_sk { + label {Shiny Knobs} + callback {set_color(KNOBS, o->value());} + tooltip {Make knobs bright} xywh {400 223 101 15} down_box DOWN_BOX selection_color 49 + } + Fl_Button {} { + label Default + callback {set_color(DEFAULT, 0);} + tooltip {Set default colors.} xywh {330 201 60 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 11 labelcolor 49 + } + Fl_Value_Slider c_bg { + label S1 + callback {set_color(BG, o->value());} + tooltip {Shade 1} xywh {350 97 255 15} type {Horz Knob} box FLAT_BOX selection_color 7 labelsize 12 labelcolor 15 align 4 maximum 255 step 1 textsize 12 + } + Fl_Value_Slider c_bg2 { + label S2 + callback {set_color(BG2, o->value());} + tooltip {Shade 2} xywh {350 116 255 15} type {Horz Knob} box FLAT_BOX selection_color 7 labelsize 12 labelcolor 15 align 4 maximum 255 step 1 textsize 12 + } + Fl_Value_Slider c_rr { + label {C R} + callback {set_color(RR, o->value());} + tooltip {Color red} xywh {350 135 255 15} type {Horz Knob} box FLAT_BOX selection_color 7 labelsize 12 labelcolor 15 align 4 maximum 255 step 1 textsize 12 + } + Fl_Value_Slider c_gg { + label {C G} + callback {set_color(GG, o->value());} + tooltip {Color green} xywh {350 154 255 15} type {Horz Knob} box FLAT_BOX selection_color 7 labelsize 12 labelcolor 15 align 4 maximum 255 step 1 textsize 12 + } + Fl_Value_Slider c_bb { + label {C B} + callback {set_color(BB, o->value());} + tooltip {Color blue} xywh {350 173 255 15} type {Horz Knob} box FLAT_BOX selection_color 7 labelsize 12 labelcolor 15 align 4 maximum 255 step 1 textsize 12 + } + Fl_Choice {} { + label stderr + callback {set_msglevel(o->value());} open + tooltip {stderr message level (for debugging)} xywh {525 269 80 20} down_box BORDER_BOX labelsize 11 labelcolor 15 textsize 11 + code0 {o->add("Error");o->add("Info");o->add("Debug");} + code1 {o->value(0);} + } {} + Fl_Button b_close_prefs { + label Close + callback {preferences->hide();} + xywh {330 300 275 20} box THIN_UP_BOX shortcut 0x70 selection_color 15 labelsize 12 + } + } + Fl_Window piano_w { + label Keyboard + callback {o->hide();} + xywh {273 430 931 192} type Double box BORDER_BOX hide + class Double_Window + } { + Fl_Group pi_mode { + label M + callback {for (int i = 0; i < o->children(); i++) +if (((Fl_Button*) o->array()[i])->value()) +{ + piano->set_mode(i); + break; +}} + tooltip {Switch Modes} xywh {556 4 46 20} labelsize 10 labelcolor 15 align 4 when 0 + } { + Fl_Button {} { + label K + callback {((Group*)o->parent())->do_callback();} + xywh {557 4 15 20} type Radio down_box UP_BOX value 1 selection_color 15 labelsize 12 labelcolor 15 + } + Fl_Button {} { + label V + callback {((Group*)o->parent())->do_callback();} + xywh {572 4 15 20} type Radio down_box UP_BOX selection_color 15 labelsize 12 labelcolor 15 + } + Fl_Button {} { + label R + callback {((Group*)o->parent())->do_callback();} + xywh {587 4 15 20} type Radio down_box UP_BOX selection_color 15 labelsize 12 labelcolor 15 + } + } + Fl_Button b_fs1 { + label {FOOTSW 1} + callback {int val = 0; +if (o->value()) +val = 127; +pd->cc_callback(13, val);} + xywh {609 4 69 20} type Toggle down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 when 6 + code0 {main->ctrl_x[13] = o;} + } + Fl_Button b_fs2 { + label {FOOTSW 2} + callback {int val = 0; +if (o->value()) +val = 127; +pd->cc_callback(14, val);} + xywh {679 4 69 20} type Toggle down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 when 6 + code0 {main->ctrl_x[14] = o;} + } + Fl_Button b_fs3 { + label {FOOTSW 3} + callback {int val = 0; +if (o->value()) +val = 127; +pd->cc_callback(15, val);} + xywh {749 4 69 20} type Toggle down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 when 6 + code0 {main->ctrl_x[15] = o;} + } + Fl_Button all_notes_off { + label {ALL NOTES OFF} + callback {midi->write_event(0xb0, 0x7b, 0); +piano->reset_active_keys();} + tooltip {Turns off all notes (Ignored/Disabled in omni mode)} xywh {826 4 96 20} down_box UP_BOX selection_color 15 labelsize 10 labelcolor 15 when 6 + } + Fl_Slider pitchwheel { + label PITCH + callback {int val = (int) o->value(); +midi->write_event(0xe0, val & 0x007f, val >> 7);} + tooltip {Pitch "Wheel": Use right mouse button to enable hold, left for common behaviour} xywh {42 4 256 20} type Horizontal box UP_BOX selection_color 15 labelsize 10 labelcolor 15 align 4 maximum 16383 step 1 value 8192 + class Pitch_Slider + } + Fl_Group g_transpose_layer { + label T + callback {for (int i = 0; i < o->children(); i++) +if (((Fl_Button*) o->array()[i])->value()) +{ + piano->select_transpose_layer(i); + break; +}} open + tooltip {Transpose Layer: Choose the layer to transpose then "Middle-Click" the key that shall be middle-C} xywh {476 4 61 20} labelsize 10 labelcolor 15 align 4 when 0 + } { + Fl_Button {} { + label 1 + callback {((Group*)o->parent())->do_callback();} + xywh {477 4 15 20} type Radio down_box UP_BOX value 1 selection_color 15 labelsize 12 labelcolor 15 + } + Fl_Button {} { + label 2 + callback {((Group*)o->parent())->do_callback();} + xywh {492 4 15 20} type Radio down_box UP_BOX selection_color 15 labelsize 12 labelcolor 15 + } + Fl_Button {} { + label 3 + callback {((Group*)o->parent())->do_callback();} + xywh {507 4 15 20} type Radio down_box UP_BOX selection_color 15 labelsize 12 labelcolor 15 + } + Fl_Button {} { + label 4 + callback {((Group*)o->parent())->do_callback();} + xywh {522 4 15 20} type Radio down_box UP_BOX selection_color 15 labelsize 12 labelcolor 15 + } + } + Fl_Slider modwheel { + label MOD + callback {midi->write_event(0xb0, 1, (int) o->value());} + tooltip {Modulation "Wheel"} xywh {332 4 127 20} type Horizontal box UP_BOX selection_color 15 labelsize 10 labelcolor 15 align 4 maximum 127 step 1 + } + Fl_Box piano { + xywh {5 27 921 162} labeltype NO_LABEL + class Piano + } + } + Fl_Window log_w { + label {Message Log} + xywh {529 160 491 265} type Double box BORDER_BOX hide resizable + class Double_Window size_range {320 108 0 0} + } { + Fl_Text_Display log { + xywh {1 1 489 228} box DOWN_BOX selection_color 7 labelcolor 15 align 0 textcolor 49 resizable + class Text_Display + } + Fl_Group {} {open + xywh {1 233 489 29} + } { + Fl_Button {} { + label C + callback {logbuf->remove(0, logbuf->length());} + tooltip {Clear Buffer} xywh {340 237 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 10 labelcolor 49 align 64 + } + Fl_Check_Button log_sysex_in { + label IS + callback {cfg->set_cfg_option(CFG_LOG_SYSEX_IN, o->value());} + tooltip {Log Incoming SysEx} xywh {185 237 35 20} down_box DOWN_BOX value 1 selection_color 49 labelfont 4 labelcolor 15 + } + Fl_Check_Button log_sysex_out { + label OS + callback {cfg->set_cfg_option(CFG_LOG_SYSEX_OUT, o->value());} + tooltip {Log Outgoing SysEx} xywh {223 237 35 20} down_box DOWN_BOX value 1 selection_color 49 labelfont 4 labelcolor 15 + } + Fl_Check_Button log_events_in { + label IE + callback {cfg->set_cfg_option(CFG_LOG_EVENTS_IN, o->value());} + tooltip {Log Incoming Events} xywh {261 237 35 20} down_box DOWN_BOX selection_color 49 labelfont 4 labelcolor 15 + } + Fl_Check_Button log_events_out { + label OE + callback {cfg->set_cfg_option(CFG_LOG_EVENTS_OUT, o->value());} + tooltip {Log Outgoing Events} xywh {299 237 35 20} down_box DOWN_BOX selection_color 49 labelfont 4 labelcolor 15 + } + Fl_Button scroll_lock { + label {SCR LK} + xywh {374 237 48 20} type Toggle box THIN_UP_BOX color 7 selection_color 15 labelsize 10 labelcolor 49 align 64 + } + Fl_Button {} { + label Close + callback {log_w->hide();} + xywh {427 237 48 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + Fl_Box {} { + label label + xywh {3 258 1 1} labeltype NO_LABEL resizable + } + } + } + Fl_Window about { + label {About prodatum} open selected + xywh {510 121 275 128} type Double box BORDER_BOX hide modal + } { + Fl_Box {} { + xywh {10 10 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Box about_text { + xywh {85 10 180 40} labelfont 1 labelsize 18 align 144 + } + Fl_Box {} { + label {Copyright © Jan Eidtmann +2008-2011} + xywh {85 55 180 40} labelsize 12 align 144 + } + Fl_Button {} { + label Close + callback {about->hide();} + xywh {10 98 255 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + } + Fl_Window copy_layer { + label Copy + xywh {327 533 274 98} type Double box BORDER_BOX hide modal + } { + Fl_Group layer_dst { + label TARGET open + tooltip {Target layer. Double-click target to copy (hold SHIFT to copy and close window).. (Hint: ESC closes windows)} xywh {10 22 255 33} labelfont 1 labelcolor 15 + } { + Fl_Button {} { + label {VOICE 1} + callback {if (Fl::event_clicks()) +{ +Fl::event_clicks(0); +pd->preset->copy(copy_type, copy_src, 0); +if (Fl::event_state(FL_SHIFT)) +copy_layer->hide(); +else +o->deactivate(); +}} + xywh {10 30 60 20} type Radio box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 when 6 + } + Fl_Button {} { + label {VOICE 2} + callback {if (Fl::event_clicks()) +{ +Fl::event_clicks(0); +pd->preset->copy(copy_type, copy_src, 1); +if (Fl::event_state(FL_SHIFT)) +copy_layer->hide(); +else +o->deactivate(); +}} + xywh {75 30 60 20} type Radio box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 when 6 + } + Fl_Button {} { + label {VOICE 3} + callback {if (Fl::event_clicks()) +{ +Fl::event_clicks(0); +pd->preset->copy(copy_type, copy_src, 2); +if (Fl::event_state(FL_SHIFT)) +copy_layer->hide(); +else +o->deactivate(); +}} + xywh {140 30 60 20} type Radio box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 when 6 + } + Fl_Button {} { + label {VOICE 4} + callback {if (Fl::event_clicks()) +{ +Fl::event_clicks(0); +pd->preset->copy(copy_type, copy_src, 3); +if (Fl::event_state(FL_SHIFT)) +copy_layer->hide(); +else +o->deactivate(); +}} + xywh {205 30 60 20} type Radio box THIN_UP_BOX down_box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 when 6 + } + } + Fl_Button {} { + label Close + callback {copy_layer->hide();} + xywh {205 69 60 20} selection_color 15 labelsize 12 + } + } + Fl_Window copy_preset { + label Copy + xywh {703 83 216 366} type Double box BORDER_BOX hide modal + } { + Fl_Group g_copy_preset { + label DESTINATION open + xywh {10 22 196 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 + } { + Fl_Choice copy_arp_rom {open + xywh {20 28 176 21} down_box BORDER_BOX labeltype NO_LABEL labelcolor 15 align 0 textsize 13 deactivate + code0 {o->set_id(2);} + class ROM_Choice + } {} + Fl_Browser copy_browser { + tooltip {Double-click/Enter/Space target to copy/save (hold SHIFT to copy/save and close window). ESC/Backspace cancels.} xywh {20 54 176 241} type Hold when 1 textfont 4 textsize 12 textcolor 49 + class Browser + } + Fl_Input copy_browser_filter { + label {F } + callback {copy_browser->set_filter(o->value());} + xywh {36 300 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->cursor_color(FL_BACKGROUND_COLOR);} + code1 {o->tooltip(filter_tooltip);} + class Input + } + Fl_Button {} { + label C + callback {copy_browser_filter->value(0); +copy_browser_filter->do_callback();} + xywh {170 300 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + Fl_Group g_copy_arp_pattern { + label DESTINATION open + xywh {10 22 196 304} box THIN_DOWN_BOX labelfont 1 labelcolor 15 hide + } { + Fl_Browser copy_arp_pattern_browser { + tooltip {Execute Copy/Save command by either double clicking or pressing Enter or Space on the target. ESC/Backspace cancels.} xywh {20 29 176 266} type Hold when 1 textfont 4 textsize 12 textcolor 49 + class Browser + } + Fl_Input copy_arp_pattern_browser_filter { + label {F } + callback {copy_arp_pattern_browser->set_filter(o->value());} + xywh {36 300 129 20} box UP_BOX labelsize 10 labelcolor 7 when 1 textfont 5 textsize 12 textcolor 49 + code0 {o->tooltip(filter_tooltip);} + code1 {o->cursor_color(FL_BACKGROUND_COLOR);} + class Input + } + Fl_Button {} { + label C + callback {copy_arp_pattern_browser_filter->value(0); +copy_arp_pattern_browser_filter->do_callback();} + xywh {170 300 26 20} box THIN_UP_BOX color 7 selection_color 15 labelsize 12 labelcolor 49 + } + } + Fl_Button {} { + label Close + callback {copy_preset->hide();} + xywh {145 338 60 20} selection_color 15 labelsize 12 + } + } + Fl_Window loading_w { + label {Please wait...} + callback {;} + xywh {538 66 290 86} type Double box BORDER_BOX hide modal + } { + Fl_Box {} { + xywh {1 1 104 43} box FLAT_BOX color 7 labeltype NO_LABEL labelfont 1 labelcolor 49 align 26 + } + Fl_Box {} { + label {Loading program...} + xywh {105 1 184 43} box FLAT_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 154 + } + Fl_Box {} { + xywh {5 0 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Progress progress { + label label + xywh {115 64 60 6} box FLAT_BOX selection_color 49 labeltype NO_LABEL labelcolor 7 + } + } + Fl_Window reset_w { + label Reset + callback {;} open + xywh {740 72 286 168} type Double box BORDER_BOX hide modal + } { + Fl_Box {} { + xywh {1 1 84 43} box FLAT_BOX color 7 labeltype NO_LABEL labelfont 1 labelcolor 49 align 26 + } + Fl_Box {} { + label {What do you want me to reset?} + xywh {85 1 200 43} box FLAT_BOX color 7 labelfont 1 labelsize 12 labelcolor 49 align 154 + } + Fl_Box {} { + xywh {5 0 64 64} deactivate + code0 {o->image(image_l64);} + } + Fl_Check_Button r_user { + label {User Data} + callback {if (o->value()) +g_r_user->activate(); +else +g_r_user->deactivate();} + tooltip {Delete Program- and Arp-Name data!} xywh {8 79 87 20} down_box DOWN_BOX selection_color 49 + } + Fl_Group g_r_user {open + xywh {111 75 149 25} labeltype NO_LABEL labelcolor 15 align 0 deactivate + } { + Fl_Check_Button r_user_all { + label All + callback {if (o->value()) +r_user_id->deactivate(); +else +r_user_id->activate();} + tooltip {Delete all User data!} xywh {111 79 39 20} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Spinner r_user_id { + label ID + tooltip {Delete User data for the device configured using this ID only!} xywh {193 79 58 20} color 7 selection_color 15 labelsize 12 when 1 minimum 0 maximum 126 value 0 textfont 4 textsize 13 textcolor 49 deactivate + } + } + Fl_Check_Button r_rom { + label {ROM Data} + callback {if (o->value()) +g_r_rom->activate(); +else +g_r_rom->deactivate();} + tooltip {Delete ROM data (once downloaded they never change so this is only useful if initialization went wrong)!} xywh {8 104 90 20} down_box DOWN_BOX selection_color 49 + } + Fl_Group g_r_rom {open + xywh {111 100 174 25} labeltype NO_LABEL align 0 deactivate + } { + Fl_Check_Button r_rom_all { + label All + callback {if (o->value()) +r_rom_rom->deactivate(); +else +r_rom_rom->activate();} + tooltip {Delete all ROM data!} xywh {111 104 39 20} down_box DOWN_BOX value 1 selection_color 49 + } + Fl_Choice r_rom_rom { + label {ROM } open + tooltip {Delete ROM data of this ROM only!} xywh {193 104 82 21} down_box BORDER_BOX labelsize 12 textsize 13 deactivate + class ROM_Choice + } {} + } + Fl_Button b_reset { + label Reset + callback {o->deactivate(); +int userdata = -1; +int romdata = -1; +if (r_user->value()) +{ +if (r_user_all->value()) + userdata = 127; +else + userdata = r_user_id->value(); +} +if (r_rom->value()) +{ +if (r_rom_all->value()) + romdata = 1; +else + romdata = pd->rom[r_rom_rom->value() + 1]->get_attribute(ID); +} +reset(userdata, romdata);} + tooltip {Delete chosen data and show the Open Device dialog when finished.} xywh {142 140 60 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + Fl_Button {} { + label Cancel + callback {reset_w->hide();} + tooltip {Don't delete anything!} xywh {215 140 60 20} box THIN_UP_BOX selection_color 15 labelsize 12 + } + } + code {initialize();} {} + } + Function {~PD_UI()} {open + } { + code {pd->display_status("Bye!"); +cfg->set_cfg_option(CFG_SYNCVIEW, syncview); +cfg->set_cfg_option(CFG_WINDOW_WIDTH, main_window->w()); +cfg->set_cfg_option(CFG_WINDOW_HEIGHT, main_window->h()); +if (fc) delete fc; +if (pd) delete pd; +delete midi; +delete cfg; +pmesg(1, "Bye.\\n"); +exit(0);} {} + } +} + +Function {handler(int event)} {return_type int +} { + code {pmesg(100, "unused handler event: %d\\n", event); +return 0;} {} +} + +comment {/** @\} */} {in_source in_header +} diff --git a/ringbuffer.C b/ringbuffer.C new file mode 100644 index 0000000..daa9eb4 --- /dev/null +++ b/ringbuffer.C @@ -0,0 +1,359 @@ +/* + Copyright (C) 2000 Paul Davis + Copyright (C) 2003 Rohan Drape + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code. + This is safe for the case of one read thread and one write thread. +*/ + +// slightly modified for prodatum to use unsigned char + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#ifdef USE_MLOCK +#include +#endif /* USE_MLOCK */ + +#include "ringbuffer.H" + +/* Create a new ringbuffer to hold at least `sz' bytes of data. The + actual buffer size is rounded up to the next power of two. */ + +jack_ringbuffer_t * +jack_ringbuffer_create (size_t sz) +{ + int power_of_two; + jack_ringbuffer_t *rb; + + rb = (jack_ringbuffer_t*) malloc (sizeof (jack_ringbuffer_t)); + + for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++); + + rb->size = 1 << power_of_two; + rb->size_mask = rb->size; + rb->size_mask -= 1; + rb->write_ptr = 0; + rb->read_ptr = 0; + rb->buf = (unsigned char*) malloc (rb->size); + rb->mlocked = 0; + + return rb; +} + +/* Free all data associated with the ringbuffer `rb'. */ + +void +jack_ringbuffer_free (jack_ringbuffer_t * rb) +{ +#ifdef USE_MLOCK + if (rb->mlocked) { + munlock (rb->buf, rb->size); + } +#endif /* USE_MLOCK */ + free (rb->buf); + free (rb); +} + +/* Lock the data block of `rb' using the system call 'mlock'. */ + +int +jack_ringbuffer_mlock (jack_ringbuffer_t * rb) +{ +#ifdef USE_MLOCK + if (mlock (rb->buf, rb->size)) { + return -1; + } +#endif /* USE_MLOCK */ + rb->mlocked = 1; + return 0; +} + +/* Reset the read and write pointers to zero. This is not thread + safe. */ + +void +jack_ringbuffer_reset (jack_ringbuffer_t * rb) +{ + rb->read_ptr = 0; + rb->write_ptr = 0; +} + +/* Return the number of bytes available for reading. This is the + number of bytes in front of the read pointer and behind the write + pointer. */ + +size_t +jack_ringbuffer_read_space (const jack_ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return w - r; + } else { + return (w - r + rb->size) & rb->size_mask; + } +} + +/* Return the number of bytes available for writing. This is the + number of bytes in front of the write pointer and behind the read + pointer. */ + +size_t +jack_ringbuffer_write_space (const jack_ringbuffer_t * rb) +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + return (r - w) - 1; + } else { + return rb->size - 1; + } +} + +/* The copying data reader. Copy at most `cnt' bytes from `rb' to + `dest'. Returns the actual number of bytes copied. */ + +size_t +jack_ringbuffer_read (jack_ringbuffer_t * rb, unsigned char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) { + return 0; + } + + to_read = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->read_ptr + to_read; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->read_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_read; + n2 = 0; + } + + memcpy (dest, &(rb->buf[rb->read_ptr]), n1); + rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask; + + if (n2) { + memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2); + rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask; + } + + return to_read; +} + +/* The copying data reader w/o read pointer advance. Copy at most + `cnt' bytes from `rb' to `dest'. Returns the actual number of bytes +copied. */ + +size_t +jack_ringbuffer_peek (jack_ringbuffer_t * rb, unsigned char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + size_t tmp_read_ptr; + + tmp_read_ptr = rb->read_ptr; + + if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) { + return 0; + } + + to_read = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = tmp_read_ptr + to_read; + + if (cnt2 > rb->size) { + n1 = rb->size - tmp_read_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_read; + n2 = 0; + } + + memcpy (dest, &(rb->buf[tmp_read_ptr]), n1); + tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask; + + if (n2) { + memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2); + } + + return to_read; +} + + +/* The copying data writer. Copy at most `cnt' bytes to `rb' from + `src'. Returns the actual number of bytes copied. */ + +size_t +jack_ringbuffer_write (jack_ringbuffer_t * rb, const unsigned char *src, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) { + return 0; + } + + to_write = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->write_ptr + to_write; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->write_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_write; + n2 = 0; + } + + memcpy (&(rb->buf[rb->write_ptr]), src, n1); + rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask; + + if (n2) { + memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2); + rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask; + } + + return to_write; +} + +/* Advance the read pointer `cnt' places. */ + +void +jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt) +{ + size_t tmp = (rb->read_ptr + cnt) & rb->size_mask; + rb->read_ptr = tmp; +} + +/* Advance the write pointer `cnt' places. */ + +void +jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt) +{ + size_t tmp = (rb->write_ptr + cnt) & rb->size_mask; + rb->write_ptr = tmp; +} + +/* The non-copying data reader. `vec' is an array of two places. Set + the values at `vec' to hold the current readable data at `rb'. If + the readable data is in one segment the second segment has zero + length. */ + +void +jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb, + jack_ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = w - r; + } else { + free_cnt = (w - r + rb->size) & rb->size_mask; + } + + cnt2 = r + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = rb->size - r; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + + } else { + + /* Single part vector: just the rest of the buffer */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} + +/* The non-copying data writer. `vec' is an array of two places. Set + the values at `vec' to hold the current writeable data at `rb'. If + the writeable data is in one segment the second segment has zero + length. */ + +void +jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb, + jack_ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + free_cnt = (r - w) - 1; + } else { + free_cnt = rb->size - 1; + } + + cnt2 = w + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[w]); + vec[0].len = rb->size - w; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } else { + vec[0].buf = &(rb->buf[w]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} diff --git a/ringbuffer.H b/ringbuffer.H new file mode 100644 index 0000000..806766d --- /dev/null +++ b/ringbuffer.H @@ -0,0 +1,237 @@ +/* + Copyright (C) 2000 Paul Davis + Copyright (C) 2003 Rohan Drape + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// slightly modified for prodatum to use unsigned char + +#ifndef _RINGBUFFER_H +#define _RINGBUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @file ringbuffer.h + * + * A set of library functions to make lock-free ringbuffers available + * to JACK clients. The `capture_client.c' (in the example_clients + * directory) is a fully functioning user of this API. + * + * The key attribute of a ringbuffer is that it can be safely accessed + * by two threads simultaneously -- one reading from the buffer and + * the other writing to it -- without using any synchronization or + * mutual exclusion primitives. For this to work correctly, there can + * only be a single reader and a single writer thread. Their + * identities cannot be interchanged. + */ + +typedef struct +{ + unsigned char *buf; + size_t len; +} +jack_ringbuffer_data_t ; + +typedef struct +{ + unsigned char *buf; + volatile size_t write_ptr; + volatile size_t read_ptr; + size_t size; + size_t size_mask; + int mlocked; +} +jack_ringbuffer_t ; + +/** + * Allocates a ringbuffer data structure of a specified size. The + * caller must arrange for a call to jack_ringbuffer_free() to release + * the memory associated with the ringbuffer. + * + * @param sz the ringbuffer size in bytes. + * + * @return a pointer to a new jack_ringbuffer_t, if successful; NULL + * otherwise. + */ +jack_ringbuffer_t *jack_ringbuffer_create(size_t sz); + +/** + * Frees the ringbuffer data structure allocated by an earlier call to + * jack_ringbuffer_create(). + * + * @param rb a pointer to the ringbuffer structure. + */ +void jack_ringbuffer_free(jack_ringbuffer_t *rb); + +/** + * Fill a data structure with a description of the current readable + * data held in the ringbuffer. This description is returned in a two + * element array of jack_ringbuffer_data_t. Two elements are needed + * because the data to be read may be split across the end of the + * ringbuffer. + * + * The first element will always contain a valid @a len field, which + * may be zero or greater. If the @a len field is non-zero, then data + * can be read in a contiguous fashion using the address given in the + * corresponding @a buf field. + * + * If the second element has a non-zero @a len field, then a second + * contiguous stretch of data can be read from the address given in + * its corresponding @a buf field. + * + * @param rb a pointer to the ringbuffer structure. + * @param vec a pointer to a 2 element array of jack_ringbuffer_data_t. + * + */ +void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t *rb, + jack_ringbuffer_data_t *vec); + +/** + * Fill a data structure with a description of the current writable + * space in the ringbuffer. The description is returned in a two + * element array of jack_ringbuffer_data_t. Two elements are needed + * because the space available for writing may be split across the end + * of the ringbuffer. + * + * The first element will always contain a valid @a len field, which + * may be zero or greater. If the @a len field is non-zero, then data + * can be written in a contiguous fashion using the address given in + * the corresponding @a buf field. + * + * If the second element has a non-zero @a len field, then a second + * contiguous stretch of data can be written to the address given in + * the corresponding @a buf field. + * + * @param rb a pointer to the ringbuffer structure. + * @param vec a pointer to a 2 element array of jack_ringbuffer_data_t. + */ +void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t *rb, + jack_ringbuffer_data_t *vec); + +/** + * Read data from the ringbuffer. + * + * @param rb a pointer to the ringbuffer structure. + * @param dest a pointer to a buffer where data read from the + * ringbuffer will go. + * @param cnt the number of bytes to read. + * + * @return the number of bytes read, which may range from 0 to cnt. + */ +size_t jack_ringbuffer_read(jack_ringbuffer_t *rb, unsigned char *dest, size_t cnt); + +/** + * Read data from the ringbuffer. Opposed to jack_ringbuffer_read() + * this function does not move the read pointer. Thus it's + * a convenient way to inspect data in the ringbuffer in a + * continous fashion. The price is that the data is copied + * into a user provided buffer. For "raw" non-copy inspection + * of the data in the ringbuffer use jack_ringbuffer_get_read_vector(). + * + * @param rb a pointer to the ringbuffer structure. + * @param dest a pointer to a buffer where data read from the + * ringbuffer will go. + * @param cnt the number of bytes to read. + * + * @return the number of bytes read, which may range from 0 to cnt. + */ +size_t jack_ringbuffer_peek(jack_ringbuffer_t *rb, unsigned char *dest, size_t cnt); + +/** + * Advance the read pointer. + * + * After data have been read from the ringbuffer using the pointers + * returned by jack_ringbuffer_get_read_vector(), use this function to + * advance the buffer pointers, making that space available for future + * write operations. + * + * @param rb a pointer to the ringbuffer structure. + * @param cnt the number of bytes read. + */ +void jack_ringbuffer_read_advance(jack_ringbuffer_t *rb, size_t cnt); + +/** + * Return the number of bytes available for reading. + * + * @param rb a pointer to the ringbuffer structure. + * + * @return the number of bytes available to read. + */ +size_t jack_ringbuffer_read_space(const jack_ringbuffer_t *rb); + +/** + * Lock a ringbuffer data block into memory. + * + * Uses the mlock() system call. This is not a realtime operation. + * + * @param rb a pointer to the ringbuffer structure. + */ +int jack_ringbuffer_mlock(jack_ringbuffer_t *rb); + +/** + * Reset the read and write pointers, making an empty buffer. + * + * This is not thread safe. + * + * @param rb a pointer to the ringbuffer structure. + */ +void jack_ringbuffer_reset(jack_ringbuffer_t *rb); + +/** + * Write data into the ringbuffer. + * + * @param rb a pointer to the ringbuffer structure. + * @param src a pointer to the data to be written to the ringbuffer. + * @param cnt the number of bytes to write. + * + * @return the number of bytes write, which may range from 0 to cnt + */ +size_t jack_ringbuffer_write(jack_ringbuffer_t *rb, const unsigned char *src, + size_t cnt); + +/** + * Advance the write pointer. + * + * After data have been written the ringbuffer using the pointers + * returned by jack_ringbuffer_get_write_vector(), use this function + * to advance the buffer pointer, making the data available for future + * read operations. + * + * @param rb a pointer to the ringbuffer structure. + * @param cnt the number of bytes written. + */ +void jack_ringbuffer_write_advance(jack_ringbuffer_t *rb, size_t cnt); + +/** + * Return the number of bytes available for writing. + * + * @param rb a pointer to the ringbuffer structure. + * + * @return the amount of free space (in bytes) available for writing. + */ +size_t jack_ringbuffer_write_space(const jack_ringbuffer_t *rb); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/threads.H b/threads.H new file mode 100644 index 0000000..ee41e71 --- /dev/null +++ b/threads.H @@ -0,0 +1,38 @@ +/* + * threads.H + * + * Created on: 12.11.2008 + * Author: vvd + */ + +#ifndef THREADS_H_ +#define THREADS_H_ + +#if defined(WIN32) && !defined(__WATCOMC__) // Use Windows threading... +# include +# include +typedef unsigned long Fl_Thread; +static int fl_create_thread(Fl_Thread& t, void *(*f) (void *), void* p) +{ + return t = (Fl_Thread)_beginthread((void( __cdecl * )( void * ))f, 0, p); +} + +#elif defined(__WATCOMC__) +# include +typedef unsigned long Fl_Thread; +static int fl_create_thread(Fl_Thread& t, void *(*f) (void *), void* p) +{ + return t = (Fl_Thread)_beginthread((void(* )( void * ))f, 32000, p); +} + +#elif HAVE_PTHREAD_H // Use POSIX threading... +# include +typedef pthread_t Fl_Thread; +static int fl_create_thread(Fl_Thread& t, void *(*f)(void *), void* p) +{ + return pthread_create((pthread_t*) &t, 0, f, p); +} + +#endif // !HAVE_PTHREAD_H + +#endif /* THREADS_H_ */ diff --git a/widgets.C b/widgets.C new file mode 100644 index 0000000..9598f2e --- /dev/null +++ b/widgets.C @@ -0,0 +1,5947 @@ +// This file is part of prodatum. +// Copyright 2011 Jan Eidtmann +// +// prodatum 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 3 of the License, or +// (at your option) any later version. +// +// prodatum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with prodatum. If not, see . + +// $Id$ + +#include +#include +#include +#include + +#include "ui.H" +#include "pd.H" +#include "midi.H" +#include "cfg.H" + +#include "debug.H" + +/** + * global array that holds all device parameter widgets. + * every parameter can be accessed by their ID and layer. + */ +PWid* pwid[2000][4]; +/// pointer to widgets that is currently being edited +PWid* pwid_editing; +/// contains informations for all 51 filter types +FilterMap FM[51]; +/// contains strings for some tempo related parameters +const char* rates[25]; + +extern PD_UI* ui; +extern PD* pd; +extern Cfg* cfg; +extern MIDI* midi; +extern std::map rom_id_map; +extern unsigned char colors[5]; + +/// show warning when we are about to erase an edited edit buffer +int dismiss(bool exit) +{ + if (!pd->preset || !pd->preset->is_changed() + || !ui->confirm_dismiss->value()) + return 1; // dismiss + int answer; + if (exit) + answer = fl_choice("Dismiss changes and exit?", "Cancel", + "Dismiss and exit", "Save"); + else + answer = fl_choice("Dismiss changes?", "Cancel", "Dismiss", "Save"); + if (answer == 2) + ui->show_copy_preset(SAVE_PRESET); + return answer; +} + +// ################### +// +// ################### +void PWid::cb(PWid*, void* p) +{ + pmesg(90, "cb: id: %d, layer: %d\n", ((int*) p)[0], ((int*) p)[1]); + if (((int*) p)[0] == 897 + && (ui->b_save_p->value() || ui->b_copy_p->value())) // saving in the preset browser + goto SKIP_DISMISS; + if ((((int*) p)[0] == 129 || ((int*) p)[0] == 138 || ((int*) p)[0] == 897) + && dismiss(false) != 1) + { + // reset to previous value and return + if (((int*) p)[0] == 129) + { + pwid[129][0]->set_value(pd->selected_channel); + ui->main->channel_select->activate(); + ui->value_input->activate(); + } + else if (((int*) p)[0] == 138) + pwid[138][0]->set_value( + pd->setup->get_value(138, pd->selected_channel)); + else if (((int*) p)[0] == 897) + { + pwid[897][0]->set_value( + pd->setup->get_value(130, pd->selected_channel)); + ui->g_preset->activate(); + ui->value_input->activate(); + } + return; + } + SKIP_DISMISS: int value = 0; + // editing with the value input widget + if (((int*) p)[0] == 1) + { + if (!pwid_editing) + return; + int* layer_id = pwid_editing->get_id_layer(); + int* minimax = pwid_editing->get_minimax(); + value = pwid[1][0]->get_value(); + if (layer_id[0] == 1410 && value == -999) // layer volume + return; + // clamp value + if (value < minimax[0]) + { + value = minimax[0]; + pwid[1][0]->set_value(value); + } + else if (value > minimax[1]) + { + value = minimax[1]; + pwid[1][0]->set_value(value); + } + pwid_editing->set_value(value); + ui->forma_out->set_value(layer_id[0], layer_id[1], value); + if (layer_id[0] == 897 && (ui->b_save_p->value() + || ui->b_copy_p->value())) // saving in the preset browser + return; + pd->widget_callback(layer_id[0], value, layer_id[1]); + } + else + { + // return for those id's we use internally (that have no equivalent on the device) + if (((int*) p)[0] == 2 || (((int*) p)[0] >= 0x20 && ((int*) p)[0] + <= 0x2d)) // copy_preset window widgets + return; + if (pwid_editing != pwid[((int*) p)[0]][((int*) p)[1]]) + { + pwid_editing = pwid[((int*) p)[0]][((int*) p)[1]]; + int* minimax = pwid_editing->get_minimax(); + ui->value_input->minimum((double) minimax[0]); + ui->value_input->maximum((double) minimax[1]); + } + value = pwid[((int*) p)[0]][((int*) p)[1]]->get_value(); + if (((int*) p)[0] == 1410 && value == -999) // layer volume + return; + ui->value_input->value((double) value); + ui->forma_out->set_value(((int*) p)[0], ((int*) p)[1], value); + if (((int*) p)[0] == 897 && (ui->b_save_p->value() + || ui->b_copy_p->value())) // saving in the preset browser + return; + pd->widget_callback(((int*) p)[0], value, ((int*) p)[1]); + } +} + +// ################### +// +// ################### +int Double_Window::handle(int ev) +{ + static bool playing = false; + switch (ev) + { + case FL_KEYDOWN: + if (!playing && Fl::event_key() == 'b') + { + playing = true; + if (midi) + midi->write_event(NOTE_ON, 60, 110); + ui->piano->activate_key(1, 60); + ui->main->minipiano->activate_key(1, 60); + ui->global_minipiano->activate_key(1, 60); + return 1; + } + else if (Fl::event_key() == 'f') + { + if (ui->g_effects->visible()) + { + ui->g_preset->show(); + ui->g_effects->hide(); + } + else + { + ui->g_preset->hide(); + ui->g_effects->show(); + } + return 1; + } + else if (Fl::event_key() == 'n' && Fl::event_state() == FL_CTRL) // focus name field + { + ui->n_name_m->take_focus(); + return 1; + } + else if (Fl::event_key() == 'e' && Fl::event_state() == FL_CTRL) // focus value input + { + ui->value_input->take_focus(); + return 1; + } + break; + case FL_KEYUP: + if (playing && Fl::event_key() == 'b') + { + playing = false; + if (midi) + midi->write_event(NOTE_OFF, 60, 0); + ui->piano->activate_key(-1, 60); + ui->main->minipiano->activate_key(-1, 60); + ui->global_minipiano->activate_key(-1, 60); + return 1; + } + break; + } + return Fl_Double_Window::handle(ev); +} + +int DND_Box::handle(int ev) +{ + switch (ev) + { + case FL_DND_ENTER: + case FL_DND_RELEASE: + case FL_DND_LEAVE: + case FL_DND_DRAG: + return 1; + case FL_PASTE: + snprintf(evt_txt, Fl::event_length() + 1, "%s", Fl::event_text()); + Fl::add_timeout(0.0, DND_Box::dndcback, (void*) this); + return 1; + } + return 0; +} +void DND_Box::dnd() +{ + pd->load_export(evt_txt); +} + +// ################### +// +// ################### +void Browser::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + if (v == 1281 || v == 1290) // preset links + minimax[0] = -1; + else + minimax[0] = 0; + minimax[1] = 0; + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +int Browser::get_value() const +{ + int v = value(); + // deactivate preset selection on preset selection + if (id_layer[0] == 897) + { + //ui->g_preset->deactivate(); + //ui->value_input->deactivate(); + // select save slot + ui->copy_browser->value(v); + } + // update instrument names in channel strips + if (id_layer[0] == 1409) + { + ui->main->layer_strip[id_layer[1]]->instrument->copy_label(text(v) + 5); + if (v != 1) + ui->main->layer_strip[id_layer[1]]->activate(); + else + ui->main->layer_strip[id_layer[1]]->deactivate(); + } + else if (id_layer[0] == 1281 || id_layer[0] == 1290) // preset links + { + if (v == 1) + { + if (id_layer[0] == 1281) + ui->preset_editor->g_link1->deactivate(); + else + ui->preset_editor->g_link2->deactivate(); + } + else + { + if (id_layer[0] == 1281) + ui->preset_editor->g_link1->activate(); + else + ui->preset_editor->g_link2->activate(); + } + return v - 2; + } + return v - 1; +} + +void Browser::set_value(int v) +{ + pmesg(90, "Browser::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + if (size() > v) + { + if ((id_layer[0] == 1281 || id_layer[0] == 1290) && v >= -1) // preset links + { + if (v == -1) + { + if (id_layer[0] == 1281) + ui->preset_editor->g_link1->deactivate(); + else + ui->preset_editor->g_link2->deactivate(); + } + else + { + if (id_layer[0] == 1281) + ui->preset_editor->g_link1->activate(); + else + ui->preset_editor->g_link2->activate(); + } + value(v + 2); + } + else if (v >= 0) + value(v + 1); + else + return; + apply_filter(); + // deactivate preset selection on preset selection + if (id_layer[0] == 897) + { + //ui->g_preset->deactivate(); + //ui->value_input->deactivate(); + // select save slot + ui->copy_browser->value(v + 1); + } + // update instrument names in channel strips + else if (id_layer[0] == 1409) + { + ui->main->layer_strip[id_layer[1]]->instrument->copy_label( + text(v + 1) + 5); + if (v != 0) + ui->main->layer_strip[id_layer[1]]->activate(); + else + ui->main->layer_strip[id_layer[1]]->deactivate(); + } + } +} + +void Browser::load_n(int type, int rom_id, int preset) +{ + pmesg(90, "Browser::load_n(%d, %d, %d) (id:%d layer:%d)\n", type, rom_id, + preset, id_layer[0], id_layer[1]); + if (rom_id_map.find(rom_id) == rom_id_map.end()) + return; + if (!pd->rom[rom_id_map[rom_id]]) + return; + int val = value(); + // only load a new list if its different from the loaded one + if (selected_rom != rom_id || preset != -1) + { + selected_rom = rom_id; + char name[22]; + // load a new list + if (preset == -1) + { + int number = pd->rom[rom_id_map[rom_id]]->get_attribute(type); + const unsigned char* names = pd->rom[rom_id_map[rom_id]]->get_name( + type, 0); + clear(); + if (id_layer[0] == 1409) // instruments + { + for (int i = 0; i < number; i++) + { + snprintf(name, 22, "%04d %s", i, names + i * 16); + add(name); + } + } + else + { + if (id_layer[0] == 1281 || id_layer[0] == 1290) // preset links + add("Off"); + for (int i = 0; i < number; i++) + { + snprintf(name, 21, "%03d %s", i, names + i * 16); + add(name); + } + } + if (val <= size() && val > 0) + { + select(val); + apply_filter(); + } + } + // replace single item + else + { + snprintf(name, 21, "%03d %s", preset, + pd->rom[rom_id_map[rom_id]]->get_name(type, preset)); + if (id_layer[0] == 1281 || id_layer[0] == 1290) // preset links + text(preset + 2, name); + else + text(preset + 1, name); + } + } + // update instrument names in channel strips + if (id_layer[0] == 1409) + { + if (val > 1 && val <= size()) + { + ui->main->layer_strip[id_layer[1]]->instrument->copy_label( + text(val) + 5); + ui->main->layer_strip[id_layer[1]]->activate(); + } + else + { + ui->main->layer_strip[id_layer[1]]->instrument->copy_label( + " :None"); + ui->main->layer_strip[id_layer[1]]->deactivate(); + } + } +} + +void Browser::set_filter(const char* fs) +{ + pmesg(90, "Browser::set_filter(char*) (id:%d layer:%d)\n", id_layer[0], + id_layer[1]); + if (filter) + { + free(filter); + filter = 0; + } + filter = strdup(fs); + apply_filter(); +} + +void Browser::apply_filter() +{ + pmesg(90, "Browser::apply_filter() (id:%d layer:%d)\n", id_layer[0], + id_layer[1]); + if (!size() || !filter) + return; + int val = value(); + static char f[19]; + if (strlen(filter)) + { + snprintf(f, 19, "*%s*", filter); + for (int i = 0; i < (int) strlen(f); i++) + if (!isascii(f[i])) + f[i] = '?'; + for (int i = 1; i <= size(); i++) + { + if (fl_filename_match(text(i), f)) + show(i); + else + hide(i); + } + } + else + for (int i = 1; i <= size(); i++) + show(i); + // scroll the list + if (val > 0) + { + show(val); + topline(1); // fixes issues with the scrollbar not being updated correctly + deselect(); + select(val); + } +} + +int Browser::handle(int ev) +{ + static int key; + switch (ev) + { + // Mouse Events + case FL_ENTER: // 1 = receive FL_LEAVE and FL_MOVE events (widget becomes Fl::belowmouse()) + case FL_LEAVE: + return 1; + case FL_MOVE: // sent to Fl::belowmouse() + return 1; + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + if (ev == Fl::event_clicks() && pd->preset) // double click + { + Fl::event_clicks(0); + if (id_layer[0] == 643 && ui->main->arp_rom->value() == 0) //master arp browser + { + ui->main->edit_arp->do_callback(); + return 1; + } + if (id_layer[0] == 1027 && ui->preset_editor->arp_rom->value() == 0) //preset arp browser + { + ui->preset_editor->edit_arp->do_callback(); + return 1; + } + // saving with the browsers + if (id_layer[0] == 897) // preset browser + { + if (ui->b_save_p->value()) + { + pd->preset->copy(SAVE_PRESET, -1, value() - 1); + if (Fl::event_state(FL_SHIFT)) + { + ui->b_save_p->clear(); + ui->b_save_p->do_callback(); + } + return 1; + } + else if (ui->b_copy_p->value()) + { + pd->preset->copy(C_PRESET, -1, value() - 1); + if (Fl::event_state(FL_SHIFT)) + { + ui->b_copy_p->clear(); + ui->b_copy_p->do_callback(); + } + return 1; + } + } + if (id_layer[0] >= 0x20 && id_layer[0] <= 0x2d) // copy browsers + { + pd->preset->copy(id_layer[0], -1, value() - 1); // check enum in pd.H for id meaning + if (Fl::event_state(FL_SHIFT)) + ui->copy_preset->hide(); + return 1; + } + } + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + // right-click "undo" + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] == 897) // preset + { + // select preset in browser + select(pd->setup_copy->get_value(130, pd->selected_channel) + 1); + // set rom (will also trigger the browser callback) + pwid[138][0]->set_value( + pd->setup_copy->get_value(138, pd->selected_channel)); + ui->preset_rom->do_callback(); + } + else if (id_layer[0] == 928) // preset riff + { + pwid[929][0]->set_value(pd->preset_copy->get_value(929)); + ui->preset_editor->riff_rom->do_callback(); + set_value(pd->preset_copy->get_value(id_layer[0])); + do_callback(); + } + else if (id_layer[0] == 1409) // instrument + { + pwid[1439][id_layer[1]]->set_value( + pd->preset_copy->get_value(1439, id_layer[1])); + ui->layer_editor[id_layer[1]]->instrument_rom->do_callback(); + set_value(pd->preset_copy->get_value(id_layer[0], id_layer[1])); + do_callback(); + } + else if (id_layer[0] == 278) // master riff + { + pwid[277][0]->set_value(pd->setup_copy->get_value(277)); + ui->main->riff_rom->do_callback(); + set_value(pd->setup_copy->get_value(id_layer[0])); + do_callback(); + } + else if (id_layer[0] == 1027) // preset arp + { + pwid[1042][0]->set_value(pd->preset_copy->get_value(1042)); + ui->preset_editor->arp_rom->do_callback(); + set_value(pd->preset_copy->get_value(id_layer[0])); + do_callback(); + } + else if (id_layer[0] == 1281) // link1 + { + pwid[1299][0]->set_value(pd->preset_copy->get_value(1299)); + ui->preset_editor->l1_rom->do_callback(); + set_value(pd->preset_copy->get_value(id_layer[0])); + do_callback(); + } + else if (id_layer[0] == 1290) // link2 + { + pwid[1300][0]->set_value(pd->preset_copy->get_value(1300)); + ui->preset_editor->l2_rom->do_callback(); + set_value(pd->preset_copy->get_value(id_layer[0])); + do_callback(); + } + else if (id_layer[0] == 643) // master arp + { + pwid[660][0]->set_value(pd->setup_copy->get_value(660)); + ui->main->arp_rom->do_callback(); + set_value(pd->setup_copy->get_value(id_layer[0])); + do_callback(); + } + return 1; + } + break; + case FL_DRAG: // button state is in Fl::event_state() (FL_SHIFT FL_CAPS_LOCK FL_CTRL FL_ALT FL_NUM_LOCK FL_META FL_SCROLL_LOCK FL_BUTTON1 FL_BUTTON2 FL_BUTTON3) + return 0; + case FL_MOUSEWHEEL: + if (this != Fl::belowmouse()) + return 0; + break; + // keyboard events + case FL_FOCUS: // 1 = receive FL_KEYDOWN, FL_KEYUP, and FL_UNFOCUS events (widget becomes Fl::focus()) + case FL_UNFOCUS: // received when another widget gets the focus and we had the focus + return 1; + case FL_KEYDOWN: // key press (Fl::event_key()) + key = Fl::event_key(); + if (key == FL_Down) + { + select(value() + 1); + return 1; + } + if (key == FL_Up) + { + select(value() - 1); + return 1; + } + if (key == FL_Enter || key == 32) // copy/save with enter or space key + { + if (id_layer[0] == 897) // preset browser + { + if (ui->b_save_p->value()) + { + pd->preset->copy(SAVE_PRESET, -1, value() - 1); + if (Fl::event_state(FL_SHIFT)) + { + ui->b_save_p->clear(); + ui->b_save_p->do_callback(); + } + return 1; + } + else if (ui->b_copy_p->value()) + { + pd->preset->copy(C_PRESET, -1, value() - 1); + if (Fl::event_state(FL_SHIFT)) + { + ui->b_copy_p->clear(); + ui->b_copy_p->do_callback(); + } + return 1; + } + } + if (id_layer[0] >= 0x20 && id_layer[0] <= 0x2d) // copy browsers + { + pd->preset->copy(id_layer[0], -1, value() - 1); // check enum in pd.H for id meaning + if (Fl::event_state(FL_SHIFT)) + ui->copy_preset->hide(); + return 1; + } + } + else if (key == FL_BackSpace) // cancel copy/save + { + if (id_layer[0] == 897) // preset browser + { + if (ui->b_save_p->value()) + { + ui->b_save_p->value(0); + ui->b_save_p->do_callback(); + return 1; + } + else if (ui->b_copy_p->value()) + { + ui->b_copy_p->value(0); + ui->b_copy_p->do_callback(); + return 1; + } + } + else if (id_layer[0] >= 0x20 && id_layer[0] <= 0x2d) // copy browsers + { + ui->copy_preset->hide(); // check enum in pd.H for id meaning + return 1; + } + } + break; + case FL_KEYUP: // key release (Fl::event_key()) + if (!Fl::event_key(key) && (key == FL_Down || key == FL_Up)) + { + do_callback(); + return 1; + } + break; + case FL_DND_ENTER: // 1 = receive FL_DND_DRAG, FL_DND_LEAVE and FL_DND_RELEASE events + return 0; + } + return Fl_Browser::handle(ev); +} + +// ################### +// +// ################### +void ROM_Choice::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = 0; + minimax[1] = 0; + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; + // do we also include user "rom"? + if (v == 2 || v == 138 || v == 660 || v == 1042 || v == 1299 || v == 1300) // presets and arps and links and copy browsers + no_user = 0; +} + +void ROM_Choice::set_value(int v) +{ + pmesg(90, "ROM_Choice::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + if (v == 0 || rom_id_map.find(v) != rom_id_map.end()) + { + value(rom_id_map[v] - no_user); + dependency(v, false); + } +} + +int ROM_Choice::get_value() const +{ + if (!size()) + return 0; + int v = pd->rom[value() + no_user]->get_attribute(ID); + dependency(v, true); + return v; +} + +void ROM_Choice::dependency(int v, bool get) const +{ + // load new name list + switch (id_layer[0]) + { + case 2: // copy arp + ui->copy_browser->load_n(PRESET, v); + break; + case 138: // preset + if (v == 0) + ui->preset_editor->copy_arp_b->activate(); + else + ui->preset_editor->copy_arp_b->deactivate(); + ui->preset->load_n(PRESET, v); + break; + case 277: // master riff + if (get) + { + ui->main->riff->select(1); + pd->setup->set_value(278, 0); + } + ui->main->riff->load_n(RIFF, v); + break; + case 660: // master arp pattern + if (get) + { + ui->main->arp->set_value(0); + pd->setup->set_value(643, 0); + } + ui->main->arp->load_n(ARP, v); + if (v) + { + ui->main->edit_arp->deactivate(); + if (ui->main->g_main_arp->get_value() == 1) + ui->main->main_edit_arp->deactivate(); + } + else + { + ui->main->edit_arp->activate(); + if (ui->main->g_main_arp->get_value() == 1) + ui->main->main_edit_arp->activate(); + } + break; + case 929: // preset riff + if (get) + { + ui->preset_editor->riff->select(1); + pd->preset->set_value(928, 0); + } + ui->preset_editor->riff->load_n(RIFF, v); + break; + case 1042: // preset arp pattern + if (get) + { + ui->preset_editor->arp->set_value(0); + pd->preset->set_value(1027, 0); + } + ui->preset_editor->arp->load_n(ARP, v); + if (v) + { + ui->preset_editor->edit_arp->deactivate(); + if (ui->main->g_main_arp->get_value() == 0 + || ui->main->g_main_arp->get_value() == -1) + ui->main->main_edit_arp->deactivate(); + } + else + { + ui->preset_editor->edit_arp->activate(); + if (ui->main->g_main_arp->get_value() == 0 + || ui->main->g_main_arp->get_value() == -1) + ui->main->main_edit_arp->activate(); + } + break; + case 1299: // link 1 + if (get) + { + ui->preset_editor->l1->select(2); + pd->preset->set_value(1281, 0); + ui->preset_editor->g_link1->activate(); + } + ui->preset_editor->l1->load_n(PRESET, v); + break; + case 1300: // link 2 + if (get) + { + ui->preset_editor->l2->select(2); + pd->preset->set_value(1290, 0); + ui->preset_editor->g_link2->activate(); + } + ui->preset_editor->l2->load_n(PRESET, v); + break; + case 1439: // instrument rom + if (get) + { + ui->layer_editor[id_layer[1]]->instrument->select(1); + pd->preset->set_value(1409, 0, id_layer[1]); + } + ui->layer_editor[id_layer[1]]->instrument->load_n(INSTRUMENT, v); + break; + } +} + +int ROM_Choice::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + set_value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + set_value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = v1 + dy; + if (v2 < 0) + v2 = size() - 2; + else if (v2 > size() - 2) + v2 = 0; + value(v2); + do_callback(); + return 1; + } + break; + } + return Fl_Choice::handle(ev); +} + +// ################### +// name and filter inputs +// +// ################### +int Input::handle(int ev) +{ + switch (ev) + { + case FL_KEYUP: // don't unfocus if we press enter + case FL_KEYDOWN: + if (Fl::event_key() == FL_Enter) + { + if (ev == FL_KEYDOWN) + mark(0); + return 1; + } + break; + } + return Fl_Input::handle(ev); +} + +// ################### +// value in/output widget +// +// ################### +void Value_Input::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Value_Input::set_value(int v) +{ + value((double) v); + ui->forma_out->value((double) v); +} + +int Value_Input::get_value() const +{ + return (int) value(); +} + +int Value_Input::handle(int ev) +{ + if (!pwid_editing) + return 0; + switch (ev) + { + case FL_LEAVE: + fl_cursor(FL_CURSOR_DEFAULT); + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy() * -1; + double v1 = value(); // current value + double v2 = clamp(increment(v1, dy)); + if (v1 == v2) + return 1; + value(v2); + do_callback(); + return 1; + } + break; + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) // reset to initial value + { + int* la_id = pwid_editing->get_id_layer(); + if (la_id[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(la_id[0], + pd->selected_channel)); + else + // preset + value((double) pd->preset_copy->get_value(la_id[0], la_id[1])); + do_callback(); + return 1; + } + fl_cursor(FL_CURSOR_DEFAULT); + if (when() & FL_WHEN_ENTER_KEY && changed()) + { + do_callback(); + return 1; + } + break; + case FL_KEYUP: // don't unfocus if we press enter + case FL_KEYDOWN: + if (when() & FL_WHEN_CHANGED && Fl::event_key() == FL_Enter) + { + if (ev == FL_KEYDOWN) + input.mark(0); + return 1; + } + break; + case FL_DRAG: + if (FL_BUTTON3 & Fl::event_state()) // prevent value dragging with right mouse button + return 1; + // prevent dragging when we are editing the preset browser or channel + if (((int*) pwid_editing->get_id_layer())[0] == 897 + || ((int*) pwid_editing->get_id_layer())[0] == 129) + return 1; + break; + case FL_DND_ENTER: + return 0; + } + return Fl_Value_Input::handle(ev); +} + +// ################### +// Formatted output +// ################### +void Formatted_Output::set_value(int p, int l, int v) +{ + id = p; + layer = l; + value((double) v); + redraw(); +} + +int Formatted_Output::format(char *buf) +{ + switch (id) + { + case 129: // selected channel + { + return sprintf(buf, "Channel %2d selected", (int) value() + 1); + } + case 140: // fx channel + { + if ((int) value() == -1) + return sprintf(buf, "Master FX"); + return sprintf(buf, "Channel %2d FX", (int) value() + 1); + } + case 132: // channel pan + { + int v = (int) value(); + if (v == 64) + return sprintf(buf, "Center"); + return sprintf(buf, "%2d %s", abs(v - 64), v < 64 ? "L" : "R"); + } + case 259: // Master transpose + case 1425: + { + const char* transpose_values[] = + { "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", + "B " }; + int v = (int) value(); + int p = v % 12; + if (v < 0 && p != 0) + p += 12; + return sprintf(buf, "%s (%+4d semitones)", transpose_values[p], v); + } + case 1284: // link transpose + case 1293: + return sprintf(buf, "%+3d semitones", (int) value()); + case 257: // BPM + { + int v = (int) value(); + if (v == 0) + return sprintf(buf, "External MIDI Clock"); + return sprintf(buf, "%d", v); + } + case 260: // Master tune + case 1426: + { + int v = (int) value(); + const char* cents[] = + { "0", "1.2", "3.5", "4.7", "6.0", "7.2", "9.5", "10.7", "12.0", + "14.2", "15.5", "17.7", "18.0", "20.2", "21.5", "23.7", "25.0", + "26.2", "28.5", "29.7", "31.0", "32.2", "34.5", "35.7", "37.0", + "39.2", "40.5", "42.7", "43.0", "45.2", "46.6", "48.7", "50.0", + "51.2", "53.5", "54.7", "56.0", "57.2", "59.5", "60.7", "62.0", + "64.2", "65.5", "67.7", "68.0", "70.2", "71.5", "73.7", "75.0", + "76.2", "78.5", "79.7", "81.0", "82.2", "84.5", "85.7", "87.0", + "89.2", "90.5", "92.7", "93.0", "95.2", "96.6", "98.7" }; + if (v >= 0) + return sprintf(buf, "+%4s cents (%+3d/64)", cents[v], v); + else + return sprintf(buf, "-%4s cents (%+3d/64)", cents[abs(v)], v); + } + case 402: // Tempo control + case 403: + { + int v = (int) value(); + if (v == -1) + return sprintf(buf, "Pitch Wheel"); + if (v == -2) + return sprintf(buf, "Mono Pressure"); + if (v == -3) + return sprintf(buf, "Off"); + return sprintf(buf, "Ctrl %i", v); + } + case 1163: // FX Delay + case 523: + { + int v = (int) value(); + const char* delay[] = + { "1/32 32nd", "1/16t 16th triplet", "1/32d dotted 32th", + "1/16 16th", "1/8t 8th triplet", "1/16d dotted 16th", + "1/8 8th", "1/4t quarter triplet", "1/8d dotted 8th", + "1/4 quarter", "1/2t half triplet", "1/4d dotted quarter" }; + if (v < 0) + return sprintf(buf, "%s", delay[abs(v) - 1]); + return sprintf(buf, "%d ms", v * 5); + } + case 644: // Arp note + case 651: + case 650: + case 661: + case 1028: + case 1034: + case 1035: + case 1043: + { + int v = (int) value(); + if (v) + return sprintf(buf, "%s", rates[25 - v]); + return sprintf(buf, "%s", "Off"); + } + case 915: // initial controller amounts + case 916: + case 917: + case 918: + case 919: + case 920: + case 921: + case 922: + case 924: + case 925: + case 926: + case 927: + { + int v = (int) value(); + if (v == -1) + return sprintf(buf, "Current Controller Value"); + return sprintf(buf, "%d", v); + } + case 1029: // arp velocity + case 645: + { + int v = (int) value(); + if (v == 0) + return sprintf(buf, "As played"); + return sprintf(buf, "%d", v); + } + case 1030: // arp note gate + case 1427: // chorus + case 1428: + { + return sprintf(buf, "%3d %%", (int) value()); + } + case 1410: // layer volume + case 1282: + case 1291: + { + return sprintf(buf, "%+3d db", (int) value()); + } + case 1411: // layer pan + case 1283: + case 1292: + { + int v = (int) value(); + if (v == 0) + return sprintf(buf, "Center"); + return sprintf(buf, "%2d %s", abs(v), v < 0 ? "L" : "R"); + } + case 1431: // layer bend range + { + int v = (int) value(); + if (v == -1) + return sprintf(buf, "Master Bend Range"); + else if (v == 0) + return sprintf(buf, "Disabled"); + else + return sprintf(buf, "+/- %2d semitones", v); + } + case 1432: // Glide rate + { + const unsigned char envunits1[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, + 22, 23, 24, 26, 28, 30, 32, 34, 36, 38, 41, 44, 47, 51, 55, 59, + 64, 70, 76, 83, 91, 100, 112, 125, 142, 163, }; + const unsigned char envunits2[] = + { 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 25, 26, 28, 29, 32, 34, 36, 38, 41, 43, + 46, 49, 52, 55, 58, 62, 65, 70, 74, 79, 83, 88, 93, 98, 04, 10, + 17, 24, 31, 39, 47, 56, 65, 74, 84, 95, 06, 18, 31, 44, 59, 73, + 89, 06, 23, 42, 62, 82, 04, 28, 52, 78, 05, 34, 64, 97, 32, 67, + 06, 46, 90, 35, 83, 34, 87, 45, 06, 70, 38, 11, 88, 70, 56, 49, + 48, 53, 65, 85, 13, 50, 97, 54, 24, 06, 02, 15, 44, 93, 64, 60, + 84, 41, 34, 70, 56, 03, 22, 28, 40, 87, 9, 65, 36, 69, }; + int v = (int) value(); + int msec = (envunits1[v] * 1000 + envunits2[v] * 10) / 5; + return sprintf(buf, "%02d.%03d seconds/octave", msec / 1000, + msec % 1000); + } + case 1433: // glide curve + { + int v = (int) value(); + if (v == 0) + return sprintf(buf, "Linear"); + return sprintf(buf, "Exponential %d", v); + } + case 1435: // Sample Delay + case 1667: // LFO Delay + case 1672: + case 1285: + case 1294: + { + int v = (int) value(); + if (v < 0) + { + return sprintf(buf, "%s", rates[25 + v]); + } + else + return sprintf(buf, "%d", v); + } + case 1538: // Cutoff frequency + { + int v = (int) value(); + int maxfreq = 0, mul = 0; + int filter_selected = pwid[1537][layer]->get_value(); + if (filter_selected == 0 || filter_selected == 1 || filter_selected + == 2) + { + maxfreq = 20000; + mul = 1002; + } + else if (filter_selected == 8 || filter_selected == 9) + { + maxfreq = 18000; + mul = 1003; + } + else if (filter_selected == 16 || filter_selected == 17 + || filter_selected == 18 || filter_selected == 32 + || filter_selected == 33 || filter_selected == 34 + || filter_selected == 64 || filter_selected == 65 + || filter_selected == 66 || filter_selected == 72) + { + maxfreq = 10000; + mul = 1006; + } + else + return sprintf(buf, "%d", v); + + int input = 255 - v; + while (input-- > 0) + maxfreq *= mul, maxfreq /= 1024; + return sprintf(buf, "%5d Hz", maxfreq); + } + case 1665: // LFO rates + case 1670: + { + int v = (int) value(); + if (v < 0) + return sprintf(buf, "%s", rates[25 + v]); + else + { + const unsigned char lfounits1[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, + 14, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, }; + + const unsigned char lfounits2[] = + { 8, 11, 15, 18, 21, 25, 28, 32, 35, 39, 42, 46, 50, 54, 58, 63, + 67, 71, 76, 80, 85, 90, 94, 99, 04, 10, 15, 20, 25, 31, 37, + 42, 48, 54, 60, 67, 73, 79, 86, 93, 00, 07, 14, 21, 29, 36, + 44, 52, 60, 68, 77, 85, 94, 03, 12, 21, 31, 40, 50, 60, 70, + 81, 91, 02, 13, 25, 36, 48, 60, 72, 84, 97, 10, 23, 37, 51, + 65, 79, 94, 8, 24, 39, 55, 71, 88, 04, 21, 39, 57, 75, 93, + 12, 32, 51, 71, 92, 13, 34, 56, 78, 00, 23, 47, 71, 95, 20, + 46, 71, 98, 25, 52, 80, 9, 38, 68, 99, 30, 61, 93, 26, 60, + 94, 29, 65, 01, 38, 76, 14, }; + return sprintf(buf, "%2d.%02d Hz", lfounits1[v], lfounits2[v]); + } + } + case 933: // preset controller amounts + case 936: + case 939: + case 942: + case 945: + case 948: + case 951: + case 954: + case 957: + case 960: + case 963: + case 966: + case 1923: // layer controller amounts + case 1926: + case 1929: + case 1932: + case 1935: + case 1938: + case 1941: + case 1944: + case 1947: + case 1950: + case 1953: + case 1956: + case 1959: + case 1962: + case 1965: + case 1968: + case 1971: + case 1974: + case 1977: + case 1980: + case 1983: + case 1986: + case 1989: + case 1992: + { + int v = (int) value(); + switch (abs(v)) + { + case 3: + return sprintf(buf, "%0+4d ( 1 semitone)", v); + case 6: + return sprintf(buf, "%0+4d ( 2 semitones)", v); + case 9: + return sprintf(buf, "%0+4d ( 3 semitones approx.)", v); + case 12: + return sprintf(buf, "%0+4d ( 4 semitones approx.)", v); + case 16: + return sprintf(buf, "%0+4d ( 5 semitones)", v); + case 19: + return sprintf(buf, "%0+4d ( 6 semitones)", v); + case 22: + return sprintf(buf, "%0+4d ( 7 semitones)", v); + case 25: + return sprintf(buf, "%0+4d ( 8 semitones)", v); + case 28: + return sprintf(buf, "%0+4d ( 9 semitones)", v); + case 31: + return sprintf(buf, "%0+4d (10 semitones approx.)", v); + case 35: + return sprintf(buf, "%0+4d (11 semitones)", v); + case 38: + return sprintf(buf, "%0+4d (12 semitones) [Pat]", v); + case 41: + return sprintf(buf, "%0+4d (13 semitones)", v); + case 44: + return sprintf(buf, "%0+4d (14 semitones)", v); + case 47: + return sprintf(buf, "%0+4d (15 semitones)", v); + case 50: + return sprintf(buf, "%0+4d (16 semitones)", v); + case 53: + return sprintf(buf, "%0+4d (17 semitones approx.)", v); + case 57: + return sprintf(buf, "%0+4d (18 semitones)", v); + case 60: + return sprintf(buf, "%0+4d (19 semitones)", v); + case 63: + return sprintf(buf, "%0+4d (20 semitones)", v); + case 66: + return sprintf(buf, "%0+4d (21 semitones)", v); + case 69: + return sprintf(buf, "%0+4d (22 semitones)", v); + case 72: + return sprintf(buf, "%0+4d (23 semitones approx.)", v); + case 76: + return sprintf(buf, "%0+4d (24 semitones approx.)", v); + case 79: + return sprintf(buf, "%0+4d (25 semitones)", v); + case 82: + return sprintf(buf, "%0+4d (26 semitones)", v); + case 88: + return sprintf(buf, "%0+4d (27 semitones)", v); + case 91: + return sprintf(buf, "%0+4d (28 semitones)", v); + case 95: + return sprintf(buf, "%0+4d (29 semitones approx.)", v); + case 98: + return sprintf(buf, "%0+4d (30 semitones)", v); + default: + return sprintf(buf, "%0+4d", v); + } + } + default: + return sprintf(buf, "%d", (int) value()); + } +} + +// ################### +// +// ################### +void Value_Output::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = (int) minimum(); + minimax[1] = (int) maximum(); + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Value_Output::set_value(int v) +{ + value((double) v); +} + +int Value_Output::get_value() const +{ + return (int) value(); +} + +int Value_Output::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + if (Fl::event_clicks() && ((id_layer[0] >= 1921 && id_layer[0] <= 1992) + || (id_layer[0] >= 933 && id_layer[0] <= 966))) // double click on patchcord amounts + { + Fl::event_clicks(0); + if (value()) + { + double_click_value = (int) value(); + value(0); + } + else + value((double) double_click_value); + do_callback(); + return 1; + } + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button()) + { + if (pd->setup_copy && pd->preset_copy && id_layer[0] != -1) + { + if (id_layer[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + } + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = v1 - dy; + if (v2 < minimum()) + v2 = maximum(); + else if (v2 > maximum()) + v2 = minimum(); + value(v2); + do_callback(); + return 1; + } + break; + } + return Fl_Value_Output::handle(ev); +} + +// ################### +// +// ################### +void Slider::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + if (v == 1410) // layer volume + { + minimax[0] = -96; + minimax[1] = 10; + } + else + { + minimax[0] = (int) maximum(); + minimax[1] = (int) minimum(); + } + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Slider::set_value(int v) +{ + if (id_layer[0] == 1410) // layer volume + { + prev_value = v; + value(pow(v + 96, 3)); // cubic slider + return; + } + value((double) v); +} + +int Slider::get_value() const +{ + if (id_layer[0] == 1410) // layer volume + { + int val = (int) cbrt(value()) - 96; + if (val != prev_value) + { + prev_value = val; + return val; + } + else + return -999; + } + return (int) value(); +} + +void Slider::draw(int X, int Y, int W, int H) +{ + double val; + if (minimum() == maximum()) + val = 0.5; + else + { + val = (value() - minimum()) / (maximum() - minimum()); + if (val > 1.0) + val = 1.0; + else if (val < 0.0) + val = 0.0; + } + int ww = H; + int xx, S; + S = 17; + xx = int(val * (ww - S) + .5); + int xsl, ysl, wsl, hsl; + ysl = Y + xx; + hsl = S; + xsl = X; + wsl = W - 1; + fl_push_clip(X, Y, W, H); + draw_box(); + draw_box(FL_FLAT_BOX, X + 2, Y + 2, W - 5, xx + 5, FL_INACTIVE_COLOR); + //draw_box(FL_FLAT_BOX, X, Y + xx, W - 1, H - xx, FL_INACTIVE_COLOR); + fl_pop_clip(); + if (wsl > 0 && hsl > 0) + draw_box(FL_THIN_UP_BOX, xsl, ysl, wsl, hsl, selection_color()); + + draw_label(xsl, ysl, wsl, hsl); + if (Fl::focus() == this) + draw_focus(FL_BORDER_BOX, xsl, ysl, wsl, hsl); +} + +void Slider::draw() +{ + if (damage() & FL_DAMAGE_ALL) + draw_box(); + draw(x() + Fl::box_dx(box()), y() + Fl::box_dy(box()), + w() - Fl::box_dw(box()), h() - Fl::box_dh(box())); +} + +// mousewheel support for slider +int Slider::handle(int ev) +{ + switch (ev) + { + // Mouse Events + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button()) + { + if (pd->setup_copy && pd->preset_copy) + { + if (id_layer[0] == 1410) // layer volume fader + { + int + v = pd->preset_copy->get_value(id_layer[0], + id_layer[1]); + value((double) pow(v + 96, 3)); + prev_value = v; + } + else + { + if (id_layer[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + value( + (double) pd->preset_copy->get_value( + id_layer[0], id_layer[1])); + } + do_callback(); + } + return 1; + } + break; + case FL_DRAG: + if (FL_BUTTON3 & Fl::event_state()) + return 1; + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + if (id_layer[0] == 1410) // layer volume + { + int dy = Fl::event_dy(); + int v = prev_value - dy; + if (v < -96) + v = -96; + else if (v > 10) + v = 10; + if (v == prev_value) + return 1; + value(pow(v + 96, 3)); + do_callback(); + prev_value = v; + } + else + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = clamp(increment(v1, dy)); + if (v1 == v2) + return 1; + value(v2); + do_callback(); + } + return 1; + } + break; + // keyboard events + case FL_KEYDOWN: + // key press (Fl::event_key()) + if (id_layer[0] == 1410) + { + int key = Fl::event_key(); + int v = prev_value; + switch (key) + { + case FL_Up: + if (Fl::event_shift()) + v = 0; + else + { + ++v; + if (v < -96) + v = -96; + else if (v > 10) + v = 10; + } + break; + case FL_Down: + if (Fl::event_shift()) + v = 0; + else + { + --v; + if (v < -96) + v = -96; + else if (v > 10) + v = 10; + } + break; + case FL_Left: + if (Fl::event_shift()) + v = -96; + else + return 0; + break; + case FL_Right: + if (Fl::event_shift()) + v = 10; + else + return 0; + break; + default: + return 0; + } + if (v != prev_value) + { + value(pow(v + 96, 3)); + do_callback(); + prev_value = v; + } + return 1; + } + break; + } + return Fl_Slider::handle(ev); +} + +// ################### +// +// ################### +void Spinner::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = (int) minimum(); + minimax[1] = (int) maximum(); + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Spinner::set_value(int v) +{ + value((double) v); +} + +int Spinner::get_value() const +{ + return (int) value(); +} + +int Spinner::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()->parent()) + { + int dy = Fl::event_dy() * -1; + double v1 = value(); + double v2 = v1 + dy; + if (v2 < minimum()) + v2 = minimum(); + else if (v2 > maximum()) + v2 = maximum(); + value(v2); + do_callback(); + return 1; + } + } + return Fl_Spinner::handle(ev); +} + +// ################### +// +// ################### +void Counter::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = (int) minimum(); + minimax[1] = (int) maximum(); + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; + lstep(10); +} + +void Counter::set_value(int v) +{ + value((double) v); +} + +int Counter::get_value() const +{ + return (int) value(); +} + +int Counter::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy() * -1; + double v1 = value(); // current value + double v2 = clamp(increment(v1, dy)); + if (v1 == v2) + return 1; + value(v2); + do_callback(); + return 1; + } + } + return Fl_Counter::handle(ev); +} + +// ################### +// +// ################### +void Group::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = 0; + switch (v) + { + case 129: // channel + minimax[1] = 15; + break; + case 134: // multimode arp + minimax[0] = -2; + minimax[1] = 1; + break; + case 1026: // arp mode + case 642: + minimax[1] = 7; + break; + case 1036: // arp recycle + case 652: + minimax[1] = 2; + break; + case 1041: // arp pattern speed + case 659: + minimax[0] = -2; + minimax[1] = 2; + break; + case 1412: // layer mix out + minimax[1] = 3; + break; + default: + minimax[1] = 0; + } + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Group::set_value(int v) +{ + pmesg(90, "Group::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + int childs = children(); + if (id_layer[0] == 1041 || id_layer[0] == 659 || id_layer[0] == 134) // arp pattern speed / multimode arp + { + if (childs > v + 2 && v >= -2) + ((Fl_Button*) child(v + 2))->setonly(); + else + return; + } + else if (id_layer[0] == 133 || id_layer[0] == 930) // mix out/tempo offset + { + if (childs > v + 1 && v >= -1) + ((Fl_Button*) child(v + 1))->setonly(); + else + return; + } + else + { + if (childs > v && v >= 0) + ((Fl_Button*) child(v))->setonly(); + else + return; + } + dependency(v); +} + +int Group::get_value() const +{ + int v = 0; + for (int i = 0; i < children(); i++) + { + if (((Fl_Button*) array()[i])->value()) + { + if (id_layer[0] == 1041 || id_layer[0] == 659 || id_layer[0] == 134) + v = i - 2; + else if (id_layer[0] == 133 || id_layer[0] == 930) + v = i - 1; + else + v = i; + break; + } + } + dependency(v); + return v; +} + +int Group::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788 && id_layer[0] != 129) // master setting + set_value( + pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + set_value(pd->preset_copy->get_value(id_layer[0], id_layer[1])); + do_callback(); + return 1; + } + break; + } + return Fl_Group::handle(ev); +} + +void Group::dependency(int v) const +{ + if (id_layer[0] == 129) // channel select + { + //((Fl_Widget*) this)->deactivate(); + //ui->value_input->deactivate(); + if (MULTI != pd->midi_mode || v == pd->selected_fx_channel || -1 + == pd->selected_fx_channel) + ui->fx->activate(); + else + ui->fx->deactivate(); + } + else if (id_layer[0] == 133) // mix out + { + if (v == -1) + for (int i = 0; i < 4; i++) + ui->main->layer_strip[i]->mix_out->activate(); + else + for (int i = 0; i < 4; i++) + ui->main->layer_strip[i]->mix_out->deactivate(); + } + else if (id_layer[0] == 134) // arp mode + { + if ((v == 0 || v == -1) && ui->preset_editor->arp_rom->value() == 0) // preset arp + ui->main->main_edit_arp->activate(); + else if (v == 1 && ui->main->arp_rom->value() == 0) // master arp + ui->main->main_edit_arp->activate(); + else + ui->main->main_edit_arp->deactivate(); + } + else if (id_layer[0] == 1026) // preset arp mode + { + if (v != 7) + { + ui->preset_editor->g_pattern->deactivate(); + ui->preset_editor->g_pattern_speed->deactivate(); + ui->preset_editor->note->activate(); + } + else + { + ui->preset_editor->g_pattern->activate(); + ui->preset_editor->g_pattern_speed->activate(); + ui->preset_editor->note->deactivate(); + } + } + else if (id_layer[0] == 642) // master arp mode + { + if (v != 7) + { + ui->main->g_pattern->deactivate(); + ui->main->g_pattern_speed->deactivate(); + ui->main->note->activate(); + } + else + { + ui->main->g_pattern->activate(); + ui->main->g_pattern_speed->activate(); + ui->main->note->deactivate(); + } + } +} + +// ################### +// +// ################### +Fl_Knob::Fl_Knob(int xx, int yy, int ww, int hh, const char *l) : + Fl_Valuator(xx, yy, ww, hh, l) +{ + a1 = 35; + a2 = 325; + _type = LINELIN; + _percent = 0.7; + _scaleticks = 12; + selected = false; +} + +void Fl_Knob::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = (int) minimum(); + minimax[1] = (int) maximum(); + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; + switch (v) + { + case 259: // master transpose + _scaleticks = 4; + break; + case 1425: // coarse tune + _scaleticks = 6; + break; + case 1433: // glide curve + _scaleticks = 8; + break; + case 1435: // delay + case 1436: // offset + case 1665: // lfo1 rate + case 1670: // lfo2 rate + case 1667: // lfo1 delay + case 1672: // lfo2 delay + case 1285: // link1 delay + case 1294: // link2 delay + _scaleticks = 16; + break; + case 1538: // cutoff + case 1284: // link1 transpose + case 1293: // link2 transpose + _scaleticks = 24; + break; + case 1431: // bend + _scaleticks = 13; + break; + case 1427: // chorus + case 1428: // width + case 517: // (master) fx sends + case 518: + case 519: + case 527: + case 524: + case 525: + case 526: + case 528: + case 1157: // fx sends + case 1158: + case 1159: + case 1167: + case 1164: + case 1165: + case 1166: + case 1168: + case 1668: // lfo1 variation + case 1673: // lfo2 variation + case 646: // arp gate + case 1030: + _scaleticks = 10; + break; + case 514: // (master) fxa decay + case 1154: // fxa decay + _scaleticks = 9; + break; + case 523: // (master) fxb delay + case 1163: // fxb delay + _scaleticks = 14; + break; + case 1028: // arp note delay + case 644: + case 651: // arp duration + case 1035: + case 1034: // pre delay + case 650: + case 1043: // post delay + case 661: + _scaleticks = 19; + break; + case 1031: // arp ext count + case 647: + case 648: // arp interval + case 1032: + _scaleticks = 15; + break; + } +} + +void Fl_Knob::set_value(int v) +{ + if (id_layer[0] == 1665 || id_layer[0] == 1670) // lfo rates + dependency(v); + value((double) v); +} + +int Fl_Knob::get_value() const +{ + int v = (int) value(); + if (id_layer[0] == 1665 || id_layer[0] == 1670) // lfo rates + dependency(v); + return v; +} + +void Fl_Knob::dependency(int v) const +{ + if (id_layer[0] == 1665) // lfo1 rate + { + if (v < 0) + ui->layer_editor[id_layer[1]]->lfo1_variation->deactivate(); + else + ui->layer_editor[id_layer[1]]->lfo1_variation->activate(); + } + else if (id_layer[0] == 1670) // lfo2 rate + { + if (v < 0) + ui->layer_editor[id_layer[1]]->lfo2_variation->deactivate(); + else + ui->layer_editor[id_layer[1]]->lfo2_variation->activate(); + } +} + +void Fl_Knob::draw() +{ + int ox, oy, ww, hh, side; + ox = x(); + oy = y(); + ww = w(); + hh = h(); + draw_label(); + fl_clip(ox, oy, ww, hh); + if (ww > hh) + { + side = hh; + ox = ox + (ww - side) / 2; + } + else + { + side = ww; + oy = oy + (hh - side) / 2; + } + side = w() > h() ? hh : ww; + + // background + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(ox, oy, side, side); + // surrounding + if (!ui->shiny_knobs) + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_SELECTION_COLOR, .6)); + else + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, FL_BACKGROUND2_COLOR, .6)); + fl_pie(ox + 1, oy + 3, side - 2, side - 12, 0, 360); + // scale + draw_scale(ox, oy, side); + fl_color(FL_BACKGROUND_COLOR); + fl_pie(ox + 6, oy + 6, side - 12, side - 12, 0, 360); + // shadow + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .8f)); + fl_pie(ox + 8, oy + 12, side - 16, side - 16, 0, 360); + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .2f)); + fl_pie(ox + 9, oy + 12, side - 18, side - 18, 0, 360); + // knob edge + if (!ui->shiny_knobs) + fl_color( + active_r() ? fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .4) + : FL_INACTIVE_COLOR); + else + fl_color( + active_r() ? fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .7) + : FL_INACTIVE_COLOR); + fl_pie(ox + 8, oy + 8, side - 16, side - 16, 0, 360); + // top + if (selected) + fl_color(FL_SELECTION_COLOR); + else + { + if (!ui->shiny_knobs) + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .6)); + else + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .6)); + } + fl_pie(ox + 10, oy + 10, side - 20, side - 20, 0, 360); + draw_cursor(ox, oy, side); + fl_pop_clip(); +} + +int Fl_Knob::handle(int ev) +{ + static int ox, oy, ww, hh, px, py; + ox = x() + 10; + oy = y() + 10; + ww = w() - 20; + hh = h() - 20; + switch (ev) + { + case FL_ENTER: // 1 = receive FL_LEAVE and FL_MOVE events (widget becomes Fl::belowmouse()) + case FL_LEAVE: + return 1; + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + handle_push(); + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + take_focus(); + } + else + { + take_focus(); + px = Fl::event_x(); + py = Fl::event_y(); + } + return 1; + case FL_RELEASE: + handle_release(); + return 1; + case FL_DRAG: // button state is in Fl::event_state() (FL_SHIFT FL_CAPS_LOCK FL_CTRL FL_ALT FL_NUM_LOCK FL_META FL_SCROLL_LOCK FL_BUTTON1 FL_BUTTON2 FL_BUTTON3) + if (!(FL_BUTTON3 & Fl::event_state())) + { + double val = 0, angle, oldangle; + int mx, my; + switch (cfg->get_cfg_option(CFG_KNOBMODE)) + { + case 0: // radial + mx = Fl::event_x() - ox - ww / 2; + my = Fl::event_y() - oy - hh / 2; + angle = 270 - atan2((float) -my, (float) mx) * 180 / M_PI; + oldangle = (a2 - a1) * (value() - minimum()) / (maximum() + - minimum()) + a1; + while (angle < oldangle - 180) + angle += 360; + while (angle > oldangle + 180) + angle -= 360; + if ((a1 < a2) ? (angle <= a1) : (angle >= a1)) + val = minimum(); + else if ((a1 < a2) ? (angle >= a2) : (angle <= a2)) + val = maximum(); + else + val = minimum() + (maximum() - minimum()) * (angle - a1) + / (a2 - a1); + break; + case 1: // horizontal + mx = Fl::event_x() - px; + val = (double) mx + value(); + px += mx; + break; + case 2: // vertical + my = Fl::event_y() - py; + val = value() - (double) my; + py += my; + break; + } + handle_drag(clamp(round(val))); + } + return 1; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy() * -1; + double v1 = value(); // current value + double v2 = clamp(increment(v1, dy)); + if (v1 == v2) + return 1; + value(v2); + do_callback(); + return 1; + } + break; + // keyboard events + case FL_FOCUS: // 1 = receive FL_KEYDOWN, FL_KEYUP, and FL_UNFOCUS events (widget becomes Fl::focus()) + // show value in value field and make ourselfes the editing widget + if (pwid_editing != this) + { + pwid_editing = this; + ui->value_input->minimum((double) minimax[0]); + ui->value_input->maximum((double) minimax[1]); + } + ui->value_input->value((double) value()); + ui->forma_out->set_value(id_layer[0], id_layer[1], value()); + selected = true; + damage(2); + return 1; + case FL_UNFOCUS: // received when another widget gets the focus and we had the focus + if (selected) + { + selected = false; + redraw(); + } + return 1; + case FL_KEYDOWN: // key press (Fl::event_key()) + if (selected) + { + int key = Fl::event_key(); + double v1 = value(); // current value + double v2 = 0.; + switch (key) + { + case FL_Down: + if (Fl::event_shift()) + v2 = 0.; + else + v2 = clamp(increment(v1, -1)); + break; + case FL_Up: + if (Fl::event_shift()) + v2 = 0.; + else + v2 = clamp(increment(v1, 1)); + break; + case FL_Left: + if (Fl::event_shift()) + v2 = minimax[0]; + else + return 0; + break; + case FL_Right: + if (Fl::event_shift()) + v2 = minimax[1]; + else + return 0; + break; + default: + return 0; + } + if (v1 != v2) + { + value(v2); + do_callback(); + } + return 1; + } + } + return Fl_Valuator::handle(ev); +} + +void Fl_Knob::type(int ty) +{ + _type = ty; +} + +void Fl_Knob::draw_scale(const int ox, const int oy, const int side) +{ + float x1, y1, x2, y2, rds, cx, cy, ca, sa; + rds = side / 2; + cx = ox + side / 2; + cy = oy + side / 2; + if (_scaleticks == 0) + return; + double a_step = (10.0 * 3.14159 / 6.0) / _scaleticks; + double a_orig = -(3.14159 / 3.0); + for (int a = 0; a <= _scaleticks; a++) + { + double na = a_orig + a * a_step; + ca = cos(na); + sa = sin(na); + x1 = cx + (rds) * ca; + y1 = cy - (rds) * sa; + x2 = cx + (rds - 6) * ca; + y2 = cy - (rds - 6) * sa; + fl_color(FL_BACKGROUND_COLOR); + fl_line(x1, y1, x2, y2); + } +} + +void Fl_Knob::draw_cursor(const int ox, const int oy, const int side) +{ + float rds, cur, cx, cy; + double angle; + // top + if (selected) + fl_color(fl_contrast(FL_FOREGROUND_COLOR, FL_SELECTION_COLOR)); + else + { + if (!ui->shiny_knobs) + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .7f)); + else + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .7f)); + } + rds = (side - 18) / 2.0; + cur = _percent * rds / 2; + cx = ox + side / 2; + cy = oy + side / 2; + angle = (a2 - a1) * (value() - minimum()) / (maximum() - minimum()) + a1; + fl_push_matrix(); + fl_scale(1, 1); + fl_translate(cx, cy); + fl_rotate(-angle); + fl_translate(0, rds - cur - 3.0); + fl_begin_polygon(); + fl_vertex(-1., -cur); + fl_vertex(-1., cur); + fl_vertex(1., cur); + fl_vertex(1., -cur); + fl_end_polygon(); + fl_pop_matrix(); +} + +void Fl_Knob::cursor(const int pc) +{ + _percent = (float) pc / 100.0; + if (_percent < 0.05) + _percent = 0.05; + if (_percent > 1.0) + _percent = 1.0; + if (visible()) + damage(FL_DAMAGE_CHILD); +} + +void Fl_Knob::scaleticks(const int tck) +{ + _scaleticks = tck; + if (_scaleticks < 0) + _scaleticks = 0; + if (_scaleticks > 31) + _scaleticks = 31; + if (visible()) + damage(FL_DAMAGE_ALL); +} + +// ################### +// +// ################### +void Button::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = 0; + minimax[1] = 1; + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Button::set_value(int v) +{ + if (id_layer[0] == 258 || id_layer[0] == 1669 || id_layer[0] == 1674 + || id_layer[0] == 1033 || id_layer[0] == 649) // fx bypass / lfo syncs / arp syncs + v ? v = 0 : v = 1; + if (id_layer[0] == 258) // fx bypass + { + v ? ui->m_bypass->set() : ui->m_bypass->clear(); + v ? ui->b_pfx->color( + fl_color_average(this->selection_color(), FL_BACKGROUND_COLOR, + .3)) : ui->b_pfx->color(FL_BACKGROUND_COLOR); + ui->b_pfx->redraw(); + } + else if (id_layer[0] == 1025) // arp preset + { + if (v) + { + ((Fl_Button*) ui->main->g_main_arp->child(2))->color( + this->selection_color(), + fl_color_average(this->selection_color(), + FL_SELECTION_COLOR, .3)); + } + else + { + ((Fl_Button*) ui->main->g_main_arp->child(2))->color( + FL_BACKGROUND_COLOR, FL_SELECTION_COLOR); + } + ui->main->g_main_arp->redraw(); + } + else if (id_layer[0] == 641) // arp master + { + if (v) + { + ((Fl_Button*) ui->main->g_main_arp->child(3))->color( + this->selection_color(), + fl_color_average(this->selection_color(), + FL_SELECTION_COLOR, .3)); + } + else + { + ((Fl_Button*) ui->main->g_main_arp->child(3))->color( + FL_BACKGROUND_COLOR, FL_SELECTION_COLOR); + } + ui->main->g_main_arp->redraw(); + } + value(v); +} + +int Button::get_value() const +{ + int v = value(); + if (id_layer[0] == 258) // fx bypass + { + v ? ui->m_bypass->set() : ui->m_bypass->clear(); + v ? ui->b_pfx->color( + fl_color_average(this->selection_color(), FL_BACKGROUND_COLOR, + .3)) : ui->b_pfx->color(FL_BACKGROUND_COLOR); + ui->b_pfx->redraw(); + } + if (id_layer[0] == 258 || id_layer[0] == 1669 || id_layer[0] == 1674 + || id_layer[0] == 1033 || id_layer[0] == 649) // fx bypass / lfo syncs / arp syncs + v ? v = 0 : v = 1; + if (id_layer[0] == 137) + { + if (v) + ui->g_preset->activate(); + else + ui->g_preset->deactivate(); + } + else if (id_layer[0] == 1025) // arp preset + { + if (v) + { + ((Fl_Button*) ui->main->g_main_arp->child(2))->color( + this->selection_color(), + fl_color_average(this->selection_color(), + FL_SELECTION_COLOR, .3)); + } + else + { + ((Fl_Button*) ui->main->g_main_arp->child(2))->color( + FL_BACKGROUND_COLOR, FL_SELECTION_COLOR); + } + ui->main->g_main_arp->redraw(); + } + else if (id_layer[0] == 641) // arp master + { + if (v) + { + ((Fl_Button*) ui->main->g_main_arp->child(3))->color( + this->selection_color(), + fl_color_average(this->selection_color(), + FL_SELECTION_COLOR, .3)); + } + else + { + ((Fl_Button*) ui->main->g_main_arp->child(3))->color( + FL_BACKGROUND_COLOR, FL_SELECTION_COLOR); + } + ui->main->g_main_arp->redraw(); + } + return v; +} + +int Button::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (id_layer[0] != -1 && FL_RIGHT_MOUSE == Fl::event_button() + && pd->setup_copy && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + set_value( + pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + set_value(pd->preset_copy->get_value(id_layer[0], id_layer[1])); + do_callback(); + return 1; + } + break; + } + return Fl_Button::handle(ev); +} + +// ################### +// +// ################### +int Fixed_Button::handle(int ev) +{ + if (ev == FL_DRAG) + return 0; + return Fl_Button::handle(ev); +} + +// ################### +// +// ################### +void Choice::set_id(int v, int l) +{ + id_layer[0] = v; + id_layer[1] = l; + minimax[0] = 0; + switch (v) + { + case 271: // beats mode + case 658: // song start + case 657: // midi transmit + minimax[1] = 3; + break; + case 265: // velocity curve + minimax[1] = 13; + break; + case 140: // fx channel + case 272: // beats channel + case 273: // beats trigger channel + minimax[0] = -1; + minimax[1] = 15; + break; + case 1437: // layer solo + minimax[1] = 8; + break; + case 1438: // layer group + minimax[1] = 23; + break; + case 1537: // filter type + minimax[1] = 163; + break; + case 385: // midi mode + minimax[1] = 2; + break; + case 513: // fxa + case 1153: + minimax[1] = 44; + break; + case 520: // fxb + case 1160: + minimax[1] = 32; + break; + case 141: // tempo channel + minimax[1] = 15; + break; + case 402: // tempo ctrl up + case 403: // tempo ctrl down + minimax[0] = -3; + minimax[1] = 31; + break; + case 923: // keyboard tuning + minimax[1] = 11; + break; + case 1666: // lfo waveform + case 1671: + minimax[0] = -1; + minimax[1] = 15; + break; + } + callback((Fl_Callback*) cb, (void*) id_layer); + pwid[v][l] = this; +} + +void Choice::set_value(int v) +{ + pmesg(90, "Choice::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + if (id_layer[0] == 140)// FX channel + { + dependency(v); + v += 1; + value((double) v); + } + else if (id_layer[0] == 1153 || id_layer[0] == 1160 || id_layer[0] == 385) + { + value(v); + dependency(v); + } + else if (id_layer[0] == 513 || id_layer[0] == 520) // master fx + { + dependency(v); + value(v - 1); + } + else if (id_layer[0] == 1537) // filter type + { + for (int i = 0; i <= 50; i++) + if (FM[i].value == v) + { + value(FM[i]._index); + tooltip(FM[i].info); + break; + } + if (v == 127) + ui->main->layer_strip[id_layer[1]]->filter_knobs->deactivate(); + else + ui->main->layer_strip[id_layer[1]]->filter_knobs->activate(); + } + else if (id_layer[0] == 403 || id_layer[0] == 402) // tempo up/down ctrl + { + if (v < 1) + value(v + 3); + else + value(v + 2); + } + else if (id_layer[0] == 272 || id_layer[0] == 273 || id_layer[0] == 1666 + || id_layer[0] == 1671) // beat channels + lfo waveforms + value(v + 1); + else + value(v); +} + +int Choice::get_value() const +{ + if (id_layer[0] == 140) // FX channel + { + int val = (int) value(); + val -= 1; + dependency(val); + return val; + } + if (id_layer[0] == 1537) // filter type + { + int v = value(); + int i; + for (i = 0; i <= 50; i++) + if (FM[i]._index == v) + break; + int val = FM[i].value; + if (val == 127) + ui->main->layer_strip[id_layer[1]]->filter_knobs->deactivate(); + else + ui->main->layer_strip[id_layer[1]]->filter_knobs->activate(); + return val; + } + int val = value(); + if (id_layer[0] == 1153 || id_layer[0] == 1160 || id_layer[0] == 385) + dependency(val); + if (id_layer[0] == 513 || id_layer[0] == 520) // master fx + { + val += 1; + dependency(val); + } + if (id_layer[0] == 403 || id_layer[0] == 402) // tempo up/down ctrl + { + if (value() < 3) + return value() - 3; + else + return value() - 2; + } + if (id_layer[0] == 272 || id_layer[0] == 273 || id_layer[0] == 1666 + || id_layer[0] == 1671) // beat channels + lfo waveforms + return val - 1; + return val; +} + +int Choice::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->setup_copy + && pd->preset_copy) + { + if (id_layer[0] < 788) // master setting + set_value( + (double) pd->setup_copy->get_value(id_layer[0], + pd->selected_channel)); + else + set_value( + (double) pd->preset_copy->get_value(id_layer[0], + id_layer[1])); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = v1 + dy; + if (v2 < 0) + v2 = size() - 2; + else if (v2 > size() - 2) + v2 = 0; + value(v2); + // make sure we dont select submenus when scrolling + const Fl_Menu_Item* item = mvalue(); + if (dy > 0) // scrolling down + { + if (item->label() == 0) + { + v2 += 2; + if (v2 >= size()) + v2 = 0; + value(v2); + item = mvalue(); + } + if (item->submenu()) + value(v2 + 1); + } + else if (dy < 0) // scrolling up + { + if (item->submenu()) + { + v2 -= 1; + if (v2 < 0) + v2 = size() - 2; + value(v2); + item = mvalue(); + } + if (item->label() == 0) + value(v2 - 1); + } + do_callback(); + return 1; + } + break; + } + return Fl_Choice::handle(ev); +} + +void Choice::dependency(int v) const +{ + if (id_layer[0] == 140) // FX channel + { + if (v != -1) + { + if (v == pd->selected_channel) + ui->fx->activate(); + else + ui->fx->deactivate(); + } + else + ui->fx->activate(); + if ((v != -1 && pwid[1153][0] != 0) || (v == -1 && pwid[513][0] != 0)) + return; + ui->fxa->clear(); + ui->fxb->clear(); + if (v != -1) // Master FX + { + ui->fxa->add("Master A"); + ui->fxb->add("Master B"); + } + ui->fxa->add("Room 1"); + ui->fxa->add("Room 2"); + ui->fxa->add("Room 3"); + ui->fxa->add("Hall 1"); + ui->fxa->add("Hall 2"); + ui->fxa->add("Plate"); + ui->fxa->add("Delay"); + ui->fxa->add("Panning Delay"); + ui->fxa->add("Multitap 1"); + ui->fxa->add("Multitap Pan"); + ui->fxa->add("3 Tap"); + ui->fxa->add("3 Tap Pan"); + ui->fxa->add("Soft Room"); + ui->fxa->add("Warm Room"); + ui->fxa->add("Perfect Room"); + ui->fxa->add("Tiled Room"); + ui->fxa->add("Hard Plate"); + ui->fxa->add("Warm Hall"); + ui->fxa->add("Spacious Hall"); + ui->fxa->add("Bright Hall"); + ui->fxa->add("Brt Hall Pan"); + ui->fxa->add("Bright Plate"); + ui->fxa->add("BBall Court"); + ui->fxa->add("Gymnasium"); + ui->fxa->add("Cavern"); + ui->fxa->add("Concert 9"); + ui->fxa->add("Concert 10 Pan"); + ui->fxa->add("Reverse Gate"); + ui->fxa->add("Gate 2"); + ui->fxa->add("Gate Pan"); + ui->fxa->add("Concert 11"); + ui->fxa->add("MediumConcert"); + ui->fxa->add("Large Concert"); + ui->fxa->add("Lg Concert Pan"); + ui->fxa->add("Canyon"); + ui->fxa->add("DelayVerb 1"); + ui->fxa->add("DelayVerb 2"); + ui->fxa->add("DelayVerb 3"); + ui->fxa->add("DelayVerb4Pan"); + ui->fxa->add("DelayVerb5Pan"); + ui->fxa->add("DelayVerb 6"); + ui->fxa->add("DelayVerb 7"); + ui->fxa->add("DelayVerb 8"); + ui->fxa->add("DelayVerb 9"); + + ui->fxb->add("Chorus 1"); + ui->fxb->add("Chorus 2"); + ui->fxb->add("Chorus 3"); + ui->fxb->add("Chorus 4"); + ui->fxb->add("Chorus 5"); + ui->fxb->add("Doubling"); + ui->fxb->add("Slapback"); // 6/7 + ui->fxb->add("Flange 1"); + ui->fxb->add("Flange 2"); + ui->fxb->add("Flange 3"); + ui->fxb->add("Flange 4"); + ui->fxb->add("Flange 5"); + ui->fxb->add("Flange 6"); + ui->fxb->add("Flange 7"); + ui->fxb->add("Big Chorus"); + ui->fxb->add("Symphonic"); + ui->fxb->add("Ensemble"); + ui->fxb->add("Delay"); // 17/18 + ui->fxb->add("Delay Stereo"); + ui->fxb->add("Delay Stereo 2"); + ui->fxb->add("Panning Delay"); + ui->fxb->add("Delay Chorus"); + ui->fxb->add("Pan Dly Chrs 1"); + ui->fxb->add("Pan Dly Chrs 2"); + ui->fxb->add("a"); + ui->fxb->add("b"); + if (v != -1) + { + ui->fxb->replace(25, "DualTap 1/3"); // 24/25 + ui->fxb->replace(26, "DualTap 1/4"); + } + else + { + ui->fxb->replace(24, "DualTap 1/3"); + ui->fxb->replace(25, "DualTap 1/4"); + } + ui->fxb->add("Vibrato"); + ui->fxb->add("Distortion 1"); // 27/28 + ui->fxb->add("Distortion 2"); + ui->fxb->add("DistortedFlange"); + ui->fxb->add("DistortedChorus"); + ui->fxb->add("DistortedDouble"); // 31/32 + + if (v != -1) + { + // replace ids with preset ids + pwid[513][0] = 0; + pwid[514][0] = 0; + pwid[515][0] = 0; + pwid[516][0] = 0; + pwid[517][0] = 0; + pwid[518][0] = 0; + pwid[519][0] = 0; + pwid[527][0] = 0; + + pwid[520][0] = 0; + pwid[521][0] = 0; + pwid[522][0] = 0; + pwid[523][0] = 0; + pwid[524][0] = 0; + pwid[525][0] = 0; + pwid[526][0] = 0; + pwid[528][0] = 0; + + ui->fxa->set_id(1153); + ui->fxa_decay->set_id(1154); + ui->fxa_damp->set_id(1155); + ui->fxa_ba->set_id(1156); + ui->fxa_send1->set_id(1157); + ui->fxa_send2->set_id(1158); + ui->fxa_send3->set_id(1159); + ui->fxa_send4->set_id(1167); + + ui->fxb->set_id(1160); + ui->fxb_feedback->set_id(1161); + ui->fxb_lfo_rate->set_id(1162); + ui->fxb_delay->set_id(1163); + ui->fxb_send1->set_id(1164); + ui->fxb_send2->set_id(1165); + ui->fxb_send3->set_id(1166); + ui->fxb_send4->set_id(1168); + } + else + { + // replace ids with master ids + pwid[1153][0] = 0; + pwid[1154][0] = 0; + pwid[1155][0] = 0; + pwid[1156][0] = 0; + pwid[1157][0] = 0; + pwid[1158][0] = 0; + pwid[1159][0] = 0; + pwid[1167][0] = 0; + + pwid[1160][0] = 0; + pwid[1161][0] = 0; + pwid[1162][0] = 0; + pwid[1163][0] = 0; + pwid[1164][0] = 0; + pwid[1165][0] = 0; + pwid[1166][0] = 0; + pwid[1168][0] = 0; + + ui->fxa->set_id(513); + ui->fxa_decay->set_id(514); + ui->fxa_damp->set_id(515); + ui->fxa_ba->set_id(516); + ui->fxa_send1->set_id(517); + ui->fxa_send2->set_id(518); + ui->fxa_send3->set_id(519); + ui->fxa_send4->set_id(527); + + ui->fxb->set_id(520); + ui->fxb_feedback->set_id(521); + ui->fxb_lfo_rate->set_id(522); + ui->fxb_delay->set_id(523); + ui->fxb_send1->set_id(524); + ui->fxb_send2->set_id(525); + ui->fxb_send3->set_id(526); + ui->fxb_send4->set_id(528); + } + } + else if (id_layer[0] == 513) // Master fxa + ui->g_fxa->activate(); + else if (id_layer[0] == 520) // Master fxb + ui->g_fxb->activate(); + else if (id_layer[0] == 1153) // fxa type + { + if (text() && strcmp(text(), "Master A") == 0) + ui->g_fxa->deactivate(); + else + ui->g_fxa->activate(); + } + else if (id_layer[0] == 1160) // fxb type + { + if (text() && strcmp(text(), "Master B") == 0) + ui->g_fxb->deactivate(); + else + ui->g_fxb->activate(); + } + if (id_layer[0] == 1160 || id_layer[0] == 520) // fxb type + { + // disable lfo rate for algorithms that dont support lfo rate + if (v == 6 || v == 7 || (v >= 18 && v <= 21) || v == 25 || v == 26 || v + == 28 || v == 29 || v == 32) + ui->fxb_lfo_rate->deactivate(); + else + ui->fxb_lfo_rate->activate(); + // disable delay for algorithms that dont support delay + if (v > 17 && v < 27) + ui->fxb_delay->activate(); + else + ui->fxb_delay->deactivate(); + } + else if (id_layer[0] == 385) // MIDI Mode + { + if (v != MULTI) // not multimode + { + ui->fx_channel->deactivate(); + ui->main->channel_enable->deactivate(); + } + else + { + ui->fx_channel->activate(); + ui->main->channel_enable->activate(); + } + if (v == OMNI) + ui->all_notes_off->deactivate(); + else + ui->all_notes_off->activate(); + } +} + +// ################### +// +// ################### +void PCS_Choice::set_value(int v) +{ + if (!initialized && pd->preset) + init(pd->preset->get_extra_controller()); + int i; + for (i = 0; i < 78; i++) + if (src[i].value == v) + break; + value(src[i]._index); +} + +int PCS_Choice::get_value() const +{ + int v = value(); + int i; + for (i = 0; i < 78; i++) + if (src[i]._index == v) + break; + return (int) src[i].value; +} + +// ################### +// +// ################### +void PCD_Choice::set_value(int v) +{ + pmesg(90, "PCD_Choice::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + int i; + for (i = 0; i < 68; i++) + if (dst[i].value == v) + break; + value(dst[i]._index); +} + +int PCD_Choice::get_value() const +{ + int v = value(); + int i; + for (i = 0; i < 68; i++) + if (dst[i]._index == v) + break; + return (int) dst[i].value; +} + +// ################### +// +// ################### +void PPCD_Choice::set_value(int v) +{ + pmesg(90, "PPCD_Choice::set_value(%d) (id:%d layer:%d)\n", v, id_layer[0], + id_layer[1]); + int i; + for (i = 0; i < 28; i++) + if (dst[i].value == v) + break; + value(dst[i]._index); +} + +int PPCD_Choice::get_value() const +{ + int v = value(); + int i; + for (i = 0; i < 28; i++) + if (dst[i]._index == v) + break; + return (int) dst[i].value; +} + +// ################### +// +// ################### +void Envelope_Editor::draw() +{ + // box + Fl_Box::draw_box(); + ee_w = this->w() - 2; + ee_h = this->h() - 2; + ee_x0 = this->x() + 1; + ee_y0 = this->y() + 1; + fl_push_clip(ee_x0, ee_y0, ee_w, ee_h); + + mode_button[0] = ee_x0 + ee_w - 164; + mode_button[1] = mode_button[0] + 55; + mode_button[2] = mode_button[1] + 55; + mode_button[3] = mode_button[0] - 65; // oberlay + mode_button[4] = mode_button[3] - 55; // comp + copy_button[0] = ee_x0 + 5; + copy_button[1] = copy_button[0] + 20; + copy_button[2] = copy_button[1] + 20; + copy_button[3] = copy_button[2] + 70; + copy_button[4] = copy_button[3] + 20; + copy_button[5] = copy_button[4] + 20; + shape_button[0] = ee_x0 + ee_w - 21; + shape_button[1] = shape_button[0] - 20; + shape_button[2] = shape_button[1] - 20; + shape_button[3] = shape_button[2] - 20; + + Fl_Color light, contrast; + bg = colors[BG]; + if (cfg->get_cfg_option(CFG_COLORED_BG)) + bg = (colors[RR] * 2 + colors[GG] * 3 + colors[BB]) / 6; + if (bg > 160) + { + light = fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .8f); + contrast = fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .5f); + } + else + { + light = fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .8f); + contrast = fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .5f); + } + if (!active_r()) + return; + // top bar + // envelope type + fl_font(FL_HELVETICA_BOLD, 14); + fl_color(FL_SELECTION_COLOR); + switch (mode) + { + case VOLUME: + fl_draw("VOL", ee_x0 + 5, ee_y0 + 17); + break; + case FILTER: + fl_draw("FIL", ee_x0 + 5, ee_y0 + 17); + break; + case AUXILIARY: + fl_draw("AUX", ee_x0 + 5, ee_y0 + 17); + break; + } + fl_font(FL_COURIER, 10); + fl_line_style(FL_SOLID, 1); + for (int i = 0; i < 5; i++) + { + // Borders + fl_color(light); + fl_rect(mode_button[i], ee_y0 + 5, 50, 14); + // highlight pushed + fl_color(FL_SELECTION_COLOR); + if (button_push && button_hover == i) + { + fl_rect(mode_button[i] + 1, ee_y0 + 6, 48, 12); + } + if (env[mode].mode == i || (i == 0 && mode != VOLUME + && env[mode].repeat) || (i == 3 && overlay) || (i == 4 + && ui->syncview)) + { + if (button_push && button_hover == i) + fl_color(FL_BACKGROUND_COLOR); + fl_rect(mode_button[i] - 1, ee_y0 + 4, 52, 16); + } + // text + //fl_color(contrast); + fl_color(FL_FOREGROUND_COLOR); + if (i == 0) + { + if (mode == VOLUME) + fl_draw("Factory", mode_button[0] + 4, ee_y0 + 15); + else + fl_draw("Repeat", mode_button[0] + 7, ee_y0 + 15); + } + else if (i == 1) + fl_draw("Time", mode_button[i] + 13, ee_y0 + 15); + else if (i == 2) + fl_draw("Tempo", mode_button[i] + 10, ee_y0 + 15); + else if (i == 3) + fl_draw("/\\\\//\\\\", mode_button[i] + 4, ee_y0 + 15); + else if (i == 4) + fl_draw("(( Y ))", mode_button[i] + 4, ee_y0 + 15); + } + // lower bar + // Borders + fl_color(light); + for (int i = 0; i < 6; i++) + fl_rect(copy_button[i], ee_y0 + ee_h - 18, 16, 14); + for (int i = 0; i < 4; i++) + fl_rect(shape_button[i], ee_y0 + ee_h - 18, 16, 14); + // selected + fl_color(FL_SELECTION_COLOR); + int ypos = ee_y0 + ee_h - 8; + fl_rect(copy_button[mode] - 1, ypos - 11, 18, 16); + // highlight pushed + if (button_push && button_hover >= VOLUME_SELECTED) + { + // shape + if (button_hover >= SHAPE_A) + fl_rect(shape_button[button_hover - SHAPE_A] + 1, ypos - 9, 14, 12); + // copy + else if (button_hover - VOLUME_SELECTED != mode) + fl_rect(copy_button[button_hover - VOLUME_SELECTED] + 1, ypos - 9, + 14, 12); + } + // text + fl_color(FL_FOREGROUND_COLOR); + fl_draw("COPY TO", copy_button[2] + 22, ypos); + fl_draw("SHAPE", ee_x0 + ee_w - 115, ypos); + fl_draw("V", copy_button[0] + 5, ypos); + fl_draw("F", copy_button[1] + 5, ypos); + fl_draw("A", copy_button[2] + 5, ypos); + fl_draw("V", copy_button[3] + 5, ypos); + fl_draw("F", copy_button[4] + 5, ypos); + fl_draw("A", copy_button[5] + 5, ypos); + switch (zoomlevel) + { + case 1: + fl_draw("1x", copy_button[5] + 25, ypos); + break; + case 2: + fl_draw("2x", copy_button[5] + 25, ypos); + break; + case 4: + fl_draw("4x", copy_button[5] + 25, ypos); + break; + } + fl_draw("Pr", shape_button[0] + 2, ypos); + fl_draw("Or", shape_button[1] + 2, ypos); + fl_draw("St", shape_button[2] + 2, ypos); + fl_draw("Pl", shape_button[3] + 2, ypos); + fl_color(FL_SELECTION_COLOR); + fl_rectf(copy_button[mode + 3] + 1, ypos - 9, 14, 12); + + fl_line_style(0); + if (!active_r()) + return; + + // center (coordinate system) + fl_color(light); + // 0.0 position of coordinate system + int x0 = ee_x0 + 5; + float y0 = (float) ee_y0 + 25. + ((float) ee_h - 50.) / 2.; + + // vertikale + float x_step = ((float) (ee_w - 10) / 384.) * (float) zoomlevel; // 3*128 = 384 + float x_val = (float) x0 + 8. * x_step; + while ((x_val - x0) / zoomlevel < (ee_w - 10) / zoomlevel - 1) + { + if (mode == VOLUME) + fl_line(x_val, ee_y0 + 25, x_val, y0); + else + fl_line(x_val, ee_y0 + 25, x_val, ee_y0 + ee_h - 25); + x_val += 8. * x_step; + } + // horizontale + float y_step = ((float) ee_h - 50.) / 20.; + for (int i = -9; i <= 9; i++) + { + if (i == 0) + if (mode == VOLUME) + break; + else + continue; + fl_line(x0 + 1, y0 + y_step * i, x0 + ee_w - 11, y0 + y_step * i); + } + // rahmen + fl_rect(x0, ee_y0 + 25, ee_w - 9, ee_h - 49); + // nulllinie + fl_color(contrast); + fl_line(x0 + 1, y0, x0 + ee_w - 11, y0); + // envelopes + if (overlay) + { + for (int i = 0; i < modes; i++) + { + if (i == mode) + continue; + draw_envelope(i, x0, y0); + } + } + draw_envelope(mode, x0, y0); + // value fields + // calc number of hovers + int hovers = 0; + for (int i = 0; i < 6; i++) + if (hover_list & (1 << i)) + hovers += 12; + char info[15]; + int y_offset = 16; + for (int i = 0; i < 6; i++) + { + if (hover_list & (1 << i)) + { + const char *tmp; + switch (i) + { + case 0: + tmp = "A1"; + break; + case 1: + tmp = "D1"; + break; + case 2: + tmp = "R1"; + break; + case 3: + tmp = "A2"; + break; + case 4: + tmp = "D2"; + break; + case 5: + tmp = "R2"; + break; + } + const char *tmp_tempo; + if (env[mode].mode == TEMPO_BASED) + { + switch (env[mode].stage[i][0]) + { + case 7: + tmp_tempo = "1/64"; + break; + case 12: + tmp_tempo = "1/32t"; + break; + case 14: + tmp_tempo = "1/64d"; + break; + case 19: + tmp_tempo = "1/32"; + break; + case 24: + tmp_tempo = "1/16t"; + break; + case 26: + tmp_tempo = "1/32d"; + break; + case 31: + tmp_tempo = "1/16"; + break; + case 36: + tmp_tempo = "1/8t"; + break; + case 38: + tmp_tempo = "1/16d"; + break; + case 43: + tmp_tempo = "1/8"; + break; + case 48: + tmp_tempo = "1/4t"; + break; + case 50: + tmp_tempo = "1/8d"; + break; + case 55: + tmp_tempo = "1/4"; + break; + case 60: + tmp_tempo = "1/2t"; + break; + case 62: + tmp_tempo = "1/4d"; + break; + case 67: + tmp_tempo = "1/2"; + break; + case 72: + tmp_tempo = "1/1t"; + break; + case 74: + tmp_tempo = "1/2d"; + break; + case 79: + tmp_tempo = "1/1"; + break; + case 84: + tmp_tempo = "2/1t"; + break; + case 86: + tmp_tempo = "1/1d"; + break; + case 91: + tmp_tempo = "2/1"; + break; + case 96: + tmp_tempo = "4/1t"; + break; + case 98: + tmp_tempo = "2/1d"; + break; + default: + tmp_tempo = 0; + } + } + if (tmp_tempo) + snprintf(info, 15, "%s %5s%4d", tmp, tmp_tempo, + env[mode].stage[i][1]); + else + snprintf(info, 15, "%s %5d%4d", tmp, env[mode].stage[i][0], + env[mode].stage[i][1]); + tmp_tempo = 0; + if (i == hover) + fl_font(FL_COURIER_BOLD_ITALIC, 14); + else + fl_font(FL_COURIER_ITALIC, 14); + // when we drag out of the visible area, keep the info text inside + int x_offset = 15; + if (dragbox[hover][0] + 120 > ee_x0 + ee_w) + x_offset -= (dragbox[hover][0] + 120) - (ee_x0 + ee_w); + if (y_offset == 16 && dragbox[hover][1] + 8 + hovers > ee_y0 + ee_h + - 25) + y_offset -= (dragbox[hover][1] + 8 + hovers) - (ee_y0 + ee_h + - 25); + fl_draw(info, dragbox[hover][0] + x_offset, + dragbox[hover][1] + y_offset); + y_offset += 12; + } + } + fl_pop_clip(); +} + +void Envelope_Editor::draw_envelope(int type, int x0, int y0) +{ + // x-scaling + float x_scale = (((float) ee_w - 10.) / 768.) * (float) zoomlevel; + // y-scaling + float y_scale = ((float) ee_h - 50.) / 200.; + // calculate pixel position for 9x9 dragboxes + dragbox[ATK_1][0] = x0 + env[type].stage[ATK_1][0] * x_scale; + dragbox[ATK_1][1] = y0 - env[type].stage[ATK_1][1] * y_scale; + dragbox[ATK_2][0] = dragbox[ATK_1][0] + env[type].stage[ATK_2][0] * x_scale; + dragbox[ATK_2][1] = y0 - env[type].stage[ATK_2][1] * y_scale; + dragbox[DCY_1][0] = dragbox[ATK_2][0] + env[type].stage[DCY_1][0] * x_scale; + dragbox[DCY_1][1] = y0 - env[type].stage[DCY_1][1] * y_scale; + dragbox[DCY_2][0] = dragbox[DCY_1][0] + env[type].stage[DCY_2][0] * x_scale; + dragbox[DCY_2][1] = y0 - env[type].stage[DCY_2][1] * y_scale; + dragbox[RLS_1][0] = dragbox[DCY_2][0] + env[type].stage[RLS_1][0] * x_scale; + dragbox[RLS_1][1] = y0 - env[type].stage[RLS_1][1] * y_scale; + dragbox[RLS_2][0] = dragbox[RLS_1][0] + env[type].stage[RLS_2][0] * x_scale; + dragbox[RLS_2][1] = y0 - env[type].stage[RLS_2][1] * y_scale; + + // draw lines between dragboxes (rrbggg) + int out = -1; + switch (type) + { + case VOLUME: + fl_color(170, 90, 70); + break; + case FILTER: + fl_color(80, 180, 70); + break; + case AUXILIARY: + fl_color(80, 90, 160); + } + + Fl_Color col = fl_color(); + if (bg > 160) + fl_color(fl_color_average(col, FL_BLACK, .7f)); + else + fl_color(fl_color_average(col, FL_WHITE, .4f)); + col = fl_color(); + if (type != mode) + { + if (bg > 160) + fl_color(fl_color_average(col, FL_WHITE, .6f)); + else + fl_color(fl_color_average(col, FL_BLACK, .6f)); + } + col = fl_color(); + fl_line_style(FL_SOLID, 2); + if (dragbox[DCY_2][0] <= ee_x0 + ee_w - 5) + { + fl_line(dragbox[DCY_1][0], dragbox[DCY_1][1], dragbox[DCY_2][0], + dragbox[DCY_2][1]); + // vertical line at release + fl_color(fl_lighter(col)); + fl_line_style(FL_DASH, 2); + fl_line(dragbox[DCY_2][0], y0 - 100 * y_scale, dragbox[DCY_2][0], + y0 + 100 * y_scale); + fl_color(col); + fl_line_style(FL_SOLID, 2); + if (type == mode) + fl_rectf(dragbox[DCY_2][0] - 4, dragbox[DCY_2][1] - 4, 9, 9); + } + if (dragbox[ATK_1][0] <= ee_x0 + ee_w - 5) + { + fl_line(x0, y0, dragbox[ATK_1][0], dragbox[ATK_1][1]); + if (type == mode) + fl_rectf(dragbox[ATK_1][0] - 4, dragbox[ATK_1][1] - 4, 9, 9); + } + else + { + out = ATK_1; + goto Out; + } + if (dragbox[ATK_2][0] <= ee_x0 + ee_w - 5) + { + fl_line(dragbox[ATK_1][0], dragbox[ATK_1][1], dragbox[ATK_2][0], + dragbox[ATK_2][1]); + if (type == mode) + fl_rectf(dragbox[ATK_2][0] - 4, dragbox[ATK_2][1] - 4, 9, 9); + } + else if (out == -1) + { + out = ATK_2; + goto Out; + } + if (dragbox[DCY_1][0] <= ee_x0 + ee_w - 5) + { + fl_line(dragbox[ATK_2][0], dragbox[ATK_2][1], dragbox[DCY_1][0], + dragbox[DCY_1][1]); + if (type == mode) + fl_rectf(dragbox[DCY_1][0] - 4, dragbox[DCY_1][1] - 4, 9, 9); + } + else if (out == -1) + { + out = DCY_1; + goto Out; + } + if (dragbox[DCY_2][0] > ee_x0 + ee_w - 5) + { + out = DCY_2; + goto Out; + } + if (dragbox[RLS_1][0] <= ee_x0 + ee_w - 5) + { + fl_line(dragbox[DCY_2][0], dragbox[DCY_2][1], dragbox[RLS_1][0], + dragbox[RLS_1][1]); + if (type == mode) + fl_rectf(dragbox[RLS_1][0] - 4, dragbox[RLS_1][1] - 4, 9, 9); + } + else if (out == -1) + { + out = RLS_1; + goto Out; + } + if (dragbox[RLS_2][0] <= ee_x0 + ee_w - 5) + { + fl_line(dragbox[RLS_1][0], dragbox[RLS_1][1], dragbox[RLS_2][0], + dragbox[RLS_2][1]); + if (type == mode) + fl_rectf(dragbox[RLS_2][0] - 4, dragbox[RLS_2][1] - 4, 9, 9); + } + else if (out == -1) + out = RLS_2; + // draw partial line + Out: if (out != -1) + { + int x, y, x1, x2, y1, y2; + if (out == 0) + { + x1 = x0; + y1 = y0; + } + else + { + int tmp = 0; + switch (out) + { + case ATK_2: + tmp = ATK_1; + break; + case DCY_1: + tmp = ATK_2; + break; + case DCY_2: + tmp = DCY_1; + break; + case RLS_1: + tmp = DCY_2; + break; + case RLS_2: + tmp = RLS_1; + break; + } + x1 = dragbox[tmp][0]; + y1 = dragbox[tmp][1]; + } + x2 = dragbox[out][0]; + y2 = dragbox[out][1]; + x = ee_x0 + ee_w - 6; + y = (int) (y1 + ((float) (y2 - y1) / (float) (x2 - x1)) * (x - x1)); + fl_line(x1, y1, x, y); + } + fl_line_style(0); + if (type != mode) + return; + // highlight selected + if (hover >= 0 && dragbox[hover][0] <= ee_x0 + ee_w - 5) + { + fl_color(FL_SELECTION_COLOR); + fl_rectf(dragbox[hover][0] - 4, dragbox[hover][1] - 4, 9, 9); + } +} + +int Envelope_Editor::handle(int ev) +{ + static int dx, dy, phover = -1, first_drag; + switch (ev) + { + case FL_ENTER: + return 1; + + case FL_LEAVE: + fl_cursor(FL_CURSOR_DEFAULT); + if (hover > -1) + { + hover = -1; + redraw(); + } + return 1; + + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + if (hover != -1) + { + // switch selected dragbox + if (Fl::event_dy() > 0) + { + for (int i = hover + 1; i < 6; i++) + { + if (hover_list & (1 << i)) + { + hover = i; + redraw(); + break; + } + } + } + else + { + for (int i = hover - 1; i >= 0; i--) + { + if (hover_list & (1 << i)) + { + hover = i; + redraw(); + break; + } + } + } + } + else + { + // switch mode + if (Fl::event_dy() > 0) + mode += 1; + else + mode += modes - 1; + mode %= modes; + if (ui->syncview) + sync_view(layer); + redraw(); + } + return 1; + } + break; + + case FL_MOVE: + button_hover = -1; + phover = -1; + hover_list = 0; + // coordinate system + if (Fl::event_inside(ee_x0 + 2, ee_y0 + 22, ee_w - 4, ee_h - 43)) + { + for (int i = 0; i < 6; i++) + { + if (Fl::event_inside(dragbox[i][0] - 4, dragbox[i][1] - 4, 9, 9)) + { + phover = i; + if (hover == -1) + hover = i; + hover_list |= (1 << i); + } + } + if (phover == -1 && hover != -1) + { + fl_cursor(FL_CURSOR_DEFAULT); + hover = -1; + redraw(); + } + else if (hover != -1) + { + if (!(hover_list & (1 << hover))) + hover = phover; + fl_cursor(FL_CURSOR_CROSS); + redraw(); + } + } + // mode buttons + else if (Fl::event_inside(ee_x0, ee_y0, ee_w, 19)) + { + fl_cursor(FL_CURSOR_DEFAULT); + for (int i = 0; i < 5; i++) + if (Fl::event_inside(mode_button[i], ee_y0 + 5, 50, 14)) + button_hover = i; + } + // extra buttons + else if (Fl::event_inside(ee_x0, ee_y0 + ee_h - 18, ee_w, 15)) + { + fl_cursor(FL_CURSOR_DEFAULT); + + for (int i = 0; i < 6; i++) + { + if (Fl::event_inside(copy_button[i], ee_y0 + ee_h - 18, 16, 14)) + { + button_hover = i + VOLUME_SELECTED; + return 1; + } + } + for (int i = 0; i < 5; i++) + { + if (Fl::event_inside(shape_button[i], ee_y0 + ee_h - 18, 16, 14)) + { + button_hover = i + SHAPE_A; + return 1; + } + } + } + else + { + fl_cursor(FL_CURSOR_DEFAULT); + hover = -1; + redraw(); + } + return 1; + + case FL_PUSH: + first_drag = 1; // used only for zooming below + if (FL_LEFT_MOUSE == Fl::event_button()) + { + if (button_hover != -1) // mode buttons + { + button_push = true; + redraw(); + } + push_x = Fl::event_x(); + push_y = Fl::event_y(); + } + return 1; + + case FL_RELEASE: + fl_cursor(FL_CURSOR_DEFAULT); + if (button_push) + { + switch (button_hover) + { + case FACTORY: + if (mode == VOLUME) + { + if (env[mode].mode != FACTORY) + { + pd->widget_callback(1793, FACTORY, layer); + env[mode].mode = FACTORY; + } + } + else if (mode == FILTER) + { + if (env[FILTER].repeat) + { + pd->widget_callback(1833, 0, layer); + env[FILTER].repeat = 0; + } + else + { + pd->widget_callback(1833, 1, layer); + env[FILTER].repeat = 1; + } + } + else if (mode == AUXILIARY) + { + if (env[AUXILIARY].repeat) + { + pd->widget_callback(1834, 0, layer); + env[AUXILIARY].repeat = 0; + } + else + { + pd->widget_callback(1834, 1, layer); + env[AUXILIARY].repeat = 1; + } + } + break; + case TIME_BASED: + if (env[mode].mode != TIME_BASED) + { + pd->widget_callback(1793 + mode * 13, TIME_BASED, layer); + env[mode].mode = TIME_BASED; + } + break; + case TEMPO_BASED: + if (env[mode].mode != TEMPO_BASED) + { + pd->widget_callback(1793 + mode * 13, TEMPO_BASED, layer); + env[mode].mode = TEMPO_BASED; + } + break; + case OVERLAY: + overlay ? overlay = false : overlay = true; + if (ui->syncview) + sync_view(layer); + break; + case SYNC_VOICE_VIEW: + ui->syncview ? ui->syncview = 0 : ui->syncview = 1; + if (ui->syncview) + sync_view(layer); + break; + case VOLUME_SELECTED: + mode = VOLUME; + if (ui->syncview) + sync_view(layer); + break; + case FILTER_SELECTED: + mode = FILTER; + if (ui->syncview) + sync_view(layer); + break; + case AUXILIARY_SELECTED: + mode = AUXILIARY; + if (ui->syncview) + sync_view(layer); + break; + case CPY_VOLUME: + copy_envelope(mode, VOLUME); + break; + case CPY_FILTER: + copy_envelope(mode, FILTER); + break; + case CPY_AUXILIARY: + copy_envelope(mode, AUXILIARY); + break; + case SHAPE_A: + case SHAPE_B: + case SHAPE_C: + case SHAPE_D: + set_shape(mode, button_hover); + break; + } + } + button_push = false; + redraw(); + return 1; + + case FL_DRAG: + dx = Fl::event_x() - push_x; + dy = push_y - Fl::event_y(); + if (hover != -1) // drag the box if we hover it + { + hover_list = (1 << hover); + int dx_jump = 0; + if (zoomlevel < 1) + dx /= zoomlevel; // drag value is 2^n n>0 + else + { + if (dx % (int) zoomlevel != 0 && !(dx / zoomlevel)) // only drag +/-1 values + dx = 0; + else + { + dx_jump = dx % (int) zoomlevel; + dx /= zoomlevel; // should be +/-1 now + } + } + if (dx > 0 && env[mode].stage[hover][0] != 127) + { + if (env[mode].stage[hover][0] + dx < 127) + env[mode].stage[hover][0] += dx; + else + env[mode].stage[hover][0] = 127; + pd->widget_callback(1793 + 1 + mode * 13 + hover * 2, + env[mode].stage[hover][0], layer); + push_x = Fl::event_x() - dx_jump; + } + else if (dx < 0 && env[mode].stage[hover][0] != 0) + { + if (env[mode].stage[hover][0] + dx >= 0) + env[mode].stage[hover][0] += dx; + else + env[mode].stage[hover][0] = 0; + pd->widget_callback(1793 + 1 + mode * 13 + hover * 2, + env[mode].stage[hover][0], layer); + push_x = Fl::event_x() - dx_jump; + } + + if (dy > 0 && env[mode].stage[hover][1] != 100) + { + if (env[mode].stage[hover][1] + dy < 100) + env[mode].stage[hover][1] += dy; + else + env[mode].stage[hover][1] = 100; + pd->widget_callback(1793 + 2 + mode * 13 + hover * 2, + env[mode].stage[hover][1], layer); + push_y = Fl::event_y(); + } + else if (dy < 0) + { + if (mode == VOLUME && env[mode].stage[hover][1] != 0) + { + if (env[mode].stage[hover][1] + dy > 0) + env[mode].stage[hover][1] += dy; + else + env[mode].stage[hover][1] = 0; + pd->widget_callback(1793 + 2 + mode * 13 + hover * 2, + env[mode].stage[hover][1], layer); + push_y = Fl::event_y(); + } + else if (mode != VOLUME && env[mode].stage[hover][1] != -100) + { + if (env[mode].stage[hover][1] + dy > -100) + env[mode].stage[hover][1] += dy; + else + env[mode].stage[hover][1] = -100; + pd->widget_callback(1793 + 2 + mode * 13 + hover * 2, + env[mode].stage[hover][1], layer); + push_y = Fl::event_y(); + } + } + redraw(); + } + else if (button_hover == -1) // zoom + { + if ((abs(dx) > 5 && first_drag) || abs(dx) % 35 > 30) + { + if (dx < 0 && zoomlevel > 1) + { + zoomlevel /= 2; + redraw(); + if (ui->syncview) + sync_view(layer); + if (zoomlevel == 1) + { + push_x = Fl::event_x(); + first_drag = 1; + } + else + first_drag = 0; + } + else if (dx > 0 && zoomlevel < 4) + { + zoomlevel *= 2; + redraw(); + if (ui->syncview) + sync_view(layer); + if (zoomlevel == 4) + { + push_x = Fl::event_x(); + first_drag = 1; + } + else + first_drag = 0; + } + else + push_x = Fl::event_x(); + } + } + else if (button_hover >= 0) // lower button pushed + { + // extra buttons + if (button_hover >= SHAPE_A) + { + if (!Fl::event_inside(shape_button[button_hover - SHAPE_A], + ee_y0 + ee_h - 18, 16, 14)) + button_push = false; + else + button_push = true; + } + // copy + else if (button_hover >= VOLUME_SELECTED) + { + if (!Fl::event_inside( + copy_button[button_hover - VOLUME_SELECTED], + ee_y0 + ee_h - 18, 16, 14)) + button_push = false; + else + button_push = true; + } + else // top buttons + { + if (!Fl::event_inside(mode_button[button_hover], ee_y0 + 5, 50, + 14)) + button_push = false; + else + button_push = true; + } + redraw(); + } + return 1; + default: + break; + } + return Fl_Box::handle(ev); +} + +void Envelope_Editor::set_data(int type, int* stages, int mode, int repeat) +{ + pmesg(80, "Envelope_Editor::set_data(%d, int*, %d, %d)\n", type, mode, + repeat); + env[type].mode = mode; + env[type].repeat = repeat; + for (int i = 0; i < 6; i++) + { + env[type].stage[i][0] = *(stages + i * 2); + env[type].stage[i][1] = *(stages + i * 2 + 1); + } + redraw(); +} + +void Envelope_Editor::copy_envelope(int src, int dst) +{ + if (dst == src) + return; + for (int i = 0; i < 6; i++) + { + env[dst].stage[i][0] = env[src].stage[i][0]; + env[dst].stage[i][1] = env[src].stage[i][1]; + if (dst == VOLUME && env[src].stage[i][1] < 0) + env[dst].stage[i][1] = 0; + pd->widget_callback(1793 + 1 + dst * 13 + i * 2, env[dst].stage[i][0], + layer); + pd->widget_callback(1793 + 1 + dst * 13 + i * 2 + 1, + env[dst].stage[i][1], layer); + } + redraw(); +} + +void Envelope_Editor::set_shape(int dst, int shape) +{ + switch (shape) + { + case SHAPE_A: // prc + env[dst].stage[0][0] = 0; + env[dst].stage[0][1] = 100; + env[dst].stage[1][0] = 32; + env[dst].stage[1][1] = 0; + env[dst].stage[2][0] = 32; + env[dst].stage[2][1] = 0; + env[dst].stage[3][0] = 0; + env[dst].stage[3][1] = 100; + env[dst].stage[4][0] = 0; + env[dst].stage[4][1] = 0; + env[dst].stage[5][0] = 0; + env[dst].stage[5][1] = 0; + break; + case SHAPE_B: // organ + env[dst].stage[0][0] = 0; + env[dst].stage[0][1] = 100; + env[dst].stage[1][0] = 0; + env[dst].stage[1][1] = 100; + env[dst].stage[2][0] = 3; + env[dst].stage[2][1] = 0; + env[dst].stage[3][0] = 0; + env[dst].stage[3][1] = 100; + env[dst].stage[4][0] = 127; + env[dst].stage[4][1] = 100; + env[dst].stage[5][0] = 0; + env[dst].stage[5][1] = 0; + break; + case SHAPE_C: // string + env[dst].stage[0][0] = 23; + env[dst].stage[0][1] = 100; + env[dst].stage[1][0] = 0; + env[dst].stage[1][1] = 100; + env[dst].stage[2][0] = 58; + env[dst].stage[2][1] = 0; + env[dst].stage[3][0] = 0; + env[dst].stage[3][1] = 100; + env[dst].stage[4][0] = 80; + env[dst].stage[4][1] = 100; + env[dst].stage[5][0] = 0; + env[dst].stage[5][1] = 0; + break; + case SHAPE_D: // plucked + env[dst].stage[0][0] = 0; + env[dst].stage[0][1] = 100; + env[dst].stage[1][0] = 64; + env[dst].stage[1][1] = 50; + env[dst].stage[2][0] = 48; + env[dst].stage[2][1] = 0; + env[dst].stage[3][0] = 0; + env[dst].stage[3][1] = 100; + env[dst].stage[4][0] = 0; + env[dst].stage[4][1] = 0; + env[dst].stage[5][0] = 0; + env[dst].stage[5][1] = 0; + break; + } + redraw(); + if (!pd) // not there on init + return; + for (int i = 0; i < 6; i++) + { + pd->widget_callback(1793 + 1 + dst * 13 + i * 2, env[dst].stage[i][0], + layer); + pd->widget_callback(1793 + 1 + dst * 13 + i * 2 + 1, + env[dst].stage[i][1], layer); + } +} + +void Envelope_Editor::set_layer(int l) +{ + layer = l; +} + +void Envelope_Editor::sync_view(int l, int m, float z, bool o) +{ + if (l == layer) // set other + { + for (int i = 0; i < 4; i++) + { + if (i == layer) + continue; + ui->layer_editor[i]->envelope_editor->sync_view(layer, mode, + zoomlevel, overlay); + } + } + else // update ourselfes + { + if (ui->syncview) + { + mode = m; + zoomlevel = z; + overlay = o; + } + } +} + +// Piano keyboard widget +void Piano::draw() +{ + if (damage() & FL_DAMAGE_ALL) + { + draw_ranges(); + switch (mode) + { + case KEYRANGE: + draw_piano(); + // make sure we draw the transpose position + active_keys[72 - transpose[selected_transpose_layer]] = -1; + draw_highlights(); + draw_case(); + break; + case VELOCITY: + draw_curve(VELOCITY); + break; + case REALTIME: + draw_curve(REALTIME); + break; + } + return; + } + if (damage() & (FL_DAMAGE_ALL | D_RANGES)) + draw_ranges(); + if (damage() & (FL_DAMAGE_ALL | D_KEYS)) + draw_piano(); + if (damage() & (FL_DAMAGE_ALL | D_HIGHLIGHT)) + draw_highlights(); + if (damage() & (FL_DAMAGE_ALL | D_CASE)) + draw_case(); +} + +int Piano::handle(int ev) +{ + static int i = 0; + static int j = 0; + static int mx = 0; + mx = Fl::event_x() - w_black / 2; // dragbox beneath mousepointer + switch (ev) + { + case FL_LEAVE: + if (hovered_key != NONE) + { + if (mode == KEYRANGE) + activate_key(-1, hovered_key); + hovered_key = NONE; + previous_hovered_key = NONE; + } + fl_cursor(FL_CURSOR_DEFAULT); + return 1; + + case FL_MOUSEWHEEL: + // switch mode + int tmp; + if (Fl::event_dy() > 0) + tmp = mode + 1; + else + tmp = mode + modes - 1; + tmp %= modes; + ((Fl_Button*) ui->pi_mode->child(tmp))->setonly(); + set_mode(tmp); + return 1; + case FL_MOVE: + if (Fl::event_inside(keyboard_x0, keyboard_y0 + h_white, keyboard_w, + 120)) // ranges + { + if (hovered_key != NONE) + { + if (mode == KEYRANGE) + activate_key(-1, hovered_key); + hovered_key = NONE; + previous_hovered_key = NONE; + } + bool changed = false; + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (Fl::event_inside(dragbox[mode][i][j][0], + dragbox[mode][i][j][1], w_black, 8)) + { + fl_cursor(FL_CURSOR_CROSS); + highlight_dragbox[i][j] = 1; + changed = true; + } + else if (highlight_dragbox[i][j]) + { + highlight_dragbox[i][j] = 0; + changed = true; + } + if (changed) + damage(D_RANGES); + return 1; + } + else if (mode == KEYRANGE && Fl::event_inside(keyboard_x0, keyboard_y0, + keyboard_w, h_white)) // keys + calc_hovered(Fl::event_x(), Fl::event_y() - keyboard_y0); + else if (hovered_key != NONE) + { + if (mode == KEYRANGE) + activate_key(-1, hovered_key); + hovered_key = NONE; + previous_hovered_key = NONE; + } + fl_cursor(FL_CURSOR_DEFAULT); + return 1; + + case FL_PUSH: + push_x = 0; + pushed = NONE; + pushed_range = NONE; + switch (Fl::event_button()) + { + case FL_LEFT_MOUSE: + // play the piano + if (Fl::event_inside(keyboard_x0, keyboard_y0, keyboard_w, h_white) + && mode == KEYRANGE) + { + pushed = PIANO; + // press key + previous_hovered_key = hovered_key; + if (active_keys[hovered_key] > 1) + { + // ok, we press the key here so you might ask: + // why do you first send a note-off? + // answer: you cannot push a key twice without + // releasing it first. + midi->write_event(NOTE_OFF, hovered_key, 0); + midi->write_event(NOTE_ON, hovered_key, key_velocity); + } + else + midi->write_event(NOTE_ON, hovered_key, key_velocity); + active_keys[hovered_key] = 1; + damage(D_HIGHLIGHT); + } + else if (Fl::event_inside(keyboard_x0 - 10, keyboard_y0 + h_white, + keyboard_w + 15, 120)) + { + // pushed ranges + for (i = 0; i < 8; i++) + for (j = 0; j < 4; j++) + if (Fl::event_inside(dragbox[mode][i][j][0], + dragbox[mode][i][j][1], w_black, 8)) + { + if (mode == KEYRANGE) + { + if (j % 2 == 0) + hovered_key = prev_key_value[mode][i][j]; + else if (j == LOW_FADE) + hovered_key + = prev_key_value[mode][i][LOW_FADE] + + prev_key_value[mode][i][LOW_KEY]; + else + hovered_key + = prev_key_value[mode][i][HIGH_KEY] + - prev_key_value[mode][i][HIGH_FADE]; + previous_hovered_key = hovered_key; + if (active_keys[hovered_key] < 1) + active_keys[hovered_key] = 1; + damage(D_HIGHLIGHT); + } + pushed = i; // layer/arp + pushed_range = j; // key + return 1; + } + } + // set velocity + + else if (Fl::event_inside(keyboard_x0, keyboard_y0 - 10, + keyboard_w, 10) && mode == KEYRANGE) + push_x = Fl::event_x(); + break; + + case FL_MIDDLE_MOUSE: + // set transpose, middle-c == key 72 + if (Fl::event_inside(keyboard_x0, keyboard_y0, keyboard_w, h_white) + && mode == KEYRANGE) + { + transpose[selected_transpose_layer] = 72 - hovered_key; + pd->widget_callback(1429, transpose[selected_transpose_layer], + selected_transpose_layer); + damage(D_KEYS | D_HIGHLIGHT); + } + break; + + case FL_RIGHT_MOUSE: + if (Fl::event_inside(keyboard_x0, keyboard_y0, keyboard_w, h_white) + && mode == KEYRANGE) + { + // press + hold key + if (active_keys[hovered_key] > 1) + { + midi->write_event(NOTE_OFF, hovered_key, 0); + active_keys[hovered_key] = -1; + } + else + { + midi->write_event(NOTE_ON, hovered_key, key_velocity); + active_keys[hovered_key] = 2; + } + damage(D_HIGHLIGHT); + } + break; + } + return 1; + + case FL_DRAG: + switch (Fl::event_button()) + { + case FL_LEFT_MOUSE: + if (pushed == PIANO) + { + // dragging on keyboard + play_hovered_key = 1; + calc_hovered(Fl::event_x(), Fl::event_y() - keyboard_y0); + return 1; + } + if (pushed > NONE) + { + // fade value contraints are simple, just keep them inside the keyrange + if (pushed_range == LOW_FADE || pushed_range == HIGH_FADE) + { + if (mx < dragbox[mode][pushed][LOW_KEY][0]) + mx = dragbox[mode][pushed][LOW_KEY][0]; + else if (mx > dragbox[mode][pushed][HIGH_KEY][0]) + mx = dragbox[mode][pushed][HIGH_KEY][0]; + calc_hovered(mx + w_black / 2, 1); + } + // key values + else + { + // low key + if (pushed_range == LOW_KEY) + { + // arps return here + if (pushed == PRESET_ARP || pushed == MASTER_ARP + || pushed == LINK_ONE || pushed == LINK_TWO) + { + if (mx < keyboard_x0 + 3) + mx = keyboard_x0 + 3; + else if (mx > dragbox[0][pushed][HIGH_KEY][0]) + mx = dragbox[0][pushed][HIGH_KEY][0]; + calc_hovered(mx + w_black / 2, 1); + dragbox[0][pushed][pushed_range][0] = mx; + damage(D_RANGES); + return 1; + } + // lower edge + if (mx < keyboard_x0 + 3) + mx = keyboard_x0 + 3; + else if (mx > dragbox[mode][pushed][HIGH_KEY][0]) + mx = dragbox[mode][pushed][HIGH_KEY][0]; + calc_hovered(mx + w_black / 2, 1); + // high key aus der ecke schubsen + if (dragbox[mode][pushed][HIGH_KEY][0] <= keyboard_x0 + + 7 && dragbox[mode][pushed][LOW_KEY][0] + < keyboard_x0 + 7) + { + dragbox[mode][pushed][HIGH_KEY][0] = keyboard_x0 + + 14; + new_key_value[mode][pushed][HIGH_KEY] = 2; + commit_changes(); + } + // drag the fade value with me + dragbox[mode][pushed][LOW_FADE][0] += mx + - dragbox[mode][pushed][LOW_KEY][0]; + if (dragbox[mode][pushed][LOW_FADE][0] + > dragbox[mode][pushed][HIGH_KEY][0]) + { + dragbox[mode][pushed][LOW_FADE][0] + = dragbox[mode][pushed][HIGH_KEY][0]; + new_key_value[mode][pushed][LOW_FADE] + = prev_key_value[mode][pushed][HIGH_KEY] + - hovered_key; + } + // move the high key fade value away + if (dragbox[mode][pushed][HIGH_FADE][0] < mx) + { + dragbox[mode][pushed][HIGH_FADE][0] = mx; + new_key_value[mode][pushed][HIGH_FADE] + = prev_key_value[mode][pushed][HIGH_KEY] + - hovered_key; + } + } + // high key + + else + { + // arps return + if (pushed == PRESET_ARP || pushed == MASTER_ARP + || pushed == LINK_ONE || pushed == LINK_TWO) + { + if (mx > keyboard_w + keyboard_x0 - 9) + mx = keyboard_w + keyboard_x0 - 9; + else if (mx < dragbox[0][pushed][LOW_KEY][0]) + mx = dragbox[0][pushed][LOW_KEY][0]; + calc_hovered(mx + w_black / 2, 1); + dragbox[0][pushed][pushed_range][0] = mx; + damage(D_RANGES); + return 1; + } + // upper edge + if (mx > keyboard_w + keyboard_x0 - 9) + mx = keyboard_w + keyboard_x0 - 9; + else if (mx < dragbox[mode][pushed][LOW_KEY][0]) + mx = dragbox[mode][pushed][LOW_KEY][0]; + calc_hovered(mx + w_black / 2, 1); + // drag the fade value with me + dragbox[mode][pushed][HIGH_FADE][0] += mx + - dragbox[mode][pushed][HIGH_KEY][0]; + if (dragbox[mode][pushed][HIGH_FADE][0] + < dragbox[mode][pushed][LOW_KEY][0]) + { + dragbox[mode][pushed][HIGH_FADE][0] + = dragbox[mode][pushed][LOW_KEY][0]; + new_key_value[mode][pushed][HIGH_FADE] + = hovered_key + - prev_key_value[mode][pushed][LOW_KEY]; + } + // move the low key fade value away + if (dragbox[mode][pushed][LOW_FADE][0] > mx) + { + dragbox[mode][pushed][LOW_FADE][0] = mx; + new_key_value[mode][pushed][LOW_FADE] = hovered_key + - prev_key_value[mode][pushed][LOW_KEY]; + } + } + } + dragbox[mode][pushed][pushed_range][0] = mx; + if (mode == KEYRANGE) + damage(D_RANGES | D_HIGHLIGHT); + else + damage(FL_DAMAGE_ALL); + } + // velocity setup + + else if (push_x) + { + int dx = Fl::event_x() - push_x; + if (dx > 0) + { + if (key_velocity + dx <= 127) + key_velocity += dx; + else + key_velocity = 127; + } + else if (dx < 0) + { + if (key_velocity + dx >= 0) + key_velocity += dx; + else + key_velocity = 0; + } + push_x = Fl::event_x(); + damage(D_CASE); + } + } + return 1; + + case FL_RELEASE: + fl_cursor(FL_CURSOR_DEFAULT); + switch (Fl::event_button()) + { + case FL_LEFT_MOUSE: + if (mode == KEYRANGE && pushed == PIANO) + { + midi->write_event(NOTE_OFF, hovered_key, 0); + active_keys[hovered_key] = -1; + hovered_key = NONE; + previous_hovered_key = NONE; + play_hovered_key = 0; + pushed = NONE; + damage(D_HIGHLIGHT); + return 1; + } + // dragbox dragged: snap to grid + if (pushed > NONE && pushed != PIANO) + { + if (mode == KEYRANGE) + { + if (pushed_range % 2 == 0 + && dragbox[mode][pushed][pushed_range][0] + == dragbox[mode][pushed][pushed_range + 1][0]) + { + if (taste_x0[hovered_key][1] == 0) + { + dragbox[mode][pushed][pushed_range][0] + = taste_x0[hovered_key][0] + 3; + dragbox[mode][pushed][pushed_range + 1][0] + = taste_x0[hovered_key][0] + 3; + } + else + { + dragbox[mode][pushed][pushed_range][0] + = taste_x0[hovered_key][0]; + dragbox[mode][pushed][pushed_range + 1][0] + = taste_x0[hovered_key][0]; + } + } + else + { + if (taste_x0[hovered_key][1] == 0) + dragbox[mode][pushed][pushed_range][0] + = taste_x0[hovered_key][0] + 3; + else + dragbox[mode][pushed][pushed_range][0] + = taste_x0[hovered_key][0]; + } + damage(D_HIGHLIGHT); + } + highlight_dragbox[pushed][pushed_range] = 0; + pushed = NONE; + damage(D_RANGES); + } + } + return 1; + } + return Fl_Box::handle(ev); +} + +void Piano::draw_ranges() +{ + fl_push_clip(keyboard_x0 - 10, keyboard_y0 + h_white, keyboard_w + 15, 120); + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(keyboard_x0 - 10, keyboard_y0 + h_white + 1, keyboard_w + 15, 119); + fl_color(FL_SELECTION_COLOR); + fl_font(FL_COURIER, 10); + static int show_layers; + ui->eall ? show_layers = 1 : show_layers = 4; + char buf[4]; + for (int i = 0; i < show_layers; i++) + { + snprintf(buf, 4, "%d", i + 1); + fl_draw(buf, keyboard_x0 - 9, dragbox[mode][i][0][1] + 7); + } + if (mode == KEYRANGE) + { + // arps + snprintf(buf, 4, "P"); + fl_draw(buf, keyboard_x0 - 9, dragbox[0][4][0][1] + 7); + snprintf(buf, 4, "M"); + fl_draw(buf, keyboard_x0 - 9, dragbox[0][5][0][1] + 7); + // links + snprintf(buf, 4, "1"); + fl_draw(buf, keyboard_x0 - 9, dragbox[0][6][0][1] + 7); + snprintf(buf, 4, "2"); + fl_draw(buf, keyboard_x0 - 9, dragbox[0][7][0][1] + 7); + } + // draw grid + if (colors[BG] > 120) + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_BLACK, .8f)); + else + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_WHITE, .8f)); + if (mode == KEYRANGE) + { + for (int i = 0; i < 128; i++) + if (taste_x0[i][1] == 0) + { + fl_line_style(FL_SOLID, 1); + fl_line(taste_x0[i][0] + 7, dragbox[0][0][0][1] + 4, + taste_x0[i][0] + 7, dragbox[0][7][0][1]); + } + else + { + fl_line_style(FL_SOLID, 2); + fl_line(taste_x0[i][0] + 4, dragbox[0][0][0][1] + 8, + taste_x0[i][0] + 4, dragbox[0][7][0][1] + 4); + } + } + else + { + fl_line_style(FL_SOLID, 1); + int offset = keyboard_x0 + 4; + for (int i = 8; i < 128; i += 8) + fl_line(offset + 7 * i, dragbox[0][0][0][1] + 4, offset + 7 * i, + dragbox[0][3][0][1]); + } + + // draw selected ranges + for (int i = 0; i < show_layers; i++) // for all 4 layers + { + // key ranges + fl_color(fl_darker(FL_BACKGROUND2_COLOR)); + fl_rectf( + dragbox[mode][i][LOW_KEY][0], + dragbox[mode][i][LOW_KEY][1], + dragbox[mode][i][HIGH_KEY][0] - dragbox[mode][i][LOW_KEY][0] + + w_black, 4); + // fade ranges + // we want the selected range on top + if (highlight_dragbox[i][0] || highlight_dragbox[i][1]) + { + fl_color(FL_BACKGROUND2_COLOR); + fl_rectf( + dragbox[mode][i][HIGH_FADE][0], + dragbox[mode][i][HIGH_FADE][1], + dragbox[mode][i][HIGH_KEY][0] + - dragbox[mode][i][HIGH_FADE][0] + w_black, 4); + fl_color(FL_SELECTION_COLOR); + fl_rectf( + dragbox[mode][i][LOW_KEY][0], + dragbox[mode][i][LOW_FADE][1], + dragbox[mode][i][LOW_FADE][0] + - dragbox[mode][i][LOW_KEY][0] + w_black, 4); + } + else if (highlight_dragbox[i][2] || highlight_dragbox[i][3]) + { + fl_color(FL_BACKGROUND2_COLOR); + fl_rectf( + dragbox[mode][i][LOW_KEY][0], + dragbox[mode][i][LOW_FADE][1], + dragbox[mode][i][LOW_FADE][0] + - dragbox[mode][i][LOW_KEY][0] + w_black, 4); + fl_color(FL_SELECTION_COLOR); + fl_rectf( + dragbox[mode][i][HIGH_FADE][0], + dragbox[mode][i][HIGH_FADE][1], + dragbox[mode][i][HIGH_KEY][0] + - dragbox[mode][i][HIGH_FADE][0] + w_black, 4); + } + else + { + fl_color(FL_BACKGROUND2_COLOR); + fl_rectf( + dragbox[mode][i][LOW_KEY][0], + dragbox[mode][i][LOW_FADE][1], + dragbox[mode][i][LOW_FADE][0] + - dragbox[mode][i][LOW_KEY][0] + w_black, 4); + fl_rectf( + dragbox[mode][i][HIGH_FADE][0], + dragbox[mode][i][HIGH_FADE][1], + dragbox[mode][i][HIGH_KEY][0] + - dragbox[mode][i][HIGH_FADE][0] + w_black, 4); + } + // put handles on top + for (int j = 0; j < 4; j++) // for all 4 values + { + if (highlight_dragbox[i][j]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + if (j % 2) + fl_rectf(dragbox[mode][i][j][0], dragbox[mode][i][j][1], + w_black, 8); + else + fl_rectf(dragbox[mode][i][j][0], dragbox[mode][i][j][1], + w_black, 8); + } + } + if (mode == KEYRANGE) + { + // arp ranges + fl_color(fl_darker(FL_BACKGROUND2_COLOR)); + fl_rectf( + dragbox[0][4][LOW_KEY][0], + dragbox[0][4][LOW_KEY][1], + dragbox[0][4][HIGH_KEY][0] - dragbox[0][4][LOW_KEY][0] + + w_black, 4); + fl_rectf( + dragbox[0][5][LOW_KEY][0], + dragbox[0][5][LOW_KEY][1], + dragbox[0][5][HIGH_KEY][0] - dragbox[0][5][LOW_KEY][0] + + w_black, 4); + // link ranges + //fl_color(fl_darker(FL_SELECTION_COLOR)); + fl_rectf( + dragbox[0][6][LOW_KEY][0], + dragbox[0][6][LOW_KEY][1], + dragbox[0][6][HIGH_KEY][0] - dragbox[0][6][LOW_KEY][0] + + w_black, 4); + fl_rectf( + dragbox[0][7][LOW_KEY][0], + dragbox[0][7][LOW_KEY][1], + dragbox[0][7][HIGH_KEY][0] - dragbox[0][7][LOW_KEY][0] + + w_black, 4); + // arp handles + if (highlight_dragbox[4][LOW_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][4][LOW_KEY][0], dragbox[0][4][LOW_KEY][1], w_black, + 8); + if (highlight_dragbox[4][HIGH_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][4][HIGH_KEY][0], dragbox[0][4][HIGH_KEY][1], + w_black, 8); + if (highlight_dragbox[5][LOW_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][5][LOW_KEY][0], dragbox[0][5][LOW_KEY][1], w_black, + 8); + if (highlight_dragbox[5][HIGH_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][5][HIGH_KEY][0], dragbox[0][5][HIGH_KEY][1], + w_black, 8); + // link handles + if (highlight_dragbox[6][LOW_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][6][LOW_KEY][0], dragbox[0][6][LOW_KEY][1], w_black, + 8); + if (highlight_dragbox[6][HIGH_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][6][HIGH_KEY][0], dragbox[0][6][HIGH_KEY][1], + w_black, 8); + if (highlight_dragbox[7][LOW_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][7][LOW_KEY][0], dragbox[0][7][LOW_KEY][1], w_black, + 8); + if (highlight_dragbox[7][HIGH_KEY]) + fl_color(FL_SELECTION_COLOR); + else + fl_color(FL_FOREGROUND_COLOR); + fl_rectf(dragbox[0][7][HIGH_KEY][0], dragbox[0][7][HIGH_KEY][1], + w_black, 8); + } + fl_line_style(0); + fl_pop_clip(); +} + +void Piano::draw_piano() +{ + fl_push_clip(keyboard_x0, keyboard_y0, keyboard_w + 1, h_white); + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(keyboard_x0, keyboard_y0, keyboard_w + 1, h_white); + int tmp; + // white keys + fl_color(FL_BACKGROUND2_COLOR); + for (int i = 0; i < 11; i++) + { + tmp = 12 * i; + fl_rectf(taste_x0[0 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + fl_rectf(taste_x0[2 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + fl_rectf(taste_x0[4 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + fl_rectf(taste_x0[5 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + fl_rectf(taste_x0[7 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + if (i == 10) + break; + fl_rectf(taste_x0[9 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + fl_rectf(taste_x0[11 + tmp][0] + 1, keyboard_y0, w_white - 2, h_white); + } + + // black keys + fl_color(FL_BACKGROUND_COLOR); + for (int i = 0; i < 11; i++) + { + tmp = 12 * i; + fl_rectf(taste_x0[1 + tmp][0], keyboard_y0, w_black, h_black); + fl_rectf(taste_x0[3 + tmp][0], keyboard_y0, w_black, h_black); + fl_rectf(taste_x0[6 + tmp][0], keyboard_y0, w_black, h_black); + if (i == 10) + break; + fl_rectf(taste_x0[8 + tmp][0], keyboard_y0, w_black, h_black); + fl_rectf(taste_x0[10 + tmp][0], keyboard_y0, w_black, h_black); + } + fl_pop_clip(); +} + +void Piano::draw_highlights() +{ + for (int key = 0; key < 128; key++) + if (active_keys[key] != 0) + { + if (taste_x0[key][1] == 1) // black keys + { + if (key == 72 - transpose[selected_transpose_layer] + && active_keys[key] == -1) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, FL_GREEN, .8)); + else + { + if (active_keys[key] == 2) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, FL_RED, + .7)); + else + { + if (pushed == PIANO && key == hovered_key) + fl_color(FL_SELECTION_COLOR); + else if (active_keys[key] < 0) + fl_color(FL_BACKGROUND_COLOR); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + } + fl_rectf(taste_x0[key][0], keyboard_y0, w_black, h_black); + } + else // white keys + { + if (key == 72 - transpose[selected_transpose_layer] + && active_keys[key] == -1) + fl_color( + fl_color_average(FL_FOREGROUND_COLOR, FL_GREEN, .8)); + else + { + if (active_keys[key] == 2) + fl_color( + fl_color_average(FL_FOREGROUND_COLOR, FL_RED, + .7)); + else + { + if (pushed == PIANO && key == hovered_key) + fl_color(fl_darker(FL_SELECTION_COLOR)); + else if (active_keys[key] < 0) // deactivate key + fl_color(FL_FOREGROUND_COLOR); + else + fl_color(FL_SELECTION_COLOR); + } + } + fl_rectf(taste_x0[key][0] + 1, keyboard_y0, w_white - 2, + h_white); + // repaint black keys if a white key is hovered + int tmp; + if (key + 1 < 127 && key + 1 != hovered_key) + { + tmp = (key + 1) % 12; + if (tmp == 1 || tmp == 3 || tmp == 6 || tmp == 8 || tmp + == 10) + { + if (key + 1 == 72 - transpose[selected_transpose_layer] + && active_keys[key + 1] != 2) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, + FL_GREEN, .8)); + else + { + if (active_keys[key + 1] > 0) + { + if (active_keys[key + 1] == 2) + fl_color( + fl_color_average( + FL_BACKGROUND_COLOR, + FL_RED, .7)); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + else + fl_color(FL_BACKGROUND_COLOR); + } + fl_rectf(taste_x0[key + 1][0], keyboard_y0, w_black, + h_black); + } + } + if (key - 1 > 0) + { + tmp = (key - 1) % 12; + if (tmp == 1 || tmp == 3 || tmp == 6 || tmp == 8 || tmp + == 10) + { + if (key - 1 == hovered_key) + if (pushed == PIANO) + fl_color(FL_SELECTION_COLOR); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + else if (key - 1 == 72 + - transpose[selected_transpose_layer] + && active_keys[key - 1] != 2) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, + FL_GREEN, .8)); + else + { + if (active_keys[key - 1] > 0) + { + if (active_keys[key - 1] == 2) + fl_color( + fl_color_average( + FL_BACKGROUND_COLOR, + FL_RED, .7)); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + else + fl_color(FL_BACKGROUND_COLOR); + } + fl_rectf(taste_x0[key - 1][0], keyboard_y0, w_black, + h_black); + } + } + } + if (active_keys[key] < 0) + active_keys[key] = 0; + } +} + +void Piano::draw_case() +{ + fl_push_clip(keyboard_x0, keyboard_y0 - 12, keyboard_w + 1, 12); + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(keyboard_x0, keyboard_y0 - 12, keyboard_w + 1, 12); + fl_color(FL_SELECTION_COLOR); + fl_font(FL_COURIER, 10); + int offset = 7 * (w_white - 1); // octave + char buf[9]; + for (int i = 0; i < 11; i++) + { + snprintf(buf, 9, "C%d", i - 2); + fl_draw(buf, keyboard_x0 + i * offset, keyboard_y0 - 3); + } + fl_color(FL_FOREGROUND_COLOR); + snprintf(buf, 9, "pd"); + fl_draw(buf, keyboard_x0 + keyboard_w - 15, keyboard_y0 - 3); + // velocity + snprintf(buf, 9, "%3d", key_velocity); + fl_draw(buf, keyboard_x0 + 40, keyboard_y0 - 3); + fl_pop_clip(); +} + +void Piano::draw_curve(int type) +{ + fl_push_clip(keyboard_x0, keyboard_y0 - 12, keyboard_w + 1, 12 + h_white); + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(keyboard_x0, keyboard_y0 - 12, keyboard_w + 1, 12 + h_white); + fl_color(FL_SELECTION_COLOR); + fl_polygon(keyboard_x0 + 110, keyboard_h + keyboard_y0, + keyboard_w + keyboard_x0 - 3, keyboard_h + keyboard_y0, + keyboard_w + keyboard_x0 - 3, keyboard_y0); + fl_font(FL_COURIER, 10); + switch (type) + { + case VELOCITY: + fl_draw("VELOCITY CROSSFADE RANGE", keyboard_x0, keyboard_y0 - 3); + break; + case REALTIME: + fl_draw("REALTIME CROSSFADE RANGE", keyboard_x0, keyboard_y0 - 3); + break; + } + // values + char buf[30]; + fl_color(FL_FOREGROUND_COLOR); + fl_font(FL_COURIER, 8); + for (int i = 0; i < 4; i++) + { + snprintf(buf, 30, "L%d %3d %3d %3d %3d", i + 1, + new_key_value[mode][i][LOW_KEY], + new_key_value[mode][i][LOW_FADE], + new_key_value[mode][i][HIGH_KEY], + new_key_value[mode][i][HIGH_FADE]); + fl_draw(buf, keyboard_x0 + 3, keyboard_y0 + 8 + i * 8); + } + fl_pop_clip(); +} + +void Piano::calc_hovered(int x, int y) +{ + if (x <= keyboard_x0) + hovered_key = 0; + else if (x >= keyboard_x0 + keyboard_w) + hovered_key = 127; + else + { + hovered_key = 0; + if (y < h_black) // black and white-key area + { + while (hovered_key < 127) + { + ++hovered_key; + if (taste_x0[hovered_key][0] >= x || hovered_key == 127) + { + if (hovered_key != 127) + --hovered_key; + if (hovered_key == 0) + break; + if (taste_x0[hovered_key - 1][1] && taste_x0[hovered_key + - 1][0] + w_black >= x) + --hovered_key; + break; + } + } + } + else // only white-keys area (lower area of keyboard) + { + while (hovered_key < 127) + { + ++hovered_key; + if (taste_x0[hovered_key][0] >= x) + { + --hovered_key; + if (hovered_key == 0) + break; + if (taste_x0[hovered_key][1] == 1) + --hovered_key; + break; + } + } + } + } + if (previous_hovered_key != hovered_key) + { + if (play_hovered_key == 1) + { + midi->write_event(NOTE_ON, hovered_key, key_velocity); + if (previous_hovered_key != NONE) + midi->write_event(NOTE_OFF, previous_hovered_key, 0); + } + else if (pushed > NONE) + { + if (pushed == PRESET_ARP || pushed == MASTER_ARP) + new_key_value[0][pushed][pushed_range] = hovered_key; + else + { + if (pushed_range == HIGH_KEY || pushed_range == LOW_KEY) + new_key_value[mode][pushed][pushed_range] = hovered_key; + else if (pushed_range == LOW_FADE) + new_key_value[mode][pushed][pushed_range] = hovered_key + - new_key_value[mode][pushed][LOW_KEY]; + else if (pushed_range == HIGH_FADE) + new_key_value[mode][pushed][pushed_range] + = new_key_value[mode][pushed][HIGH_KEY] + - hovered_key; + } + commit_changes(); + } + if (mode == KEYRANGE) + { + if (active_keys[hovered_key] < 1) + active_keys[hovered_key] = 1; + if (previous_hovered_key != NONE) + if (active_keys[previous_hovered_key] < 2 || play_hovered_key + == 1) + active_keys[previous_hovered_key] = -1; + damage(D_HIGHLIGHT); + } + } + previous_hovered_key = hovered_key; +} + +void Piano::select_transpose_layer(int l) +{ + active_keys[72 - transpose[selected_transpose_layer]] = -1; + selected_transpose_layer = l; + active_keys[72 - transpose[selected_transpose_layer]] = -1; + damage(D_HIGHLIGHT); +} + +void Piano::set_mode(int m) +{ + mode = m; + if (mode == KEYRANGE) + { + ui->g_transpose_layer->activate(); + active_keys[72 - transpose[selected_transpose_layer]] = -1; + } + else + ui->g_transpose_layer->deactivate(); + damage(FL_DAMAGE_ALL); +} + +// called by midi->process_not_sysex to highlight incoming midi events +// on the keyboard +void Piano::activate_key(int value, int key) +{ + if (active_keys[key] == value || (active_keys[key] == 2 && value == -1) + || (pushed != NONE && key == hovered_key)) + return; + active_keys[key] += value; + if (active_keys[key] > 3) + active_keys[key] = 3; + else if (active_keys[key] < 1) + active_keys[key] = -1; + if (!visible_r() || mode != KEYRANGE) + return; + damage(D_HIGHLIGHT); +} + +void Piano::reset_active_keys() +{ + for (int i = 0; i < 128; i++) + if (active_keys[i] > 0) + active_keys[i] = -1; + if (mode == KEYRANGE) + damage(D_HIGHLIGHT); +} + +// map keys to 2-d space +void Piano::set_range_values(int md, int layer, int low_k, int low_f, + int high_k, int high_f) +{ + pmesg(80, "Piano::set_range_values(%d, %d, %d, %d, %d, %d)\n", md, layer, + low_k, low_f, high_k, high_f); + if (low_k < 0 || low_k > 127) + low_k = 0; + if (low_f < 0 || low_f + low_k > 127) + low_f = 0; + if (high_k < 0 || high_k > 127) + high_k = 127; + if (high_f < 0 || high_k - high_f < 0) + high_f = 0; + dragbox[md][layer][LOW_KEY][0] = taste_x0[low_k][0]; + dragbox[md][layer][LOW_FADE][0] = taste_x0[low_k + low_f][0]; + dragbox[md][layer][HIGH_KEY][0] = taste_x0[high_k][0]; + dragbox[md][layer][HIGH_FADE][0] = taste_x0[high_k - high_f][0]; + for (int i = 0; i < 4; i++) // center on white keys + { + if ((dragbox[md][layer][i][0] - keyboard_x0) % 12 == 0) + dragbox[md][layer][i][0] += 3; // center on white keys + } + // remember current values + prev_key_value[md][layer][LOW_KEY] = low_k; + prev_key_value[md][layer][LOW_FADE] = low_f; + prev_key_value[md][layer][HIGH_KEY] = high_k; + prev_key_value[md][layer][HIGH_FADE] = high_f; + new_key_value[md][layer][LOW_KEY] = low_k; + new_key_value[md][layer][LOW_FADE] = low_f; + new_key_value[md][layer][HIGH_KEY] = high_k; + new_key_value[md][layer][HIGH_FADE] = high_f; + if (visible_r()) + damage(D_RANGES); +} + +void Piano::set_transpose(int l1, int l2, int l3, int l4) +{ + pmesg(80, "Piano::set_transpose(%d, %d, %d, %d)\n", l1, l2, l3, l4); + transpose[0] = l1; + transpose[1] = l2; + transpose[2] = l3; + transpose[3] = l4; + active_keys[72 - transpose[selected_transpose_layer]] = -1; + if (visible_r() && mode == KEYRANGE) + damage(D_HIGHLIGHT); +} + +void Piano::commit_changes() +{ + pmesg(80, "Piano::commit_changes()\n"); + if (pushed < PRESET_ARP) + { + for (int range = 0; range < 4; range++) + { + if (prev_key_value[mode][pushed][range] + != new_key_value[mode][pushed][range]) + { + int id = 1413; + switch (range) + { + case LOW_KEY: + pd->widget_callback(id + LOW_KEY + mode * 4, + new_key_value[mode][pushed][range], pushed); + break; + case LOW_FADE: + pd->widget_callback(id + LOW_FADE + mode * 4, + new_key_value[mode][pushed][range], pushed); + break; + case HIGH_KEY: + pd->widget_callback(id + HIGH_KEY + mode * 4, + new_key_value[mode][pushed][range], pushed); + break; + case HIGH_FADE: + pd->widget_callback(id + HIGH_FADE + mode * 4, + new_key_value[mode][pushed][range], pushed); + } + prev_key_value[mode][pushed][range] + = new_key_value[mode][pushed][range]; + } + } + } + else + { + if (prev_key_value[0][pushed][pushed_range] + != new_key_value[0][pushed][pushed_range]) + { + switch (pushed) + { + case PRESET_ARP: + if (pushed_range == LOW_KEY) + pd->widget_callback(1039, + new_key_value[0][pushed][pushed_range], 0); + else + pd->widget_callback(1040, + new_key_value[0][pushed][pushed_range], 0); + break; + case MASTER_ARP: + if (pushed_range == LOW_KEY) + pd->widget_callback(655, + new_key_value[0][pushed][pushed_range], 0); + else + pd->widget_callback(656, + new_key_value[0][pushed][pushed_range], 0); + break; + case LINK_ONE: + if (pushed_range == LOW_KEY) + pd->widget_callback(1286, + new_key_value[0][pushed][pushed_range], 0); + else + pd->widget_callback(1287, + new_key_value[0][pushed][pushed_range], 0); + break; + case LINK_TWO: + if (pushed_range == LOW_KEY) + pd->widget_callback(1295, + new_key_value[0][pushed][pushed_range], 0); + else + pd->widget_callback(1296, + new_key_value[0][pushed][pushed_range], 0); + break; + } + prev_key_value[0][pushed][pushed_range] + = new_key_value[0][pushed][pushed_range]; + } + } +} + +// MiniPiano keyboard widget +void MiniPiano::draw() +{ + if (damage() & FL_DAMAGE_ALL) + { + draw_piano(); + draw_highlights(); + draw_case(); + return; + } + if (damage() & (FL_DAMAGE_ALL | D_KEYS)) + draw_piano(); + if (damage() & (FL_DAMAGE_ALL | D_HIGHLIGHT)) + draw_highlights(); + if (damage() & (FL_DAMAGE_ALL | D_CASE)) + draw_case(); +} + +void MiniPiano::draw_case() +{ + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(key_x, keyboard_y0, key_w, 12); + fl_color(FL_FOREGROUND_COLOR); + fl_font(FL_COURIER, 10); + // velocity + char buf[8]; + snprintf(buf, 8, "Vel %3d", key_velocity); + fl_draw(buf, key_x + 3, key_y - 3); + // position + snprintf(buf, 4, "C%d", octave - 1); + fl_draw(buf, key_x + key_w / 2 - 8, key_y - 3); + // octave shift + fl_color(FL_SELECTION_COLOR); + fl_polygon(key_x + key_w / 2 - 15, key_y - 3, key_x + key_w / 2 - 15, + key_y - 10, key_x + key_w / 2 - 30, key_y - 6); + fl_polygon(key_x + key_w / 2 + 15, key_y - 3, key_x + key_w / 2 + 15, + key_y - 10, key_x + key_w / 2 + 30, key_y - 6); +} + +void MiniPiano::draw_highlights() +{ + for (int key = 12 * octave; key <= (12 * octave + 24); key++) + if (active_keys[key] != 0) + { + int mapped_key = key - octave * 12; + if (taste_x0[key][1] == 1) // black keys (FL_BACKGROUND_COLOR) + { + if (active_keys[key] == 2) + fl_color(fl_color_average(FL_BACKGROUND_COLOR, FL_RED, .7)); + else + { + if (pushed == PIANO && key == hovered_key) + fl_color(FL_SELECTION_COLOR); + else if (active_keys[key] < 0) + fl_color(FL_BACKGROUND_COLOR); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + fl_rectf(taste_x0[mapped_key][0], key_y, w_black, h_black); + } + else // white keys FL_FOREGROUND_COLOR + { + if (active_keys[key] == 2) + fl_color(fl_color_average(FL_FOREGROUND_COLOR, FL_RED, .7)); + else + { + if (pushed == PIANO && key == hovered_key) + fl_color(fl_darker(FL_SELECTION_COLOR)); + else if (active_keys[key] < 0) // deactivate key + fl_color(FL_FOREGROUND_COLOR); + else + fl_color(FL_SELECTION_COLOR); + } + fl_rectf(taste_x0[mapped_key][0], key_y, w_white - 2, h_white); + // repaint black keys if a white key is hovered + if (mapped_key == 24) + continue; + int tmp; + if (key + 1 < 127) + { + tmp = (key + 1) % 12; + if (tmp == 1 || tmp == 3 || tmp == 6 || tmp == 8 || tmp + == 10) + { + if (active_keys[key + 1] == 2) + { + if (active_keys[key + 1] == 2) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, + FL_RED, .7)); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + else + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(taste_x0[mapped_key + 1][0], key_y, w_black, + h_black); + } + } + if (key - 1 > 0) + { + tmp = (key - 1) % 12; + if (tmp == 1 || tmp == 3 || tmp == 6 || tmp == 8 || tmp + == 10) + { + if (key - 1 == hovered_key) + if (pushed == PIANO) + fl_color(FL_SELECTION_COLOR); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + else if (active_keys[key - 1] > 0) + { + if (active_keys[key - 1] == 2) + fl_color( + fl_color_average(FL_BACKGROUND_COLOR, + FL_RED, .7)); + else + fl_color(fl_darker(FL_SELECTION_COLOR)); + } + else + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(taste_x0[mapped_key - 1][0], key_y, w_black, + h_black); + } + } + } + if (active_keys[key] < 0) + active_keys[key] = 0; + } +} + +void MiniPiano::draw_piano() +{ + // get our position and key koordinates + keyboard_x0 = this->x(); + keyboard_y0 = this->y(); + keyboard_w = this->w(); + keyboard_h = this->h(); + + // keys start/end here + key_x = keyboard_x0 + 3; + key_w = keyboard_w - 6; + // tasten- hoehen/-breiten + h_white = (float) keyboard_h - 15.; + w_white = (float) (key_w + 14.) / 15.; + h_black = h_white * 5. / 8.; + w_black = w_white * 7. / 13.; + // spalten + float s = 14. / 15.; + // start of keys (y-axis) + key_y = (float) keyboard_y0 + 12; + fl_push_clip(key_x, key_y, key_w, h_white); + fl_color(FL_BACKGROUND_COLOR); + fl_rectf(key_x, key_y, key_w, h_white); + static float offset = 1.; + for (int i = 0; i < 11; i++) + { + // for each octave on the keyboard + int octave = i * 12; + taste_x0[0 + octave][0] = key_x + offset; + taste_x0[0 + octave][1] = 0.; + taste_x0[1 + octave][0] = key_x + w_white - s - w_black / 2. + offset; + taste_x0[1 + octave][1] = 1.; + taste_x0[2 + octave][0] = key_x + w_white - s + offset; + taste_x0[2 + octave][1] = 0.; + taste_x0[3 + octave][0] = key_x + w_white - s - w_black / 2. + (w_white + - s) + offset; + taste_x0[3 + octave][1] = 1.; + taste_x0[4 + octave][0] = key_x + 2. * (w_white - s) + offset; + taste_x0[4 + octave][1] = 0.; + taste_x0[5 + octave][0] = key_x + 3. * (w_white - s) + offset; + taste_x0[5 + octave][1] = 0.; + taste_x0[6 + octave][0] = key_x + w_white - s - w_black / 2. + 3. + * (w_white - s) + offset; + taste_x0[6 + octave][1] = 1.; + taste_x0[7 + octave][0] = key_x + 4. * (w_white - s) + offset; + taste_x0[7 + octave][1] = 0.; + if (i == 10) // keyboard is smaller than full 10 full octaves + break; + taste_x0[8 + octave][0] = key_x + w_white - s - w_black / 2. + 4. + * (w_white - s) + offset; + taste_x0[8 + octave][1] = 1.; + taste_x0[9 + octave][0] = key_x + 5. * (w_white - s) + offset; + taste_x0[9 + octave][1] = 0.; + taste_x0[10 + octave][0] = key_x + w_white - s - w_black / 2. + 5. + * (w_white - s) + offset; + taste_x0[10 + octave][1] = 1.; + taste_x0[11 + octave][0] = key_x + 6. * (w_white - s) + offset; + taste_x0[11 + octave][1] = 0.; + offset += 7. * (w_white - s); + } + offset = 1.; + // keys + int octa; + // white keys + fl_color(FL_FOREGROUND_COLOR); + for (int i = 0; i < 3; i++) + { + octa = 12 * i; + fl_rectf(taste_x0[0 + octa][0], key_y, w_white - 2, h_white); + if (i == 2) + continue; + fl_rectf(taste_x0[2 + octa][0], key_y, w_white - 2, h_white); + fl_rectf(taste_x0[4 + octa][0], key_y, w_white - 2, h_white); + fl_rectf(taste_x0[5 + octa][0], key_y, w_white - 2, h_white); + fl_rectf(taste_x0[7 + octa][0], key_y, w_white - 2, h_white); + fl_rectf(taste_x0[9 + octa][0], key_y, w_white - 2, h_white); + fl_rectf(taste_x0[11 + octa][0], key_y, w_white - 2, h_white); + } + // black keys + fl_color(FL_BACKGROUND_COLOR); + for (int i = 0; i < 2; i++) + { + octa = 12 * i; + fl_rectf(taste_x0[1 + octa][0], key_y, w_black, h_black); + fl_rectf(taste_x0[3 + octa][0], key_y, w_black, h_black); + fl_rectf(taste_x0[6 + octa][0], key_y, w_black, h_black); + fl_rectf(taste_x0[8 + octa][0], key_y, w_black, h_black); + fl_rectf(taste_x0[10 + octa][0], key_y, w_black, h_black); + } + fl_pop_clip(); +} + +int MiniPiano::handle(int ev) +{ + switch (ev) + { + case FL_ENTER: + return 1; + case FL_LEAVE: + if (hovered_key != NONE) + { + activate_key(-1, hovered_key); + hovered_key = NONE; + previous_hovered_key = NONE; + } + return 1; + case FL_MOVE: + if (Fl::event_inside(key_x, key_y, key_w, h_white)) + calc_hovered(Fl::event_x(), Fl::event_y() - key_y); + else if (hovered_key != NONE) + { + activate_key(-1, hovered_key); + hovered_key = NONE; + previous_hovered_key = NONE; + } + return 1; + + case FL_PUSH: + push_x = 0; + pushed = NONE; + switch (Fl::event_button()) + { + case FL_LEFT_MOUSE: + // play the piano + if (Fl::event_inside(key_x, key_y, key_w, h_white)) + { + pushed = PIANO; + // press key + previous_hovered_key = hovered_key; + if (active_keys[hovered_key] > 1) + { + // ok, we press the key here so you might ask: + // why do you first send a note-off? + // answer: you cannot push a key twice without + // releasing it first. + midi->write_event(NOTE_OFF, hovered_key, 0); + midi->write_event(NOTE_ON, hovered_key, key_velocity); + } + else + midi->write_event(NOTE_ON, hovered_key, key_velocity); + active_keys[hovered_key] = 1; + damage(D_HIGHLIGHT); + } + // set velocity or shift octave + else if (Fl::event_inside(keyboard_x0, keyboard_y0, keyboard_w, + keyboard_h - h_white)) + { + if (Fl::event_inside(keyboard_x0 + keyboard_w / 2 - 30, + keyboard_y0, 30, keyboard_h / 3)) + shift_octave(-1); + else if (Fl::event_inside(keyboard_x0 + keyboard_w / 2, + keyboard_y0, 30, keyboard_h / 3)) // shift octave + shift_octave(1); + else + // set velo + push_x = Fl::event_x(); + } + break; + case FL_RIGHT_MOUSE: + if (Fl::event_inside(key_x, key_y, key_w, h_white)) + { + // press + hold key + if (active_keys[hovered_key] > 1) + { + midi->write_event(NOTE_OFF, hovered_key, 0); + active_keys[hovered_key] = -1; + } + else + { + midi->write_event(NOTE_ON, hovered_key, key_velocity); + active_keys[hovered_key] = 2; + } + damage(D_HIGHLIGHT); + } + } + return 1; + + case FL_DRAG: + if (FL_LEFT_MOUSE == Fl::event_button()) + { + if (pushed == PIANO) + { + // dragging on keyboard + play_hovered_key = 1; + calc_hovered(Fl::event_x(), Fl::event_y() - key_y); + return 1; + } + // velocity setup + else if (push_x) + { + int dx = Fl::event_x() - push_x; + if (dx > 0) + { + if (key_velocity + dx <= 127) + key_velocity += dx; + else + key_velocity = 127; + } + else if (dx < 0) + { + if (key_velocity + dx >= 0) + key_velocity += dx; + else + key_velocity = 0; + } + push_x = Fl::event_x(); + damage(D_CASE); + } + } + return 1; + + case FL_RELEASE: + if (FL_LEFT_MOUSE == Fl::event_button() && pushed == PIANO) + { + midi->write_event(NOTE_OFF, hovered_key, 0); + active_keys[hovered_key] = -1; + hovered_key = NONE; + previous_hovered_key = NONE; + play_hovered_key = 0; + pushed = NONE; + damage(D_HIGHLIGHT); + return 1; + } + return 1; + } + return Fl_Box::handle(ev); +} + +void MiniPiano::shift_octave(int shift) +{ + octave += shift; + if (octave < 0) + octave = 0; + else if (octave > 8) + octave = 8; + redraw(); +} + +void MiniPiano::calc_hovered(int x, int y) +{ + if (x <= key_x) + hovered_key = octave * 12; + else if (x >= key_x + key_w - w_white) + hovered_key = 24 + octave * 12; + else + { + hovered_key = 0; + if (y < h_black) // black and white-key area + { + while (hovered_key < 24) + { + ++hovered_key; + if (taste_x0[hovered_key][0] >= x) + { + --hovered_key; + if (hovered_key == 0) + break; + if (taste_x0[hovered_key - 1][0] + w_black >= x) + --hovered_key; + break; + } + } + } + else // only white-keys area (lower area of keyboard) + { + while (++hovered_key < 25) + { + if (taste_x0[hovered_key][0] >= x) + { + --hovered_key; + if (hovered_key == 0) + break; + if (taste_x0[hovered_key][1] == 1) + --hovered_key; + break; + } + } + } + hovered_key += octave * 12; + } + if (previous_hovered_key != hovered_key) + { + if (play_hovered_key == 1) + { + midi->write_event(NOTE_ON, hovered_key, key_velocity); + if (previous_hovered_key != NONE) + midi->write_event(NOTE_OFF, previous_hovered_key, 0); + } + if (active_keys[hovered_key] < 1) + active_keys[hovered_key] = 1; + if (previous_hovered_key != NONE) + if (active_keys[previous_hovered_key] < 2 || play_hovered_key == 1) + active_keys[previous_hovered_key] = -1; + damage(D_HIGHLIGHT); + } + previous_hovered_key = hovered_key; +} + +// called by midi->process_not_sysex to highlight incoming midi events +// on the keyboard +void MiniPiano::activate_key(int value, int key) +{ + if (active_keys[key] == value || (active_keys[key] == 2 && value == -1)) + return; + active_keys[key] += value; + if (active_keys[key] > 3) + active_keys[key] = 3; + else if (active_keys[key] < 1) + active_keys[key] = -1; + if (!visible_r() || key > 12 * octave + 24 || key < 12 * octave) + return; + damage(D_HIGHLIGHT); +} + +void MiniPiano::reset_active_keys() +{ + for (int i = 0; i < 128; i++) + if (active_keys[i] > 0) + active_keys[i] = -1; + damage(D_HIGHLIGHT); +} + +// ################### +// +// ################### +int Pitch_Slider::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + hold = true; + else + hold = false; + break; + case FL_RELEASE: + if (!hold) + { + value(8192.); + do_callback(); + return 1; + } + break; + } + return Fl_Slider::handle(ev); +} + +// ################### +// +// ################### +void Step_Type::set_step(int step) +{ + s = step; +} + +int Step_Type::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->arp) + { + pd->arp->reset_step(s); + return 1; + } + break; + } + return Fl_Group::handle(ev); +} + +// ################### +// +// ################### +void Step_Value::set_id(int i, int step) +{ + id = i; + s = step; +} + +int Step_Value::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->arp) + { + value((double) pd->arp->get_value(id, s)); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = v1 - dy; + if (v2 < minimum()) + v2 = maximum(); + else if (v2 > maximum()) + v2 = minimum(); + value(v2); + do_callback(); + return 1; + } + break; + } + return Fl_Value_Output::handle(ev); +} + +int Step_Value::format(char *buf) +{ + if (id == 786) + return snprintf(buf, 6, "%s", rates[25 - (int) value()]); + return sprintf(buf, "%d", (int) value()); +} + +// ################### +// +// ################### +void Step_Offset::set_step(int step) +{ + s = step; +} + +int Step_Offset::handle(int ev) +{ + switch (ev) + { + case FL_PUSH: + if (FL_RIGHT_MOUSE == Fl::event_button()) + return 1; + take_focus(); + break; + case FL_RELEASE: + if (FL_RIGHT_MOUSE == Fl::event_button() && pd->arp) + { + int val = pd->arp->get_value(784, s); + if (val > -49) + value((double) val); + else + value(0.); + do_callback(); + return 1; + } + break; + case FL_MOUSEWHEEL: + if (this == Fl::belowmouse()) + { + int dy = Fl::event_dy(); + double v1 = value(); + double v2 = clamp(increment(v1, dy)); + if (v1 == v2) + return 1; + value(v2); + do_callback(); + return 1; + } + break; + case FL_DRAG: + if (FL_BUTTON3 & Fl::event_state()) + return 1; + } + int sxx = x(), syy = y(), sww = w(), shh = h(); + syy += 18; + shh -= 18; + return Fl_Slider::handle(ev, sxx + Fl::box_dx(box()), + syy + Fl::box_dy(box()), sww - Fl::box_dw(box()), + shh - Fl::box_dh(box())); +} + +void Step_Offset::draw(int X, int Y, int W, int H) +{ + double val; + if (minimum() == maximum()) + val = 0.5; + else + { + val = (value() - minimum()) / (maximum() - minimum()); + if (val > 1.0) + val = 1.0; + else if (val < 0.0) + val = 0.0; + } + int ww = H; + int xx, S; + S = 17; + xx = int(val * (ww - S) + .5); + int xsl, ysl, wsl, hsl; + ysl = Y + xx; + hsl = S; + xsl = X; + wsl = W - 1; + fl_push_clip(X, Y, W, H); + draw_box(); + draw_box(FL_FLAT_BOX, X + 2, Y + 2, W - 5, xx + 5, FL_INACTIVE_COLOR); + //draw_box(FL_FLAT_BOX, X, Y + xx, W - 1, H - xx, FL_INACTIVE_COLOR); + fl_pop_clip(); + if (wsl > 0 && hsl > 0) + draw_box(FL_THIN_UP_BOX, xsl, ysl, wsl, hsl, selection_color()); + + draw_label(xsl, ysl, wsl, hsl); + if (Fl::focus() == this) + draw_focus(FL_BORDER_BOX, xsl, ysl, wsl, hsl); +} + +void Step_Offset::draw() +{ + + int sxx = x(), syy = y(), sww = w(), shh = h(); + int bxx = x(), byy = y(), bww = w(), bhh = h(); + syy += 18; // height of value output + bhh = 18; + shh -= 18; + if (damage() & FL_DAMAGE_ALL) + draw_box(box(), sxx, syy, sww, shh, color()); + draw(sxx + Fl::box_dx(box()), syy + Fl::box_dy(box()), + sww - Fl::box_dw(box()), shh - Fl::box_dh(box())); + draw_box(box(), bxx, byy, bww, bhh, FL_BACKGROUND_COLOR); + const char* transpose_values[] = + { "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B " }; + int v = (int) value(); + int p = v % 12; + if (v < 0 && p != 0) + p += 12; + char buf[6]; + snprintf(buf, 6, "%s%+3d", transpose_values[p], v); + fl_font(textfont(), textsize()); + fl_color(active_r() ? textcolor() : fl_inactive(textcolor())); + fl_draw(buf, bxx, byy, bww, bhh, FL_ALIGN_CLIP); +} + +// Text_Display +void Text_Display::resize(int X, int Y, int W, int H) +{ + if (w() != W) + wrap_mode(1, W / c_w - 4); + // if (w() != W || h() != H) + // show_insert_position(); + Fl_Text_Display::resize(X, Y, W, H); +} diff --git a/widgets.H b/widgets.H new file mode 100644 index 0000000..1bca0b1 --- /dev/null +++ b/widgets.H @@ -0,0 +1,1279 @@ +// $Id$ + +/** + \defgroup pd_widgets prodatum Widgets + @{ + */ + +/* + int ret = ::handle(ev); + if (!foo) + return ret; + switch (ev) + { + // Mouse Events + case FL_ENTER: // 1 = receive FL_LEAVE and FL_MOVE events (widget becomes Fl::belowmouse()) + case FL_LEAVE: + case FL_MOVE: // sent to Fl::belowmouse() + case FL_PUSH: // 1 = receive FL_DRAG and the matching (Fl::event_button()) FL_RELEASE event (becomes Fl::pushed()) + case FL_RELEASE: + case FL_DRAG: // button state is in Fl::event_state() (FL_SHIFT FL_CAPS_LOCK FL_CTRL FL_ALT FL_NUM_LOCK FL_META FL_SCROLL_LOCK FL_BUTTON1 FL_BUTTON2 FL_BUTTON3) + case FL_MOUSEWHEEL: + // keyboard events + case FL_FOCUS: // 1 = receive FL_KEYDOWN, FL_KEYUP, and FL_UNFOCUS events (widget becomes Fl::focus()) + case FL_UNFOCUS: // received when another widget gets the focus and we had the focus + case FL_KEYDOWN: // key press (Fl::event_key()) + case FL_KEYUP: // key release (Fl::event_key()) + // DND events + case FL_DND_ENTER: // 1 = receive FL_DND_DRAG, FL_DND_LEAVE and FL_DND_RELEASE events + case FL_DND_DRAG: // to indicate if we want the data + case FL_DND_RELEASE: // 1 = receive FL_PASTE + } + return ret; + */ + +#ifndef WIDGETS_H_ +#define WIDGETS_H_ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * maps filter parameter values to index in selectors array. + * also includes filter name and filter informations + */ +struct FilterMap +{ + int value; + const char* name; + const char* info; + int _index; +}; + +/** + * shows confirmation dialog on various occasions + * @param exit wether to act as an exit dialog + * @return the chosen answer + */ +int dismiss(bool exit); + +/** + * PWid abstract class. + * all device parameter widgets derive from this. those can then all + * put into the globa \c pwid[][] array, where they can be accessed + * by a parameter ID and layer number + */ +class PWid +{ +protected: + /** + * callback. + * @param p parameter ID and Layer of the caller (id_layer[]) + */ + static void cb(PWid*, void* p); + /// holds parameter ID and layer number + int id_layer[2]; + /// holds min and max values for this parameter + int minimax[2]; +public: + virtual ~PWid() + { + ; + } + /** + * assigns parameter ID and layer information. + * connects the callback, puts pointer to this into the global \c pwid[][] + * array + */ + virtual void set_id(int v, int l = 0) = 0; + /** + * updates the value of the widget. + * @param v the new integer value + */ + virtual void set_value(int v) = 0; + /** + * gets the current widget value. + * @return current integer value + */ + virtual int get_value() const = 0; + /// returns a pointer to id_layer[] + int* get_id_layer() + { + return id_layer; + } + /// returns a pointer to minimax[] + virtual int* get_minimax() + { + return minimax; + } +}; + +extern PWid* pwid[2000][4]; +extern PWid* pwid_editing; + +/** + * Double_Window class + * just overwrites the default handler to support + * key press+hold+release callbacks + */ +class Double_Window: public Fl_Double_Window +{ + int handle(int event); +public: + Double_Window(int w, int h, char* const label = 0) : + Fl_Double_Window(w, h, label) + { + ; + } +}; + +class DND_Box: public Fl_Box +{ + int handle(int event); +public: + DND_Box(int x, int y, int w, int h, char* const label = 0) : + Fl_Box(x, y, w, h, label) + { + clear_visible_focus(); + } + static void dndcback(void *v) + { + DND_Box *dbox = (DND_Box*) v; + dbox->dnd(); + } + void dnd(); +protected: + char evt_txt[BUF_PATHS]; +}; + +/** + * Browser class. + * adds a filter and a name loader method (load_n) to the Fl_Browser class. + * also adds "right-click to reset to initial" support + */ +class Browser: public Fl_Hold_Browser, public PWid +{ + /// current filter string + char* filter; + /// adds right-click support + int handle(int event); + /// local memory of the ROM ID that we have currently loaded + int selected_rom; +public: + Browser(int x, int y, int w, int h, char* const label = 0) : + Fl_Hold_Browser(x, y, w, h, label) + { + filter = '\0'; + has_scrollbar(VERTICAL); + selected_rom = -1; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; + void set_filter(const char* filter_string); + void apply_filter(); + void load_n(int type, int rom_id, int preset = -1); + int* get_minimax() + { + minimax[1] = size() - 1; + return minimax; + } +}; + +/** + * ROM_Choice class. + * adds "right-click to reset to initial" and mousewheel support + */ +class ROM_Choice: public Fl_Choice, public PWid +{ + int no_user; + int handle(int event); + void dependency(int v, bool get) const; +public: + ROM_Choice(int x, int y, int w, int h, char* const label = 0) : + Fl_Choice(x, y, w, h, label) + { + no_user = 1; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; +}; + +/** + * Input class. + * used by name and filter inputs + * changes to FL_Input: disabled the unfocus on enter key + */ +class Input: public Fl_Input +{ + int handle(int ev); +public: + Input(int x, int y, int w, int h, char const* label = 0) : + Fl_Input(x, y, w, h, label) + { + ; + } +}; + +/** + * Value_Input class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Value_Input: public Fl_Value_Input, public PWid +{ + int handle(int event); +public: + Value_Input(int x, int y, int w, int h, char const* label = 0) : + Fl_Value_Input(x, y, w, h, label) + { + ; + } + void set_id(int v, int l = 0); + void set_value(int); + int get_value() const; +}; + +/** + * Formatted_Output class. + * shows formatted parameter values + */ +class Formatted_Output: public Fl_Value_Output +{ + virtual int format(char* buf); + int id; + int layer; +public: + Formatted_Output(int x, int y, int w, int h, char const* label = 0) : + Fl_Value_Output(x, y, w, h, label) + { + ; + } + void set_value(int p, int l, int v); +}; + +/** + * Value_Output class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Value_Output: public Fl_Value_Output, public PWid +{ + int handle(int event); + int double_click_value; // used for patchcord double click toggle +public: + Value_Output(int x, int y, int w, int h, char const* label = 0) : + Fl_Value_Output(x, y, w, h, label) + { + double_click_value = 0; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; +}; + +/** + * Slider class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Slider: public Fl_Slider, public PWid +{ + int handle(int event); + mutable int prev_value; +protected: + void draw(int X, int Y, int W, int H); +public: + Slider(int x, int y, int w, int h, char const* label = 0) : + Fl_Slider(x, y, w, h, label) + { + prev_value = -96; + id_layer[0] = -1; // used by cc sliders + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; + void draw(); +}; + +/** + * Spinner class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Spinner: public Fl_Spinner, public PWid +{ + int handle(int event); +public: + Spinner(int x, int y, int w, int h, char const* label = 0) : + Fl_Spinner(x, y, w, h, label) + { + ; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; +}; + +/** + * Counter class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Counter: public Fl_Counter, public PWid +{ + int handle(int event); +public: + Counter(int x, int y, int w, int h, char const* label = 0) : + Fl_Counter(x, y, w, h, label) + { + ; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; +}; + +/** + * Group class. + * adds "right-click to reset to initial" support + */ +class Group: public Fl_Group, public PWid +{ + int handle(int event); + void dependency(int v) const; +public: + Group(int x, int y, int w, int h, char const* label = 0) : + Fl_Group(x, y, w, h, label) + { + ; + } + void set_id(int v, int l = 0); + virtual void set_value(int); + virtual int get_value() const; +}; + +/** + * Fl_Knob class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Fl_Knob: public Fl_Valuator, public PWid +{ + int _type; + float _percent; + int _scaleticks; + short a1, a2; + bool selected; + void draw(); + int handle(int event); + void draw_scale(const int ox, const int oy, const int side); + void draw_cursor(const int ox, const int oy, const int side); + void dependency(int v) const; +public: + enum Fl_Knobtype + { + DOTLIN = 0, + DOTLOG_1, + DOTLOG_2, + DOTLOG_3, + LINELIN, + LINELOG_1, + LINELOG_2, + LINELOG_3 + }; + Fl_Knob(int xx, int yy, int ww, int hh, const char *l = 0); + void type(int ty); + void cursor(const int pc); + void scaleticks(const int tck); + + void set_id(int v, int l = 0); + void set_value(int); + int get_value() const; +}; + +/** + * Button class. + * adds "right-click to reset to initial" support + */ +class Button: public Fl_Button, public PWid +{ + int handle(int event); +public: + Button(int x, int y, int w, int h, char const* label = 0) : + Fl_Button(x, y, w, h, label) + { + id_layer[0] = -1; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; + // void dependency(int v) const; +}; + +class Fixed_Button: public Fl_Button +{ + int handle(int event); +public: + Fixed_Button(int x, int y, int w, int h, char const* label = 0) : + Fl_Button(x, y, w, h, label) + { + ; + } +}; + +/** + * Choice class. + * adds "right-click to reset to initial" and mousewheel support + */ +class Choice: public Fl_Choice, public PWid +{ + int handle(int event); + void dependency(int v) const; +public: + Choice(int x, int y, int w, int h, char* const label = 0) : + Fl_Choice(x, y, w, h, label) + { + ; + } + void set_id(int v, int l = 0); + void set_value(int v); + int get_value() const; +}; + +/** + * PCS_Choice class. + * special class for patchcord sources + */ +class PCS_Choice: public Choice +{ + struct ParaMap + { + int value; + const char* name; + int _index; + } src[78]; + bool initialized; + void init(int ec) + { + clear(); + for (int i = 0; i < 74 + ec; i++) + src[i]._index = add(src[i].name); + initialized = true; + } +public: + PCS_Choice(int x, int y, int w, int h, char* const label = 0) : + Choice(x, y, w, h, label) + { + src[0].value = 0; + src[0].name = "Off"; + + src[1].value = 8; + src[1].name = "Key/Key+"; + src[2].value = 9; + src[2].name = "Key/Key~"; + src[3].value = 10; + src[3].name = "Key/Vel+"; + src[4].value = 11; + src[4].name = "Key/Vel~"; + src[5].value = 12; + src[5].name = "Key/Vel<"; + src[6].value = 13; + src[6].name = "Key/RlsVel"; + src[7].value = 14; + src[7].name = "Key/Gate"; + src[8].value = 48; + src[8].name = "Key/Glide"; + src[9].value = 4; + src[9].name = "Key/XfdRand"; + src[10].value = 100; + src[10].name = "Key/KeyRand 1"; + src[11].value = 101; + src[11].name = "Key/KeyRand 2"; + + src[12].value = 16; + src[12].name = "Controller/PitchWhl"; + src[13].value = 17; + src[13].name = "Controller/ModWhl"; + src[14].value = 18; + src[14].name = "Controller/Pressure"; + src[15].value = 19; + src[15].name = "Controller/Pedal"; + src[16].value = 22; + src[16].name = "Controller/FootSw 1"; + src[17].value = 23; + src[17].name = "Controller/FootSw 2"; + src[18].value = 38; + src[18].name = "Controller/FootSw 3"; + src[19].value = 24; + src[19].name = "Controller/FootSw 1FF"; + src[20].value = 25; + src[20].name = "Controller/FootSw 2FF"; + src[21].value = 39; + src[21].name = "Controller/FootSw 3FF"; + + src[22].value = 72; + src[22].name = "Envelope/VolEnv+"; + src[23].value = 73; + src[23].name = "Envelope/VolEnv~"; + src[24].value = 74; + src[24].name = "Envelope/VolEnv<"; + src[25].value = 80; + src[25].name = "Envelope/FilEnv+"; + src[26].value = 81; + src[26].name = "Envelope/FilEnv~"; + src[27].value = 82; + src[27].name = "Envelope/FilEnv<"; + src[28].value = 88; + src[28].name = "Envelope/AuxEnv+"; + src[29].value = 89; + src[29].name = "Envelope/AuxEnv~"; + src[30].value = 90; + src[30].name = "Envelope/AuxEnv<"; + + src[31].value = 96; + src[31].name = "LFO/LFO 1~"; + src[32].value = 97; + src[32].name = "LFO/LFO 1+"; + src[33].value = 104; + src[33].name = "LFO/LFO 2~"; + src[34].value = 105; + src[34].name = "LFO/LFO 2+"; + + src[35].value = 98; + src[35].name = "Noise/White"; + src[36].value = 99; + src[36].name = "Noise/Pink"; + + src[37].value = 106; + src[37].name = "Processor/Log0sum"; + src[38].value = 107; + src[38].name = "Processor/Lag0"; + src[39].value = 108; + src[39].name = "Processor/Log1sum"; + src[40].value = 109; + src[40].name = "Processor/Lag1"; + src[41].value = 128; + src[41].name = "Processor/PLagOut"; + src[42].value = 129; + src[42].name = "Processor/PRampOut"; + src[43].value = 160; + src[43].name = "Processor/DC"; + src[44].value = 161; + src[44].name = "Processor/Sum"; + src[45].value = 162; + src[45].name = "Processor/Switch"; + src[46].value = 163; + src[46].name = "Processor/Abs"; + src[47].value = 164; + src[47].name = "Processor/Diode"; + src[48].value = 165; + src[48].name = "Processor/FlipFlop"; + src[49].value = 166; + src[49].name = "Processor/Quantizer"; + src[50].value = 167; + src[50].name = "Processor/Gain x 4"; + + src[51].value = 144; + src[51].name = "Clock Divisor/Double Whole"; + src[52].value = 145; + src[52].name = "Clock Divisor/Whole"; + src[53].value = 146; + src[53].name = "Clock Divisor/Half"; + src[54].value = 147; + src[54].name = "Clock Divisor/Quarter"; + src[55].value = 148; + src[55].name = "Clock Divisor/8th"; + src[56].value = 149; + src[56].name = "Clock Divisor/16th"; + src[57].value = 150; + src[57].name = "Clock Divisor/Octal"; + src[58].value = 151; + src[58].name = "Clock Divisor/Quad"; + + src[59].value = 26; + src[59].name = "MIDI/MIDI Vol"; + src[60].value = 27; + src[60].name = "MIDI/MIDI Pan"; + src[61].value = 28; + src[61].name = "MIDI/MIDI Expr"; + src[62].value = 20; + src[62].name = "MIDI/MIDI A"; + src[63].value = 21; + src[63].name = "MIDI/MIDI B"; + src[64].value = 32; + src[64].name = "MIDI/MIDI C"; + src[65].value = 33; + src[65].name = "MIDI/MIDI D"; + src[66].value = 34; + src[66].name = "MIDI/MIDI E"; + src[67].value = 35; + src[67].name = "MIDI/MIDI F"; + src[68].value = 36; + src[68].name = "MIDI/MIDI G"; + src[69].value = 37; + src[69].name = "MIDI/MIDI H"; + src[70].value = 40; + src[70].name = "MIDI/MIDI I"; + src[71].value = 41; + src[71].name = "MIDI/MIDI J"; + src[72].value = 42; + src[72].name = "MIDI/MIDI K"; + src[73].value = 43; + src[73].name = "MIDI/MIDI L"; + // xtra controllers + src[74].value = 44; + src[74].name = "MIDI/MIDI M"; + src[75].value = 45; + src[75].name = "MIDI/MIDI N"; + src[76].value = 46; + src[76].name = "MIDI/MIDI O"; + src[77].value = 47; + src[77].name = "MIDI/MIDI P"; + minimax[1] = 167; + initialized = false; + } + void set_value(int v); + int get_value() const; + void uninitialize() + { + initialized = false; + } +}; + +/** + * PCD_Choice class. + * special class for patchcord destinations + */ +class PCD_Choice: public Choice +{ + struct ParaMap + { + int value; + const char* name; + int _index; + } dst[68]; +public: + PCD_Choice(int x, int y, int w, int h, char* const label = 0) : + Choice(x, y, w, h, label) + { + dst[0].value = 0; + dst[0].name = "Off"; + dst[1].value = 8; + dst[1].name = "Voice/KeySust"; + dst[2].value = 47; + dst[2].name = "Voice/FinePitch"; + dst[3].value = 48; + dst[3].name = "Voice/Pitch"; + dst[4].value = 49; + dst[4].name = "Voice/Glide"; + dst[5].value = 50; + dst[5].name = "Voice/ChorusAmt"; + dst[6].value = 52; + dst[6].name = "Voice/'SStart"; + dst[7].value = 53; + dst[7].name = "Voice/SLoop"; + dst[8].value = 54; + dst[8].name = "Voice/SRetrig"; + dst[9].value = 66; + dst[9].name = "Voice/RT X-fade"; + dst[10].value = 56; + dst[10].name = "Voice/FFrequency"; + dst[11].value = 57; + dst[11].name = "Voice/F'Resonance"; + dst[12].value = 64; + dst[12].name = "Voice/Amp Vol"; + dst[13].value = 65; + dst[13].name = "Voice/Amp Pan"; + + dst[14].value = 72; + dst[14].name = "Envelope/VolEnvRts"; + dst[15].value = 73; + dst[15].name = "Envelope/VolEnvAtk"; + dst[16].value = 74; + dst[16].name = "Envelope/VolEnvDcy"; + dst[17].value = 75; + dst[17].name = "Envelope/VolEnvRls"; + dst[18].value = 76; + dst[18].name = "Envelope/VolEnvSus"; + dst[19].value = 80; + dst[19].name = "Envelope/FilEnvRts"; + dst[20].value = 81; + dst[20].name = "Envelope/FilEnvAtk"; + dst[21].value = 82; + dst[21].name = "Envelope/FilEnvDcy"; + dst[22].value = 83; + dst[22].name = "Envelope/FilEnvRls"; + dst[23].value = 84; + dst[23].name = "Envelope/FilEnvSus"; + dst[24].value = 86; + dst[24].name = "Envelope/FilEnvTrig"; + dst[25].value = 88; + dst[25].name = "Envelope/AuxEnvRts"; + dst[26].value = 89; + dst[26].name = "Envelope/AuxEnvAtk"; + dst[27].value = 90; + dst[27].name = "Envelope/AuxEnvDcy"; + dst[28].value = 91; + dst[28].name = "Envelope/AuxEnvRls"; + dst[29].value = 92; + dst[29].name = "Envelope/AuxEnvSus"; + dst[30].value = 94; + dst[30].name = "Envelope/AuxEnvTrig"; + + dst[31].value = 96; + dst[31].name = "LFO/LFO 1 Rate"; + dst[32].value = 97; + dst[32].name = "LFO/LFO 1 Trig"; + dst[33].value = 104; + dst[33].name = "LFO/LFO 2 Rate"; + dst[34].value = 105; + dst[34].name = "LFO/LFO 2 Trig"; + + dst[35].value = 106; + dst[35].name = "Processor/Lag 0 in"; + dst[36].value = 108; + dst[36].name = "Processor/Lag 1 in"; + dst[37].value = 161; + dst[37].name = "Processor/Sum"; + dst[38].value = 162; + dst[38].name = "Processor/Switch"; + dst[39].value = 163; + dst[39].name = "Processor/Abs"; + dst[40].value = 164; + dst[40].name = "Processor/Diode"; + dst[41].value = 165; + dst[41].name = "Processor/FlipFlop"; + dst[42].value = 166; + dst[42].name = "Processor/Quantize"; + dst[43].value = 167; + dst[43].name = "Processor/Gain x 4"; + + dst[44].value = 168; + dst[44].name = "Attenuator/C 01 Amt"; + dst[45].value = 169; + dst[45].name = "Attenuator/C 02 Amt"; + dst[46].value = 170; + dst[46].name = "Attenuator/C 03 Amt"; + dst[47].value = 171; + dst[47].name = "Attenuator/C 04 Amt"; + dst[48].value = 172; + dst[48].name = "Attenuator/C 05 Amt"; + dst[49].value = 173; + dst[49].name = "Attenuator/C 06 Amt"; + dst[50].value = 174; + dst[50].name = "Attenuator/C 07 Amt"; + dst[51].value = 175; + dst[51].name = "Attenuator/C 08 Amt"; + dst[52].value = 176; + dst[52].name = "Attenuator/C 09 Amt"; + dst[53].value = 177; + dst[53].name = "Attenuator/C 10 Amt"; + dst[54].value = 178; + dst[54].name = "Attenuator/C 11 Amt"; + dst[55].value = 179; + dst[55].name = "Attenuator/C 12 Amt"; + dst[56].value = 180; + dst[56].name = "Attenuator/C 13 Amt"; + dst[57].value = 181; + dst[57].name = "Attenuator/C 14 Amt"; + dst[58].value = 182; + dst[58].name = "Attenuator/C 15 Amt"; + dst[59].value = 183; + dst[59].name = "Attenuator/C 16 Amt"; + dst[60].value = 184; + dst[60].name = "Attenuator/C 17 Amt"; + dst[61].value = 185; + dst[61].name = "Attenuator/C 18 Amt"; + dst[62].value = 186; + dst[62].name = "Attenuator/C 19 Amt"; + dst[63].value = 187; + dst[63].name = "Attenuator/C 20 Amt"; + dst[64].value = 188; + dst[64].name = "Attenuator/C 21 Amt"; + dst[65].value = 189; + dst[65].name = "Attenuator/C 22 Amt"; + dst[66].value = 190; + dst[66].name = "Attenuator/C 23 Amt"; + dst[67].value = 191; + dst[67].name = "Attenuator/C 24 Amt"; + for (int i = 0; i < 68; i++) + dst[i]._index = add(dst[i].name); + minimax[1] = 191; + } + void set_value(int v); + int get_value() const; +}; + +/** + * PPCD_Choice class. + * special class for preset patchcord destinations + */ +class PPCD_Choice: public Choice +{ + struct ParaMap + { + int value; + const char* name; + int _index; + } dst[28]; +public: + PPCD_Choice(int x, int y, int w, int h, char* const label = 0) : + Choice(x, y, w, h, label) + { + dst[0].value = 0; + dst[0].name = "Off"; + + dst[1].value = 1; + dst[1].name = "Effects/FX A Send 1"; + dst[2].value = 2; + dst[2].name = "Effects/FX A Send 2"; + dst[3].value = 3; + dst[3].name = "Effects/FX A Send 3"; + dst[4].value = 4; + dst[4].name = "Effects/FX A Send 4"; + dst[5].value = 5; + dst[5].name = "Effects/FX B Send 1"; + dst[6].value = 6; + dst[6].name = "Effects/FX B Send 2"; + dst[7].value = 7; + dst[7].name = "Effects/FX B Send 3"; + dst[8].value = 8; + dst[8].name = "Effects/FX B Send 4"; + + dst[9].value = 96; + dst[9].name = "Arpeggiator/Arp Rate"; + dst[10].value = 97; + dst[10].name = "Arpeggiator/Arp Ext."; + dst[11].value = 98; + dst[11].name = "Arpeggiator/Arp Vel"; + dst[12].value = 99; + dst[12].name = "Arpeggiator/Arp Gate"; + dst[13].value = 100; + dst[13].name = "Arpeggiator/Arp Intvl"; + + dst[14].value = 112; + dst[14].name = "Beats/BeatsVelG1"; + dst[15].value = 113; + dst[15].name = "Beats/BeatsVelG2"; + dst[16].value = 114; + dst[16].name = "Beats/BeatsVelG3"; + dst[17].value = 115; + dst[17].name = "Beats/BeatsVelG4"; + dst[18].value = 116; + dst[18].name = "Beats/BeatsXpsG1"; + dst[19].value = 117; + dst[19].name = "Beats/BeatsXpsG2"; + dst[20].value = 118; + dst[20].name = "Beats/BeatsXpsG3"; + dst[21].value = 119; + dst[21].name = "Beats/BeatsXpsG4"; + dst[22].value = 120; + dst[22].name = "Beats/BeatsBusy"; + dst[23].value = 121; + dst[23].name = "Beats/BeatsVari"; + + dst[24].value = 128; + dst[24].name = "Preset/PLag In"; + dst[25].value = 129; + dst[25].name = "Preset/PLag Amt"; + dst[26].value = 130; + dst[26].name = "Preset/PRamp In"; + dst[27].value = 131; + dst[27].name = "Preset/PRamp Rt"; + for (int i = 0; i < 28; i++) + dst[i]._index = add(dst[i].name); + minimax[1] = 131; + } + void set_value(int v); + int get_value() const; +}; + +/** + * Envelope_Editor class. + * features zooming and display of multiple envelopes. mousewheel switches + * the currently selected envelope + */ +class Envelope_Editor: public Fl_Box +{ + struct envelope + { + int stage[6][2]; // x/y coordinates of the 6 envelope stages + int mode, repeat; + }; + envelope env[3]; + enum + { + ATK_1, DCY_1, RLS_1, ATK_2, DCY_2, RLS_2 + }; + enum + { + VOLUME, FILTER, AUXILIARY + }; + enum + { + FACTORY, + TIME_BASED, + TEMPO_BASED, + OVERLAY, + SYNC_VOICE_VIEW, + VOLUME_SELECTED, + FILTER_SELECTED, + AUXILIARY_SELECTED, + CPY_VOLUME, + CPY_FILTER, + CPY_AUXILIARY, + SHAPE_A, + SHAPE_B, + SHAPE_C, + SHAPE_D + }; + virtual int handle(int event); + void draw(); + void draw_envelope(int type, int x0, int y0); + void copy_envelope(int src, int dst); + void set_shape(int dst, int shape); + int layer; + int ee_x0; + int ee_y0; + int ee_w; + int ee_h; + int mode_button[5]; // x0 of the mode buttons (width = 75, h = 20) + int copy_button[6]; + int shape_button[4]; + int button_hover; + int zoomlevel; + int dragbox[6][2]; + int hover; + int hover_list; // 1, 2, 4, 8, 16, 32 + int push_x; + int push_y; + int mode; + int modes; + bool overlay; + bool button_push; + int bg; + +public: + Envelope_Editor(int x, int y, int w, int h, char* const label = 0) : + Fl_Box(x, y, w, h, label) + { + zoomlevel = 4; + modes = 3; + mode = VOLUME; + hover = -1; + overlay = false; + // initialize with some fake data + set_shape(VOLUME, SHAPE_D); + set_shape(FILTER, SHAPE_A); + set_shape(AUXILIARY, SHAPE_C); + } + void set_data(int type, int* stages, int mode, int repeat); + void set_layer(int l); + void sync_view(int l, int m = 0, float z = .0, bool o = false); +}; + +/** + * Piano class. + * features a 127 key keyboard with velocity setting, pitch and modwheel, + * 3 footswitches, layer transpose, layer, arp and link range/fade setup + */ +class Piano: public Fl_Box +{ + virtual int handle(int event); + void draw(); + void draw_ranges(); + void draw_piano(); + void draw_highlights(); + void draw_case(); + void draw_curve(int type); + void switch_mode(); + void commit_changes(); + void calc_hovered(int x, int y); + enum + { + LOW_KEY, LOW_FADE, HIGH_KEY, HIGH_FADE + }; + enum + { + NONE = -1, PRESET_ARP = 4, MASTER_ARP, LINK_ONE, LINK_TWO, PIANO + }; + enum + { + KEYRANGE, VELOCITY, REALTIME + }; + enum + { + D_RANGES = 1, D_KEYS, D_HIGHLIGHT = 4, D_CASE = 8 + }; + int mode; // 0 = keyrange, 1 = velocity, 2 = realtime + int modes; + int keyboard_x0, keyboard_y0, keyboard_w, keyboard_h; + int h_white, w_white, h_black, w_black; + int taste_x0[128][2]; + int dragbox[3][8][4][2]; // mode, layer, type, x/y + int highlight_dragbox[8][4]; + int prev_key_value[3][8][4]; + int new_key_value[3][8][4]; + int pushed; // currently dragged part + int pushed_range; // currently dragged range (low_key, low_fade...) + int hovered_key, play_hovered_key; + int active_keys[128]; + int previous_hovered_key; + int selected_transpose_layer; + int transpose[4]; + int push_x; // used for setting the key velocity + int key_velocity; + +public: + Piano(int x, int y, int w, int h, char* const label = 0) : + Fl_Box(x, y, w, h, label) + { + // tasten- hšhen/-breiten + h_white = 32; + w_white = 13; // 15 + h_black = 20; + w_black = 7; // 9 + hovered_key = NONE; + previous_hovered_key = NONE; + play_hovered_key = 0; + pushed = NONE; + pushed_range = NONE; + mode = KEYRANGE; // load piano at startup + key_velocity = 100; + modes = 3; + selected_transpose_layer = 0; + for (int i = 0; i < 128; i++) + active_keys[i] = 0; + // widget is 921 pixels wide + // height is about 162 + // calculate our position and key koordinates + keyboard_x0 = this->x() + 10; + keyboard_y0 = this->y() + 10; + keyboard_w = 75 * (w_white - 1); + keyboard_h = h_white; + int offset = 0; + for (int i = 0; i < 11; i++) + { + // for each octave on the keyboard + int octave = i * 12; + taste_x0[0 + octave][0] = keyboard_x0 + offset; + taste_x0[0 + octave][1] = 0; + taste_x0[1 + octave][0] = keyboard_x0 + 9 + offset; + taste_x0[1 + octave][1] = 1; + taste_x0[2 + octave][0] = keyboard_x0 + w_white - 1 + offset; + taste_x0[2 + octave][1] = 0; + taste_x0[3 + octave][0] = keyboard_x0 + 9 + (w_white - 1) + offset; + taste_x0[3 + octave][1] = 1; + taste_x0[4 + octave][0] = keyboard_x0 + 2 * (w_white - 1) + offset; + taste_x0[4 + octave][1] = 0; + taste_x0[5 + octave][0] = keyboard_x0 + 3 * (w_white - 1) + offset; + taste_x0[5 + octave][1] = 0; + taste_x0[6 + octave][0] = keyboard_x0 + 9 + 3 * (w_white - 1) + + offset; + taste_x0[6 + octave][1] = 1; + taste_x0[7 + octave][0] = keyboard_x0 + 4 * (w_white - 1) + offset; + taste_x0[7 + octave][1] = 0; + if (i == 10) // keyboard is smaller than full 10 full octaves + break; + taste_x0[8 + octave][0] = keyboard_x0 + 9 + 4 * (w_white - 1) + + offset; + taste_x0[8 + octave][1] = 1; + taste_x0[9 + octave][0] = keyboard_x0 + 5 * (w_white - 1) + offset; + taste_x0[9 + octave][1] = 0; + taste_x0[10 + octave][0] = keyboard_x0 + 9 + 5 * (w_white - 1) + + offset; + taste_x0[10 + octave][1] = 1; + taste_x0[11 + octave][0] = keyboard_x0 + 6 * (w_white - 1) + offset; + taste_x0[11 + octave][1] = 0; + offset += 7 * (w_white - 1); + } + // y-koordinaten der dragboxes + for (int m = 0; m < 3; m++) + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + { + if (j == LOW_KEY || j == HIGH_KEY) + dragbox[m][i][j][1] = keyboard_y0 + 5 + keyboard_h + i + * 18; + else + dragbox[m][i][j][1] = keyboard_y0 + 5 + keyboard_h + i + * 18 + 8; + } + // arps + dragbox[0][4][LOW_KEY][1] = dragbox[0][3][LOW_KEY][1] + 20; + dragbox[0][4][HIGH_KEY][1] = dragbox[0][4][LOW_KEY][1]; + dragbox[0][5][LOW_KEY][1] = dragbox[0][4][LOW_KEY][1] + 10; + dragbox[0][5][HIGH_KEY][1] = dragbox[0][5][LOW_KEY][1]; + // links + dragbox[0][6][LOW_KEY][1] = dragbox[0][5][LOW_KEY][1] + 10; + dragbox[0][6][HIGH_KEY][1] = dragbox[0][6][LOW_KEY][1]; + dragbox[0][7][LOW_KEY][1] = dragbox[0][6][LOW_KEY][1] + 10; + dragbox[0][7][HIGH_KEY][1] = dragbox[0][7][LOW_KEY][1]; + // x koordinaten + for (int m = 0; m < 3; m++) + for (int i = 0; i < 8; i++) + set_range_values(m, i, 0, 0, 127, 0); + } + + void set_range_values(int md, int layer, int low_k, int low_f, int high_k, + int high_f); + void set_transpose(int l1, int l2, int l3, int l4); + void select_transpose_layer(int l); + void set_mode(int m); + void activate_key(int value, int key); + void reset_active_keys(); +}; + +/** + * MiniPiano. + * 2 octaves of key goodness + */ +class MiniPiano: public Fl_Box +{ + virtual int handle(int event); + void draw(); + void draw_piano(); + void draw_highlights(); + void draw_case(); + void calc_hovered(int x, int y); + void shift_octave(int); + + int keyboard_x0, keyboard_y0, keyboard_w, keyboard_h; + float key_x, key_w, key_y; + float h_white, w_white, h_black, w_black; + float taste_x0[128][2]; + int octave; + + int hovered_key, play_hovered_key; + int active_keys[128]; + int previous_hovered_key; + int pushed; + int push_x; // used for setting the key velocity + int key_velocity; + enum + { + NONE = -1, PIANO + }; + enum + { + D_KEYS = 2, D_HIGHLIGHT = 4, D_CASE = 8 + }; + +public: + MiniPiano(int x, int y, int w, int h, char* const label = 0) : + Fl_Box(x, y, w, h, label) + { + pushed = NONE; + hovered_key = NONE; + previous_hovered_key = NONE; + key_velocity = 100; + for (int i = 0; i < 128; i++) + active_keys[i] = 0; + octave = 4; + } + void activate_key(int value, int key); + void reset_active_keys(); +}; + +// ################### +// +// ################### +class Pitch_Slider: public Fl_Slider +{ + int handle(int event); + bool hold; +public: + Pitch_Slider(int x, int y, int w, int h, char* const label = 0) : + Fl_Slider(x, y, w, h, label) + { + hold = false; + } +}; + +// ################### +// +// ################### +class Step_Type: public Fl_Group +{ + int handle(int event); + int s; +public: + Step_Type(int x, int y, int w, int h, char* const label = 0) : + Fl_Group(x, y, w, h, label) + { + ; + } + void set_step(int step); + int p; // prev value + int c; // current value +}; + +// ################### +// +// ################### +class Step_Value: public Fl_Value_Output +{ + virtual int format(char* buf); + int handle(int event); + int id; + int s; +public: + Step_Value(int x, int y, int w, int h, char const* label = 0) : + Fl_Value_Output(x, y, w, h, label) + { + ; + } + void set_id(int i, int step); +}; + +// ################### +// +// ################### +class Step_Offset: public Fl_Value_Slider +{ + int handle(int event); + int s; +protected: + void draw(int X, int Y, int W, int H); +public: + Step_Offset(int x, int y, int w, int h, char* const label = 0) : + Fl_Value_Slider(x, y, w, h, label) + { + ; + } + void draw(); + void set_step(int step); +}; + +// ################### +// +// ################### +class Text_Display: public Fl_Text_Display +{ + virtual void resize(int X, int Y, int W, int H); + int c_w; +public: + Text_Display(int x, int y, int w, int h, char const* label = 0) : + Fl_Text_Display(x, y, w, h, label) + { + textfont(FL_COURIER); + textsize(12); + fl_font(FL_COURIER, 12); + c_w = fl_width("w"); + wrap_mode(1, w / c_w - 4); + } +}; +#endif /* WIDGETS_H_ */ +/** @} */