mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-19 09:01:15 +02:00
Update Nyquist to v3.09.
This commit is contained in:
102
lib-src/libnyquist/nyquist/nyqsrc/phasevocoder.c
Normal file
102
lib-src/libnyquist/nyquist/nyqsrc/phasevocoder.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/* phasevocoder.c -- this is a stub showing how you might hook a
|
||||
phase vocoder into Nyquist using pvshell
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#ifndef mips
|
||||
#include "stdlib.h"
|
||||
#endif
|
||||
#include "xlisp.h"
|
||||
#include "sound.h"
|
||||
|
||||
#include "falloc.h"
|
||||
#include "cext.h"
|
||||
#include "pvshell.h"
|
||||
|
||||
#include "phasevocoder.h"
|
||||
|
||||
/* use the state[] info for sample interpolation */
|
||||
#define X_VALUE state[0] /* a parameter value */
|
||||
#define F_COUNT state[1] /* counts samples of f */
|
||||
#define G_COUNT state[2] /* counts samples of g */
|
||||
#define G_PREV state[3] /* previous value from g */
|
||||
#define G_NEXT state[4] /* next (current?) value from g */
|
||||
/* invariant: G_NEXT is the G_COUNT'th sample of g */
|
||||
|
||||
/* pv_fetch -- this is an example, but it doesn't really do
|
||||
* phase vocoding. Instead, it will just multiply f, g, and x
|
||||
*
|
||||
* To make things a bit more interesting, we will assume g has
|
||||
* an arbitrary sample rate with respect to f, and will interpolate.
|
||||
*
|
||||
*/
|
||||
long pv_fetch(pvshell_type susp,
|
||||
sample_block_values_type out, long *n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < *n; i++) {
|
||||
long new_flags;
|
||||
sample_type f;
|
||||
double g;
|
||||
/* NOTE: in DSP terms, this is poor code because of the
|
||||
* division operations -- it could be made faster
|
||||
*/
|
||||
/* To get a value from g, first compute the time */
|
||||
double f_time = susp->F_COUNT / susp->f->sr;
|
||||
/* Now compute g count that is past the time */
|
||||
double g_count = f_time * susp->g->sr;
|
||||
while (susp->G_COUNT < g_count) {
|
||||
PVSHELL_TEST_G(susp); /* prepare to get a sample */
|
||||
/* ignore flags from g -- we could, if we wanted,
|
||||
* terminate when either f or g terminated, etc.
|
||||
*/
|
||||
susp->G_PREV = susp->G_NEXT;
|
||||
susp->G_NEXT = PVSHELL_FETCH_G(susp);
|
||||
susp->G_COUNT++;
|
||||
}
|
||||
/* now interpolate to get the value of g at f_time */
|
||||
g = susp->G_PREV + (susp->G_NEXT - susp->G_PREV) *
|
||||
(g_count - (susp->G_COUNT - 1));
|
||||
new_flags = PVSHELL_TEST_F(susp);
|
||||
susp->flags |= new_flags;
|
||||
if (new_flags) break;
|
||||
f = PVSHELL_FETCH_F(susp);
|
||||
susp->F_COUNT++; /* count how many samples we have taken */
|
||||
|
||||
/* now we have f, g, x */
|
||||
*out++ = f * g * susp->X_VALUE;
|
||||
}
|
||||
/* i is the number of samples we acutally computed */
|
||||
*n = i;
|
||||
/* if we computed samples, we want to return them before
|
||||
* returning flags that say we're done or stopped
|
||||
*/
|
||||
return (i ? 0 : susp->flags);
|
||||
}
|
||||
|
||||
|
||||
sound_type snd_phasevocoder(sound_type f, sound_type g, double x)
|
||||
{
|
||||
/* we're using 5 doubles of state. The first is a parameter,
|
||||
* and the rest are initialized to zero except for state[2],
|
||||
* aka G_COUNT. This is the number of samples we have read
|
||||
* from G. Since we're interpolating we need a one-sample
|
||||
* lookahead, and initializing the count to -1 causes an
|
||||
* extra fetch and hence 1-sample lookahead. This state is copied
|
||||
* into the pvshell structure, so we don't need to allocate
|
||||
* a vector on the heap.
|
||||
*/
|
||||
double state[5] = {0, 0, -1, 0, 0};
|
||||
state[0] = x;
|
||||
/* If f and g do not start at the same time, we should really
|
||||
* should do something about it, but we'll just throw an error.
|
||||
* Be careful to allow small differences (within one sample).
|
||||
*/
|
||||
if (fabs(f->t0 - g->t0) * f->sr > 0.5) {
|
||||
xlfail("phasevocoder inputs must start at the same time");
|
||||
}
|
||||
/* output the same sample rate and start time as f */
|
||||
return snd_make_pvshell("snd_phasevocoder", f->sr, f->t0,
|
||||
&pv_fetch, f, g,
|
||||
state, sizeof(state) / sizeof(state[0]));
|
||||
}
|
Reference in New Issue
Block a user