Codebase list squeezelite / 66c9585
add async resampling to max rate for device using -u X Adrian Smith 10 years ago
5 changed file(s) with 66 addition(s) and 38 deletion(s). Raw diff Collapse all Expand all
4646 #endif
4747 " -r <rate>\t\tMax sample rate for output device, enables output device to be off when squeezelite is started\n"
4848 #if RESAMPLE
49 " -u [params]\t\tUpsample to max rate for device, params = <quality>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
50 " \t\t\t quality = (v|h|m|l|q)(|L|I|M)(|s),\n"
49 " -u [params]\t\tUpsample, params = <recipe>:<flags>:<attenuation>:<precision>:<passband_end>:<stopband_start>:<phase_response>,\n"
50 " \t\t\t recipe = (v|h|m|l|q)(|L|I|M)(|s), (|X) = async - resample to max rate for device, otherwise resample to max sync rate\n"
5151 " \t\t\t flags = num in hex,\n"
5252 " \t\t\t attenuation = attenuation in dB to apply (default is -1db if not explicitly set),\n"
5353 " \t\t\t precision = number of bits precision (NB. HQ = 20. VHQ = 28),\n"
377377
378378 printf("Output devices:\n");
379379 for (i = 0; i < Pa_GetDeviceCount(); ++i) {
380 printf(" %i - %s\n", i, Pa_GetDeviceInfo(i)->name);
380 printf(" %i - %s [%s]\n", i, Pa_GetDeviceInfo(i)->name, Pa_GetHostApiInfo(Pa_GetDeviceInfo(i)->hostApi)->name);
381381 }
382382 printf("\n");
383383
111111
112112 } while (!done);
113113
114 LOG_DEBUG("processing track complete - frames in: %lu out: %lu diff: %i", process.total_in, process.total_out,
115 process.total_in * process.sample_factor - process.total_out);
114 LOG_DEBUG("processing track complete - frames in: %lu out: %lu", process.total_in, process.total_out);
116115 }
117116
118117 // new stream - called with decode mutex set
126125
127126 if (active) {
128127
129 if (process.inbuf) free(process.inbuf);
130 if (process.outbuf) free(process.outbuf);
128 unsigned max_in_frames, max_out_frames;
129
130 process.in_frames = process.out_frames = 0;
131 process.total_in = process.total_out = 0;
132
133 max_in_frames = codec->min_space / BYTES_PER_FRAME ;
134
135 // increase size of output buffer by 10% as output rate is not an exact multiple of input rate
136 if (process.out_sample_rate % process.in_sample_rate == 0) {
137 max_out_frames = max_in_frames * process.out_sample_rate / process.in_sample_rate;
138 } else {
139 max_out_frames = (int)(1.1 * (float)max_in_frames * (float)process.out_sample_rate / (float)process.in_sample_rate);
140 }
141
142 if (process.max_in_frames != max_in_frames) {
143 LOG_DEBUG("creating process buf in frames: %u", max_in_frames);
144 if (process.inbuf) free(process.inbuf);
145 process.inbuf = malloc(max_in_frames * BYTES_PER_FRAME);
146 process.max_in_frames = max_in_frames;
147 }
131148
132 process.inbuf = malloc(codec->min_space);
133 process.outbuf = malloc(codec->min_space * process.sample_factor);
149 if (process.max_out_frames != max_out_frames) {
150 LOG_DEBUG("creating process buf out frames: %u", max_out_frames);
151 if (process.outbuf) free(process.outbuf);
152 process.outbuf = malloc(max_out_frames * BYTES_PER_FRAME);
153 process.max_out_frames = max_out_frames;
154 }
134155
135156 if (!process.inbuf || !process.outbuf) {
136157 LOG_ERROR("malloc fail creating process buffers");
137158 *direct = true;
138159 return raw_sample_rate;
139160 }
140
141 process.sample_rate = raw_sample_rate;
142 process.max_in_frames = codec->min_space / BYTES_PER_FRAME ;
143 process.max_out_frames = codec->min_space / BYTES_PER_FRAME * process.sample_factor;
144
145 process.in_frames = process.out_frames = 0;
146 process.total_in = process.total_out = 0;
147161
148 return raw_sample_rate * process.sample_factor;
162 return process.out_sample_rate;
149163 }
150164
151165 return raw_sample_rate;
166180
167181 bool enabled = INIT_FUNC(opt);
168182
183 memset(&process, 0, sizeof(process));
184
169185 if (enabled) {
170186 LOCK_D;
171187 decode.process = true;
5656 void (* soxr_delete)(soxr_t);
5757 soxr_error_t (* soxr_process)(soxr_t, soxr_in_t, size_t, size_t *, soxr_out_t, size_t olen, size_t *);
5858 size_t *(* soxr_num_clips)(soxr_t);
59 bool max_rate;
5960 };
6061
6162 static struct soxr *r;
7374
7475 if (idone != process->in_frames) {
7576 // should not get here if buffers are big enough...
76 LOG_ERROR("should not get here - partial sox process: %u of %u", (unsigned)idone, process->in_frames);
77 LOG_ERROR("should not get here - partial sox process: %u of %u processed %u of %u out",
78 (unsigned)idone, process->in_frames, (unsigned)odone, process->max_out_frames);
7779 }
7880
7981 process->out_frames = odone;
121123 }
122124
123125 bool resample_newstream(struct processstate *process, unsigned raw_sample_rate, unsigned max_sample_rate) {
124 unsigned outrate = raw_sample_rate;
125 while (outrate <= max_sample_rate) outrate <<= 1;
126 outrate >>= 1;
127
128 process->sample_factor = outrate / raw_sample_rate;
126 unsigned outrate;
127
128 if (r->max_rate) {
129 outrate = max_sample_rate;
130 } else {
131 outrate = raw_sample_rate;
132 while (outrate <= max_sample_rate) outrate <<= 1;
133 outrate >>= 1;
134 }
135
136 process->in_sample_rate = raw_sample_rate;
137 process->out_sample_rate = outrate;
129138
130139 if (r->resampler) {
131140 r->soxr_delete(r->resampler);
197206
198207 r->resampler = NULL;
199208 r->old_clips = 0;
209 r->max_rate = false;
200210 r->soxr_io_spec = dlsym(handle, "soxr_io_spec");
201211 r->soxr_quality_spec = dlsym(handle, "soxr_quality_spec");
202212 r->soxr_create = dlsym(handle, "soxr_create");
214224 }
215225
216226 bool resample_init(char *opt) {
217 char *qual = NULL, *flags = NULL;
227 char *recipe = NULL, *flags = NULL;
218228 char *atten = NULL;
219229 char *precision = NULL, *passband_end = NULL, *stopband_begin = NULL, *phase_response = NULL;
220230
224234 }
225235
226236 if (opt) {
227 qual = next_param(opt, ':');
237 recipe = next_param(opt, ':');
228238 flags = next_param(NULL, ':');
229239 atten = next_param(NULL, ':');
230240 precision = next_param(NULL, ':');
244254 r->q_stopband_begin = 0;
245255 r->q_phase_response = -1;
246256
247 if (qual && qual[0] != '\0') {
248 if (strchr(qual, 'v')) r->q_recipe = SOXR_VHQ;
249 if (strchr(qual, 'h')) r->q_recipe = SOXR_HQ;
250 if (strchr(qual, 'm')) r->q_recipe = SOXR_MQ;
251 if (strchr(qual, 'l')) r->q_recipe = SOXR_LQ;
252 if (strchr(qual, 'q')) r->q_recipe = SOXR_QQ;
253 if (strchr(qual, 'L')) r->q_recipe |= SOXR_LINEAR_PHASE;
254 if (strchr(qual, 'I')) r->q_recipe |= SOXR_INTERMEDIATE_PHASE;
255 if (strchr(qual, 'M')) r->q_recipe |= SOXR_MINIMUM_PHASE;
256 if (strchr(qual, 's')) r->q_recipe |= SOXR_STEEP_FILTER;
257 if (recipe && recipe[0] != '\0') {
258 if (strchr(recipe, 'v')) r->q_recipe = SOXR_VHQ;
259 if (strchr(recipe, 'h')) r->q_recipe = SOXR_HQ;
260 if (strchr(recipe, 'm')) r->q_recipe = SOXR_MQ;
261 if (strchr(recipe, 'l')) r->q_recipe = SOXR_LQ;
262 if (strchr(recipe, 'q')) r->q_recipe = SOXR_QQ;
263 if (strchr(recipe, 'L')) r->q_recipe |= SOXR_LINEAR_PHASE;
264 if (strchr(recipe, 'I')) r->q_recipe |= SOXR_INTERMEDIATE_PHASE;
265 if (strchr(recipe, 'M')) r->q_recipe |= SOXR_MINIMUM_PHASE;
266 if (strchr(recipe, 's')) r->q_recipe |= SOXR_STEEP_FILTER;
267 // X = async resampling to max_rate
268 if (strchr(recipe, 'X')) r->max_rate = true;
257269 }
258270
259271 if (flags) {
283295 r->q_phase_response = atof(phase_response);
284296 }
285297
286 LOG_INFO("resampling enabled recipe: 0x%02x, flags: 0x%02x, scale: %03.2f, precision: %03.1f, passband_end: %03.5f, stopband_begin: %03.5f, phase_response: %03.1f",
298 LOG_INFO("resampling %s recipe: 0x%02x, flags: 0x%02x, scale: %03.2f, precision: %03.1f, passband_end: %03.5f, stopband_begin: %03.5f, phase_response: %03.1f",
299 r->max_rate ? "async" : "sync",
287300 r->q_recipe, r->q_flags, r->scale, r->q_precision, r->q_passband_end, r->q_stopband_begin, r->q_phase_response);
288301
289302 return true;
375375 u8_t *inbuf, *outbuf;
376376 unsigned max_in_frames, max_out_frames;
377377 unsigned in_frames, out_frames;
378 unsigned sample_factor;
379 unsigned sample_rate;
378 unsigned in_sample_rate, out_sample_rate;
380379 unsigned long total_in, total_out;
381380 };
382381 #endif