Module Name:    src
Committed By:   snj
Date:           Tue Jan  9 19:35:03 UTC 2018

Modified Files:
        src/sys/dev [netbsd-8]: auconv.c auconv.h mulaw.c mulaw.h

Log Message:
Pull up following revision(s) (requested by nat in ticket #485):
        sys/dev/auconv.c: 1.32-1.35
        sys/dev/auconv.h: 1.20-1.21
        sys/dev/mulaw.c: 1.33
        sys/dev/mulaw.h: 1.25
Improve LINEAR_LINEARN macro - inparticular BE/LE conversions.
Addresses part of PR kern/52586 analyzed and reported by isaki@.
--
Allow maxused to be an odd number of bytes.  This makes single byte
conversions work for the test described in the PR.
Addresses another part of PR kern/52586.
--
Remove 24 bit in a 32 bit container filters.
At present this filter did not work well and has caused problems with
the audio mixer disabled for hdaudio(4).
These filters may return when they are fixed.
--
Replace LINEARN_TO_LINEARN macro with individual optimized functions for
8, 16, 24 and 32 bits linear to linear conversions.
Addresses PR kern/52586.
--
mulaw/alaw_to_linearN macros replaced with individual faster filters.
NFC.


To generate a diff of this commit:
cvs rdiff -u -r1.26.2.3 -r1.26.2.4 src/sys/dev/auconv.c
cvs rdiff -u -r1.16.42.2 -r1.16.42.3 src/sys/dev/auconv.h
cvs rdiff -u -r1.28.42.2 -r1.28.42.3 src/sys/dev/mulaw.c
cvs rdiff -u -r1.20.80.1 -r1.20.80.2 src/sys/dev/mulaw.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/auconv.c
diff -u src/sys/dev/auconv.c:1.26.2.3 src/sys/dev/auconv.c:1.26.2.4
--- src/sys/dev/auconv.c:1.26.2.3	Tue Aug  1 23:23:00 2017
+++ src/sys/dev/auconv.c	Tue Jan  9 19:35:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: auconv.c,v 1.26.2.3 2017/08/01 23:23:00 snj Exp $	*/
+/*	$NetBSD: auconv.c,v 1.26.2.4 2018/01/09 19:35:03 snj Exp $	*/
 
 /*
  * Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.26.2.3 2017/08/01 23:23:00 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: auconv.c,v 1.26.2.4 2018/01/09 19:35:03 snj Exp $");
 
 #include <sys/types.h>
 #include <sys/audioio.h>
@@ -113,6 +113,7 @@ struct conv_table {
 	stream_filter_factory_t *play_conv;
 	stream_filter_factory_t *rec_conv;
 };
+
 #define TABLE_LIST(prec, valid, target) 				\
 	{AUDIO_ENCODING_SLINEAR_LE, prec, valid,			\
 	 linear##target##_##target##_to_linear##prec,			\
@@ -141,7 +142,6 @@ struct conv_table {
  */
 static const struct conv_table s8_table[] = {
 	TABLE_LIST(32, 32, 8)
-	TABLE_LIST(24, 32, 8)
 	TABLE_LIST(24, 24, 8)
 	TABLE_LIST(16, 16, 8)
 	TABLE_LIST(8, 8, 8)
@@ -151,7 +151,6 @@ static const struct conv_table s8_table[
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u8_table[] = {
 	TABLE_LIST(32, 32, 8)
-	TABLE_LIST(24, 32, 8)
 	TABLE_LIST(24, 24, 8)
 	TABLE_LIST(16, 16, 8)
 	TABLE_LIST(8, 8, 8)
@@ -161,7 +160,6 @@ static const struct conv_table u8_table[
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table s16le_table[] = {
 	TABLE_LIST(32, 32, 16)
-	TABLE_LIST(24, 32, 16)
 	TABLE_LIST(24, 24, 16)
 	TABLE_LIST(16, 16, 16)
 	TABLE_LIST(8, 8, 16)
@@ -171,7 +169,6 @@ static const struct conv_table s16le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table s16be_table[] = {
 	TABLE_LIST(32, 32, 16)
-	TABLE_LIST(24, 32, 16)
 	TABLE_LIST(24, 24, 16)
 	TABLE_LIST(16, 16, 16)
 	TABLE_LIST(8, 8, 16)
@@ -181,7 +178,6 @@ static const struct conv_table s16be_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u16le_table[] = {
 	TABLE_LIST(32, 32, 16)
-	TABLE_LIST(24, 32, 16)
 	TABLE_LIST(24, 24, 16)
 	TABLE_LIST(16, 16, 16)
 	TABLE_LIST(8, 8, 16)
@@ -191,7 +187,6 @@ static const struct conv_table u16le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u16be_table[] = {
 	TABLE_LIST(32, 32, 16)
-	TABLE_LIST(24, 32, 16)
 	TABLE_LIST(24, 24, 16)
 	TABLE_LIST(16, 16, 16)
 	TABLE_LIST(8, 8, 16)
@@ -202,7 +197,6 @@ static const struct conv_table u16be_tab
 #ifdef notdef
 static const struct conv_table s24le_table[] = {
 	TABLE_LIST(32, 32, 24)
-	TABLE_LIST(24, 32, 24)
 	TABLE_LIST(24, 24, 24)
 	TABLE_LIST(16, 16, 24)
 	TABLE_LIST(8, 8, 24)
@@ -212,7 +206,6 @@ static const struct conv_table s24le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table s24be_table[] = {
 	TABLE_LIST(32, 32, 24)
-	TABLE_LIST(24, 32, 24)
 	TABLE_LIST(24, 24, 24)
 	TABLE_LIST(16, 16, 24)
 	TABLE_LIST(8, 8, 24)
@@ -222,7 +215,6 @@ static const struct conv_table s24be_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u24le_table[] = {
 	TABLE_LIST(32, 32, 24)
-	TABLE_LIST(24, 32, 24)
 	TABLE_LIST(24, 24, 24)
 	TABLE_LIST(16, 16, 24)
 	TABLE_LIST(8, 8, 24)
@@ -232,7 +224,6 @@ static const struct conv_table u24le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u24be_table[] = {
 	TABLE_LIST(32, 32, 24)
-	TABLE_LIST(24, 32, 24)
 	TABLE_LIST(24, 24, 24)
 	TABLE_LIST(16, 16, 24)
 	TABLE_LIST(8, 8, 24)
@@ -243,7 +234,6 @@ static const struct conv_table u24be_tab
 #endif
 static const struct conv_table s32le_table[] = {
 	TABLE_LIST(32, 32, 32)
-	TABLE_LIST(24, 32, 32)
 	TABLE_LIST(24, 24, 32)
 	TABLE_LIST(16, 16, 32)
 	TABLE_LIST(8, 8, 32)
@@ -253,7 +243,6 @@ static const struct conv_table s32le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table s32be_table[] = {
 	TABLE_LIST(32, 32, 32)
-	TABLE_LIST(24, 32, 32)
 	TABLE_LIST(24, 24, 32)
 	TABLE_LIST(16, 16, 32)
 	TABLE_LIST(8, 8, 32)
@@ -263,7 +252,6 @@ static const struct conv_table s32be_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u32le_table[] = {
 	TABLE_LIST(32, 32, 32)
-	TABLE_LIST(24, 32, 32)
 	TABLE_LIST(24, 24, 32)
 	TABLE_LIST(16, 16, 32)
 	TABLE_LIST(8, 8, 32)
@@ -273,7 +261,6 @@ static const struct conv_table u32le_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table u32be_table[] = {
 	TABLE_LIST(32, 32, 32)
-	TABLE_LIST(24, 32, 32)
 	TABLE_LIST(24, 24, 32)
 	TABLE_LIST(16, 16, 32)
 	TABLE_LIST(8, 8, 32)
@@ -312,7 +299,6 @@ static const struct conv_table u32be_tab
 
 static const struct conv_table mulaw_table[] = {
 	MULAW_LIST(32, 32, 32)
-	MULAW_LIST(24, 32, 24)
 	MULAW_LIST(24, 24, 24)
 	MULAW_LIST(16, 16, 16)
 	{AUDIO_ENCODING_SLINEAR_LE, 8, 8,
@@ -322,7 +308,6 @@ static const struct conv_table mulaw_tab
 	{0, 0, 0, NULL, NULL}};
 static const struct conv_table alaw_table[] = {
 	ALAW_LIST(32, 32, 32)
-	ALAW_LIST(24, 32, 24)
 	ALAW_LIST(24, 24, 24)
 	ALAW_LIST(16, 16, 16)
 	{AUDIO_ENCODING_SLINEAR_LE, 8, 8,
@@ -501,193 +486,1395 @@ DEFINE_FILTER(swap_bytes_change_sign16)
 	return 0;
 }
 
-#define LINEARN_LINEAR(n_prec, n_validbits, t_prec)			\
-	DEFINE_FILTER(linear##n_prec##_##n_validbits##_to_linear##t_prec)\
-{									\
-	stream_filter_t *this;						\
-	int m, err, enc_dst, enc_src;					\
-	int target, valid, hw, i, j;					\
-									\
-	hw = n_prec / NBBY;						\
-	valid = n_validbits / NBBY;					\
-	target = t_prec / NBBY;						\
-	this = (stream_filter_t *)self;					\
-	max_used = ((max_used / hw) * hw) & ~1;				\
-									\
-	if ((err = this->prev->fetch_to(sc, this->prev, this->src,	\
-			max_used)))					\
-		return err;						\
-	m = (((dst->end - dst->start) / target) * target) & ~1;		\
-	m = min(m, max_used * hw / target);				\
-	enc_dst = dst->param.encoding;					\
-	enc_src = this->src->param.encoding;				\
-	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE			\
-	     && enc_dst == AUDIO_ENCODING_SLINEAR_LE)			\
-	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE			\
-		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {		\
-		/*							\
-		 * slinearNle -> slinearNle				\
-		 * ulinearNle -> ulinearNle				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0)				\
-					d[--j] = s[--i];		\
-			} else {					\
-				while (i > 0)				\
-					d[--j] = s[--i];		\
-				while (j > 0)				\
-					d[--j] = 0;			\
-			}						\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE		\
-		    && enc_dst == AUDIO_ENCODING_SLINEAR_BE)		\
-		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE		\
-		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {	\
-		/*							\
-		 * slinearNle -> slinearNbe				\
-		 * ulinearNle -> ulinearNbe				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0) {				\
-					d[--j] = s[target - i];		\
-					i--;				\
-				}					\
-			} else {					\
-				while (j > i)				\
-					d[--j] = 0;			\
-				while (j > 0) {				\
-					d[--j] = s[target - i];		\
-					i--;				\
-				}					\
-			}						\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE		\
-		    && enc_dst == AUDIO_ENCODING_SLINEAR_LE)		\
-		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE		\
-		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {	\
-		/*							\
-		 * ulinearNbe -> slinearNle				\
-		 * slinearNbe -> ulinearNle				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0) {				\
-					d[--j] = s[valid - i];		\
-					i--;				\
-				}					\
-			} else {					\
-				while (j > 0) {				\
-					d[--j] = s[valid - i];		\
-					i--;				\
-				}					\
-				while (j > 0)				\
-					d[--j] = 0;			\
-			}						\
-			d[target - 1] ^= 0x80;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE		\
-		    && enc_dst == AUDIO_ENCODING_SLINEAR_LE)		\
-		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE		\
-		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {	\
-		/*							\
-		 * slinearNbe -> slinearNle				\
-		 * ulinearNbe -> ulinearNle				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0) {				\
-					d[--j] = s[valid - i];		\
-					i--;				\
-				}					\
-			} else {					\
-				while (j > 0) {				\
-					d[--j] = s[valid - i];		\
-					i--;				\
-				}					\
-				while (j > 0)				\
-					d[--j] = 0;			\
-			}						\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE		\
-		    && enc_dst == AUDIO_ENCODING_ULINEAR_BE)		\
-		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE		\
-		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {	\
-		/*							\
-		 * slinearNbe -> ulinearNbe				\
-		 * ulinearNbe -> slinearNbe				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0) {				\
-					d[target - j] = s[target - j];	\
-					j--;				\
-				}					\
-			} else {					\
-				while (i > 0) {				\
-					d[target - j] = s[target - j];	\
-					j--;				\
-					i--;				\
-				}					\
-				while (j > 0)				\
-					d[target - j] = 0;		\
-			}						\
-			d[0] ^= 0x80;					\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	} else {							\
-		/*							\
-		 * slinearNle -> ulinearNle				\
-		 * ulinearNle -> slinearNle				\
-		 */							\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, target, m) {	\
-			i = valid;					\
-			j = target;					\
-			if (j < i) {					\
-				while (j > 0)				\
-					d[--j] = s[--i];		\
-			} else {					\
-				while (i > 0)				\
-					d[--j] = s[--i];		\
-				while (j > 0)				\
-					d[--j] = 0;			\
-			}						\
-			d[target - 1] ^= 0x80;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-	}								\
-	return 0;							\
-}
-
-LINEARN_LINEAR(32, 32, 32);
-LINEARN_LINEAR(32, 32, 24);
-LINEARN_LINEAR(32, 32, 16);
-LINEARN_LINEAR(32, 32, 8);
-LINEARN_LINEAR(24, 32, 32);
-LINEARN_LINEAR(24, 32, 24);
-LINEARN_LINEAR(24, 32, 16);
-LINEARN_LINEAR(24, 32, 8);
-LINEARN_LINEAR(24, 24, 32);
-LINEARN_LINEAR(24, 24, 24);
-LINEARN_LINEAR(24, 24, 16);
-LINEARN_LINEAR(24, 24, 8);
-LINEARN_LINEAR(16, 16, 32);
-LINEARN_LINEAR(16, 16, 24);
-LINEARN_LINEAR(16, 16, 16);
-LINEARN_LINEAR(16, 16, 8);
-LINEARN_LINEAR(8, 8, 32);
-LINEARN_LINEAR(8, 8, 24);
-LINEARN_LINEAR(8, 8, 16);
-LINEARN_LINEAR(8, 8, 8);
+DEFINE_FILTER(linear8_8_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~3;
+	m = min(m, max_used / 4);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear8be -> slinear32le
+		 * ulinear8be -> ulinear32le
+		 *
+		 * slinear8le -> slinear32le
+		 * ulinear8le -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = s[0];
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+	    	   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear8le -> slinear32be
+		 * ulinear8le -> ulinear32be
+		 *
+		 * slinear8be -> slinear32be
+		 * ulinear8be -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear8be -> ulinear32be
+		 * ulinear8be -> slinear32be
+		 *
+		 * slinear8le -> ulinear32be
+		 * ulinear8le -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear8le -> ulinear32le
+		 * ulinear8le -> slinear32le
+		 *
+		 * ulinear8be -> slinear32le
+		 * slinear8be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = s[0] ^ 0x80;
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear8_8_to_linear24)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (((dst->end - dst->start) / 3) * 3) & ~1;
+	m = min(m, max_used / 3);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear8be -> slinear24le
+		 * ulinear8be -> ulinear24le
+		 *
+		 * slinear8le -> slinear24le
+		 * ulinear8le -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = s[0];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear8le -> slinear24be
+		 * ulinear8le -> ulinear24be
+		 *
+		 * slinear8be -> slinear24be
+		 * ulinear8be -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear8be -> ulinear24be
+		 * ulinear8be -> slinear24be
+		 *
+		 * slinear8le -> ulinear24be
+		 * ulinear8le -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = 0;
+			d[1] = 0;
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear8le -> ulinear24le
+		 * ulinear8le -> slinear24le
+		 *
+		 * ulinear8be -> slinear24le
+		 * slinear8be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = s[0] ^ 0x80;
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear8_8_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used / 2);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear8be -> slinear16le
+		 * ulinear8be -> ulinear16le
+		 *
+		 * slinear8le -> slinear16le
+		 * ulinear8le -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = s[0];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear8le -> slinear16be
+		 * ulinear8le -> ulinear16be
+		 *
+		 * slinear8be -> slinear16be
+		 * ulinear8be -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = 0;
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear8be -> ulinear16be
+		 * ulinear8be -> slinear16be
+		 *
+		 * slinear8le -> ulinear16be
+		 * ulinear8le -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = 0;
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear8le -> ulinear16le
+		 * ulinear8le -> slinear16le
+		 *
+		 * ulinear8be -> slinear16le
+		 * slinear8be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = s[0] ^ 0x80;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linearN_to_linear8)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+	int valid, hw;
+
+	this = (stream_filter_t *)self;
+	hw = this->src->param.precision / NBBY;
+	valid = this->src->param.validbits / NBBY;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start);
+	m = min(m, max_used * hw);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinearNle -> slinear8le
+		 * ulinearNle -> ulinear8le
+		 *
+		 * slinearNle -> slinear8be
+		 * ulinearNle -> ulinear8be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = s[valid - 1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+	     	       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+	           || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+	               && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+	           || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)) {
+		/*
+		 * slinearNbe -> slinear8le
+		 * ulinearNbe -> ulinear8le
+		 *
+		 * slinearNbe -> slinear8be
+		 * ulinearNbe -> ulinear8be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * ulinearNbe -> slinear8le
+		 * slinearNbe -> ulinear8le
+		 *
+		 * slinearNbe -> ulinear8be
+		 * ulinearNbe -> slinear8be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinearNle -> ulinear8le
+		 * ulinearNle -> slinear8le
+		 *
+		 * slinearNle -> ulinear8be
+		 * ulinearNle -> slinear8be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = s[valid - 1] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear16_16_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 2) * 2;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~3;
+	m = min(m, max_used / 2);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear16le -> slinear32le
+		 * ulinear16le -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = s[1];
+			d[2] = s[0];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear16be -> slinear32be
+		 * ulinear16be -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear16le -> slinear32be
+		 * ulinear16le -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = s[0];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear16be -> slinear32le
+		 * slinear16be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = s[0] ^ 0x80;
+			d[2] = s[1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear16be -> slinear32le
+		 * ulinear16be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = s[0];
+			d[2] = s[1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16le -> ulinear32be
+		 * ulinear16le -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = s[0];
+			d[0] = s[1] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16be -> ulinear32be
+		 * ulinear16be -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = 0;
+			d[2] = 0;
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear16le -> ulinear32le
+		 * ulinear16le -> slinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 4, m) {
+			d[3] = s[1] ^ 0x80;
+			d[2] = s[0];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear16_16_to_linear24)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 2) * 2;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = ((dst->end - dst->start) / 3) * 3;
+	m = min(m, max_used * 2 / 3);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear16le -> slinear24le
+		 * ulinear16le -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = s[1];
+			d[1] = s[0];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear16be -> slinear24be
+		 * ulinear16be -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = 0;
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear16le -> slinear24be
+		 * ulinear16le -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = 0;
+			d[1] = s[0];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear16be -> slinear24le
+		 * slinear16be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = s[0] ^ 0x80;
+			d[1] = s[1];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear16be -> slinear24le
+		 * ulinear16be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16le -> ulinear24be
+		 * ulinear16le -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = 0;
+			d[1] = s[0];
+			d[0] = s[1] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16be -> ulinear24be
+		 * ulinear16be -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = 0;
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear16le -> ulinear24le
+		 * ulinear16le -> slinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 3, m) {
+			d[2] = s[1] ^ 0x80;
+			d[1] = s[0];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear16_16_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 2) * 2;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear16be -> slinear16le
+		 * ulinear16be -> ulinear16le
+		 *
+		 * slinear16le -> slinear16be
+		 * ulinear16le -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[0];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear16be -> slinear16be
+		 * slinear16le -> slinear16le
+		 *
+		 * ulinear16be -> ulinear16be
+		 * ulinear16le -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear16be -> slinear16le
+		 * slinear16be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[0] ^ 0x80;
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16le -> ulinear16be
+		 * ulinear16le -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[0];
+			d[0] = s[1] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear16be -> ulinear16be
+		 * ulinear16be -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear16le -> ulinear16le
+		 * ulinear16le -> slinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 2, dst, 2, m) {
+			d[1] = s[1] ^ 0x80;
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear24_24_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 3) * 3;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~3;
+	m = min(m, max_used * 3 / 4);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear24le -> slinear32le
+		 * ulinear24le -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = s[2];
+			d[2] = s[1];
+			d[1] = s[0];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear24be -> slinear32be
+		 * ulinear24be -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = 0;
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear24le -> slinear32be
+		 * ulinear24le -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = 0;
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear24be -> slinear32le
+		 * slinear24be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = s[0] ^ 0x80;
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear24be -> slinear32le
+		 * ulinear24be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = s[0];
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24le -> ulinear32be
+		 * ulinear24le -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = 0;
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = s[2] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24be -> ulinear32be
+		 * ulinear24be -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = 0;
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear24le -> ulinear32le
+		 * ulinear24le -> slinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 4, m) {
+			d[3] = s[2] ^ 0x80;
+			d[2] = s[1];
+			d[1] = s[0];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear24_24_to_linear24)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 3) * 3;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) / 3 * 3;
+	m = min(m, max_used);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear24be -> slinear24le
+		 * ulinear24be -> ulinear24le
+		 *
+		 * slinear24le -> slinear24be
+		 * ulinear24le -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear24be -> slinear24be
+		 * slinear24le -> slinear24le
+		 *
+		 * ulinear24be -> ulinear24be
+		 * ulinear24le -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear24be -> slinear24le
+		 * slinear24be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[0] ^ 0x80;
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24le -> ulinear24be
+		 * ulinear24le -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = s[2] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24be -> ulinear24be
+		 * ulinear24be -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear24le -> ulinear24le
+		 * ulinear24le -> slinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 3, m) {
+			d[2] = s[2] ^ 0x80;
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear24_24_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 2) * 2;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used * 3 / 2);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear24le -> slinear16le
+		 * ulinear24le -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[2];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear24be -> slinear16be
+		 * ulinear24be -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear24le -> slinear16be
+		 * ulinear24le -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear24be -> slinear16le
+		 * slinear24be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[0] ^ 0x80;
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear24be -> slinear16le
+		 * ulinear24be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[0];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24le -> ulinear16be
+		 * ulinear24le -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[2] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear24be -> ulinear16be
+		 * ulinear24be -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear24le -> ulinear16le
+		 * ulinear24le -> slinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 3, dst, 2, m) {
+			d[1] = s[2] ^ 0x80;
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear32_32_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 4) * 4;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~3;
+	m = min(m, max_used);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+	 	&& enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+	    || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear32be -> slinear32le
+		 * ulinear32be -> ulinear32le
+		 *
+		 * slinear32le -> slinear32be
+		 * ulinear32le -> ulinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[0];
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = s[3];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear32be -> slinear32be
+		 * slinear32le -> slinear32le
+		 *
+		 * ulinear32be -> ulinear32be
+		 * ulinear32le -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[3];
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear32be -> slinear32le
+		 * slinear32be -> ulinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[0] ^ 0x80;
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = s[3];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32le -> ulinear32be
+		 * ulinear32le -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[0];
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = s[3] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32be -> ulinear32be
+		 * ulinear32be -> slinear32be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[3];
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear32le -> ulinear32le
+		 * ulinear32le -> slinear32le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 4, m) {
+			d[3] = s[3] ^ 0x80;
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear32_32_to_linear24)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 3) * 3;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = ((dst->end - dst->start) / 3) * 3;
+	m = min(m, max_used * 4 / 3);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear32le -> slinear24le
+		 * ulinear32le -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[3];
+			d[1] = s[2];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear32be -> slinear24be
+		 * ulinear32be -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear32le -> slinear24be
+		 * ulinear32le -> ulinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = s[3];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear32be -> slinear24le
+		 * slinear32be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[0] ^ 0x80;
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear32be -> slinear24le
+		 * ulinear32be -> ulinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[0];
+			d[1] = s[1];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32le -> ulinear24be
+		 * ulinear32le -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[1];
+			d[1] = s[2];
+			d[0] = s[3] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32be -> ulinear24be
+		 * ulinear32be -> slinear24be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[2];
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear32le -> ulinear24le
+		 * ulinear32le -> slinear24le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 3, m) {
+			d[2] = s[3] ^ 0x80;
+			d[1] = s[2];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
+
+DEFINE_FILTER(linear32_32_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err, enc_dst, enc_src;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used / 2) * 2;
+
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used * 2);
+	enc_dst = dst->param.encoding;
+	enc_src = this->src->param.encoding;
+	if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+	    || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		&& enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear32le -> slinear16le
+		 * ulinear32le -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[3];
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear32be -> slinear16be
+		 * ulinear32be -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)) {
+		/*
+		 * slinear32le -> slinear16be
+		 * ulinear32le -> ulinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[2];
+			d[0] = s[3];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * ulinear32be -> slinear16le
+		 * slinear32be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[0] ^ 0x80;
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_LE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_LE)) {
+		/*
+		 * slinear32be -> slinear16le
+		 * ulinear32be -> ulinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[0];
+			d[0] = s[1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_LE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32le -> ulinear16be
+		 * ulinear32le -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[2];
+			d[0] = s[3] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else if ((enc_src == AUDIO_ENCODING_SLINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_ULINEAR_BE)
+		   || (enc_src == AUDIO_ENCODING_ULINEAR_BE
+		       && enc_dst == AUDIO_ENCODING_SLINEAR_BE)) {
+		/*
+		 * slinear32be -> ulinear16be
+		 * ulinear32be -> slinear16be
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[1];
+			d[0] = s[0] ^ 0x80;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	} else {
+		/*
+		 * slinear32le -> ulinear16le
+		 * ulinear32le -> slinear16le
+		 */
+		FILTER_LOOP_PROLOGUE(this->src, 4, dst, 2, m) {
+			d[1] = s[3] ^ 0x80;
+			d[0] = s[2];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+	}
+	return 0;
+}
 
 /**
  * Set appropriate parameters in `param,' and return the index in

Index: src/sys/dev/auconv.h
diff -u src/sys/dev/auconv.h:1.16.42.2 src/sys/dev/auconv.h:1.16.42.3
--- src/sys/dev/auconv.h:1.16.42.2	Tue Aug  1 23:21:30 2017
+++ src/sys/dev/auconv.h	Tue Jan  9 19:35:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: auconv.h,v 1.16.42.2 2017/08/01 23:21:30 snj Exp $	*/
+/*	$NetBSD: auconv.h,v 1.16.42.3 2018/01/09 19:35:03 snj Exp $	*/
 
 /*-
  * Copyright (c) 1997 The NetBSD Foundation, Inc.
@@ -65,26 +65,23 @@ extern stream_filter_factory_t swap_byte
 extern stream_filter_factory_t linear32_32_to_linear32;
 extern stream_filter_factory_t linear32_32_to_linear24;
 extern stream_filter_factory_t linear32_32_to_linear16;
-extern stream_filter_factory_t linear32_32_to_linear8;
-extern stream_filter_factory_t linear24_32_to_linear32;
-extern stream_filter_factory_t linear24_32_to_linear24;
-extern stream_filter_factory_t linear24_32_to_linear16;
-extern stream_filter_factory_t linear24_32_to_linear8;
 extern stream_filter_factory_t linear24_24_to_linear32;
 extern stream_filter_factory_t linear24_24_to_linear24;
 extern stream_filter_factory_t linear24_24_to_linear16;
-extern stream_filter_factory_t linear24_24_to_linear8;
 extern stream_filter_factory_t linear16_16_to_linear32;
 extern stream_filter_factory_t linear16_16_to_linear24;
 extern stream_filter_factory_t linear16_16_to_linear16;
-extern stream_filter_factory_t linear16_16_to_linear8;
 extern stream_filter_factory_t linear8_8_to_linear32;
 extern stream_filter_factory_t linear8_8_to_linear24;
 extern stream_filter_factory_t linear8_8_to_linear16;
-extern stream_filter_factory_t linear8_8_to_linear8;
+extern stream_filter_factory_t linearN_to_linear8;
 extern stream_filter_factory_t null_filter;
 
-#define linear16_to_linear8 linear16_16_to_linear8
+#define linear32_32_to_linear8 linearN_to_linear8
+#define linear24_24_to_linear8 linearN_to_linear8
+#define linear16_16_to_linear8 linearN_to_linear8
+#define linear8_8_to_linear8 linearN_to_linear8
+#define linear16_to_linear8 linearN_to_linear8
 #define linear8_to_linear16 linear8_8_to_linear16
 
 /* sampling rate conversion (aurateconv.c) */

Index: src/sys/dev/mulaw.c
diff -u src/sys/dev/mulaw.c:1.28.42.2 src/sys/dev/mulaw.c:1.28.42.3
--- src/sys/dev/mulaw.c:1.28.42.2	Fri Jun 30 06:51:28 2017
+++ src/sys/dev/mulaw.c	Tue Jan  9 19:35:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mulaw.c,v 1.28.42.2 2017/06/30 06:51:28 snj Exp $	*/
+/*	$NetBSD: mulaw.c,v 1.28.42.3 2018/01/09 19:35:03 snj Exp $	*/
 
 /*
  * Copyright (c) 1991-1993 Regents of the University of California.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mulaw.c,v 1.28.42.2 2017/06/30 06:51:28 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mulaw.c,v 1.28.42.3 2018/01/09 19:35:03 snj Exp $");
 
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -295,118 +295,197 @@ DEFINE_FILTER(mulaw_to_linear8)
 	return 0;
 }
 
-#define MULAWTOLINEARN(n_prec) 						\
-DEFINE_FILTER(mulaw_to_linear##n_prec)					\
-{									\
-	stream_filter_t *this;						\
-	int hw, j, m, err;						\
-									\
-	hw = n_prec / NBBY;						\
-	this = (stream_filter_t *)self;					\
-	max_used = (max_used + 1) & ~1; /* round up to even */		\
-	if ((err = this->prev->fetch_to(sc, this->prev,			\
-		this->src, max_used / hw)))				\
-		return err;						\
-	m = (dst->end - dst->start) & ~1;				\
-	m = min(m, max_used);						\
-	switch (dst->param.encoding) {					\
-	case AUDIO_ENCODING_ULINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = hw - 2;					\
-			d[hw - 2] = mulawtolin16[s[0]][1];		\
-			d[hw - 1] = mulawtolin16[s[0]][0];		\
-			while (j > 0)					\
-				d[--j] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = 2;						\
-			d[0] = mulawtolin16[s[0]][0];			\
-			d[1] = mulawtolin16[s[0]][1];			\
-			while (j < hw)					\
-				d[j++] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = hw - 2;					\
-			d[hw - 2] = mulawtolin16[s[0]][1];		\
-			d[hw - 1] = mulawtolin16[s[0]][0] ^ 0x80;	\
-			while (j > 0)					\
-				d[--j] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = 2;						\
-			d[0] = mulawtolin16[s[0]][0] ^ 0x80;		\
-			d[1] = mulawtolin16[s[0]][1];			\
-			while (j < hw)					\
-				d[j++] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	default:							\
-		aprint_error(						\
-		    "%s: encoding must be [s/u]linear_[le/be]\n",	\
-		    __func__);						\
-		break;							\
-	}								\
-	return 0;							\
+DEFINE_FILTER(mulaw_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used + 1) & ~1;
+	if ((err = this->prev->fetch_to(sc, this->prev,
+		this->src, max_used / 2)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = mulawtolin16[s[0]][0];
+			d[0] = mulawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[0] = mulawtolin16[s[0]][0];
+			d[1] = mulawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[0] = mulawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[0] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[1] = mulawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
 }								
 
-MULAWTOLINEARN(32)
-MULAWTOLINEARN(24)
-MULAWTOLINEARN(16)
-
-#define LINEARNTOMULAW(n_prec, n_valid)					\
-DEFINE_FILTER(linear##n_prec##_##n_valid##_to_mulaw)			\
-{									\
-	stream_filter_t *this;						\
-	int hw, m, err;							\
-									\
-	hw = n_prec / NBBY;						\
-	this = (stream_filter_t *)self;					\
-	if ((err = this->prev->fetch_to(sc, this->prev, this->src,	\
-		 max_used * hw)))					\
-		return err;						\
-	m = dst->end - dst->start;					\
-	m = min(m, max_used);						\
-	switch (this->src->param.encoding) {				\
-	case AUDIO_ENCODING_SLINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintomulaw[s[hw - 1] ^ 0x80];		\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintomulaw[s[0] ^ 0x80];			\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintomulaw[s[hw - 1]];			\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintomulaw[s[0]];			\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	default:							\
-		aprint_error(						\
-		    "%s: encoding must be [s/u]linear_[le/be]\n",	\
-		    __func__);						\
-		break;							\
-	}								\
-	return 0;							\
-}
+DEFINE_FILTER(mulaw_to_linear24)
+{
+	stream_filter_t *this;
+	int m, err;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used + 1) & ~1;
+	if ((err = this->prev->fetch_to(sc, this->prev,
+		this->src, max_used / 3)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = mulawtolin16[s[0]][0];
+			d[1] = mulawtolin16[s[0]][1];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[0] = mulawtolin16[s[0]][0];
+			d[1] = mulawtolin16[s[0]][1];
+			d[2] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[1] = mulawtolin16[s[0]][1];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[0] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[1] = mulawtolin16[s[0]][1];
+			d[2] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
+}								
+
+DEFINE_FILTER(mulaw_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used + 1) & ~1;
+	if ((err = this->prev->fetch_to(sc, this->prev,
+		this->src, max_used / 4)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = mulawtolin16[s[0]][0];
+			d[2] = mulawtolin16[s[0]][1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[0] = mulawtolin16[s[0]][0];
+			d[1] = mulawtolin16[s[0]][1];
+			d[2] = 0;
+			d[3] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[2] = mulawtolin16[s[0]][1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[0] = mulawtolin16[s[0]][0] ^ 0x80;
+			d[1] = mulawtolin16[s[0]][1];
+			d[2] = 0;
+			d[3] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
+}								
+
+DEFINE_FILTER(linearN_to_mulaw)
+{
+	stream_filter_t *this;
+	int hw, m, err;
 
-LINEARNTOMULAW(32, 32)
-LINEARNTOMULAW(24, 32)
-LINEARNTOMULAW(24, 24)
-LINEARNTOMULAW(16, 16)
-LINEARNTOMULAW(8, 8)
+	this = (stream_filter_t *)self;
+	hw = this->src->param.precision / NBBY;
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src,
+		 max_used * hw)))
+		return err;
+	m = dst->end - dst->start;
+	m = min(m, max_used);
+	switch (this->src->param.encoding) {
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintomulaw[s[hw - 1] ^ 0x80];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintomulaw[s[0] ^ 0x80];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintomulaw[s[hw - 1]];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintomulaw[s[0]];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]n",
+		    __func__);
+		break;
+	}
+	return 0;
+}
 
 DEFINE_FILTER(alaw_to_linear8)
 {
@@ -430,136 +509,194 @@ DEFINE_FILTER(alaw_to_linear8)
 	return 0;
 }
 
-#define ALAWTOLINEARN(n_prec) 						\
-DEFINE_FILTER(alaw_to_linear##n_prec)					\
-{									\
-	stream_filter_t *this;						\
-	int hw, j, m, err;						\
-									\
-	hw = n_prec / NBBY;						\
-	this = (stream_filter_t *)self;					\
-	max_used = (max_used + 1) & ~1; /* round up to even */		\
-	if ((err = this->prev->fetch_to(sc, this->prev, this->src,	\
-		 max_used / hw)))					\
-		return err;						\
-	m = (dst->end - dst->start) & ~1;				\
-	m = min(m, max_used);						\
-	switch (dst->param.encoding) {					\
-	case AUDIO_ENCODING_ULINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = hw - 2;					\
-			d[hw - 2] = alawtolin16[s[0]][1];		\
-			d[hw - 1] = alawtolin16[s[0]][0];		\
-			while (j > 0)					\
-				d[--j] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = 2;						\
-			d[0] = alawtolin16[s[0]][0];			\
-			d[1] = alawtolin16[s[0]][1];			\
-			while (j < hw)					\
-				d[j++] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = hw - 2;					\
-			d[hw - 2] = alawtolin16[s[0]][1];		\
-			d[hw - 1] = alawtolin16[s[0]][0] ^ 0x80;	\
-			while (j > 0)					\
-				d[--j] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, hw, m) {	\
-			j = 2;						\
-			d[0] = alawtolin16[s[0]][0] ^ 0x80;		\
-			d[1] = alawtolin16[s[0]][1];			\
-			while (j < hw)					\
-				d[j++] = 0;				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	default:							\
-		aprint_error(						\
-		    "%s: encoding must be [s/u]linear_[le/be]\n",	\
-		    __func__);						\
-		break;							\
-	}								\
-	return 0;							\
-}
+DEFINE_FILTER(alaw_to_linear16)
+{
+	stream_filter_t *this;
+	int m, err;
 
-ALAWTOLINEARN(32)
-ALAWTOLINEARN(24)
-ALAWTOLINEARN(16)
+	this = (stream_filter_t *)self;
+	max_used = (max_used + 1) & ~1; /* round up to even */
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src,
+		 max_used / 2)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = alawtolin16[s[0]][0];
+			d[0] = alawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[0] = alawtolin16[s[0]][0];
+			d[1] = alawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[1] = alawtolin16[s[0]][0] ^ 0x80;
+			d[0] = alawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 2, m) {
+			d[0] = alawtolin16[s[0]][0] ^ 0x80;
+			d[1] = alawtolin16[s[0]][1];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
+}
 
-DEFINE_FILTER(linear8_to_alaw)
+DEFINE_FILTER(alaw_to_linear24)
 {
 	stream_filter_t *this;
 	int m, err;
 
 	this = (stream_filter_t *)self;
-	if ((err = this->prev->fetch_to(sc, this->prev, this->src, max_used)))
+	max_used = (max_used + 1) & ~1; /* round up to even */
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src,
+		 max_used / 3)))
 		return err;
-	m = dst->end - dst->start;
+	m = (dst->end - dst->start) & ~1;
 	m = min(m, max_used);
-	if (this->src->param.encoding == AUDIO_ENCODING_ULINEAR_LE) {
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 1, m) {
-			*d = lintoalaw[*s];
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = alawtolin16[s[0]][0];
+			d[1] = alawtolin16[s[0]][1];
+			d[0] = 0;
 		} FILTER_LOOP_EPILOGUE(this->src, dst);
-	} else {		/* SLINEAR_LE */
-		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 1, m) {
-			*d = lintoalaw[*s ^ 0x80];
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[0] = alawtolin16[s[0]][0];
+			d[1] = alawtolin16[s[0]][1];
+			d[2] = 0;
 		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[2] = alawtolin16[s[0]][0] ^ 0x80;
+			d[1] = alawtolin16[s[0]][1];
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 3, m) {
+			d[0] = alawtolin16[s[0]][0] ^ 0x80;
+			d[1] = alawtolin16[s[0]][1];
+			d[2] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
 	}
 	return 0;
 }
 
-#define LINEARNTOALAW(n_prec, n_valid)					\
-DEFINE_FILTER(linear##n_prec##_##n_valid##_to_alaw)			\
-{									\
-	stream_filter_t *this;						\
-	int hw, m, err;							\
-									\
-	hw = n_prec / NBBY;						\
-	this = (stream_filter_t *)self;					\
-	if ((err = this->prev->fetch_to(sc, this->prev, this->src,	\
-			max_used * hw)))				\
-		return err;						\
-	m = dst->end - dst->start;					\
-	m = min(m, max_used);						\
-	switch (this->src->param.encoding) {				\
-	case AUDIO_ENCODING_SLINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintoalaw[s[hw - 1] ^ 0x80];		\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_SLINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintoalaw[s[0] ^ 0x80];			\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_LE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintoalaw[s[hw - 1]];			\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	case AUDIO_ENCODING_ULINEAR_BE:					\
-		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {	\
-			d[0] = lintoalaw[s[0]];				\
-		} FILTER_LOOP_EPILOGUE(this->src, dst);			\
-		break;							\
-	default:							\
-		aprint_error(						\
-		    "%s: encoding must be [s/u]linear_[le/be]\n",	\
-		    __func__);						\
-		break;							\
-	}								\
-	return 0;							\
+DEFINE_FILTER(alaw_to_linear32)
+{
+	stream_filter_t *this;
+	int m, err;
+
+	this = (stream_filter_t *)self;
+	max_used = (max_used + 1) & ~1; /* round up to even */
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src,
+		 max_used / 4)))
+		return err;
+	m = (dst->end - dst->start) & ~1;
+	m = min(m, max_used);
+	switch (dst->param.encoding) {
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = alawtolin16[s[0]][0];
+			d[2] = alawtolin16[s[0]][1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[0] = alawtolin16[s[0]][0];
+			d[1] = alawtolin16[s[0]][1];
+			d[2] = 0;
+			d[3] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[3] = alawtolin16[s[0]][0] ^ 0x80;
+			d[2] = alawtolin16[s[0]][1];
+			d[1] = 0;
+			d[0] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, 1, dst, 4, m) {
+			d[0] = alawtolin16[s[0]][0] ^ 0x80;
+			d[1] = alawtolin16[s[0]][1];
+			d[2] = 0;
+			d[3] = 0;
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
 }
 
-LINEARNTOALAW(32, 32)
-LINEARNTOALAW(24, 32)
-LINEARNTOALAW(24, 24)
-LINEARNTOALAW(16, 16)
+DEFINE_FILTER(linearN_to_alaw)
+{
+	stream_filter_t *this;
+	int hw, m, err;
+
+	this = (stream_filter_t *)self;
+	hw = this->src->param.precision / NBBY;
+	if ((err = this->prev->fetch_to(sc, this->prev, this->src,
+			max_used * hw)))
+		return err;
+	m = dst->end - dst->start;
+	m = min(m, max_used);
+	switch (this->src->param.encoding) {
+	case AUDIO_ENCODING_SLINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintoalaw[s[hw - 1] ^ 0x80];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_SLINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintoalaw[s[0] ^ 0x80];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_LE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintoalaw[s[hw - 1]];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	case AUDIO_ENCODING_ULINEAR_BE:
+		FILTER_LOOP_PROLOGUE(this->src, hw, dst, 1, m) {
+			d[0] = lintoalaw[s[0]];
+		} FILTER_LOOP_EPILOGUE(this->src, dst);
+		break;
+	default:
+		aprint_error(
+		    "%s: encoding must be [s/u]linear_[le/be]\n",
+		    __func__);
+		break;
+	}
+	return 0;
+}

Index: src/sys/dev/mulaw.h
diff -u src/sys/dev/mulaw.h:1.20.80.1 src/sys/dev/mulaw.h:1.20.80.2
--- src/sys/dev/mulaw.h:1.20.80.1	Fri Jun 30 06:38:00 2017
+++ src/sys/dev/mulaw.h	Tue Jan  9 19:35:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mulaw.h,v 1.20.80.1 2017/06/30 06:38:00 snj Exp $	*/
+/*	$NetBSD: mulaw.h,v 1.20.80.2 2018/01/09 19:35:03 snj Exp $	*/
 
 /*-
  * Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -35,34 +35,35 @@
 
 /* Convert 8-bit mu-law to/from 32 bit unsigned/signed linear. */
 extern stream_filter_factory_t mulaw_to_linear32;
+#define linear32_32_to_mulaw linearN_to_mulaw
 extern stream_filter_factory_t linear32_32_to_mulaw;
 /* Convert 8-bit mu-law to/from 24 bit unsigned/signed linear. */
 extern stream_filter_factory_t mulaw_to_linear24;
-extern stream_filter_factory_t linear24_24_to_mulaw;
-extern stream_filter_factory_t linear24_32_to_mulaw;
+#define linear24_24_to_mulaw linearN_to_mulaw
 /* Convert 8-bit mu-law to/from 16 bit unsigned/signed linear. */
 extern stream_filter_factory_t mulaw_to_linear16;
-extern stream_filter_factory_t linear16_16_to_mulaw;
-#define linear16_to_mulaw linear16_16_to_mulaw
+#define linear16_16_to_mulaw linearN_to_mulaw
+#define linear16_to_mulaw linearN_to_mulaw
 /* Convert 8-bit mu-law to/from 8 bit unsigned/signed linear. */
 extern stream_filter_factory_t mulaw_to_linear8;
-extern stream_filter_factory_t linear8_8_to_mulaw;
-#define linear8_to_mulaw linear8_8_to_mulaw
+#define linear8_8_to_mulaw linearN_to_mulaw
+#define linear8_to_mulaw linearN_to_mulaw
+extern stream_filter_factory_t linearN_to_mulaw;
 
 /* Convert 8-bit alaw to/from 32 bit unsigned/signed linear. */
 extern stream_filter_factory_t alaw_to_linear32;
-extern stream_filter_factory_t linear32_32_to_alaw;
+#define linear32_32_to_alaw linearN_to_alaw
 /* Convert 8-bit alaw to/from 24 bit unsigned/signed linear. */
 extern stream_filter_factory_t alaw_to_linear24;
-extern stream_filter_factory_t linear24_24_to_alaw;
-extern stream_filter_factory_t linear24_32_to_alaw;
+#define linear24_24_to_alaw linearN_to_alaw
 /* Convert 8-bit alaw to/from 16 bit unsigned/signed linear. */
 extern stream_filter_factory_t alaw_to_linear16;
-extern stream_filter_factory_t linear16_16_to_alaw;
-#define linear16_to_alaw linear16_16_to_alaw
+#define linear16_to_alaw linearN_to_alaw
+#define linear16_16_to_alaw linearN_to_alaw
 /* Convert 8-bit A-law to/from 8 bit unsigned/signed linear. */
 extern stream_filter_factory_t alaw_to_linear8;
-extern stream_filter_factory_t linear8_to_alaw;
-#define linear8_8_to_alaw linear8_to_alaw
+#define linear8_8_to_alaw linearN_to_alaw
+#define linear8_to_alaw linearN_to_alaw
+extern stream_filter_factory_t linearN_to_alaw;
 
 #endif /* _SYS_DEV_MULAW_H_ */

Reply via email to