Fixes 2 bugs in Nyquist: (1) Bug 2706 probably already has a workaround in place, but the original code called snd-samples with ny:all for the maximum length to retrieve, and now that ny:all is bigger than 32-bits, the value was getting truncated. This change fixes legacy code to be 64-bit-aware. (2) allows sounds to be accessed beyond their stop time even when they stop in the middle of a block of samples. For example, this Nyquist prompt no longer generates garbage or crashes:

(setf idur 5000)
(setf impulse (extract-abs 0 (/ idur *sound-srate*) (cue *track*)))
(mult 0.01 (convolve *track* impulse))
This commit is contained in:
Roger Dannenberg 2021-03-28 22:55:36 -04:00
parent c9afd39845
commit ff60f598f3
5 changed files with 66 additions and 20 deletions

View File

@ -62,12 +62,13 @@
*/
// You can turn on debugging output with: #define D if (1)
#define D if (0)
#define D if (0)
#define MAX_IR_LEN 4000000 /* maximum impulse response length */
#define MAX_LOG_FFT_SIZE 16 /* maximum fft size for convolution */
//#define MAX_LOG_FFT_SIZE 4 /* maximum fft size for convolution */
#define _USE_MATH_DEFINES 1 /* for Visual C++ to get M_LN2 */
#include <assert.h>
#include <math.h>
#include "stdio.h"
#ifndef mips
@ -191,11 +192,16 @@ void convolve_s_fetch(snd_susp_type a_susp, snd_list_type snd_list)
}
/* zero fill to size 2N */
memset(Xj + N, 0, N * sizeof(Xj[0]));
D printf("Xj at offset %td: ", Xj - susp->X);
D for (i = 0; i < susp->N * 2; i++) {
printf("%g ", Xj[i]);
D {
printf("Xj at offset %td: ", Xj - susp->X);
printf(" %d samples ", susp->N * 2);
float big = 0.0;
for (i = 0; i < susp->N * 2; i++) {
// printf("%g ", Xj[i]);
big = max(big, fabs(Xj[i]));
}
printf("MAX: %g\n", big);
}
D printf("\n");
/* Compute FFT of Xj in place */
fftInit(susp->M);
rffts(Xj, susp->M, 1);
@ -208,20 +214,28 @@ void convolve_s_fetch(snd_susp_type a_susp, snd_list_type snd_list)
/* Compute IFFT of Y in place */
riffts(Y, susp->M, 1);
/* R += Y */
D printf("Output block %d, X offset %td: ", k, X - susp->X);
D { printf("Output block %d, X offset %td: ", k, X - susp->X);
printf(" %d samples ", 2 * N);
float big = 0.0;
for (i = 0; i < 2 * N; i++) {
big = max(big, fabs(Y[i]));
}
printf("MAX: %g\n", big);
}
for (i = 0; i < 2 * N; i++) {
R[i] += Y[i];
D printf("%g ", Y[i]);
}
D printf("\n");
}
/* now N samples of R can be output */
susp->R_current = R;
D printf("R: ");
D for (i = 0; i < susp->N; i++) {
printf("%g ", R[i]);
D printf("R: %d samples ", susp->N);
D { float big = 0.0;
for (i = 0; i < susp->N; i++) {
// printf("%g ", R[i]);
big = max(big, fabs(R[i]));
}
printf("MAX: %g\n", big);
}
D printf("\n");
susp->j = (susp->j + 1) % susp->L;
}
/* compute togo, the number of samples to "compute" */
@ -338,12 +352,22 @@ void fill_with_samples(sample_type *x, sound_type s, long n)
s->CNT = s->INDEX = 0;
}
int icnt = (int) s->CNT; /* need this to be int type */
assert(icnt >= 0);
if (icnt == s->INDEX) {
sound_get_next(s, &icnt);
assert(icnt >= 0);
s->CNT = icnt; /* save the count back into s->extra */
s->INDEX = 0;
}
x[i] = s->SAMPLES[s->INDEX++] * s->scale;
assert(x[i] < 2);
}
D { float big = 0.0;
for (i = 0; i < n; i++) {
big = max(big, fabs(x[i]));
assert(big < 2);
}
printf("fill_with_samples n %ld scale %g max %g\n", n, s->scale, big);
}
}
@ -400,9 +424,16 @@ sound_type snd_make_convolve(sound_type x_snd, sound_type h_snd)
for (i = 0; i < susp->L; i++) {
int j;
float *H = susp->H + i * susp->N * 2;
D printf("H_%d at %td: ", i, H - susp->H);
D for (j = 0; j < susp->N * 2; j++) printf("%g ", H[j]);
D printf("\n");
D { printf("H_%d at %td: ", i, H - susp->H);
printf("%d samples ", susp->N * 2);
float big = 0.0;
for (j = 0; j < susp->N * 2; j++) {
big = max(big, fabs(H[j]));
assert(big < 2);
// printf("%g ", H[j]);
}
printf("big %g\n", big);
}
}
sound_unref(h_snd);
h_snd = NULL;

View File

@ -9,7 +9,7 @@ void samples_symbols(void);
sound_type snd_from_array(double t0, double sr, LVAL array);
/* LISP: (SND-FROM-ARRAY ANYNUM ANYNUM ANY) */
LVAL snd_samples(sound_type s, long len); /* LISP: (SND-SAMPLES SOUND LONG) */
LVAL snd_samples(sound_type s, int64_t len); /* LISP: (SND-SAMPLES SOUND FIXNUM) */
int64_t snd_length(sound_type s, int64_t len); /* LISP: (SND-LENGTH SOUND FIXNUM) */
double snd_maxsamp(sound_type s); /* LISP: (SND-MAXSAMP SOUND) */

View File

@ -588,7 +588,7 @@ LVAL xlc_snd_from_array(void)
LVAL xlc_snd_samples(void)
{
sound_type arg1 = getsound(xlgasound());
long arg2 = (long) getfixnum(xlgafixnum());
int64_t arg2 = getfixnum(xlgafixnum());
LVAL result;
xllastarg();

View File

@ -545,7 +545,6 @@ void snd_list_unref(snd_list_type list)
break; // the rest of the list is shared, nothing more to free
}
next = NULL;
// list nodes either point to a block of samples or this is the
// last list node (list->block == NULL) which points to a suspension
// lists can also terminate at the zero_block, which is an infinite
@ -1111,7 +1110,21 @@ sample_block_type SND_get_first(sound_type snd, int *cnt)
/* block boundary: replace with zero sound */
snd->list = zero_snd_list;
snd_list_unref(snd_list);
} else {
// the idea here is that we have reached snd->stop, which
// means the next samples have to be zero, but we are reading
// from the middle of a block of samples. Maybe, for example,
// snd was constructed by snd_xform that imposed a new stop
// time. Since we haven't read the next sample, we can take
// care of this by just creating a new snd_list with a shorter
// block_len to take whatever samples we need before stop, then
// link ot zero_snd_list so that subsequent samples are zero.
// However, if we actually start reading zeros from zero_snd_list,
// the test above for > snd->stop will bring us back here. We
// ignore these cases just below by testing if the current list
// is the zero_snd_list. If so, we're just reading zeros, we're
// past the stop time, and we can just keep reading zeros, so
// do nothing.
} else if (snd->list != zero_snd_list) {
/* not a block boundary: build new list */
snd->list = snd_list_create((snd_susp_type) zero_snd_list);
snd->list->block_len = (short) (snd->stop - snd->current);
@ -1123,6 +1136,7 @@ sample_block_type SND_get_first(sound_type snd, int *cnt)
}
*cnt = snd_list->block_len;
assert(snd_list->block_len >= 0);
/* this should never happen */
if (*cnt == 0) {
stdputstr("SND_get_first returned 0 samples\n");

View File

@ -22,6 +22,7 @@ using namespace std;
#include "algsmfrd_internal.h"
// #include "trace.h" -- only needed for debugging
#include "math.h"
#include "inttypes.h" // for PRId64
#define ALGDBG(x) ;
// #define ALGDBG(x) x; // turn on some printing for tracing/debugging
@ -132,7 +133,7 @@ void Alg_parameter::show()
printf("%s:%s", attr_name(), s);
break;
case 'i':
printf("%s:%lld", attr_name(), i);
printf("%s:%" PRId64, attr_name(), i);
break;
case 'l':
printf("%s:%s", attr_name(), (l ? "t" : "f"));