mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-29 15:19:44 +02:00
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:
parent
c9afd39845
commit
ff60f598f3
@ -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;
|
||||
|
@ -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) */
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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"));
|
||||
|
Loading…
x
Reference in New Issue
Block a user