diff --git a/src/spicelib/devices/vsrc/vsjack.c b/src/spicelib/devices/vsrc/vsjack.c index a5d181b6a..06bf3b45a 100644 --- a/src/spicelib/devices/vsrc/vsjack.c +++ b/src/spicelib/devices/vsrc/vsjack.c @@ -13,13 +13,14 @@ #define VS_RESAMPLING_CHUNK 1024 #include "ngspice/ngspice.h" +#include "vsjack.h" extern char* inp_pathresolve(const char* name); #define MAX_D 6 -static char* (sources[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 uint32_t m_samplerate[MAX_D]; //< samplerate of source 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 #include -static double src_ratio = 64.0; -#define SRC_RATIO (src_ratio) +static double src_ratio[MAX_D]; static SRC_STATE* rabbit[MAX_D]; static int rabbit_err[MAX_D]; 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]; #endif -void vsjack_initialize(void) { +static void vsjack_initialize(void) { int d; for (d = 0; d < MAX_D; d++) { m_sndfile[d] = NULL; @@ -46,19 +46,16 @@ void vsjack_initialize(void) { #ifdef HAVE_SRC resampled[d] = NULL; #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]); interleaved[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float)); } #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]); resampled[d] = (float*)calloc(m_channels[d] * buffersize, sizeof(float)); } @@ -75,8 +72,8 @@ void closefile_sf(int d) { } #endif -int openfile_sf(int d, char* filename) { - uint32_t nframes; +static int openfile_sf(int d, char* filename, uint32_t channel, double oversampling) { + int nframes; SF_INFO sfinfo; if (!m_sndfile[d]) sf_close(m_sndfile[d]); @@ -102,17 +99,22 @@ int openfile_sf(int d, char* filename) { return (-1); } 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_samplerate[d] = sfinfo.samplerate; m_frames[d] = nframes; realloc_sf(d, nframes); #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])); - src_set_ratio(rabbit[d], SRC_RATIO); + src_set_ratio(rabbit[d], oversampling); src_reset(rabbit[d]); output_frames_generated[d] = 0; input_frames_used[d] = 0; @@ -120,14 +122,15 @@ int openfile_sf(int d, char* filename) { #endif nframes = sf_readf_float(m_sndfile[d], (interleaved[d]), nframes); if (nframes < 0) { - fprintf(stderr, "Error: Failed to read audio frames\n"); - return (-1); + fprintf(stderr, "Error: Failed to read audio frames\n"); + return (-1); } m_frames[d] = nframes; 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]; double sample_fp = time * ((double)m_samplerate[d]); 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); #ifdef HAVE_SRC + double SRC_RATIO = src_ratio[d]; sample_fp *= SRC_RATIO; sample = (uint32_t)floor(sample_fp); // Do we need to generate more output frames? while (sample >= output_frames_generated[d]) { - SRC_DATA src_data; - uint32_t output_generated = output_frames_generated[d]; - uint32_t input_used = input_frames_used[d]; - uint32_t input_frames_left = nframes - input_used; + SRC_DATA src_data; + uint32_t output_generated = output_frames_generated[d]; + uint32_t input_used = input_frames_used[d]; + uint32_t input_frames_left = nframes - input_used; - // Not enough output frames, and nothing more to input? - // Give up. - if (!input_frames_left) - return (0.0); + // Not enough output frames, and nothing more to input? + // Give up. + if (!input_frames_left) + return (0.0); - // Do the resampling in smaller chunks - src_data.end_of_input = 1; - if (input_frames_left > VS_RESAMPLING_CHUNK) { - input_frames_left = VS_RESAMPLING_CHUNK; - src_data.end_of_input = 0; - } + // Do the resampling in smaller chunks + src_data.end_of_input = 1; + if (input_frames_left > VS_RESAMPLING_CHUNK) { + input_frames_left = VS_RESAMPLING_CHUNK; + src_data.end_of_input = 0; + } - src_data.data_in = interleaved[d] + m_channels[d] * input_used; - src_data.data_out = resampled[d] + m_channels[d] * output_generated; - src_data.input_frames = input_frames_left; - src_data.output_frames = nframes * SRC_RATIO - output_generated; - src_data.src_ratio = SRC_RATIO; - src_data.output_frames_gen = 0; - src_data.input_frames_used = 0; + src_data.data_in = interleaved[d] + m_channels[d] * input_used; + src_data.data_out = resampled[d] + m_channels[d] * output_generated; + src_data.input_frames = input_frames_left; + src_data.output_frames = nframes * SRC_RATIO - output_generated; + src_data.src_ratio = SRC_RATIO; + src_data.output_frames_gen = 0; + src_data.input_frames_used = 0; - if (src_process(rabbit[d], &src_data)) { - fprintf(stderr, "src_process() failed on sound file"); - return -1; - } + if (src_process(rabbit[d], &src_data)) { + fprintf(stderr, "src_process() failed on sound file"); + return -1; + } - output_frames_generated[d] += src_data.output_frames_gen; - input_frames_used[d] += src_data.input_frames_used; - if (src_data.end_of_input) - break; + output_frames_generated[d] += src_data.output_frames_gen; + input_frames_used[d] += src_data.input_frames_used; + if (src_data.end_of_input) + break; } // Are we past all the generated samples? if (sample >= output_frames_generated[d]) - return (0.0); + return (0.0); float val = ((float*)(resampled[d]))[m_channels[d] * sample + channel]; // Are we the last sample? if (sample + 1 == output_frames_generated[d]) - return val; + return val; // linear interpolation between samples double diff = sample_fp - sample; @@ -201,32 +205,24 @@ double get_value(int d, double time, int channel) { * "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); 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); } -void vsjack_set_file(int d, char* fn) { - assert(d >= 0 && d < MAX_D); - if (sources[d] != NULL) free(sources[d]); - sources[d] = strdup(fn); -} - -int vsjack_open(int d) { +int vsjack_open(int d, char *file, int channel, double oversampling) { static int initialized = 0; if (!initialized) { initialized = 1; vsjack_initialize(); } - if (d == -1) return -1;// initialize only assert(d >= 0 && d < MAX_D); - assert(sources[d] != NULL); - if (openfile_sf(d, sources[d])) { - fprintf(stderr, "Error: Could not open or read '%s'\n", sources[d]); + + if (openfile_sf(d, file, channel, oversampling)) { + fprintf(stderr, "Error: Could not open or read '%s'\n", file); controlled_exit(1); } return (d); diff --git a/src/spicelib/devices/vsrc/vsjack.h b/src/spicelib/devices/vsrc/vsjack.h index fe151a648..b7577f72f 100644 --- a/src/spicelib/devices/vsrc/vsjack.h +++ b/src/spicelib/devices/vsrc/vsjack.h @@ -1,4 +1,3 @@ -double vsjack_get_value (int, double, double, int, double); -int vsjack_open (int); -void vsjack_set_file (int, char*); +double vsjack_get_value (int, double time, double time_offset); +int vsjack_open (int, char *file, int channel, double oversampling); diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index 393f1980c..2f3c16f4c 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -425,7 +425,7 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise break; 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]; } break; diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index b9c6847be..ccfa077e6 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -295,18 +295,25 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) break; case VSRC_SOUND: { + int id, channel; + double oversampling; here->VSRCfunctionType = SOUND; here->VSRCfuncTGiven = TRUE; copy_coeffs(here, value); here->VSRCcoeffsGiven = TRUE; - vsjack_open(-1); // initialize - if (jfile) { - vsjack_set_file((int)rint(here->VSRCcoeffs[0]), jfile); - tfree(jfile); + if (!jfile) { + fprintf(stderr, "Warning! Need filename for sound input"); + return(E_BADPARM); } - 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); - 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;