From ff60f598f3d377cfc208dba757ff1ece53b335f8 Mon Sep 17 00:00:00 2001 From: Roger Dannenberg Date: Sun, 28 Mar 2021 22:55:36 -0400 Subject: [PATCH] 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)) --- lib-src/libnyquist/nyquist/nyqsrc/convolve.c | 61 +++++++++++++++----- lib-src/libnyquist/nyquist/nyqsrc/samples.h | 2 +- lib-src/libnyquist/nyquist/nyqsrc/sndfnint.c | 2 +- lib-src/libnyquist/nyquist/nyqsrc/sound.c | 18 +++++- lib-src/portsmf/allegro.cpp | 3 +- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/lib-src/libnyquist/nyquist/nyqsrc/convolve.c b/lib-src/libnyquist/nyquist/nyqsrc/convolve.c index 3e2fe91e2..e513bb2fa 100644 --- a/lib-src/libnyquist/nyquist/nyqsrc/convolve.c +++ b/lib-src/libnyquist/nyquist/nyqsrc/convolve.c @@ -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 #include #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; diff --git a/lib-src/libnyquist/nyquist/nyqsrc/samples.h b/lib-src/libnyquist/nyquist/nyqsrc/samples.h index 1d57af443..0a6259d59 100644 --- a/lib-src/libnyquist/nyquist/nyqsrc/samples.h +++ b/lib-src/libnyquist/nyquist/nyqsrc/samples.h @@ -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) */ diff --git a/lib-src/libnyquist/nyquist/nyqsrc/sndfnint.c b/lib-src/libnyquist/nyquist/nyqsrc/sndfnint.c index 4cd838af3..a974a9830 100644 --- a/lib-src/libnyquist/nyquist/nyqsrc/sndfnint.c +++ b/lib-src/libnyquist/nyquist/nyqsrc/sndfnint.c @@ -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(); diff --git a/lib-src/libnyquist/nyquist/nyqsrc/sound.c b/lib-src/libnyquist/nyquist/nyqsrc/sound.c index 6078502de..a8af14836 100644 --- a/lib-src/libnyquist/nyquist/nyqsrc/sound.c +++ b/lib-src/libnyquist/nyquist/nyqsrc/sound.c @@ -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"); diff --git a/lib-src/portsmf/allegro.cpp b/lib-src/portsmf/allegro.cpp index 2e0fd5274..a87117e38 100644 --- a/lib-src/portsmf/allegro.cpp +++ b/lib-src/portsmf/allegro.cpp @@ -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"));