Allow loading the entire audio file at vsjack_open() time,
get the actual oversampling, to allocate the sample space.
This commit is contained in:
parent
dbb81ae1e7
commit
6e9e5f7d80
|
|
@ -13,13 +13,14 @@
|
||||||
#define VS_RESAMPLING_CHUNK 1024
|
#define VS_RESAMPLING_CHUNK 1024
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
#include "ngspice/ngspice.h"
|
||||||
|
#include "vsjack.h"
|
||||||
|
|
||||||
extern char* inp_pathresolve(const char* name);
|
extern char* inp_pathresolve(const char* name);
|
||||||
|
|
||||||
#define MAX_D 6
|
#define MAX_D 6
|
||||||
static char* (sources[MAX_D]);
|
|
||||||
|
|
||||||
static SNDFILE* m_sndfile[MAX_D];
|
static SNDFILE* m_sndfile[MAX_D];
|
||||||
|
static int m_channel[MAX_D]; //< channel to be used in src-file
|
||||||
static int m_channels[MAX_D]; //< number of channles in src-file
|
static int m_channels[MAX_D]; //< number of channles in src-file
|
||||||
static uint32_t m_samplerate[MAX_D]; //< samplerate of source
|
static uint32_t m_samplerate[MAX_D]; //< samplerate of source
|
||||||
static uint32_t m_frames[MAX_D]; //< duration of source in frames
|
static uint32_t m_frames[MAX_D]; //< duration of source in frames
|
||||||
|
|
@ -29,8 +30,7 @@ static float* (interleaved[MAX_D]); //< internal soundfile buffer
|
||||||
|
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
#include <samplerate.h>
|
#include <samplerate.h>
|
||||||
static double src_ratio = 64.0;
|
static double src_ratio[MAX_D];
|
||||||
#define SRC_RATIO (src_ratio)
|
|
||||||
static SRC_STATE* rabbit[MAX_D];
|
static SRC_STATE* rabbit[MAX_D];
|
||||||
static int rabbit_err[MAX_D];
|
static int rabbit_err[MAX_D];
|
||||||
static float* (resampled[MAX_D]); //< internal soundfile buffer
|
static float* (resampled[MAX_D]); //< internal soundfile buffer
|
||||||
|
|
@ -38,7 +38,7 @@ static uint32_t input_frames_used[MAX_D];
|
||||||
static uint32_t output_frames_generated[MAX_D];
|
static uint32_t output_frames_generated[MAX_D];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void vsjack_initialize(void) {
|
static void vsjack_initialize(void) {
|
||||||
int d;
|
int d;
|
||||||
for (d = 0; d < MAX_D; d++) {
|
for (d = 0; d < MAX_D; d++) {
|
||||||
m_sndfile[d] = NULL;
|
m_sndfile[d] = NULL;
|
||||||
|
|
@ -46,19 +46,16 @@ void vsjack_initialize(void) {
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
resampled[d] = NULL;
|
resampled[d] = NULL;
|
||||||
#endif
|
#endif
|
||||||
sources[d] = NULL;
|
|
||||||
}
|
}
|
||||||
sources[0] = strdup("/tmp/test.wav");
|
|
||||||
sources[1] = strdup("/tmp/test1.wav");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void realloc_sf(int d, uint32_t buffersize) {
|
static void realloc_sf(int d, uint32_t buffersize) {
|
||||||
if (interleaved[d]) free(interleaved[d]);
|
if (interleaved[d]) free(interleaved[d]);
|
||||||
interleaved[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float));
|
interleaved[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
void realloc_src(int d, uint32_t buffersize) {
|
static void realloc_src(int d, uint32_t buffersize) {
|
||||||
if (resampled[d]) free(resampled[d]);
|
if (resampled[d]) free(resampled[d]);
|
||||||
resampled[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float));
|
resampled[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
@ -75,8 +72,8 @@ void closefile_sf(int d) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int openfile_sf(int d, char* filename) {
|
static int openfile_sf(int d, char* filename, uint32_t channel, double oversampling) {
|
||||||
uint32_t nframes;
|
int nframes;
|
||||||
SF_INFO sfinfo;
|
SF_INFO sfinfo;
|
||||||
if (!m_sndfile[d])
|
if (!m_sndfile[d])
|
||||||
sf_close(m_sndfile[d]);
|
sf_close(m_sndfile[d]);
|
||||||
|
|
@ -102,17 +99,22 @@ int openfile_sf(int d, char* filename) {
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
nframes = sfinfo.frames;
|
nframes = sfinfo.frames;
|
||||||
|
if (channel >= sfinfo.channels) {
|
||||||
|
fprintf(stderr, "Error: Audio file does not have channel %d (0-%d)\n", channel, sfinfo.channels-1);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_channel[d] = channel;
|
||||||
m_channels[d] = sfinfo.channels;
|
m_channels[d] = sfinfo.channels;
|
||||||
m_samplerate[d] = sfinfo.samplerate;
|
m_samplerate[d] = sfinfo.samplerate;
|
||||||
m_frames[d] = nframes;
|
m_frames[d] = nframes;
|
||||||
realloc_sf(d, nframes);
|
realloc_sf(d, nframes);
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
SRC_DATA src_data;
|
|
||||||
|
|
||||||
realloc_src(d, nframes * SRC_RATIO);
|
src_ratio[d] = oversampling;
|
||||||
|
realloc_src(d, nframes * oversampling);
|
||||||
rabbit[d] = src_new(SRC_SINC_BEST_QUALITY, m_channels[d], &(rabbit_err[d]));
|
rabbit[d] = src_new(SRC_SINC_BEST_QUALITY, m_channels[d], &(rabbit_err[d]));
|
||||||
src_set_ratio(rabbit[d], SRC_RATIO);
|
src_set_ratio(rabbit[d], oversampling);
|
||||||
src_reset(rabbit[d]);
|
src_reset(rabbit[d]);
|
||||||
output_frames_generated[d] = 0;
|
output_frames_generated[d] = 0;
|
||||||
input_frames_used[d] = 0;
|
input_frames_used[d] = 0;
|
||||||
|
|
@ -120,14 +122,15 @@ int openfile_sf(int d, char* filename) {
|
||||||
#endif
|
#endif
|
||||||
nframes = sf_readf_float(m_sndfile[d], (interleaved[d]), nframes);
|
nframes = sf_readf_float(m_sndfile[d], (interleaved[d]), nframes);
|
||||||
if (nframes < 0) {
|
if (nframes < 0) {
|
||||||
fprintf(stderr, "Error: Failed to read audio frames\n");
|
fprintf(stderr, "Error: Failed to read audio frames\n");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
m_frames[d] = nframes;
|
m_frames[d] = nframes;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_value(int d, double time, int channel) {
|
static double get_value(int d, double time) {
|
||||||
|
uint32_t channel = m_channel[d];
|
||||||
uint32_t nframes = m_frames[d];
|
uint32_t nframes = m_frames[d];
|
||||||
double sample_fp = time * ((double)m_samplerate[d]);
|
double sample_fp = time * ((double)m_samplerate[d]);
|
||||||
uint32_t sample = (uint32_t)floor(sample_fp);
|
uint32_t sample = (uint32_t)floor(sample_fp);
|
||||||
|
|
@ -135,54 +138,55 @@ double get_value(int d, double time, int channel) {
|
||||||
if (sample >= nframes) return (0.0);
|
if (sample >= nframes) return (0.0);
|
||||||
|
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
|
double SRC_RATIO = src_ratio[d];
|
||||||
sample_fp *= SRC_RATIO;
|
sample_fp *= SRC_RATIO;
|
||||||
sample = (uint32_t)floor(sample_fp);
|
sample = (uint32_t)floor(sample_fp);
|
||||||
|
|
||||||
// Do we need to generate more output frames?
|
// Do we need to generate more output frames?
|
||||||
while (sample >= output_frames_generated[d]) {
|
while (sample >= output_frames_generated[d]) {
|
||||||
SRC_DATA src_data;
|
SRC_DATA src_data;
|
||||||
uint32_t output_generated = output_frames_generated[d];
|
uint32_t output_generated = output_frames_generated[d];
|
||||||
uint32_t input_used = input_frames_used[d];
|
uint32_t input_used = input_frames_used[d];
|
||||||
uint32_t input_frames_left = nframes - input_used;
|
uint32_t input_frames_left = nframes - input_used;
|
||||||
|
|
||||||
// Not enough output frames, and nothing more to input?
|
// Not enough output frames, and nothing more to input?
|
||||||
// Give up.
|
// Give up.
|
||||||
if (!input_frames_left)
|
if (!input_frames_left)
|
||||||
return (0.0);
|
return (0.0);
|
||||||
|
|
||||||
// Do the resampling in smaller chunks
|
// Do the resampling in smaller chunks
|
||||||
src_data.end_of_input = 1;
|
src_data.end_of_input = 1;
|
||||||
if (input_frames_left > VS_RESAMPLING_CHUNK) {
|
if (input_frames_left > VS_RESAMPLING_CHUNK) {
|
||||||
input_frames_left = VS_RESAMPLING_CHUNK;
|
input_frames_left = VS_RESAMPLING_CHUNK;
|
||||||
src_data.end_of_input = 0;
|
src_data.end_of_input = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
src_data.data_in = interleaved[d] + m_channels[d] * input_used;
|
src_data.data_in = interleaved[d] + m_channels[d] * input_used;
|
||||||
src_data.data_out = resampled[d] + m_channels[d] * output_generated;
|
src_data.data_out = resampled[d] + m_channels[d] * output_generated;
|
||||||
src_data.input_frames = input_frames_left;
|
src_data.input_frames = input_frames_left;
|
||||||
src_data.output_frames = nframes * SRC_RATIO - output_generated;
|
src_data.output_frames = nframes * SRC_RATIO - output_generated;
|
||||||
src_data.src_ratio = SRC_RATIO;
|
src_data.src_ratio = SRC_RATIO;
|
||||||
src_data.output_frames_gen = 0;
|
src_data.output_frames_gen = 0;
|
||||||
src_data.input_frames_used = 0;
|
src_data.input_frames_used = 0;
|
||||||
|
|
||||||
if (src_process(rabbit[d], &src_data)) {
|
if (src_process(rabbit[d], &src_data)) {
|
||||||
fprintf(stderr, "src_process() failed on sound file");
|
fprintf(stderr, "src_process() failed on sound file");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_frames_generated[d] += src_data.output_frames_gen;
|
output_frames_generated[d] += src_data.output_frames_gen;
|
||||||
input_frames_used[d] += src_data.input_frames_used;
|
input_frames_used[d] += src_data.input_frames_used;
|
||||||
if (src_data.end_of_input)
|
if (src_data.end_of_input)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we past all the generated samples?
|
// Are we past all the generated samples?
|
||||||
if (sample >= output_frames_generated[d])
|
if (sample >= output_frames_generated[d])
|
||||||
return (0.0);
|
return (0.0);
|
||||||
float val = ((float*)(resampled[d]))[m_channels[d] * sample + channel];
|
float val = ((float*)(resampled[d]))[m_channels[d] * sample + channel];
|
||||||
// Are we the last sample?
|
// Are we the last sample?
|
||||||
if (sample + 1 == output_frames_generated[d])
|
if (sample + 1 == output_frames_generated[d])
|
||||||
return val;
|
return val;
|
||||||
|
|
||||||
// linear interpolation between samples
|
// linear interpolation between samples
|
||||||
double diff = sample_fp - sample;
|
double diff = sample_fp - sample;
|
||||||
|
|
@ -201,32 +205,24 @@ double get_value(int d, double time, int channel) {
|
||||||
* "public" functions
|
* "public" functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double vsjack_get_value(int d, double time, double time_offset, int channel, double oversampling) {
|
double vsjack_get_value(int d, double time, double time_offset) {
|
||||||
assert(d >= 0 && d < MAX_D);
|
assert(d >= 0 && d < MAX_D);
|
||||||
if (m_sndfile[d] == NULL) return (0.0); // FIXME
|
if (m_sndfile[d] == NULL) return (0.0); // FIXME
|
||||||
if (oversampling > 0) src_ratio = oversampling;
|
|
||||||
|
|
||||||
double value = get_value(d, time + time_offset, channel);
|
double value = get_value(d, time + time_offset);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vsjack_set_file(int d, char* fn) {
|
int vsjack_open(int d, char *file, int channel, double oversampling) {
|
||||||
assert(d >= 0 && d < MAX_D);
|
|
||||||
if (sources[d] != NULL) free(sources[d]);
|
|
||||||
sources[d] = strdup(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsjack_open(int d) {
|
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
vsjack_initialize();
|
vsjack_initialize();
|
||||||
}
|
}
|
||||||
if (d == -1) return -1;// initialize only
|
|
||||||
assert(d >= 0 && d < MAX_D);
|
assert(d >= 0 && d < MAX_D);
|
||||||
assert(sources[d] != NULL);
|
|
||||||
if (openfile_sf(d, sources[d])) {
|
if (openfile_sf(d, file, channel, oversampling)) {
|
||||||
fprintf(stderr, "Error: Could not open or read '%s'\n", sources[d]);
|
fprintf(stderr, "Error: Could not open or read '%s'\n", file);
|
||||||
controlled_exit(1);
|
controlled_exit(1);
|
||||||
}
|
}
|
||||||
return (d);
|
return (d);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
double vsjack_get_value (int, double, double, int, double);
|
double vsjack_get_value (int, double time, double time_offset);
|
||||||
int vsjack_open (int);
|
int vsjack_open (int, char *file, int channel, double oversampling);
|
||||||
void vsjack_set_file (int, char*);
|
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SOUND: {
|
case SOUND: {
|
||||||
value = here->VSRCcoeffs[2] * vsjack_get_value((int)here->VSRCcoeffs[0], time, here->VSRCcoeffs[3], (int)rint(here->VSRCcoeffs[4]), rint(here->VSRCcoeffs[5]));
|
value = here->VSRCcoeffs[2] * vsjack_get_value((int)here->VSRCcoeffs[0], time, here->VSRCcoeffs[3]);
|
||||||
value += here->VSRCcoeffs[1];
|
value += here->VSRCcoeffs[1];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -295,18 +295,25 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VSRC_SOUND: {
|
case VSRC_SOUND: {
|
||||||
|
int id, channel;
|
||||||
|
double oversampling;
|
||||||
here->VSRCfunctionType = SOUND;
|
here->VSRCfunctionType = SOUND;
|
||||||
here->VSRCfuncTGiven = TRUE;
|
here->VSRCfuncTGiven = TRUE;
|
||||||
copy_coeffs(here, value);
|
copy_coeffs(here, value);
|
||||||
here->VSRCcoeffsGiven = TRUE;
|
here->VSRCcoeffsGiven = TRUE;
|
||||||
vsjack_open(-1); // initialize
|
if (!jfile) {
|
||||||
if (jfile) {
|
fprintf(stderr, "Warning! Need filename for sound input");
|
||||||
vsjack_set_file((int)rint(here->VSRCcoeffs[0]), jfile);
|
return(E_BADPARM);
|
||||||
tfree(jfile);
|
|
||||||
}
|
}
|
||||||
if (value->v.numValue != 6)
|
if (value->v.numValue != 6) {
|
||||||
fprintf(stderr, "Warning! invalid jack args: %i\nFormat: jack(id v_off v_mult t_off channel oversampling)", value->v.numValue);
|
fprintf(stderr, "Warning! invalid jack args: %i\nFormat: jack(id v_off v_mult t_off channel oversampling)", value->v.numValue);
|
||||||
vsjack_open((int)rint(here->VSRCcoeffs[0]));
|
return (E_BADPARM);
|
||||||
|
}
|
||||||
|
id = (int)rint(here->VSRCcoeffs[0]);
|
||||||
|
channel = (int)rint(here->VSRCcoeffs[4]);
|
||||||
|
oversampling = here->VSRCcoeffs[5];
|
||||||
|
vsjack_open(id, jfile, channel, oversampling);
|
||||||
|
tfree(jfile);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue