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