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