[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] : fix dmasound_awacs record down sampling



Hi,

The following patch implements record down sampling for awacs
(recording when the requested sample rate is less than the native
44100 or 22050 hardware rates).  It has been tested on a PowerBook
Pismo and applies to the Debian 2.4.21 powerpc kernel source (though
should be easy to apply to others).  I noticed down sampling was
missing when I tried to use gnomemeeting.  The gnomemeeting sound
device test code sets the device to record at 8000 Hz.

I used the attached script to test the change.  Without the patch
record/playback doesn't work properly.  With the patch it works as
expected.  I couldn't test the little endian modes (s16_le, u16_le)
since my Pismo doesn't do byte swapping, but I wrote the patch to
handle those modes.

There is still a bug remaining in either rawrec or the dmasound driver
but I believe it to be unrelated to the attached patch.  The bug is
that sometimes when I record I get what sounds like white noise.  The
looks to be the record stage because when I look at the raw audio
data with 'od' it is obviously incorrect.  Most of the time it records
properly, which makes the bug hard to track down.

In the patch I also removed unnecessary ptototypes from the top of
trans_16.c.

-David

Log message and patch follows:

-------------------
Allow awacs to record at lower sample rates than those supported by the
hardware.  Applications (gnomemeeting, at least) sometimes assume that
the driver can record at 8000 Hz, for example.

* dmasound_awacs.c :
  (read_expand_bal) : Running balance factor for read expansion.
  (PMacInit) : Use transAwacsExpandRead functions for reading from the
  device if a frame rate lower than the hardware frame rate is set.
  Initialize read balance factor.
* trans_16.c : Remove unnecessary prototypes.
  (pmac_ctx_s8_read,pmac_ctx_u8_read,pmac_ctx_s16_read,pmac_ctx_u16_read) :
  New functions.
  (transAwacsExpandRead) : New structure.

--- dmasound_awacs.c.orig	2002-08-03 02:39:44.000000000 +0200
+++ dmasound_awacs.c	2003-09-22 21:23:48.000000000 +0200
@@ -248,6 +248,7 @@ struct pmu_sleep_notifier awacs_sleep_no
 
 /* for (soft) sample rate translations */
 int expand_bal;		/* Balance factor for expanding (not volume!) */
+int read_expand_bal;		/* Balance factor for expanding (not volume!) */
 
 /*** Low level stuff *********************************************************/
 
@@ -285,6 +286,7 @@ static void PMacAbortRead(void);
 extern TRANS transAwacsNormal ;
 extern TRANS transAwacsExpand ;
 extern TRANS transAwacsNormalRead ;
+extern TRANS transAwacsExpandRead ;
 
 extern int daca_init(void);
 extern int daca_cleanup(void);
@@ -702,7 +704,11 @@ static void PMacInit(void)
 		dmasound.trans_write = &transAwacsNormal;
 	else
 		dmasound.trans_write = &transAwacsExpand;
-	dmasound.trans_read = &transAwacsNormalRead;
+	
+	if (dmasound.soft.speed < dmasound.hard.speed)
+		dmasound.trans_read = &transAwacsExpandRead;
+	else
+		dmasound.trans_read = &transAwacsNormalRead;
 
 	if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE))
 		out_le32(&awacs->byteswap, BS_VAL);
@@ -710,6 +716,7 @@ static void PMacInit(void)
 		out_le32(&awacs->byteswap, 0);
 
 	expand_bal = -dmasound.soft.speed;
+	read_expand_bal = -dmasound.soft.speed;
 }
 
 static int PMacSetFormat(int format)
--- trans_16.c.orig	2002-02-25 20:38:05.000000000 +0100
+++ trans_16.c	2003-09-30 09:43:32.000000000 +0200
@@ -17,50 +17,13 @@
 static short dmasound_alaw2dma16[] ;
 static short dmasound_ulaw2dma16[] ;
 
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
-			  u_char frame[], ssize_t *frameUsed,
-			  ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
-			    u_char frame[], ssize_t *frameUsed,
-			    ssize_t frameLeft);
-
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
-			   u_char frame[], ssize_t *frameUsed,
-			   ssize_t frameLeft);
-
 /*** Translations ************************************************************/
 
 extern int expand_bal;	/* Balance factor for expanding (not volume!) */
 static int expand_data;	/* Data for expanding */
 
+extern int read_expand_bal;	/* Balance factor for expanding (not volume!) */
+
 static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
 			   u_char frame[], ssize_t *frameUsed,
 			   ssize_t frameLeft)
@@ -572,6 +535,197 @@
 	return stereo? used * 4: used * 2;
 }
 
+static ssize_t pmac_ctx_s8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	char *up = (char *) userPtr;
+	int bal = read_expand_bal;
+	int utotal, ftotal;
+	int val;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+
+	while (frameLeft) {
+		u_char data;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			val = *fp++;
+			data = val >> 8;
+			if (put_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				val = *fp;
+				data = val >> 8;
+				if (put_user(data, up++))
+					return -EFAULT;
+			}
+			fp++;
+			bal += hSpeed;
+			userCount--;
+		} else {
+			fp+=2;
+		}
+		bal -= sSpeed;
+		frameLeft--;
+	}
+	read_expand_bal = bal;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_u8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	char *up = (char *) userPtr;
+	int bal = read_expand_bal;
+	int utotal, ftotal;
+	int val;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	ftotal = frameLeft;
+	utotal = userCount;
+
+	while (frameLeft) {
+		u_char data;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			val = *fp++;
+			data = (val >> 8) ^ 0x80;
+			if (put_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				val = *fp;
+				data = (val >> 8) ^ 0x80;
+				if (put_user(data, up++))
+					return -EFAULT;
+			}
+			fp++;
+			bal += hSpeed;
+			userCount--;
+		} else {
+			fp+=2;
+		}
+		bal -= sSpeed;
+		frameLeft--;
+	}
+	read_expand_bal = bal;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	short *up = (short *) userPtr;
+	int bal = read_expand_bal;
+	int utotal, ftotal;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	ftotal = frameLeft;
+	utotal = userCount;
+
+	while (frameLeft) {
+		short data;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			data = *fp++;
+			if (put_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				data = *fp;
+				if (put_user(data, up++))
+					return -EFAULT;
+			}
+			fp++;
+			bal += hSpeed;
+			userCount--;
+		} else {
+			fp+=2;
+		}
+		bal -= sSpeed;
+		frameLeft--;
+	}
+	read_expand_bal = bal;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
+}
+
+
+static ssize_t pmac_ctx_u16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	int stereo = dmasound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+	short *up = (short *) userPtr;
+	int bal = read_expand_bal;
+	int utotal, ftotal;
+	int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	ftotal = frameLeft;
+	utotal = userCount;
+
+	while (frameLeft) {
+		short data;
+		if (bal < 0) {
+			if (userCount == 0)
+				break;
+			data = *fp++;
+			data ^= mask;
+			if (put_user(data, up++))
+				return -EFAULT;
+			if (stereo) {
+				data = *fp;
+				data ^= mask;
+				if (put_user(data, up++))
+					return -EFAULT;
+			}
+			fp++;
+			bal += hSpeed;
+			userCount--;
+		} else {
+			fp+=2;
+		}
+		bal -= sSpeed;
+		frameLeft--;
+	}
+	read_expand_bal = bal;
+	*frameUsed += (ftotal - frameLeft) * 4;
+	utotal -= userCount;
+	return stereo? utotal * 4: utotal * 2;
+}
+
 TRANS transAwacsNormal = {
 	ct_ulaw:	pmac_ct_law,
 	ct_alaw:	pmac_ct_law,
@@ -603,6 +757,15 @@
 	ct_u16le:	pmac_ct_u16_read,
 };
 
+TRANS transAwacsExpandRead = {
+	ct_s8:		pmac_ctx_s8_read,
+	ct_u8:		pmac_ctx_u8_read,
+	ct_s16be:	pmac_ctx_s16_read,
+	ct_u16be:	pmac_ctx_u16_read,
+	ct_s16le:	pmac_ctx_s16_read,
+	ct_u16le:	pmac_ctx_u16_read,
+};
+
 /* translation tables */
 /* 16 bit mu-law */
 

#!/bin/sh

TIME=4
SPEED=8000
FORMATS="s16_be u16_be s8 u8"
RAWREC=rawrec
RAWPLAY=rawplay

set -x

for FORMAT in $FORMATS; do
  for CHANNELS in 1 2 ; do
    echo Recording $FORMAT at $SPEED Hz $CHANNELS channels
    $RAWREC -v -c $CHANNELS -s $SPEED -f $FORMAT \
      $FORMAT-$SPEED-$CHANNELS.wav -t $TIME
    echo continue?
    read unused
    echo Playing $FORMAT at $SPEED HZ $CHANNEL channels
    $RAWPLAY -v -c $CHANNELS -s $SPEED -f $FORMAT \
      $FORMAT-$SPEED-$CHANNELS.wav
    echo continue?
    read unused
  done
done

Reply to: