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 via email to