xref: /dragonfly/sys/dev/sound/pcm/feeder_rate.c (revision ae071d8d)
1 /*-
2  * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
3  * Copyright (c) 2003 Orion Hodson <orion@FreeBSD.org>
4  * Copyright (c) 2005 Ariff Abdullah <ariff@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * 2005-06-11:
29  * ==========
30  *
31  * *New* and rewritten soft sample rate converter supporting arbitrary sample
32  * rates, fine grained scaling/coefficients and a unified up/down stereo
33  * converter. Most of the disclaimers from orion's notes also applies
34  * here, regarding linear interpolation deficiencies and pre/post
35  * anti-aliasing filtering issues. This version comes with a much simpler and
36  * tighter interface, although it works almost exactly like the older one.
37  *
38  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
39  *                                                                         *
40  * This new implementation is fully dedicated in memory of Cameron Grant,  *
41  * the creator of the magnificent, highly addictive feeder infrastructure. *
42  *                                                                         *
43  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
44  *
45  * Orion's notes:
46  * =============
47  *
48  * This rate conversion code uses linear interpolation without any
49  * pre- or post- interpolation filtering to combat aliasing.  This
50  * greatly limits the sound quality and should be addressed at some
51  * stage in the future.
52  *
53  * Since this accuracy of interpolation is sensitive and examination
54  * of the algorithm output is harder from the kernel, the code is
55  * designed to be compiled in the kernel and in a userland test
56  * harness.  This is done by selectively including and excluding code
57  * with several portions based on whether _KERNEL is defined.  It's a
58  * little ugly, but exceedingly useful.  The testsuite and its
59  * revisions can be found at:
60  *		http://people.freebsd.org/~orion/files/feedrate/
61  *
62  * Special thanks to Ken Marx for exposing flaws in the code and for
63  * testing revisions.
64  *
65  * $FreeBSD: src/sys/dev/sound/pcm/feeder_rate.c,v 1.11.2.2 2006/01/29 02:27:28 ariff Exp $
66  */
67 
68 #include <dev/sound/pcm/sound.h>
69 #include "feeder_if.h"
70 
71 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pcm/feeder_rate.c,v 1.5 2007/01/04 21:47:03 corecode Exp $");
72 
73 #define RATE_ASSERT(x, y) /* KASSERT(x,y) */
74 #define RATE_TEST(x, y)  /* if (!(x)) printf y */
75 #define RATE_TRACE(x...) /* printf(x) */
76 
77 MALLOC_DEFINE(M_RATEFEEDER, "ratefeed", "pcm rate feeder");
78 
79 #define FEEDBUFSZ	8192
80 #define ROUNDHZ		25
81 #define RATEMIN		4000
82 /* 8000 * 138 or 11025 * 100 . This is insane, indeed! */
83 #define RATEMAX		1102500
84 #define MINGAIN		92
85 #define MAXGAIN		96
86 
87 #define FEEDRATE_CONVERT_64		0
88 #define FEEDRATE_CONVERT_SCALE64	1
89 #define FEEDRATE_CONVERT_SCALE32	2
90 #define FEEDRATE_CONVERT_PLAIN		3
91 #define FEEDRATE_CONVERT_FIXED		4
92 #define FEEDRATE_CONVERT_OPTIMAL	5
93 #define FEEDRATE_CONVERT_WORST		6
94 
95 #define FEEDRATE_64_MAXROLL	32
96 #define FEEDRATE_32_MAXROLL	16
97 
98 struct feed_rate_info {
99 	uint32_t src, dst;	/* rounded source / destination rates */
100 	uint32_t rsrc, rdst;	/* original source / destination rates */
101 	uint32_t gx, gy;	/* interpolation / decimation ratio */
102 	uint32_t alpha;		/* interpolation distance */
103 	uint32_t pos, bpos;	/* current sample / buffer positions */
104 	uint32_t bufsz;		/* total buffer size */
105 	uint32_t stray;		/* stray bytes */
106 	int32_t  scale, roll;	/* scale / roll factor */
107 	int16_t  *buffer;
108 	uint32_t (*convert)(struct feed_rate_info *, int16_t *, uint32_t);
109 };
110 
111 static uint32_t
112 feed_convert_64(struct feed_rate_info *, int16_t *, uint32_t);
113 static uint32_t
114 feed_convert_scale64(struct feed_rate_info *, int16_t *, uint32_t);
115 static uint32_t
116 feed_convert_scale32(struct feed_rate_info *, int16_t *, uint32_t);
117 static uint32_t
118 feed_convert_plain(struct feed_rate_info *, int16_t *, uint32_t);
119 
120 int feeder_rate_ratemin = RATEMIN;
121 int feeder_rate_ratemax = RATEMAX;
122 /*
123  * See 'Feeder Scaling Type' below..
124  */
125 static int feeder_rate_scaling = FEEDRATE_CONVERT_OPTIMAL;
126 static int feeder_rate_buffersize = FEEDBUFSZ & ~1;
127 
128 #if 0
129 /*
130  * sysctls.. I love sysctls..
131  */
132 TUNABLE_INT("hw.snd.feeder_rate_ratemin", &feeder_rate_ratemin);
133 TUNABLE_INT("hw.snd.feeder_rate_ratemax", &feeder_rate_ratemin);
134 TUNABLE_INT("hw.snd.feeder_rate_scaling", &feeder_rate_scaling);
135 TUNABLE_INT("hw.snd.feeder_rate_buffersize", &feeder_rate_buffersize);
136 
137 static int
138 sysctl_hw_snd_feeder_rate_ratemin(SYSCTL_HANDLER_ARGS)
139 {
140 	int err, val;
141 
142 	val = feeder_rate_ratemin;
143 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
144 	if (val < 1 || val >= feeder_rate_ratemax)
145 		err = EINVAL;
146 	else
147 		feeder_rate_ratemin = val;
148 	return err;
149 }
150 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_ratemin, CTLTYPE_INT | CTLFLAG_RW,
151 	0, sizeof(int), sysctl_hw_snd_feeder_rate_ratemin, "I", "");
152 
153 static int
154 sysctl_hw_snd_feeder_rate_ratemax(SYSCTL_HANDLER_ARGS)
155 {
156 	int err, val;
157 
158 	val = feeder_rate_ratemax;
159 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
160 	if (val <= feeder_rate_ratemin || val > 0x7fffff)
161 		err = EINVAL;
162 	else
163 		feeder_rate_ratemax = val;
164 	return err;
165 }
166 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_ratemax, CTLTYPE_INT | CTLFLAG_RW,
167 	0, sizeof(int), sysctl_hw_snd_feeder_rate_ratemax, "I", "");
168 
169 static int
170 sysctl_hw_snd_feeder_rate_scaling(SYSCTL_HANDLER_ARGS)
171 {
172 	int err, val;
173 
174 	val = feeder_rate_scaling;
175 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
176 	/*
177 	 *      Feeder Scaling Type
178 	 *      ===================
179 	 *
180 	 *	1. Plain 64bit (high precision)
181 	 *	2. 64bit scaling (high precision, CPU friendly, but can
182 	 *	   cause gain up/down).
183 	 *	3. 32bit scaling (somehow can cause hz roundup, gain
184 	 *	   up/down).
185 	 *	4. Plain copy (default if src == dst. Except if src == dst,
186 	 *	   this is the worst / silly conversion method!).
187 	 *
188 	 *	Sysctl options:-
189 	 *
190 	 *	0 - Plain 64bit - no fallback.
191 	 *	1 - 64bit scaling - no fallback.
192 	 *	2 - 32bit scaling - no fallback.
193 	 *	3 - Plain copy - no fallback.
194 	 *	4 - Fixed rate. Means that, choose optimal conversion method
195 	 *	    without causing hz roundup.
196 	 *	    32bit scaling (as long as hz roundup does not occur),
197 	 *	    64bit scaling, Plain 64bit.
198 	 *	5 - Optimal / CPU friendly (DEFAULT).
199 	 *	    32bit scaling, 64bit scaling, Plain 64bit
200 	 *	6 - Optimal to worst, no 64bit arithmetic involved.
201 	 *	    32bit scaling, Plain copy.
202 	 */
203 	if (val < FEEDRATE_CONVERT_64 || val > FEEDRATE_CONVERT_WORST)
204 		err = EINVAL;
205 	else
206 		feeder_rate_scaling = val;
207 	return err;
208 }
209 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_scaling, CTLTYPE_INT | CTLFLAG_RW,
210 	0, sizeof(int), sysctl_hw_snd_feeder_rate_scaling, "I", "");
211 
212 static int
213 sysctl_hw_snd_feeder_rate_buffersize(SYSCTL_HANDLER_ARGS)
214 {
215 	int err, val;
216 
217 	val = feeder_rate_buffersize;
218 	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
219 	/*
220 	 * Don't waste too much kernel space
221 	 */
222 	if (val < 2 || val > 65536)
223 		err = EINVAL;
224 	else
225 		feeder_rate_buffersize = val & ~1;
226 	return err;
227 }
228 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_buffersize, CTLTYPE_INT | CTLFLAG_RW,
229 	0, sizeof(int), sysctl_hw_snd_feeder_rate_buffersize, "I", "");
230 #endif
231 
232 static void
233 feed_speed_ratio(uint32_t x, uint32_t y, uint32_t *gx, uint32_t *gy)
234 {
235 	uint32_t w, src = x, dst = y;
236 
237 	while (y != 0) {
238 		w = x % y;
239 		x = y;
240 		y = w;
241 	}
242 	*gx = src / x;
243 	*gy = dst / x;
244 }
245 
246 static void
247 feed_scale_roll(uint32_t dst, int32_t *scale, int32_t *roll, int32_t max)
248 {
249 	int64_t k, tscale;
250 	int32_t j, troll;
251 
252 	*scale = *roll = -1;
253 	for (j = MAXGAIN; j >= MINGAIN; j -= 3) {
254 		for (troll = 0; troll < max; troll++) {
255 			tscale = (1 << troll) / dst;
256 			k = (tscale * dst * 100) >> troll;
257 			if (k > j && k <= 100) {
258 				*scale = tscale;
259 				*roll = troll;
260 				return;
261 			}
262 		}
263 	}
264 }
265 
266 static int
267 feed_get_best_coef(uint32_t *src, uint32_t *dst, uint32_t *gx, uint32_t *gy,
268 			int32_t *scale, int32_t *roll)
269 {
270 	uint32_t tsrc, tdst, sscale, dscale;
271 	int32_t tscale, troll;
272 	int i, j, hzmin, hzmax;
273 
274 	*scale = *roll = -1;
275 	for (i = 0; i < 2; i++) {
276 		hzmin = (ROUNDHZ * i) + 1;
277 		hzmax = hzmin + ROUNDHZ;
278 		for (j = hzmin; j < hzmax; j++) {
279 			tsrc = *src - (*src % j);
280 			tdst = *dst;
281 			if (tsrc < 1 || tdst < 1)
282 				goto coef_failed;
283 			feed_speed_ratio(tsrc, tdst, &sscale, &dscale);
284 			feed_scale_roll(dscale, &tscale, &troll,
285 						FEEDRATE_32_MAXROLL);
286 			if (tscale != -1 && troll != -1) {
287 				*src = tsrc;
288 				*gx = sscale;
289 				*gy = dscale;
290 				*scale = tscale;
291 				*roll = troll;
292 				return j;
293 			}
294 		}
295 		for (j = hzmin; j < hzmax; j++) {
296 			tsrc = *src - (*src % j);
297 			tdst = *dst - (*dst % j);
298 			if (tsrc < 1 || tdst < 1)
299 				goto coef_failed;
300 			feed_speed_ratio(tsrc, tdst, &sscale, &dscale);
301 			feed_scale_roll(dscale, &tscale, &troll,
302 						FEEDRATE_32_MAXROLL);
303 			if (tscale != -1 && troll != -1) {
304 				*src = tsrc;
305 				*dst = tdst;
306 				*gx = sscale;
307 				*gy = dscale;
308 				*scale = tscale;
309 				*roll = troll;
310 				return j;
311 			}
312 		}
313 		for (j = hzmin; j < hzmax; j++) {
314 			tsrc = *src;
315 			tdst = *dst - (*dst % j);
316 			if (tsrc < 1 || tdst < 1)
317 				goto coef_failed;
318 			feed_speed_ratio(tsrc, tdst, &sscale, &dscale);
319 			feed_scale_roll(dscale, &tscale, &troll,
320 						FEEDRATE_32_MAXROLL);
321 			if (tscale != -1 && troll != -1) {
322 				*src = tsrc;
323 				*dst = tdst;
324 				*gx = sscale;
325 				*gy = dscale;
326 				*scale = tscale;
327 				*roll = troll;
328 				return j;
329 			}
330 		}
331 	}
332 coef_failed:
333 	feed_speed_ratio(*src, *dst, gx, gy);
334 	feed_scale_roll(*gy, scale, roll, FEEDRATE_32_MAXROLL);
335 	return 0;
336 }
337 
338 static void
339 feed_rate_reset(struct feed_rate_info *info)
340 {
341 	info->scale = -1;
342 	info->roll = -1;
343 	info->src = info->rsrc;
344 	info->dst = info->rdst;
345 	info->gx = 0;
346 	info->gy = 0;
347 }
348 
349 static int
350 feed_rate_setup(struct pcm_feeder *f)
351 {
352 	struct feed_rate_info *info = f->data;
353 	int r = 0;
354 
355 	info->pos = 2;
356 	info->bpos = 4;
357 	info->alpha = 0;
358 	info->stray = 0;
359 	feed_rate_reset(info);
360 	if (info->src == info->dst) {
361 		/*
362 		 * No conversion ever needed. Just do plain copy.
363 		 */
364 		info->convert = feed_convert_plain;
365 		info->gx = 1;
366 		info->gy = 1;
367 	} else {
368 		switch (feeder_rate_scaling) {
369 			case FEEDRATE_CONVERT_64:
370 				feed_speed_ratio(info->src, info->dst,
371 					&info->gx, &info->gy);
372 				info->convert = feed_convert_64;
373 				break;
374 			case FEEDRATE_CONVERT_SCALE64:
375 				feed_speed_ratio(info->src, info->dst,
376 					&info->gx, &info->gy);
377 				feed_scale_roll(info->gy, &info->scale,
378 					&info->roll, FEEDRATE_64_MAXROLL);
379 				if (info->scale == -1 || info->roll == -1)
380 					return -1;
381 				info->convert = feed_convert_scale64;
382 				break;
383 			case FEEDRATE_CONVERT_SCALE32:
384 				r = feed_get_best_coef(&info->src, &info->dst,
385 					&info->gx, &info->gy, &info->scale,
386 					&info->roll);
387 				if (r == 0)
388 					return -1;
389 				info->convert = feed_convert_scale32;
390 				break;
391 			case FEEDRATE_CONVERT_PLAIN:
392 				feed_speed_ratio(info->src, info->dst,
393 					&info->gx, &info->gy);
394 				info->convert = feed_convert_plain;
395 				break;
396 			case FEEDRATE_CONVERT_FIXED:
397 				r = feed_get_best_coef(&info->src, &info->dst,
398 					&info->gx, &info->gy, &info->scale,
399 					&info->roll);
400 				if (r != 0 && info->src == info->rsrc &&
401 						info->dst == info->rdst)
402 					info->convert = feed_convert_scale32;
403 				else {
404 					/* Fallback */
405 					feed_rate_reset(info);
406 					feed_speed_ratio(info->src, info->dst,
407 						&info->gx, &info->gy);
408 					feed_scale_roll(info->gy, &info->scale,
409 						&info->roll, FEEDRATE_64_MAXROLL);
410 					if (info->scale != -1 && info->roll != -1)
411 						info->convert = feed_convert_scale64;
412 					else
413 						info->convert = feed_convert_64;
414 				}
415 				break;
416 			case FEEDRATE_CONVERT_OPTIMAL:
417 				r = feed_get_best_coef(&info->src, &info->dst,
418 					&info->gx, &info->gy, &info->scale,
419 					&info->roll);
420 				if (r != 0)
421 					info->convert = feed_convert_scale32;
422 				else {
423 					/* Fallback */
424 					feed_rate_reset(info);
425 					feed_speed_ratio(info->src, info->dst,
426 						&info->gx, &info->gy);
427 					feed_scale_roll(info->gy, &info->scale,
428 						&info->roll, FEEDRATE_64_MAXROLL);
429 					if (info->scale != -1 && info->roll != -1)
430 						info->convert = feed_convert_scale64;
431 					else
432 						info->convert = feed_convert_64;
433 				}
434 				break;
435 			case FEEDRATE_CONVERT_WORST:
436 				r = feed_get_best_coef(&info->src, &info->dst,
437 					&info->gx, &info->gy, &info->scale,
438 					&info->roll);
439 				if (r != 0)
440 					info->convert = feed_convert_scale32;
441 				else {
442 					/* Fallback */
443 					feed_rate_reset(info);
444 					feed_speed_ratio(info->src, info->dst,
445 						&info->gx, &info->gy);
446 					info->convert = feed_convert_plain;
447 				}
448 				break;
449 			default:
450 				return -1;
451 				break;
452 		}
453 		/* No way! */
454 		if (info->gx == 0 || info->gy == 0)
455 			return -1;
456 		/*
457 		 * No need to interpolate/decimate, just do plain copy.
458 		 * This probably caused by Hz roundup.
459 		 */
460 		if (info->gx == info->gy)
461 			info->convert = feed_convert_plain;
462 	}
463 	return 0;
464 }
465 
466 static int
467 feed_rate_set(struct pcm_feeder *f, int what, int value)
468 {
469 	struct feed_rate_info *info = f->data;
470 
471 	if (value < feeder_rate_ratemin || value > feeder_rate_ratemax)
472 		return -1;
473 
474 	switch (what) {
475 		case FEEDRATE_SRC:
476 			info->rsrc = value;
477 			break;
478 		case FEEDRATE_DST:
479 			info->rdst = value;
480 			break;
481 		default:
482 			return -1;
483 	}
484 	return feed_rate_setup(f);
485 }
486 
487 static int
488 feed_rate_get(struct pcm_feeder *f, int what)
489 {
490 	struct feed_rate_info *info = f->data;
491 
492 	/*
493 	 * Return *real* src/dst rate.
494 	 */
495 	switch (what) {
496 		case FEEDRATE_SRC:
497 			return info->rsrc;
498 		case FEEDRATE_DST:
499 			return info->rdst;
500 		default:
501 			return -1;
502 	}
503 	return -1;
504 }
505 
506 static int
507 feed_rate_init(struct pcm_feeder *f)
508 {
509 	struct feed_rate_info *info;
510 
511 	info = kmalloc(sizeof(*info), M_RATEFEEDER, M_WAITOK | M_ZERO);
512 	/*
513 	 * bufsz = sample from last cycle + conversion space
514 	 */
515 	info->bufsz = 2 + feeder_rate_buffersize;
516 	info->buffer = kmalloc(sizeof(*info->buffer) * info->bufsz,
517 					M_RATEFEEDER, M_WAITOK | M_ZERO);
518 	info->rsrc = DSP_DEFAULT_SPEED;
519 	info->rdst = DSP_DEFAULT_SPEED;
520 	f->data = info;
521 	return feed_rate_setup(f);
522 }
523 
524 static int
525 feed_rate_free(struct pcm_feeder *f)
526 {
527 	struct feed_rate_info *info = f->data;
528 
529 	if (info) {
530 		if (info->buffer)
531 			kfree(info->buffer, M_RATEFEEDER);
532 		kfree(info, M_RATEFEEDER);
533 	}
534 	f->data = NULL;
535 	return 0;
536 }
537 
538 static uint32_t
539 feed_convert_64(struct feed_rate_info *info, int16_t *dst, uint32_t max)
540 {
541 	int64_t x, alpha, distance;
542 	uint32_t ret;
543 	int32_t pos, bpos, gx, gy;
544 	int16_t *src;
545 	/*
546 	 * Plain, straight forward 64bit arith. No bit-magic applied here.
547 	 */
548 	ret = 0;
549 	alpha = info->alpha;
550 	gx = info->gx;
551 	gy = info->gy;
552 	pos = info->pos;
553 	bpos = info->bpos;
554 	src = info->buffer;
555 	for (;;) {
556 		if (alpha < gx) {
557 			alpha += gy;
558 			pos += 2;
559 			if (pos == bpos)
560 				break;
561 		} else {
562 			alpha -= gx;
563 			distance = gy - alpha;
564 			x = (alpha * src[pos - 2]) + (distance * src[pos]);
565 			dst[ret++] = x / gy;
566 			x = (alpha * src[pos - 1]) + (distance * src[pos + 1]);
567 			dst[ret++] = x / gy;
568 			if (ret == max)
569 				break;
570 		}
571 	}
572 	info->alpha = alpha;
573 	info->pos = pos;
574 	return ret;
575 }
576 
577 static uint32_t
578 feed_convert_scale64(struct feed_rate_info *info, int16_t *dst, uint32_t max)
579 {
580 	int64_t x, alpha, distance;
581 	uint32_t ret;
582 	int32_t pos, bpos, gx, gy, roll;
583 	int16_t *src;
584 	/*
585 	 * 64bit scaling.
586 	 */
587 	ret = 0;
588 	roll = info->roll;
589 	alpha = info->alpha * info->scale;
590 	gx = info->gx * info->scale;
591 	gy = info->gy * info->scale;
592 	pos = info->pos;
593 	bpos = info->bpos;
594 	src = info->buffer;
595 	for (;;) {
596 		if (alpha < gx) {
597 			alpha += gy;
598 			pos += 2;
599 			if (pos == bpos)
600 				break;
601 		} else {
602 			alpha -= gx;
603 			distance = gy - alpha;
604 			x = (alpha * src[pos - 2]) + (distance * src[pos]);
605 			dst[ret++] = x >> roll;
606 			x = (alpha * src[pos - 1]) + (distance * src[pos + 1]);
607 			dst[ret++] = x >> roll;
608 			if (ret == max)
609 				break;
610 		}
611 	}
612 	info->alpha = alpha / info->scale;
613 	info->pos = pos;
614 	return ret;
615 }
616 
617 static uint32_t
618 feed_convert_scale32(struct feed_rate_info *info, int16_t *dst, uint32_t max)
619 {
620 	uint32_t ret;
621 	int32_t x, pos, bpos, gx, gy, alpha, roll, distance;
622 	int16_t *src;
623 	/*
624 	 * 32bit scaling.
625 	 */
626 	ret = 0;
627 	roll = info->roll;
628 	alpha = info->alpha * info->scale;
629 	gx = info->gx * info->scale;
630 	gy = info->gy * info->scale;
631 	pos = info->pos;
632 	bpos = info->bpos;
633 	src = info->buffer;
634 	for (;;) {
635 		if (alpha < gx) {
636 			alpha += gy;
637 			pos += 2;
638 			if (pos == bpos)
639 				break;
640 		} else {
641 			alpha -= gx;
642 			distance = gy - alpha;
643 			x = (alpha * src[pos - 2]) + (distance * src[pos]);
644 			dst[ret++] = x >> roll;
645 			x = (alpha * src[pos - 1]) + (distance * src[pos + 1]);
646 			dst[ret++] = x >> roll;
647 			if (ret == max)
648 				break;
649 		}
650 	}
651 	info->alpha = alpha / info->scale;
652 	info->pos = pos;
653 	return ret;
654 }
655 
656 static uint32_t
657 feed_convert_plain(struct feed_rate_info *info, int16_t *dst, uint32_t max)
658 {
659 	uint32_t ret;
660 	int32_t pos, bpos, gx, gy, alpha;
661 	int16_t *src;
662 	/*
663 	 * Plain copy.
664 	 */
665 	ret = 0;
666 	gx = info->gx;
667 	gy = info->gy;
668 	alpha = info->alpha;
669 	pos = info->pos;
670 	bpos = info->bpos;
671 	src = info->buffer;
672 	for (;;) {
673 		if (alpha < gx) {
674 			alpha += gy;
675 			pos += 2;
676 			if (pos == bpos)
677 				break;
678 		} else {
679 			alpha -= gx;
680 			dst[ret++] = src[pos];
681 			dst[ret++] = src[pos + 1];
682 			if (ret == max)
683 				break;
684 		}
685 	}
686 	info->pos = pos;
687 	info->alpha = alpha;
688 	return ret;
689 }
690 
691 static int32_t
692 feed_rate(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
693 			uint32_t count, void *source)
694 {
695 	struct feed_rate_info *info = f->data;
696 	uint32_t i;
697 	int32_t fetch, slot;
698 	int16_t *dst = (int16_t *)b;
699 	/*
700 	 * This loop has been optimized to generalize both up / down
701 	 * sampling without causing missing samples or excessive buffer
702 	 * feeding.
703 	 */
704 	RATE_TEST(count >= 4 && (count & 3) == 0,
705 		("%s: Count size not byte integral (%d)\n", __func__, count));
706 	if (count < 4)
707 		return 0;
708 	count >>= 1;
709 	count &= ~1;
710 	slot = (((info->gx * (count >> 1)) + info->gy - info->alpha - 1) / info->gy) << 1;
711 	RATE_TEST((slot & 1) == 0, ("%s: Slot count not sample integral (%d)\n",
712 						__func__, slot));
713 	/*
714 	 * Optimize buffer feeding aggressively to ensure calculated slot
715 	 * can be fitted nicely into available buffer free space, hence
716 	 * avoiding multiple feeding.
717 	 */
718 	RATE_TEST(info->stray == 0, ("%s: [1] Stray bytes: %u\n",
719 		__func__,info->stray));
720 	if (info->pos != 2 && info->bpos - info->pos == 2 &&
721 			info->bpos + slot > info->bufsz) {
722 		/*
723 		 * Copy last unit sample and its previous to
724 		 * beginning of buffer.
725 		 */
726 		info->buffer[0] = info->buffer[info->pos - 2];
727 		info->buffer[1] = info->buffer[info->pos - 1];
728 		info->buffer[2] = info->buffer[info->pos];
729 		info->buffer[3] = info->buffer[info->pos + 1];
730 		info->pos = 2;
731 		info->bpos = 4;
732 	}
733 	RATE_ASSERT(slot >= 0, ("%s: Negative Slot: %d\n",
734 			__func__, slot));
735 	i = 0;
736 	for (;;) {
737 		for (;;) {
738 			fetch = (info->bufsz - info->bpos) << 1;
739 			fetch -= info->stray;
740 			RATE_ASSERT(fetch >= 0,
741 				("%s: [1] Buffer overrun: %d > %d\n",
742 					__func__, info->bpos, info->bufsz));
743 			if ((slot << 1) < fetch)
744 				fetch = slot << 1;
745 			if (fetch > 0) {
746 				RATE_ASSERT(((info->bpos << 1) - info->stray) >= 0 &&
747 					((info->bpos << 1) - info->stray) < (info->bufsz << 1),
748 					("%s: DANGER - BUFFER OVERRUN! bufsz=%d, pos=%d\n", __func__,
749 					info->bufsz << 1, (info->bpos << 1) - info->stray));
750 				fetch = FEEDER_FEED(f->source, c,
751 						(uint8_t *)(info->buffer) + (info->bpos << 1) - info->stray,
752 						fetch, source);
753 				info->stray = 0;
754 				if (fetch == 0)
755 					break;
756 				RATE_TEST((fetch & 3) == 0,
757 					("%s: Fetch size not byte integral (%d)\n",
758 					__func__, fetch));
759 				info->stray += fetch & 3;
760 				RATE_TEST(info->stray == 0,
761 					("%s: Stray bytes detected (%d)\n",
762 					__func__, info->stray));
763 				fetch >>= 1;
764 				fetch &= ~1;
765 				info->bpos += fetch;
766 				slot -= fetch;
767 				RATE_ASSERT(slot >= 0,
768 					("%s: Negative Slot: %d\n", __func__,
769 						slot));
770 				if (slot == 0)
771 					break;
772 				if (info->bpos == info->bufsz)
773 					break;
774 			} else
775 				break;
776 		}
777 		if (info->pos == info->bpos) {
778 			RATE_TEST(info->pos == 2,
779 				("%s: EOF while in progress\n", __func__));
780 			break;
781 		}
782 		RATE_ASSERT(info->pos <= info->bpos,
783 			("%s: [2] Buffer overrun: %d > %d\n", __func__,
784 			info->pos, info->bpos));
785 		RATE_ASSERT(info->pos < info->bpos,
786 			("%s: Zero buffer!\n", __func__));
787 		RATE_ASSERT(((info->bpos - info->pos) & 1) == 0,
788 			("%s: Buffer not sample integral (%d)\n",
789 			__func__, info->bpos - info->pos));
790 		i += info->convert(info, dst + i, count - i);
791 		RATE_ASSERT(info->pos <= info->bpos,
792 				("%s: [3] Buffer overrun: %d > %d\n",
793 					__func__, info->pos, info->bpos));
794 		if (info->pos == info->bpos) {
795 			/*
796 			 * End of buffer cycle. Copy last unit sample
797 			 * to beginning of buffer so next cycle can
798 			 * interpolate using it.
799 			 */
800 			RATE_TEST(info->stray == 0, ("%s: [2] Stray bytes: %u\n", __func__, info->stray));
801 			info->buffer[0] = info->buffer[info->pos - 2];
802 			info->buffer[1] = info->buffer[info->pos - 1];
803 			info->bpos = 2;
804 			info->pos = 2;
805 		}
806 		if (i == count)
807 			break;
808 	}
809 #if 0
810 	RATE_TEST(count == i, ("Expect: %u , Got: %u\n", count << 1, i << 1));
811 #endif
812 	RATE_TEST(info->stray == 0, ("%s: [3] Stray bytes: %u\n", __func__, info->stray));
813 	return i << 1;
814 }
815 
816 static struct pcm_feederdesc feeder_rate_desc[] = {
817 	{FEEDER_RATE, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
818 	{0, 0, 0, 0},
819 };
820 static kobj_method_t feeder_rate_methods[] = {
821     	KOBJMETHOD(feeder_init,		feed_rate_init),
822     	KOBJMETHOD(feeder_free,		feed_rate_free),
823     	KOBJMETHOD(feeder_set,		feed_rate_set),
824     	KOBJMETHOD(feeder_get,		feed_rate_get),
825     	KOBJMETHOD(feeder_feed,		feed_rate),
826 	KOBJMETHOD_END
827 };
828 FEEDER_DECLARE(feeder_rate, 2, NULL);
829