xref: /freebsd/sys/dev/sound/pcm/feeder_rate.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
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 
29 /*
30  * 2006-02-21:
31  * ==========
32  *
33  * Major cleanup and overhaul to remove much redundant codes.
34  * Highlights:
35  *	1) Support for signed / unsigned 16, 24 and 32 bit,
36  *	   big / little endian,
37  *	2) Unlimited channels.
38  *
39  * 2005-06-11:
40  * ==========
41  *
42  * *New* and rewritten soft sample rate converter supporting arbitrary sample
43  * rates, fine grained scaling/coefficients and a unified up/down stereo
44  * converter. Most of the disclaimers from orion's notes also applies
45  * here, regarding linear interpolation deficiencies and pre/post
46  * anti-aliasing filtering issues. This version comes with a much simpler and
47  * tighter interface, although it works almost exactly like the older one.
48  *
49  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
50  *                                                                         *
51  * This new implementation is fully dedicated in memory of Cameron Grant,  *
52  * the creator of the magnificent, highly addictive feeder infrastructure. *
53  *                                                                         *
54  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55  *
56  * Orion's notes:
57  * =============
58  *
59  * This rate conversion code uses linear interpolation without any
60  * pre- or post- interpolation filtering to combat aliasing.  This
61  * greatly limits the sound quality and should be addressed at some
62  * stage in the future.
63  *
64  * Since this accuracy of interpolation is sensitive and examination
65  * of the algorithm output is harder from the kernel, the code is
66  * designed to be compiled in the kernel and in a userland test
67  * harness.  This is done by selectively including and excluding code
68  * with several portions based on whether _KERNEL is defined.  It's a
69  * little ugly, but exceedingly useful.  The testsuite and its
70  * revisions can be found at:
71  *		http://people.freebsd.org/~orion/files/feedrate/
72  *
73  * Special thanks to Ken Marx for exposing flaws in the code and for
74  * testing revisions.
75  */
76 
77 #include <dev/sound/pcm/sound.h>
78 #include "feeder_if.h"
79 
80 SND_DECLARE_FILE("$FreeBSD$");
81 
82 #define RATE_ASSERT(x, y)	/* KASSERT(x,y) */
83 #define RATE_TEST(x, y)		/* if (!(x)) printf y */
84 #define RATE_TRACE(x...)	/* printf(x) */
85 
86 MALLOC_DEFINE(M_RATEFEEDER, "ratefeed", "pcm rate feeder");
87 
88 /*
89  * Don't overflow 32bit integer, since everything is done
90  * within 32bit arithmetic.
91  */
92 #define RATE_FACTOR_MIN		1
93 #define RATE_FACTOR_MAX		PCM_S24_MAX
94 #define RATE_FACTOR_SAFE(val)	(!((val) < RATE_FACTOR_MIN || \
95 				(val) > RATE_FACTOR_MAX))
96 
97 struct feed_rate_info;
98 
99 typedef uint32_t (*feed_rate_converter)(struct feed_rate_info *,
100 							uint8_t *, uint32_t);
101 
102 struct feed_rate_info {
103 	uint32_t src, dst;	/* rounded source / destination rates */
104 	uint32_t rsrc, rdst;	/* original source / destination rates */
105 	uint32_t gx, gy;	/* interpolation / decimation ratio */
106 	uint32_t alpha;		/* interpolation distance */
107 	uint32_t pos, bpos;	/* current sample / buffer positions */
108 	uint32_t bufsz;		/* total buffer size limit */
109 	uint32_t bufsz_init;	/* allocated buffer size */
110 	uint32_t channels;	/* total channels */
111 	uint32_t bps;		/* bytes-per-sample */
112 #ifdef FEEDRATE_STRAY
113 	uint32_t stray;		/* stray bytes */
114 #endif
115 	uint8_t  *buffer;
116 	feed_rate_converter convert;
117 };
118 
119 int feeder_rate_min = FEEDRATE_RATEMIN;
120 int feeder_rate_max = FEEDRATE_RATEMAX;
121 int feeder_rate_round = FEEDRATE_ROUNDHZ;
122 
123 TUNABLE_INT("hw.snd.feeder_rate_min", &feeder_rate_min);
124 TUNABLE_INT("hw.snd.feeder_rate_max", &feeder_rate_max);
125 TUNABLE_INT("hw.snd.feeder_rate_round", &feeder_rate_round);
126 
127 static int
128 sysctl_hw_snd_feeder_rate_min(SYSCTL_HANDLER_ARGS)
129 {
130 	int err, val;
131 
132 	val = feeder_rate_min;
133 	err = sysctl_handle_int(oidp, &val, 0, req);
134 	if (err != 0 || req->newptr == NULL)
135 		return (err);
136 	if (RATE_FACTOR_SAFE(val) && val < feeder_rate_max)
137 		feeder_rate_min = val;
138 	else
139 		err = EINVAL;
140 	return (err);
141 }
142 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_min, CTLTYPE_INT | CTLFLAG_RW,
143 	0, sizeof(int), sysctl_hw_snd_feeder_rate_min, "I",
144 	"minimum allowable rate");
145 
146 static int
147 sysctl_hw_snd_feeder_rate_max(SYSCTL_HANDLER_ARGS)
148 {
149 	int err, val;
150 
151 	val = feeder_rate_max;
152 	err = sysctl_handle_int(oidp, &val, 0, req);
153 	if (err != 0 || req->newptr == NULL)
154 		return (err);
155 	if (RATE_FACTOR_SAFE(val) && val > feeder_rate_min)
156 		feeder_rate_max = val;
157 	else
158 		err = EINVAL;
159 	return (err);
160 }
161 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_max, CTLTYPE_INT | CTLFLAG_RW,
162 	0, sizeof(int), sysctl_hw_snd_feeder_rate_max, "I",
163 	"maximum allowable rate");
164 
165 static int
166 sysctl_hw_snd_feeder_rate_round(SYSCTL_HANDLER_ARGS)
167 {
168 	int err, val;
169 
170 	val = feeder_rate_round;
171 	err = sysctl_handle_int(oidp, &val, 0, req);
172 	if (err != 0 || req->newptr == NULL)
173 		return (err);
174 	if (val < FEEDRATE_ROUNDHZ_MIN || val > FEEDRATE_ROUNDHZ_MAX)
175 		err = EINVAL;
176 	else
177 		feeder_rate_round = val - (val % FEEDRATE_ROUNDHZ);
178 	return (err);
179 }
180 SYSCTL_PROC(_hw_snd, OID_AUTO, feeder_rate_round, CTLTYPE_INT | CTLFLAG_RW,
181 	0, sizeof(int), sysctl_hw_snd_feeder_rate_round, "I",
182 	"sample rate converter rounding threshold");
183 
184 #define FEEDER_RATE_CONVERT(FMTBIT, RATE_INTCAST, SIGN, SIGNS, ENDIAN, ENDIANS)	\
185 static uint32_t									\
186 feed_convert_##SIGNS##FMTBIT##ENDIANS(struct feed_rate_info *info,		\
187 						uint8_t *dst, uint32_t max)	\
188 {										\
189 	uint32_t ret, smpsz, ch, pos, bpos, gx, gy, alpha, d1, d2;		\
190 	int32_t x, y;								\
191 	int i;									\
192 	uint8_t *src, *sx, *sy;							\
193 										\
194 	ret = 0;								\
195 	alpha = info->alpha;							\
196 	gx = info->gx;								\
197 	gy = info->gy;								\
198 	pos = info->pos;							\
199 	bpos = info->bpos;							\
200 	src = info->buffer + pos;						\
201 	ch = info->channels;							\
202 	smpsz = PCM_##FMTBIT##_BPS * ch;					\
203 	for (;;) {								\
204 		if (alpha < gx) {						\
205 			alpha += gy;						\
206 			pos += smpsz;						\
207 			if (pos == bpos)					\
208 				break;						\
209 			src += smpsz;						\
210 		} else {							\
211 			alpha -= gx;						\
212 			d1 = (alpha << PCM_FXSHIFT) / gy;			\
213 			d2 = (1U << PCM_FXSHIFT) - d1;				\
214 			sx = src - smpsz;					\
215 			sy = src;						\
216 			i = ch;							\
217 			do {							\
218 				x = PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sx);	\
219 				y = PCM_READ_##SIGN##FMTBIT##_##ENDIAN(sy);	\
220 				x = (((RATE_INTCAST)x * d1) +			\
221 				    ((RATE_INTCAST)y * d2)) >> PCM_FXSHIFT;	\
222 				PCM_WRITE_##SIGN##FMTBIT##_##ENDIAN(dst, x);	\
223 				dst += PCM_##FMTBIT##_BPS;			\
224 				sx += PCM_##FMTBIT##_BPS;			\
225 				sy += PCM_##FMTBIT##_BPS;			\
226 				ret += PCM_##FMTBIT##_BPS;			\
227 			} while (--i != 0);					\
228 			if (ret == max)						\
229 				break;						\
230 		}								\
231 	}									\
232 	info->alpha = alpha;							\
233 	info->pos = pos;							\
234 	return (ret);								\
235 }
236 
237 FEEDER_RATE_CONVERT(8, int32_t, S, s, NE, ne)
238 FEEDER_RATE_CONVERT(16, int32_t, S, s, LE, le)
239 FEEDER_RATE_CONVERT(24, int32_t, S, s, LE, le)
240 FEEDER_RATE_CONVERT(32, intpcm_t, S, s, LE, le)
241 FEEDER_RATE_CONVERT(16, int32_t, S, s, BE, be)
242 FEEDER_RATE_CONVERT(24, int32_t, S, s, BE, be)
243 FEEDER_RATE_CONVERT(32, intpcm_t, S, s, BE, be)
244 FEEDER_RATE_CONVERT(8, int32_t, U, u, NE, ne)
245 FEEDER_RATE_CONVERT(16, int32_t, U, u, LE, le)
246 FEEDER_RATE_CONVERT(24, int32_t, U, u, LE, le)
247 FEEDER_RATE_CONVERT(32, intpcm_t, U, u, LE, le)
248 FEEDER_RATE_CONVERT(16, int32_t, U, u, BE, be)
249 FEEDER_RATE_CONVERT(24, int32_t, U, u, BE, be)
250 FEEDER_RATE_CONVERT(32, intpcm_t, U, u, BE, be)
251 
252 static void
253 feed_speed_ratio(uint32_t src, uint32_t dst, uint32_t *gx, uint32_t *gy)
254 {
255 	uint32_t w, x = src, y = dst;
256 
257 	while (y != 0) {
258 		w = x % y;
259 		x = y;
260 		y = w;
261 	}
262 	*gx = src / x;
263 	*gy = dst / x;
264 }
265 
266 static void
267 feed_rate_reset(struct feed_rate_info *info)
268 {
269 	info->src = info->rsrc - (info->rsrc %
270 	    ((feeder_rate_round > 0) ? feeder_rate_round : 1));
271 	info->dst = info->rdst - (info->rdst %
272 	    ((feeder_rate_round > 0) ? feeder_rate_round : 1));
273 	info->gx = 1;
274 	info->gy = 1;
275 	info->alpha = 0;
276 	info->channels = 1;
277 	info->bps = PCM_8_BPS;
278 	info->convert = NULL;
279 	info->bufsz = info->bufsz_init;
280 	info->pos = 1;
281 	info->bpos = 2;
282 #ifdef FEEDRATE_STRAY
283 	info->stray = 0;
284 #endif
285 }
286 
287 static int
288 feed_rate_setup(struct pcm_feeder *f)
289 {
290 	struct feed_rate_info *info = f->data;
291 	static const struct {
292 		uint32_t format;	/* pcm / audio format */
293 		uint32_t bps;		/* bytes-per-sample, regardless of
294 					   total channels */
295 		feed_rate_converter convert;
296 	} convtbl[] = {
297 		{ AFMT_S8,     PCM_8_BPS,  feed_convert_s8ne  },
298 		{ AFMT_S16_LE, PCM_16_BPS, feed_convert_s16le },
299 		{ AFMT_S24_LE, PCM_24_BPS, feed_convert_s24le },
300 		{ AFMT_S32_LE, PCM_32_BPS, feed_convert_s32le },
301 		{ AFMT_S16_BE, PCM_16_BPS, feed_convert_s16be },
302 		{ AFMT_S24_BE, PCM_24_BPS, feed_convert_s24be },
303 		{ AFMT_S32_BE, PCM_32_BPS, feed_convert_s32be },
304 		{ AFMT_U8,     PCM_8_BPS,  feed_convert_u8ne  },
305 		{ AFMT_U16_LE, PCM_16_BPS, feed_convert_u16le },
306 		{ AFMT_U24_LE, PCM_24_BPS, feed_convert_u24le },
307 		{ AFMT_U32_LE, PCM_32_BPS, feed_convert_u32le },
308 		{ AFMT_U16_BE, PCM_16_BPS, feed_convert_u16be },
309 		{ AFMT_U24_BE, PCM_24_BPS, feed_convert_u24be },
310 		{ AFMT_U32_BE, PCM_32_BPS, feed_convert_u32be },
311 		{ 0, 0, NULL },
312 	};
313 	uint32_t i;
314 
315 	feed_rate_reset(info);
316 
317 	if (info->src != info->dst)
318 		feed_speed_ratio(info->src, info->dst, &info->gx, &info->gy);
319 
320 	if (!(RATE_FACTOR_SAFE(info->gx) && RATE_FACTOR_SAFE(info->gy)))
321 		return (-1);
322 
323 	for (i = 0; i < sizeof(convtbl) / sizeof(convtbl[0]); i++) {
324 		if (convtbl[i].format == 0)
325 			return (-1);
326 		if ((f->desc->out & ~AFMT_STEREO) == convtbl[i].format) {
327 			info->bps = convtbl[i].bps;
328 			info->convert = convtbl[i].convert;
329 			break;
330 		}
331 	}
332 
333 	/*
334 	 * No need to interpolate/decimate, just do plain copy.
335 	 */
336 	if (info->gx == info->gy)
337 		info->convert = NULL;
338 
339 	info->channels = (f->desc->out & AFMT_STEREO) ? 2 : 1;
340 	info->pos = info->bps * info->channels;
341 	info->bpos = info->pos << 1;
342 	info->bufsz -= info->bufsz % info->pos;
343 
344 	memset(info->buffer, sndbuf_zerodata(f->desc->out), info->bpos);
345 
346 	RATE_TRACE("%s: %u (%u) -> %u (%u) [%u/%u] , "
347 	    "format=0x%08x, channels=%u, bufsz=%u\n",
348 	    __func__, info->src, info->rsrc, info->dst, info->rdst,
349 	    info->gx, info->gy, f->desc->out, info->channels,
350 	    info->bufsz - info->pos);
351 
352 	return (0);
353 }
354 
355 static int
356 feed_rate_set(struct pcm_feeder *f, int what, int32_t value)
357 {
358 	struct feed_rate_info *info = f->data;
359 
360 	if (value < feeder_rate_min || value > feeder_rate_max)
361 		return (-1);
362 
363 	switch (what) {
364 	case FEEDRATE_SRC:
365 		info->rsrc = value;
366 		break;
367 	case FEEDRATE_DST:
368 		info->rdst = value;
369 		break;
370 	default:
371 		return (-1);
372 	}
373 	return (feed_rate_setup(f));
374 }
375 
376 static int
377 feed_rate_get(struct pcm_feeder *f, int what)
378 {
379 	struct feed_rate_info *info = f->data;
380 
381 	switch (what) {
382 	case FEEDRATE_SRC:
383 		return (info->rsrc);
384 	case FEEDRATE_DST:
385 		return (info->rdst);
386 	default:
387 		return (-1);
388 	}
389 	return (-1);
390 }
391 
392 static int
393 feed_rate_init(struct pcm_feeder *f)
394 {
395 	struct feed_rate_info *info;
396 
397 	if (f->desc->out != f->desc->in)
398 		return (EINVAL);
399 
400 	info = malloc(sizeof(*info), M_RATEFEEDER, M_NOWAIT | M_ZERO);
401 	if (info == NULL)
402 		return (ENOMEM);
403 	/*
404 	 * bufsz = sample from last cycle + conversion space
405 	 */
406 	info->bufsz_init = 8 + feeder_buffersize;
407 	info->buffer = malloc(info->bufsz_init, M_RATEFEEDER,
408 	    M_NOWAIT | M_ZERO);
409 	if (info->buffer == NULL) {
410 		free(info, M_RATEFEEDER);
411 		return (ENOMEM);
412 	}
413 	info->rsrc = DSP_DEFAULT_SPEED;
414 	info->rdst = DSP_DEFAULT_SPEED;
415 	f->data = info;
416 	return (feed_rate_setup(f));
417 }
418 
419 static int
420 feed_rate_free(struct pcm_feeder *f)
421 {
422 	struct feed_rate_info *info = f->data;
423 
424 	if (info != NULL) {
425 		if (info->buffer != NULL)
426 			free(info->buffer, M_RATEFEEDER);
427 		free(info, M_RATEFEEDER);
428 	}
429 	f->data = NULL;
430 	return (0);
431 }
432 
433 static int
434 feed_rate(struct pcm_feeder *f, struct pcm_channel *c, uint8_t *b,
435 						uint32_t count, void *source)
436 {
437 	struct feed_rate_info *info = f->data;
438 	uint32_t i, smpsz;
439 	int32_t fetch, slot;
440 
441 	if (info->convert == NULL)
442 		return (FEEDER_FEED(f->source, c, b, count, source));
443 
444 	/*
445 	 * This loop has been optimized to generalize both up / down
446 	 * sampling without causing missing samples or excessive buffer
447 	 * feeding. The tricky part is to calculate *precise* (slot) value
448 	 * needed for the entire conversion space since we are bound to
449 	 * return and fill up the buffer according to the requested 'count'.
450 	 * Too much feeding will cause the extra buffer stay within temporary
451 	 * circular buffer forever and always manifest itself as a truncated
452 	 * sound during end of playback / recording. Too few, and we end up
453 	 * with possible underruns and waste of cpu cycles.
454 	 *
455 	 * 'Stray' management exist to combat with possible unaligned
456 	 * buffering by the caller.
457 	 */
458 	smpsz = info->bps * info->channels;
459 	RATE_TEST(count >= smpsz && (count % smpsz) == 0,
460 	    ("%s: Count size not sample integral (%d)\n", __func__, count));
461 	if (count < smpsz)
462 		return (0);
463 	count -= count % smpsz;
464 	/*
465 	 * This slot count formula will stay here for the next million years
466 	 * to come. This is the key of our circular buffering precision.
467 	 */
468 	slot = (((info->gx * (count / smpsz)) + info->gy - info->alpha - 1) /
469 	    info->gy) * smpsz;
470 	RATE_TEST((slot % smpsz) == 0,
471 	    ("%s: Slot count not sample integral (%d)\n", __func__, slot));
472 #ifdef FEEDRATE_STRAY
473 	RATE_TEST(info->stray == 0, ("%s: [1] Stray bytes: %u\n", __func__,
474 	    info->stray));
475 #endif
476 	if (info->pos != smpsz && info->bpos - info->pos == smpsz &&
477 	    info->bpos + slot > info->bufsz) {
478 		/*
479 		 * Copy last unit sample and its previous to
480 		 * beginning of buffer.
481 		 */
482 		bcopy(info->buffer + info->pos - smpsz, info->buffer,
483 		    smpsz << 1);
484 		info->pos = smpsz;
485 		info->bpos = smpsz << 1;
486 	}
487 	RATE_ASSERT(slot >= 0, ("%s: Negative Slot: %d\n", __func__, slot));
488 	i = 0;
489 	for (;;) {
490 		for (;;) {
491 			fetch = info->bufsz - info->bpos;
492 #ifdef FEEDRATE_STRAY
493 			fetch -= info->stray;
494 #endif
495 			RATE_ASSERT(fetch >= 0,
496 			    ("%s: [1] Buffer overrun: %d > %d\n", __func__,
497 			    info->bpos, info->bufsz));
498 			if (slot < fetch)
499 				fetch = slot;
500 #ifdef FEEDRATE_STRAY
501 			if (fetch < 1)
502 #else
503 			if (fetch < smpsz)
504 #endif
505 				break;
506 			RATE_ASSERT((int)(info->bpos
507 #ifdef FEEDRATE_STRAY
508 			    - info->stray
509 #endif
510 			    ) >= 0 &&
511 			    (info->bpos  - info->stray) < info->bufsz,
512 			    ("%s: DANGER - BUFFER OVERRUN! bufsz=%d, pos=%d\n",
513 			    __func__, info->bufsz, info->bpos
514 #ifdef FEEDRATE_STRAY
515 			    - info->stray
516 #endif
517 			    ));
518 			fetch = FEEDER_FEED(f->source, c,
519 			    info->buffer + info->bpos
520 #ifdef FEEDRATE_STRAY
521 			    - info->stray
522 #endif
523 			    , fetch, source);
524 #ifdef FEEDRATE_STRAY
525 			info->stray = 0;
526 			if (fetch == 0)
527 #else
528 			if (fetch < smpsz)
529 #endif
530 				break;
531 			RATE_TEST((fetch % smpsz) == 0,
532 			    ("%s: Fetch size not sample integral (%d)\n",
533 			    __func__, fetch));
534 #ifdef FEEDRATE_STRAY
535 			info->stray += fetch % smpsz;
536 			RATE_TEST(info->stray == 0,
537 			    ("%s: Stray bytes detected (%d)\n", __func__,
538 			    info->stray));
539 #endif
540 			fetch -= fetch % smpsz;
541 			info->bpos += fetch;
542 			slot -= fetch;
543 			RATE_ASSERT(slot >= 0, ("%s: Negative Slot: %d\n",
544 			    __func__, slot));
545 			if (slot == 0 || info->bpos == info->bufsz)
546 				break;
547 		}
548 		if (info->pos == info->bpos) {
549 			RATE_TEST(info->pos == smpsz,
550 			    ("%s: EOF while in progress\n", __func__));
551 			break;
552 		}
553 		RATE_ASSERT(info->pos <= info->bpos,
554 		    ("%s: [2] Buffer overrun: %d > %d\n", __func__, info->pos,
555 		    info->bpos));
556 		RATE_ASSERT(info->pos < info->bpos,
557 		    ("%s: Zero buffer!\n", __func__));
558 		RATE_ASSERT(((info->bpos - info->pos) % smpsz) == 0,
559 		    ("%s: Buffer not sample integral (%d)\n", __func__,
560 		    info->bpos - info->pos));
561 		i += info->convert(info, b + i, count - i);
562 		RATE_ASSERT(info->pos <= info->bpos,
563 		    ("%s: [3] Buffer overrun: %d > %d\n", __func__, info->pos,
564 		    info->bpos));
565 		if (info->pos == info->bpos) {
566 			/*
567 			 * End of buffer cycle. Copy last unit sample
568 			 * to beginning of buffer so next cycle can
569 			 * interpolate using it.
570 			 */
571 #ifdef FEEDRATE_STRAY
572 			RATE_TEST(info->stray == 0,
573 			    ("%s: [2] Stray bytes: %u\n", __func__,
574 			    info->stray));
575 #endif
576 			bcopy(info->buffer + info->pos - smpsz, info->buffer,
577 			    smpsz);
578 			info->bpos = smpsz;
579 			info->pos = smpsz;
580 		}
581 		if (i == count)
582 			break;
583 	}
584 
585 	RATE_TEST((slot == 0 && count == i) || (slot > 0 && count > i &&
586 	    info->pos == info->bpos && info->pos == smpsz),
587 	    ("%s: Inconsistent slot/count! "
588 	    "Count Expect: %u , Got: %u, Slot Left: %d\n", __func__, count, i,
589 	    slot));
590 
591 #ifdef FEEDRATE_STRAY
592 	RATE_TEST(info->stray == 0, ("%s: [3] Stray bytes: %u\n", __func__,
593 	    info->stray));
594 #endif
595 
596 	return (i);
597 }
598 
599 static struct pcm_feederdesc feeder_rate_desc[] = {
600 	{FEEDER_RATE, AFMT_S8, AFMT_S8, 0},
601 	{FEEDER_RATE, AFMT_S16_LE, AFMT_S16_LE, 0},
602 	{FEEDER_RATE, AFMT_S24_LE, AFMT_S24_LE, 0},
603 	{FEEDER_RATE, AFMT_S32_LE, AFMT_S32_LE, 0},
604 	{FEEDER_RATE, AFMT_S16_BE, AFMT_S16_BE, 0},
605 	{FEEDER_RATE, AFMT_S24_BE, AFMT_S24_BE, 0},
606 	{FEEDER_RATE, AFMT_S32_BE, AFMT_S32_BE, 0},
607 	{FEEDER_RATE, AFMT_S8 | AFMT_STEREO, AFMT_S8 | AFMT_STEREO, 0},
608 	{FEEDER_RATE, AFMT_S16_LE | AFMT_STEREO, AFMT_S16_LE | AFMT_STEREO, 0},
609 	{FEEDER_RATE, AFMT_S24_LE | AFMT_STEREO, AFMT_S24_LE | AFMT_STEREO, 0},
610 	{FEEDER_RATE, AFMT_S32_LE | AFMT_STEREO, AFMT_S32_LE | AFMT_STEREO, 0},
611 	{FEEDER_RATE, AFMT_S16_BE | AFMT_STEREO, AFMT_S16_BE | AFMT_STEREO, 0},
612 	{FEEDER_RATE, AFMT_S24_BE | AFMT_STEREO, AFMT_S24_BE | AFMT_STEREO, 0},
613 	{FEEDER_RATE, AFMT_S32_BE | AFMT_STEREO, AFMT_S32_BE | AFMT_STEREO, 0},
614 	{FEEDER_RATE, AFMT_U8, AFMT_U8, 0},
615 	{FEEDER_RATE, AFMT_U16_LE, AFMT_U16_LE, 0},
616 	{FEEDER_RATE, AFMT_U24_LE, AFMT_U24_LE, 0},
617 	{FEEDER_RATE, AFMT_U32_LE, AFMT_U32_LE, 0},
618 	{FEEDER_RATE, AFMT_U16_BE, AFMT_U16_BE, 0},
619 	{FEEDER_RATE, AFMT_U24_BE, AFMT_U24_BE, 0},
620 	{FEEDER_RATE, AFMT_U32_BE, AFMT_U32_BE, 0},
621 	{FEEDER_RATE, AFMT_U8 | AFMT_STEREO, AFMT_U8 | AFMT_STEREO, 0},
622 	{FEEDER_RATE, AFMT_U16_LE | AFMT_STEREO, AFMT_U16_LE | AFMT_STEREO, 0},
623 	{FEEDER_RATE, AFMT_U24_LE | AFMT_STEREO, AFMT_U24_LE | AFMT_STEREO, 0},
624 	{FEEDER_RATE, AFMT_U32_LE | AFMT_STEREO, AFMT_U32_LE | AFMT_STEREO, 0},
625 	{FEEDER_RATE, AFMT_U16_BE | AFMT_STEREO, AFMT_U16_BE | AFMT_STEREO, 0},
626 	{FEEDER_RATE, AFMT_U24_BE | AFMT_STEREO, AFMT_U24_BE | AFMT_STEREO, 0},
627 	{FEEDER_RATE, AFMT_U32_BE | AFMT_STEREO, AFMT_U32_BE | AFMT_STEREO, 0},
628 	{0, 0, 0, 0},
629 };
630 
631 static kobj_method_t feeder_rate_methods[] = {
632 	KOBJMETHOD(feeder_init,		feed_rate_init),
633 	KOBJMETHOD(feeder_free,		feed_rate_free),
634 	KOBJMETHOD(feeder_set,		feed_rate_set),
635 	KOBJMETHOD(feeder_get,		feed_rate_get),
636 	KOBJMETHOD(feeder_feed,		feed_rate),
637 	{0, 0}
638 };
639 
640 FEEDER_DECLARE(feeder_rate, 2, NULL);
641