Commit 16973649 authored by Jonathan Wilkes's avatar Jonathan Wilkes
Browse files

Merge branch 'soundfiler-fixes'

Conflicts:
	pd/src/m_pd.h
parents 15094e4c a4782de2
......@@ -16,3 +16,6 @@
[submodule "externals/lyonpotpourri"]
path = externals/lyonpotpourri
url = https://github.com/ericlyon/lyonpotpourri3.0.git
[submodule "externals/cyclone"]
path = externals/cyclone
url = https://git.purrdata.net/jwilkes/pd-cyclone.git
......@@ -431,16 +431,26 @@ cxc_clean:
#------------------------------------------------------------------------------#
# CYCLONE
cyclone:
make -C $(externals_src)/miXed/cyclone -f Makefile.libdir \
PD_PATH=$(pd_src) PD_INCLUDE=$(DESTDIR)$(includedir)
ifeq ($(OS_NAME),windows)
make -C $(externals_src)/cyclone \
pdbinpath=$(pd_src)/src PDINCLUDEDIR=$(DESTDIR)$(includedir)
else
make -C $(externals_src)/cyclone \
PDDIR=$(pd_src)
endif
cyclone_install:
make -C $(externals_src)/miXed/cyclone -f Makefile.libdir \
make -C $(externals_src)/cyclone \
DESTDIR="$(DESTDIR)" objectsdir="$(objectsdir)" \
install
install -p $(externals_src)/cyclone/documentation/purr_help/*.pd \
$(DESTDIR)$(objectsdir)/cyclone
install -p \
$(externals_src)/cyclone/documentation/purr_help/abs_GUI/*.pd \
$(DESTDIR)$(objectsdir)/cyclone
cyclone_clean:
make -C $(externals_src)/miXed/cyclone -f Makefile.libdir \
make -C $(externals_src)/cyclone \
clean
#------------------------------------------------------------------------------#
......
Subproject commit d22585a21bf88246298e0ae0cd80c45b803e3fd5
......@@ -350,18 +350,18 @@ static void grid_properties(t_gobj *z, t_glist *owner)
gui_start_vmess("gui_external_dialog", "ss", gfx_tag, "grid");
gui_start_array();
gui_s("receive_symbol"); gui_s(x->x_name->s_name);
gui_s("width"); gui_i(x->x_width);
gui_s("min"); gui_f(x->x_min);
gui_s("max"); gui_f(x->x_max);
gui_s("height"); gui_i(x->x_height);
gui_s("y-min"); gui_f(x->y_min);
gui_s("y-max"); gui_f(x->y_max);
gui_s("grid_toggle"); gui_i(x->x_grid);
gui_s("x-steps"); gui_f(x->x_xstep);
gui_s("y-steps"); gui_f(x->x_ystep);
gui_s("x-lines"); gui_i(x->x_xlines);
gui_s("y-lines"); gui_i(x->x_ylines);
gui_s("symbol"); gui_s("receive_symbol"); gui_s(x->x_name->s_name);
gui_s("int"); gui_s("width"); gui_i(x->x_width);
gui_s("int"); gui_s("min"); gui_f(x->x_min);
gui_s("float"); gui_s("max"); gui_f(x->x_max);
gui_s("int"); gui_s("height"); gui_i(x->x_height);
gui_s("float"); gui_s("y-min"); gui_f(x->y_min);
gui_s("float"); gui_s("y-max"); gui_f(x->y_max);
gui_s("toggle"); gui_s("show_grid"); gui_i(x->x_grid);
gui_s("float"); gui_s("x-steps"); gui_f(x->x_xstep);
gui_s("float"); gui_s("y-steps"); gui_f(x->x_ystep);
gui_s("int"); gui_s("x-lines"); gui_i(x->x_xlines);
gui_s("int"); gui_s("y-lines"); gui_i(x->x_ylines);
gui_end_array();
gui_end_vmess();
......@@ -450,6 +450,11 @@ static void grid_displace(t_gobj *z, t_glist *glist, int dx, int dy)
x->y_current += dy;
if (xold != text_xpix(&x->x_obj, glist) || yold != text_ypix(&x->x_obj, glist))
{
gui_vmess("gui_text_displace", "xxii",
glist,
x,
dx,
dy);
//grid_draw_move(x, x->x_glist);
canvas_fixlinesfor(glist, (t_text *)z);
}
......@@ -882,10 +887,10 @@ void grid_setup(void)
/* Big hack for receiving edit-mode resize anchor clicks from
g_editor.c. */
class_addmethod(grid_class, (t_method)grid_click_for_resizing,
gensym("_click_for_resizing"),
gensym("_click"),
A_FLOAT, A_FLOAT, A_FLOAT, 0);
class_addmethod(grid_class, (t_method)grid_motion_for_resizing,
gensym("_motion_for_resizing"),
gensym("_motion"),
A_FLOAT, A_FLOAT, 0);
grid_widgetbehavior.w_getrectfn = grid_getrect;
grid_widgetbehavior.w_displacefn = grid_displace;
......
......@@ -86,30 +86,31 @@ function ok() {
// value: a value for the input
function parse_attrs(attrs) {
var ret = [],
elem;
attrs.forEach(function(token, i) {
if (i % 2 === 0) {
elem = {};
token = token.split("_");
if (token.length > 1) {
elem.type = token[token.length - 1];
if (elem.type !== "symbol" &&
elem.type !== "toggle") {
// no suffix defaults to "number"
elem.type = "number";
elem,
gate = false;
attrs.forEach(function(attr, i) {
if (i % 3 === 0) {
elem = gate ? elem : {};
gate = attr === "enum";
elem.type = attr;
} else if (i % 3 === 1) {
elem.name = attr;
elem.label = attr.replace("_", " ");
} else {
if (elem.type === "enum") {
if (elem.options) {
elem.options.push(attr);
} else {
// remove the type suffix
token = token.slice(0, -1);
elem.options = [attr];
}
} else {
elem.type = "number";
elem.value = attr;
}
elem.name = token.join("_");
elem.label = token.join(" ");
} else {
elem.value = token;
// now push the object onto the array
ret.push(elem);
if (elem.type !== "enum") {
elem.type = elem.type === "enum_index" ? "enum" : elem.type;
ret.push(elem);
}
}
});
return ret;
......@@ -134,7 +135,6 @@ function register_window_id(gfxstub, args) {
translate_form();
build_form(external_name, array_of_objects);
// We don't turn on rendering of the "container" div until
// We've finished displaying all the spans and populating the
// labels and form elements. That makes it more efficient and
......@@ -160,7 +160,10 @@ function translate_form() {
function get_input_type(t) {
return t === "symbol" ? "text" :
t === "number" ? "text" :
t === "int" ? "text" :
t === "float" ? "text" :
t === "color" ? "color" :
t === "enum" ? "select" :
t === "toggle" ? "checkbox":
"text";
}
......@@ -168,23 +171,39 @@ function get_input_type(t) {
function build_form(external_name, array_of_objects) {
var fieldset = document.querySelector("fieldset");
document.querySelector("legend").textContent = external_name;
array_of_objects.forEach(function(elem) {
var input_elem = document.createElement("input"),
label = document.createElement("label");
input_elem.type = get_input_type(elem.type);
if (input_elem.type === "checkbox") {
input_elem.checked = elem.value !== 0;
input_elem.onchange = function() {
elem.value = input_elem.checked ? 1 : 0;
array_of_objects.forEach(function(ob) {
var elem,
label,
type = get_input_type(ob.type);
if (type === "select") {
elem = document.createElement("select");
ob.options.forEach(function(e) {
var option = document.createElement("option");
option.textContent = e;
elem.appendChild(option);
});
elem.selectedIndex = ob.value;
elem.onchange = function() {
ob.value = elem.selectedIndex;
}
} else if (type === "checkbox") {
elem = document.createElement("input");
elem.type = "checkbox";
elem.checked = ob.value !== 0;
elem.onchange = function() {
ob.value = elem.checked ? 1 : 0;
};
} else {
input_elem.value = elem.value;
input_elem.onchange = function() {
elem.value = input_elem.value;
elem = document.createElement("input");
elem.type = type;
elem.value = ob.value;
elem.onchange = function() {
ob.value = elem.value;
}
}
label.textContent = elem.label;
label.appendChild(input_elem);
label = document.createElement("label");
label.textContent = ob.label;
label.appendChild(elem);
fieldset.appendChild(label);
// stop-gap until we make this prettier through css: insert a break
fieldset.appendChild(document.createElement("br"));
......
......@@ -3751,6 +3751,7 @@ function gui_scope_draw_bg(cid, tag, fg_color, bg_color, w, h, grid_width, dx, d
path_string = "",
fg_xy_path, // to be used for the foreground lines
fg_mono_path,
border,
i, x, y, align_x, align_y;
// Path strings for the grid lines
// vertical lines...
......@@ -3767,6 +3768,7 @@ function gui_scope_draw_bg(cid, tag, fg_color, bg_color, w, h, grid_width, dx, d
d: path_string,
fill: "none",
stroke: "black",
class: "grid",
"stroke-width": grid_width,
});
// We go ahead and create a path to be used in the foreground. We'll
......@@ -3783,10 +3785,18 @@ function gui_scope_draw_bg(cid, tag, fg_color, bg_color, w, h, grid_width, dx, d
stroke: fg_color,
class: "fgmono"
});
border = create_item(cid, "rect", {
style: "fill: none;",
width: w,
height: h,
class: "border",
"stroke-width": grid_width
});
g.appendChild(bg);
g.appendChild(path);
g.appendChild(fg_xy_path);
g.appendChild(fg_mono_path);
g.appendChild(border);
}
function scope_configure_fg(cid, tag, type, data_array) {
......@@ -3805,13 +3815,13 @@ function gui_scope_configure_fg_mono(cid, tag, data_array) {
scope_configure_fg(cid, tag, ".fgmono", data_array);
}
function gui_scope_configure_bg_color(cid, tag, color) {
function scope_configure_bg_color(cid, tag, color) {
var g = get_gobj(cid, tag),
elem = g.querySelector(".bg");
configure_item(elem, { fill: color });
}
function gui_scope_configure_fg_color(cid, tag, color) {
function scope_configure_fg_color(cid, tag, color) {
var g = get_gobj(cid, tag),
xy = g.querySelector(".fgxy"),
mono = g.querySelector(".fgmono");
......@@ -3819,11 +3829,33 @@ function gui_scope_configure_fg_color(cid, tag, color) {
configure_item(mono, { stroke: color });
}
function scope_configure_grid_color(cid, tag, color) {
var g = get_gobj(cid, tag),
grid = g.querySelector(".grid");
configure_item(grid, { stroke: color });
}
function gui_scope_configure_color(cid, tag, layer, color) {
if (layer === "fg") {
scope_configure_fg_color(cid, tag, color);
} else if (layer === "bg") {
scope_configure_bg_color(cid, tag, color);
} else if (layer === "grid") {
scope_configure_grid_color(cid, tag, color);
}
}
function gui_scope_clear_fg(cid, tag) {
scope_configure_fg(cid, tag, ".fgxy", []);
scope_configure_fg(cid, tag, ".fgmono", []);
}
function gui_scope_erase_innards(cid, tag) {
var g = get_gobj(cid, tag);
// Nuke it
g.innerHTML = '';
}
// unauthorized/grid
function get_grid_data(w, h, x_l, y_l) {
......
......@@ -298,6 +298,7 @@ static t_int *tabread_tilde_perform(t_int *w)
int i;
maxindex = x->x_npoints - 1;
if (maxindex < 0) goto zero;
if (!buf) goto zero;
for (i = 0; i < n; i++)
......@@ -398,6 +399,7 @@ static t_int *tabread4_tilde_perform(t_int *w)
int i;
maxindex = x->x_npoints - 3;
if (maxindex < 0) goto zero;
if (!buf) goto zero;
......
......@@ -29,6 +29,7 @@ objects use Posix-like threads. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "m_pd.h"
......@@ -200,6 +201,21 @@ static void swapstring(char *foo, int doit)
}
}
/* write a sample rate as an 80-bit AIFF-compatible number */
static void makeaiffsamprate(double sr, unsigned char *shit)
{
int exponent;
double mantissa = frexp(sr, &exponent);
unsigned long fixmantissa = ldexp(mantissa, 32);
shit[0] = (exponent+16382)>>8;
shit[1] = exponent+16382;
shit[2] = fixmantissa >> 24;
shit[3] = fixmantissa >> 16;
shit[4] = fixmantissa >> 8;
shit[5] = fixmantissa;
shit[6] = shit[7] = shit[8] = shit[9] = 0;
}
/******************** soundfile access routines **********************/
/* This routine opens a file, looks for either a nextstep or "wave" header,
......@@ -292,7 +308,8 @@ int open_soundfile_via_fd(int fd, int headersize,
{
long chunksize = swap4(((t_wavechunk *)buf)->wc_size,
swap), seekto = headersize + chunksize + 8, seekout;
if (seekto & 1) /* pad up to even number of bytes */
seekto++;
if (!strncmp(((t_wavechunk *)buf)->wc_id, "fmt ", 4))
{
long commblockonset = headersize + 8;
......@@ -344,6 +361,8 @@ int open_soundfile_via_fd(int fd, int headersize,
{
long chunksize = swap4(((t_datachunk *)buf)->dc_size,
swap), seekto = headersize + chunksize + 8, seekout;
if (seekto & 1) /* pad up to even number of bytes */
seekto++;
/* post("chunk %c %c %c %c seek %d",
((t_datachunk *)buf)->dc_id[0],
((t_datachunk *)buf)->dc_id[1],
......@@ -374,8 +393,8 @@ int open_soundfile_via_fd(int fd, int headersize,
goto badheader;
headersize = seekto;
}
bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap);
headersize += 8;
bytelimit = swap4(((t_datachunk *)buf)->dc_size, swap) - 8;
headersize += sizeof(t_datachunk);
}
}
/* seek past header and any sample frames to skip */
......@@ -781,8 +800,6 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
{
long datasize = nframes * nchannels * bytespersamp;
long longtmp;
static unsigned char dogdoo[] =
{0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
if (strcmp(filenamebuf + strlen(filenamebuf)-4, ".aif") &&
strcmp(filenamebuf + strlen(filenamebuf)-5, ".aiff"))
strcat(filenamebuf, ".aif");
......@@ -795,10 +812,11 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
longtmp = swap4(nframes, swap);
memcpy(&aiffhdr->a_nframeshi, &longtmp, 4);
aiffhdr->a_bitspersamp = swap2(8 * bytespersamp, swap);
memcpy(aiffhdr->a_samprate, dogdoo, sizeof(dogdoo));
longtmp = swap4(datasize, swap);
memcpy(aiffhdr->a_samprate + sizeof(dogdoo), &longtmp, 4);
memset(aiffhdr->a_samprate + sizeof(dogdoo) + 4, 0, 8);
makeaiffsamprate(samplerate, aiffhdr->a_samprate);
strncpy(((char *)(&aiffhdr->a_samprate))+10, "SSND", 4);
longtmp = swap4(datasize + 8, swap);
memcpy(((char *)(&aiffhdr->a_samprate))+14, &longtmp, 4);
memset(((char *)(&aiffhdr->a_samprate))+18, 0, 8);
headersize = AIFFPLUS;
}
else /* WAVE format */
......@@ -1264,9 +1282,9 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
poswas = lseek(fd, 0, SEEK_CUR);
eofis = lseek(fd, 0, SEEK_END);
if (poswas < 0 || eofis < 0)
if (poswas < 0 || eofis < 0 || eofis < poswas)
{
pd_error(x, "lseek failed");
pd_error(x, "lseek failed: %ld..%ld", poswas, eofis);
goto done;
}
lseek(fd, poswas, SEEK_SET);
......@@ -1283,14 +1301,13 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
{
int vecsize;
garray_resize(garrays[i], finalsize);
garray_resize_long(garrays[i], finalsize);
/* for sanity's sake let's clear the save-in-patch flag here */
garray_setsaveit(garrays[i], 0);
garray_getfloatwords(garrays[i], &vecsize,
&vecs[i]);
/* if the resize failed, garray_resize reported the error */
if (vecsize != framesinfile)
if (!garray_getfloatwords(garrays[i], &vecsize, &vecs[i])
|| (vecsize != framesinfile))
{
/* if the resize failed, garray_resize reported the error */
pd_error(x, "resize failed");
goto done;
}
......@@ -1318,18 +1335,18 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
for (i = 0; i < argc; i++)
{
int vecsize;
garray_getfloatwords(garrays[i], &vecsize, &vecs[i]);
for (j = itemsread; j < vecsize; j++)
vecs[i][j].w_float = 0;
if (garray_getfloatwords(garrays[i], &vecsize, &vecs[i]))
for (j = itemsread; j < vecsize; j++)
vecs[i][j].w_float = 0;
}
/* zero out vectors in excess of number of channels */
for (i = channels; i < argc; i++)
{
int vecsize;
t_word *foo;
garray_getfloatwords(garrays[i], &vecsize, &foo);
for (j = 0; j < vecsize; j++)
foo[j].w_float = 0;
if (garray_getfloatwords(garrays[i], &vecsize, &foo))
for (j = 0; j < vecsize; j++)
foo[j].w_float = 0;
}
/* do all graphics updates */
for (i = 0; i < argc; i++)
......@@ -1339,7 +1356,7 @@ static void soundfiler_read(t_soundfiler *x, t_symbol *s,
goto done;
usage:
pd_error(x, "usage: read [flags] filename tablename...");
post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
post("flags: -skip <n> -resize -maxsize <n> ...");
post("-raw <headerbytes> <channels> <bytespersamp> <endian (b, l, or n)>.");
done:
if (fd >= 0)
......@@ -1799,13 +1816,13 @@ static void *readsf_child_main(void *zz)
{
x->x_fifohead += sysrtn;
x->x_bytelimit -= sysrtn;
if (x->x_fifohead == fifosize)
x->x_fifohead = 0;
if (x->x_bytelimit <= 0)
{
x->x_eof = 1;
break;
}
if (x->x_fifohead == fifosize)
x->x_fifohead = 0;
}
#ifdef DEBUG_SOUNDFILE
sprintf(boo, "after: head %d, tail %d\n",
......@@ -2432,20 +2449,23 @@ static t_int *writesf_perform(t_int *w)
bigendian = x->x_bigendian;
if (x->x_state == STATE_STREAM)
{
int wantbytes;
int wantbytes, roominfifo;
pthread_mutex_lock(&x->x_mutex);
wantbytes = sfchannels * vecsize * bytespersample;
while (x->x_fifotail > x->x_fifohead &&
x->x_fifotail < x->x_fifohead + wantbytes + 1)
roominfifo = x->x_fifotail - x->x_fifohead;
if (roominfifo <= 0)
roominfifo += x->x_fifosize;
while (roominfifo < wantbytes + 1)
{
#ifdef DEBUG_SOUNDFILE
pute("wait...\n");
#endif
fprintf(stderr, "writesf waiting for disk write..\n");
fprintf(stderr, "(head %d, tail %d, room %d, want %d)\n",
x->x_fifohead, x->x_fifotail, roominfifo, wantbytes);
sfread_cond_signal(&x->x_requestcondition);
sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
#ifdef DEBUG_SOUNDFILE
pute("done\n");
#endif
fprintf(stderr, "... done waiting.\n");
roominfifo = x->x_fifotail - x->x_fifohead;
if (roominfifo <= 0)
roominfifo += x->x_fifosize;
}
soundfile_xferout_sample(sfchannels, x->x_outvec,
......@@ -2550,10 +2570,8 @@ static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv)
(x->x_bytespersample * x->x_sfchannels * MAXVECSIZE));
/* arrange for the "request" condition to be signalled 16
times per buffer */
x->x_sigcountdown = x->x_sigperiod =
(x->x_fifosize /
(16 * x->x_bytespersample * x->x_sfchannels *
x->x_vecsize));
x->x_sigcountdown = x->x_sigperiod = (x->x_fifosize /
(16 * x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
sfread_cond_signal(&x->x_requestcondition);
pthread_mutex_unlock(&x->x_mutex);
}
......@@ -2563,9 +2581,8 @@ static void writesf_dsp(t_writesf *x, t_signal **sp)
int i, ninlets = x->x_sfchannels;
pthread_mutex_lock(&x->x_mutex);
x->x_vecsize = sp[0]->s_n;
x->x_sigperiod = (x->x_fifosize /
(x->x_bytespersample * ninlets * x->x_vecsize));
(16 * x->x_bytespersample * x->x_sfchannels * x->x_vecsize));
for (i = 0; i < ninlets; i++)
x->x_outvec[i] = sp[i]->s_vec;
x->x_insamplerate = sp[0]->s_sr;
......
......@@ -698,7 +698,7 @@ void garray_arraydialog(t_garray *x, t_symbol *s, int argc, t_atom *argv)
template_findbyname(x->x_scalar->sc_template),
gensym("style"), x->x_scalar->sc_vec, 1);*/
int size;
long size;
t_symbol *argname = sharptodollar(name);
t_array *a = garray_getarray(x);
t_template *scalartemplate;
......@@ -757,7 +757,7 @@ void garray_arraydialog(t_garray *x, t_symbol *s, int argc, t_atom *argv)
x->x_style = style;
if (size != a->a_n)
{
garray_resize(x, size);
garray_resize_long(x, size);
}
else
{
......@@ -1680,7 +1680,7 @@ static void garray_const(t_garray *x, t_floatarg g)
}
/* sum of Fourier components; called from routines below */
static void garray_dofo(t_garray *x, int npoints, t_float dcval,
static void garray_dofo(t_garray *x, long npoints, t_float dcval,
int nsin, t_float *vsin, int sineflag)
{
double phase, phaseincr, fj;
......@@ -1696,7 +1696,7 @@ static void garray_dofo(t_garray *x, int npoints, t_float dcval,
if (npoints != (1 << ilog2(npoints)))
post("%s: rounding to %d points", array->a_templatesym->s_name,
(npoints = (1<<ilog2(npoints))));
garray_resize(x, npoints + 3);
garray_resize_long(x, npoints + 3);
phaseincr = 2. * 3.14159 / npoints;
for (i = 0, phase = -phaseincr; i < array->a_n; i++, phase += phaseincr)
{
......@@ -1716,7 +1716,8 @@ static void garray_dofo(t_garray *x, int npoints, t_float dcval,
static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
{
t_float *svec;
int npoints, i;
long npoints;
int i;
if (argc < 2)
{
error("sinesum: %s: need number of points and partial strengths",
......@@ -1739,7 +1740,8 @@ static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv)
{
t_float *svec;
int npoints, i;
long npoints;
int i;
if (argc < 2)
{
error("sinesum: %s: need number of points and partial strengths",
......@@ -1956,10 +1958,11 @@ int garray_ambigendian(void)
return (c==0);
}
void garray_resize(t_garray *x, t_floatarg f)
void garray_resize_long(t_garray *x, long n)
{
t_array *array = garray_getarray(x);
int n = (f < 1 ? 1 : f);
if (n < 1)
n = 1;
//fprintf(stderr,"garray_resize %d\n", n);
array_resize(array, n);
garray_fittograph(x, n, 1);/*template_getfloat(
......@@ -1970,6 +1973,12 @@ void garray_resize(t_garray *x, t_floatarg f)