aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Bullock <postlude@users.sourceforge.net>2015-03-16 14:56:17 +0000
committerJamie Bullock <postlude@users.sourceforge.net>2015-03-16 14:56:17 +0000
commitebaabd0f2e3203be4700d01260b81c5971289c14 (patch)
treed844cb423fdee133e16ea8b9f80accb23d3b5197
parentc8f157b2231ba21d40a6699ffbdeb7874b9b1abd (diff)
Add support for a wider range of DX-based SYSEX files including those with more than 32-voices. NOTE: for now files with up to 128 voices can be “read”, but only the first 32 voices will be “loaded”
svn path=/trunk/externals/postlude/; revision=17445
-rw-r--r--pluginhost~/handlers_pd.c401
-rw-r--r--pluginhost~/ph_common.c7
-rw-r--r--pluginhost~/ph_common.h2
3 files changed, 392 insertions, 18 deletions
diff --git a/pluginhost~/handlers_pd.c b/pluginhost~/handlers_pd.c
index 4604a07..1a83ba4 100644
--- a/pluginhost~/handlers_pd.c
+++ b/pluginhost~/handlers_pd.c
@@ -41,11 +41,12 @@
-
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <stdint.h> /* for uint8_t */
+#include <stdarg.h>
#include "jutils.h"
#include "handlers_osc.h"
@@ -71,6 +72,10 @@
#define CLASS_NAME_STR "pluginhost~"
+/* From hexter_types.h */
+#define DX7_DUMP_SIZE_VOICE_SINGLE 155+8
+#define DX7_DUMP_SIZE_VOICE_BULK 4096+8
+
/*From dx7_voice.h by Sean Bolton */
typedef struct _dx7_patch_t {
uint8_t data[128];
@@ -80,6 +85,59 @@ typedef struct _dx7_patch_t {
/*From dx7_voice_data.c by Sean Bolton */
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+char *
+dssp_error_message(const char *fmt, ...)
+{
+ va_list args;
+ char buffer[256];
+
+ va_start(args, fmt);
+ vsnprintf(buffer, 256, fmt, args);
+ va_end(args);
+ return strdup(buffer);
+}
+
+void
+dx7_patch_pack(uint8_t *unpacked_patch, dx7_patch_t *packed_patch, uint8_t number)
+{
+ uint8_t *up = unpacked_patch,
+ *pp = (uint8_t *)(&packed_patch[number]);
+ int i, j;
+
+ /* ugly because it used to be 68000 assembly... */
+ for (i = 6; i > 0; i--) {
+ for (j = 11; j > 0; j--) {
+ *pp++ = *up++;
+ } /* through rd */
+ *pp++ = ((*up) & 0x03) | (((*(up + 1)) & 0x03) << 2);
+ up += 2; /* rc+lc */
+ *pp++ = ((*up) & 0x07) | (((*(up + 7)) & 0x0f) << 3);
+ up++; /* pd+rs */
+ *pp++ = ((*up) & 0x03) | (((*(up + 1)) & 0x07) << 2);
+ up += 2; /* kvs+ams */
+ *pp++ = *up++; /* ol */
+ *pp++ = ((*up) & 0x01) | (((*(up + 1)) & 0x1f) << 1);
+ up += 2; /* fc+m */
+ *pp++ = *up;
+ up += 2; /* ff */
+ } /* operator done */
+ for (i = 9; i > 0; i--) {
+ *pp++ = *up++;
+ } /* through algorithm */
+ *pp++ = ((*up) & 0x07) | (((*(up + 1)) & 0x01) << 3);
+ up += 2; /* oks+fb */
+ for (i = 4; i > 0; i--) {
+ *pp++ = *up++;
+ } /* through lamd */
+ *pp++ = ((*up) & 0x01) |
+ (((*(up + 1)) & 0x07) << 1) |
+ (((*(up + 2)) & 0x07) << 4);
+ up += 3; /* lpms+lfw+lks */
+ for (i = 11; i > 0; i--) {
+ *pp++ = *up++;
+ } /* through name */
+}
+
/*
* dx7_bulk_dump_checksum
** Taken from dx7_voice_data.c by Sean Bolton **
@@ -141,6 +199,291 @@ char *encode_7in6(uint8_t *data, int length)
return buffer;
}
+void
+dx7_patch_unpack(dx7_patch_t *packed_patch, uint8_t number, uint8_t *unpacked_patch)
+{
+ uint8_t *up = unpacked_patch,
+ *pp = (uint8_t *)(&packed_patch[number]);
+ int i, j;
+
+ /* ugly because it used to be 68000 assembly... */
+ for(i = 6; i > 0; i--) {
+ for(j = 11; j > 0; j--) {
+ *up++ = *pp++;
+ } /* through rd */
+ *up++ = (*pp) & 0x03; /* lc */
+ *up++ = (*pp++) >> 2; /* rc */
+ *up++ = (*pp) & 0x07; /* rs */
+ *(up + 6) = (*pp++) >> 3; /* pd */
+ *up++ = (*pp) & 0x03; /* ams */
+ *up++ = (*pp++) >> 2; /* kvs */
+ *up++ = *pp++; /* ol */
+ *up++ = (*pp) & 0x01; /* m */
+ *up++ = (*pp++) >> 1; /* fc */
+ *up = *pp++; /* ff */
+ up += 2;
+ } /* operator done */
+ for(i = 9; i > 0; i--) {
+ *up++ = *pp++;
+ } /* through algorithm */
+ *up++ = (*pp) & 0x07; /* feedback */
+ *up++ = (*pp++) >> 3; /* oks */
+ for(i = 4; i > 0; i--) {
+ *up++ = *pp++;
+ } /* through lamd */
+ *up++ = (*pp) & 0x01; /* lfo ks */
+ *up++ = ((*pp) >> 1) & 0x07; /* lfo wave */
+ *up++ = (*pp++) >> 4; /* lfo pms */
+ for(i = 11; i > 0; i--) {
+ *up++ = *pp++;
+ }
+}
+
+
+
+int
+dx7_patchbank_load(const char *filename, dx7_patch_t *firstpatch,
+ int maxpatches, char **errmsg)
+{
+ FILE *fp;
+ long filelength;
+ unsigned char *raw_patch_data = NULL;
+ size_t filename_length;
+ int count;
+ int patchstart;
+ int midshift;
+ int datastart;
+ int i;
+ int op;
+
+ /* this needs to 1) open and parse the file, 2a) if it's good, copy up
+ * to maxpatches patches beginning at firstpath, and not touch errmsg,
+ * 2b) if it's not good, set errmsg to a malloc'd error message that
+ * the caller must free. */
+
+ if ((fp = fopen(filename, "rb")) == NULL) {
+ if (errmsg) *errmsg = dssp_error_message("could not open file '%s' for reading: %s", filename, strerror(errno));
+ return 0;
+ }
+
+ if (fseek(fp, 0, SEEK_END) ||
+ (filelength = ftell(fp)) == -1 ||
+ fseek(fp, 0, SEEK_SET)) {
+ if (errmsg) *errmsg = dssp_error_message("couldn't get length of patch file: %s", strerror(errno));
+ fclose(fp);
+ return 0;
+ }
+ if (filelength == 0) {
+ if (errmsg) *errmsg = strdup("patch file has zero length");
+ fclose(fp);
+ return 0;
+ } else if (filelength > 2097152) {
+ if (errmsg) *errmsg = strdup("patch file is too large");
+ fclose(fp);
+ return 0;
+ } else if (filelength < 128) {
+ if (errmsg) *errmsg = strdup ("patch file is too small");
+ fclose (fp);
+ return 0;
+ }
+
+ if (!(raw_patch_data = (unsigned char *)malloc(filelength))) {
+ if (errmsg) *errmsg = strdup("couldn't allocate memory for raw patch file");
+ fclose(fp);
+ return 0;
+ }
+
+ if (fread(raw_patch_data, 1, filelength, fp) != (size_t)filelength) {
+ if (errmsg) *errmsg = dssp_error_message("short read on patch file: %s", strerror(errno));
+ free(raw_patch_data);
+ fclose(fp);
+ return 0;
+ }
+ fclose(fp);
+ filename_length = strlen (filename);
+
+ /* check if the file is a standard MIDI file */
+ if (raw_patch_data[0] == 0x4d && /* "M" */
+ raw_patch_data[1] == 0x54 && /* "T" */
+ raw_patch_data[2] == 0x68 && /* "h" */
+ raw_patch_data[3] == 0x64) /* "d" */
+ midshift = 2;
+ else
+ midshift = 0;
+
+ /* scan SysEx or MIDI file for SysEx header(s) */
+ count = 0;
+ datastart = 0;
+ for (patchstart = 0; patchstart + midshift + 5 < filelength; patchstart++) {
+
+ if (raw_patch_data[patchstart] == 0xf0 &&
+ raw_patch_data[patchstart + 1 + midshift] == 0x43 &&
+ raw_patch_data[patchstart + 2 + midshift] <= 0x0f &&
+ raw_patch_data[patchstart + 3 + midshift] == 0x09 &&
+ raw_patch_data[patchstart + 5 + midshift] == 0x00 &&
+ patchstart + 4103 + midshift < filelength &&
+ raw_patch_data[patchstart + 4103 + midshift] == 0xf7) { /* DX7 32 voice dump */
+
+ memmove(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
+ raw_patch_data + patchstart + 6 + midshift, 4096);
+ count += 32;
+ patchstart += (DX7_DUMP_SIZE_VOICE_BULK - 1);
+
+ } else if (raw_patch_data[patchstart] == 0xf0 &&
+ raw_patch_data[patchstart + midshift + 1] == 0x43 &&
+ raw_patch_data[patchstart + midshift + 2] <= 0x0f &&
+ raw_patch_data[patchstart + midshift + 4] == 0x01 &&
+ raw_patch_data[patchstart + midshift + 5] == 0x1b &&
+ patchstart + midshift + 162 < filelength &&
+ raw_patch_data[patchstart + midshift + 162] == 0xf7) { /* DX7 single voice (edit buffer) dump */
+
+ unsigned char buf[DX7_VOICE_SIZE_PACKED]; /* to avoid overlap in dx7_patch_pack() */
+
+ dx7_patch_pack(raw_patch_data + patchstart + midshift + 6,
+ (dx7_patch_t *)buf, 0);
+ memcpy(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
+ buf, DX7_VOICE_SIZE_PACKED);
+
+ count += 1;
+ patchstart += (DX7_DUMP_SIZE_VOICE_SINGLE - 1);
+ }
+ }
+
+ /* assume raw DX7/TX7 data if no SysEx header was found. */
+ /* assume the user knows what he is doing ;-) */
+
+ if (count == 0)
+ count = filelength / DX7_VOICE_SIZE_PACKED;
+
+ /* Dr.T and Steinberg TX7 file needs special treatment */
+ if ((!strcmp(filename + filename_length - 4, ".TX7") ||
+ !strcmp(filename + filename_length -4, ".SND") ||
+ !strcmp(filename + filename_length -4, ".tx7") ||
+ !strcmp(filename + filename_length - 4, ".snd")) && filelength == 8192) {
+
+ count = 32;
+ filelength = 4096;
+ }
+
+ /* Transform XSyn file also needs special treatment */
+ if ((!strcmp(filename + filename_length - 4, ".BNK") ||
+ !strcmp(filename + filename_length - 4, ".bnk")) && filelength == 8192) {
+
+ for (i=0; i<32; i++)
+ {
+ memmove(raw_patch_data + 128*i, raw_patch_data + 256*i, 128);
+ }
+ count = 32;
+ filelength = 4096;
+ }
+
+ /* Steinberg Synthworks DX7 SND */
+ if ((!strcmp (filename + filename_length - 4, ".SND") ||
+ !strcmp (filename + filename_length - 4, ".snd")) && filelength == 5216) {
+
+ count = 32;
+ filelength = 4096;
+ }
+
+ /* Voyetra SIDEMAN DX/TX
+ * Voyetra Patchmaster DX7/TX7 */
+ if ((filelength == 9816 || filelength == 5663) &&
+ raw_patch_data[0] == 0xdf &&
+ raw_patch_data[1] == 0x05 &&
+ raw_patch_data[2] == 0x01 && raw_patch_data[3] == 0x00) {
+
+ count = 32;
+ datastart = 0x60f;
+ }
+
+ /* Yamaha DX200 editor .DX2 */
+ if ((!strcmp (filename + filename_length - 4, ".DX2") ||
+ !strcmp (filename + filename_length - 4, ".dx2"))
+ && filelength == 326454)
+ {
+ memmove (raw_patch_data + 16384, raw_patch_data + 34, 128 * 381);
+ for (count = 0; count < 128; count++)
+ {
+ for (op = 0; op < 6; op++)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ raw_patch_data[17 * (5 - op) + i + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 76 + i + 381 * count];
+ }
+ raw_patch_data[17 * (5 - op) + 8 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 84 + 381 * count] - 21;
+ raw_patch_data[17 * (5 - op) + 9 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 87 + 381 * count];
+ raw_patch_data[17 * (5 - op) + 10 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 88 + 381 * count];
+ raw_patch_data[17 * (5 - op) + 11 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 85 + 381 * count] +
+ raw_patch_data[16384 + 35 * op + 86 + 381 * count] * 4;
+ raw_patch_data[17 * (5 - op) + 12 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 89 + 381 * count] +
+ raw_patch_data[16384 + 35 * op + 75 + 381 * count] * 8;
+ if (raw_patch_data[16384 + 35 * op + 71 + 381 * count] > 3)
+ raw_patch_data[16384 + 35 * op + 71 + 381 * count] = 3;
+ raw_patch_data[17 * (5 - op) + 13 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 71 + 381 * count] / 2 +
+ raw_patch_data[16384 + 35 * op + 91 + 381 * count] * 4;
+ raw_patch_data[17 * (5 - op) + 14 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 90 + 381 * count];
+ raw_patch_data[17 * (5 - op) + 15 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 72 + 381 * count] +
+ raw_patch_data[16384 + 35 * op + 73 + 381 * count] * 2;
+ raw_patch_data[17 * (5 - op) + 16 + 128 * count] =
+ raw_patch_data[16384 + 35 * op + 74 + 381 * count];
+ }
+ for (i = 0; i < 4; i++)
+ {
+ raw_patch_data[102 + i + 128 * count] =
+ raw_patch_data[16384 + 26 + i + 381 * count];
+ }
+ for (i = 0; i < 4; i++)
+ {
+ raw_patch_data[106 + i + 128 * count] =
+ raw_patch_data[16384 + 32 + i + 381 * count];
+ }
+ raw_patch_data[110 + 128 * count] =
+ raw_patch_data[16384 + 17 + 381 * count];
+ raw_patch_data[111 + 128 * count] =
+ raw_patch_data[16384 + 18 + 381 * count] +
+ raw_patch_data[16384 + 38 + 381 * count] * 8;
+ for (i = 0; i < 4; i++)
+ {
+ raw_patch_data[112 + i + 128 * count] =
+ raw_patch_data[16384 + 20 + i + 381 * count];
+ }
+ raw_patch_data[116 + 128 * count] =
+ raw_patch_data[16384 + 24 + 381 * count] +
+ raw_patch_data[16384 + 19 + 381 * count] * 2 +
+ raw_patch_data[16384 + 25 + 381 * count] * 16;
+ raw_patch_data[117 + 128 * count] =
+ raw_patch_data[16384 + 37 + 381 * count] - 36;
+ for (i = 0; i < 10; i++)
+ {
+ raw_patch_data[118 + i + 128 * count] =
+ raw_patch_data[16384 + i + 381 * count];
+ }
+ }
+
+ count = 128;
+ filelength = 16384;
+ datastart = 0;
+
+ }
+
+ /* finally, copy patchdata to the right location */
+ if (count > maxpatches)
+ count = maxpatches;
+
+ memcpy(firstpatch, raw_patch_data + datastart, 128 * count);
+ free (raw_patch_data);
+ return count;
+}
+
/* end hexter code */
@@ -692,7 +1035,7 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
unsigned char *raw_patch_data = NULL;
FILE *fp = NULL;
size_t filename_length, key_size, value_size;
- dx7_patch_t patchbuf[DX7_BANK_SIZE];
+ dx7_patch_t patchbuf[DX7_BANK_SIZE * 4]; // 128
dx7_patch_t *firstpatch;
atom_string(argv, msg_type, TYPE_STRING_SIZE);
debug = NULL;
@@ -712,11 +1055,11 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
filename, instance);
if(!strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter") ||
- !strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter6")) {
-
- key = malloc(10 * sizeof(char)); /* holds "patchesN" */
- strcpy(key, "patches0");
+ !strcmp(x->descriptor->LADSPA_Plugin->Label, "hexter6"))
+ {
+ key = malloc(9 * sizeof(char)); /* holds "patchesN" */
+ snprintf(key, 9, "patches0");
/* TODO: duplicates code from load_plugin() */
fd = canvas_open(x->x_canvas, filename, "",
mydir, &filename, MAXPDSTRING, 0);
@@ -726,12 +1069,29 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
pathlen = strlen(mydir);
temp = &mydir[pathlen];
sprintf(temp, "/%s", filename);
- fp = fopen(filepath, "rb");
+ //fp = fopen(filepath, "rb");
}
else{
pd_error(x, "unable to get file descriptor");
}
+
+ char *message = NULL;
+ int count = dx7_patchbank_load(filepath, firstpatch, 128, &message);
+
+ if (count) {
+ ph_debug_post("patch load successful");
+ }
+ else
+ {
+ pd_error(x, "unable to load patch bank");
+ ph_debug_post("%s", message);
+ free(message);
+ }
+ //sprintf("%s", message);
+
+
+#if 0
/*From dx7_voice_data by Sean Bolton */
if(fp == NULL){
pd_error(x, "unable to open patch file: %s", filename);
@@ -833,15 +1193,24 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
free(raw_patch_data);
- if(count == 32)
- value = encode_7in6((uint8_t *)&patchbuf[0].data[0],
- count * DX7_VOICE_SIZE_PACKED);
+#endif
+
+ if(count != 32)
+ {
+ pd_error(x, "invalid count");
+ ph_debug_post("count was: %d", count);
+ }
+
+ /* Regardless of the count, try to load the first 32 voices anyway */
+ value = encode_7in6((uint8_t *)&patchbuf[0],
+ 32 * DX7_VOICE_SIZE_PACKED);
+ // count * DX7_VOICE_SIZE_PACKED
}
else if(!strcmp(x->descriptor->LADSPA_Plugin->Label,
"FluidSynth-DSSI")){
- key = malloc(6 * sizeof(char));
- strcpy(key, "load");
+ key = malloc(5 * sizeof(char));
+ snprintf(key, 5, "load");
value = filename;
}
else{
@@ -855,7 +1224,9 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
x->project_dir = malloc((pathlen) * sizeof(char));
atom_string(&argv[1], x->project_dir, pathlen);
pd_error(x, "project directory for instance %d has been set to: %s", instance, x->project_dir);
- key = DSSI_PROJECT_DIRECTORY_KEY;
+ size_t project_directory_key_len = strlen(DSSI_PROJECT_DIRECTORY_KEY); // #defined in dssi.h
+ key = malloc(project_directory_key_len + 1);
+ snprintf(key, project_directory_key_len, DSSI_PROJECT_DIRECTORY_KEY);
value = x->project_dir;
} else if (!strcmp(msg_type, "dir")) {
pd_error(x, "%s: %s %s: operation not supported",
@@ -987,8 +1358,10 @@ void handle_pd_dssi(ph *x, t_symbol *s, int argc, t_atom *argv)
}
ph_configure_buffer(x, key, value, instance);
}
+ free(key); // should be either NULL or malloc'd
}
- ph_debug_post("The plugin returned %s", debug);
+
+ if(debug) ph_debug_post("The plugin returned %s", debug);
}
diff --git a/pluginhost~/ph_common.c b/pluginhost~/ph_common.c
index e85f6fa..ca65e66 100644
--- a/pluginhost~/ph_common.c
+++ b/pluginhost~/ph_common.c
@@ -278,6 +278,7 @@ static void ph_init_instance(ph *x, unsigned int i)
x->instances[i].pending_bank_msb = -1;
x->instances[i].ui_hidden = 1;
x->instances[i].ui_show = 0;
+ x->instances[i].ui_target = NULL;
memcpy(x->instances[i].perf_buffer, &dx7_init_performance, DX7_PERFORMANCE_SIZE);
//x->instances[i].plugin_port_ctlin_numbers = NULL;
@@ -695,8 +696,9 @@ void ph_instance_send_osc(t_outlet *outlet, ph_instance *instance,
t_int argc, t_atom *argv)
{
- outlet_anything(outlet, gensym("connect"), UI_TARGET_ELEMS,
- instance->ui_target);
+ // TODO: ui_target should be host / port, but not yet implemented
+ //outlet_anything(outlet, gensym("connect"), UI_TARGET_ELEMS,
+ // instance->ui_target);
outlet_anything(outlet, gensym("send"), argc, argv);
outlet_anything(outlet, gensym("disconnect"), 0, NULL);
@@ -1043,7 +1045,6 @@ void ph_init_plugin(ph *x)
x->ports_control_out = 0;
x->buf_write_index = 0;
x->buf_read_index = 0;
-
}
void ph_free_plugin(ph *x)
diff --git a/pluginhost~/ph_common.h b/pluginhost~/ph_common.h
index bed5751..31f30be 100644
--- a/pluginhost~/ph_common.h
+++ b/pluginhost~/ph_common.h
@@ -56,7 +56,7 @@ typedef struct _ph_instance {
int pending_bank_msb;
int ui_hidden;
int ui_show;
- t_atom ui_target[UI_TARGET_ELEMS]; /* host, port */
+ char * ui_target; /* TODO: should be host, port */
uint8_t perf_buffer[DX7_PERFORMANCE_SIZE];
pid_t gui_pid;