[Pkg-voip-commits] r3665 - in zaptel/trunk: . debian debian/patches oslec oslec/spandsp

tzafrir-guest at alioth.debian.org tzafrir-guest at alioth.debian.org
Sat Jun 16 19:52:21 UTC 2007


Author: tzafrir-guest
Date: 2007-06-16 19:52:21 +0000 (Sat, 16 Jun 2007)
New Revision: 3665

Added:
   zaptel/trunk/debian/patches/oslec_zaptap.dpatch
   zaptel/trunk/debian/patches/oslec_zaptel.dpatch
   zaptel/trunk/oslec/
   zaptel/trunk/oslec/Kbuild
   zaptel/trunk/oslec/echo.c
   zaptel/trunk/oslec/oslec-ctrl-panel.sh
   zaptel/trunk/oslec/oslec.h
   zaptel/trunk/oslec/oslec_wrap.c
   zaptel/trunk/oslec/spandsp/
   zaptel/trunk/oslec/spandsp/bit_operations.h
   zaptel/trunk/oslec/spandsp/echo.h
   zaptel/trunk/oslec/spandsp/fir.h
Removed:
   zaptel/trunk/debian/zaptel-modules.modules
   zaptel/trunk/debian/zaptel.modprobe.d
   zaptel/trunk/debian/zaptel.modules
Modified:
   zaptel/trunk/debian/README.Debian
   zaptel/trunk/debian/changelog
   zaptel/trunk/debian/copyright
   zaptel/trunk/debian/patches/00list
   zaptel/trunk/debian/rules
Log:
oslec added:
* The oslec/ directory with most of the files (including spandsp files).
* oslec_zaptel.dpatch: Minimal changes to zaptel to add oslec, beyond
  the oslec directory.
* oslec_zaptap.dpatch: The oslec zaptap echo sampling device (probably 
  still does not apply).
* Copying oslec/ to the zaptel source tarball.
* oslec-strl-panel.sh is so far just added to the exampes directory.
* Default echo canceller is still MG2 (oslec is experimental). 
  Instructions for building with oslec added to README.Debian.

Other changes:
* Removing unrequired/harmful and useless modprobe / modutils config.
* README.Debian updates.


Modified: zaptel/trunk/debian/README.Debian
===================================================================
--- zaptel/trunk/debian/README.Debian	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/README.Debian	2007-06-16 19:52:21 UTC (rev 3665)
@@ -16,6 +16,7 @@
 You can also use the environment variable TARBALL to build the modules 
 with a custom zaptel.tar.bz2 tarball with some local modifications.
 
+
 Using udev
 ----------
 
@@ -24,31 +25,72 @@
 
 If you cannot access the zap/ctl device, check which user asterisk is 
 running as and add these permissions to your permissions file
-(ie /etc/udev/permissions.d/50-udev.permissions):
+(i.e. /etc/udev/permissions.d/50-udev.permissions):
 # zaptel devices -- asterisk is expected to be part of 'dialout' group
 zap/*:root:dialout:660
 
-Note, however, that sarting from Sarge, the defualt udev settings should 
+Note, however, that beginning with Sarge, the default udev settings should 
 include those lines.
 
+FXOTune
+-------
+FXOTune is a utility provided by Digium for fine-tuning parameters of the 
+FXO modules of their TDM cards and compatibles, as well as of those of the 
+Xorcom Astribank.
 
-Bristuff
---------
-This version has the bristuff (0.3.0-PRE1d) of the bristuff patch and 
-kernel modules. The bristuffed modules require a bristuffed Asterisk
-to work.
-(TODO: what about standard Digium cards? can they work with a non-bristuffed 
-chn_zap?)
+This package includes the fxotune utility. It will also load configuration 
+from /etc/fxotune.conf if fxotune was used to tune the FXO modules. Note 
+that fxotune will not work with X100P and similar cards.
 
-fxotune
--------
-fxotune is a utulity provided by Digium for fine-tuning parameters of the 
-FXO modules of their TDM cards.
 
-This package includes the fxotune binary. It will also load configuration
-from /etc/fxotune.conf if fxotune was used to tune the FXO modules. Note
-that fxotune onlt works with the newer wctdm driver of zaptel 1.2 and will
-not work ith X100P and clones.
+/etc/zaptel.conf
+----------------
+A sample /etc/zaptel.conf is no longer installed by default. You should 
+generate it manually (or automatically with genzaptelconf) if and when
+you actually have zaptel hardware and installed a zaptel-modules package
+for your kernel version.
 
--- Debian VoIP Team <pkg-voip-maintainers at lists.alioth.debian.org>
--- 30 December 2005
+
+Supported tone-zones
+--------------------
+Zaptel is capable of playing ring tone, buy tone etc. for a large variety of
+countries. This is done using the loadzone and defaultzone settings in 
+zaptel.conf.  A list of tone-zones supported by zaptel and libtonezone is 
+included in the file tonezones.txt in the documentation directory. 
+
+Example section of zaptel.conf:
+loadzone=us,uk,de
+defaultzone=us
+
+
+OSLEC
+-----
+Open Source Line Echo Canceller (OSLEC) is an alternative echo canceller 
+developed outside the main Zaptel tree. It is currently labelled "Beta".
+For more information see http://www.rowetel.com/ucasterisk/oslec.html .
+
+It will not build by default, as it introduces an extra kernel module that 
+doesn't wit well so far with the current modules loading / unloading 
+procedures. To build and install a zaptel-modules package with oslec as the 
+echo canceller, install the package zaptel-source and use the following 
+command:
+
+  ECHO_CAN_NAME=OSLEC m-a a-i zaptel
+
+The oslec code is the package required some minor changes to the code in
+from the oslec repository. Specifically, I have not included the full copy 
+of spandsp here. Instead I picked only the relevant parts. I also placed 
+all the files in the directory oslec/ except the changes required to the
+zaptel sources and makefiles. I have also separated the implementation
+of the zaptap device to a separate patch, as it has a better chances of
+failing to apply with upcoming version of Zaptel and its functionality
+seems to me less important and not as clean.
+
+The oslec echo canceller can be controlled at runtime through files
+under /proc/oslec . A dialg-based interface is available under
+/usr/share/zaptel/examples/oslec-ctrl-panel.sh .
+
+Please help testing oslec.
+
+
+-- Debian VoIP Team <pkg-voip-maintainers at lists.alioth.debian.org>  16 June 2007

Modified: zaptel/trunk/debian/changelog
===================================================================
--- zaptel/trunk/debian/changelog	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/changelog	2007-06-16 19:52:21 UTC (rev 3665)
@@ -1,8 +1,14 @@
 zaptel (1:1.4.3~dfsg-3) UNRELEASED; urgency=low
 
-  * INTEGRATING OSLEC. DON'T RELEASE YET.
   * echocan_env.dpatch: set the echo canceller from the environment. 
+  * oslec/ The bulk of the oslec files.
+  * oslec_zaptel.dpatch: Minimal changes to zaptel to add oslec, beyond
+    the oslec directory.
+  * oslec_zaptap.dpatch: The oslec zaptap echo sampling device (probably 
+    still does not apply).
   * man_fixes.dpatch: Documentation fixes from upstream.
+  * Removing unrequired/harmful and useless modprobe / modutils config.
+  * README.Debian updates.
 
  -- Tzafrir Cohen <tzafrir.cohen at xorcom.com>  Sat, 16 Jun 2007 19:03:02 +0300
 

Modified: zaptel/trunk/debian/copyright
===================================================================
--- zaptel/trunk/debian/copyright	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/copyright	2007-06-16 19:52:21 UTC (rev 3665)
@@ -63,3 +63,17 @@
 http://www.openvox.com.cn/members_downloads.php
 (requires no login. Does require javascript)
 
+
+Files in oslec/ subdirectory and oslec patches:
+Part of the Open Source Line Echo Canceller (OSLEC) project:
+http://www.rowetel.com/ucasterisk/oslec.html
+Current version downloaded from the subversion repository at:
+http://svn.rowetel.com/software/oslec/trunk
+
+oslec/echo.c: * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
+oslec/oslec-ctrl-panel.sh:#  Copyright (C) 2007 David Rowe
+oslec/oslec.h:  Copyright (C) 2007 David Rowe
+oslec/oslec_wrap.c:  Copyright (C) 2007 David Rowe
+oslec/spandsp/fir.h: * Copyright (C) 2002 Steve Underwood
+oslec/spandsp/bit_operations.h: * Copyright (C) 2006 Steve Underwood
+oslec/spandsp/echo.h: * Copyright (C) 2001 Steve Underwood and 2007 David Rowe

Modified: zaptel/trunk/debian/patches/00list
===================================================================
--- zaptel/trunk/debian/patches/00list	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/patches/00list	2007-06-16 19:52:21 UTC (rev 3665)
@@ -1,4 +1,5 @@
 ztdiag
 zaptel_perl
 echocan_env
+oslec_zaptel
 man_fixes

Added: zaptel/trunk/debian/patches/oslec_zaptap.dpatch
===================================================================
--- zaptel/trunk/debian/patches/oslec_zaptap.dpatch	                        (rev 0)
+++ zaptel/trunk/debian/patches/oslec_zaptap.dpatch	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,267 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## oslec_zaptap.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: The zaptap device for sampling echo. Part of the oslec echo canceller.
+
+ at DPATCH@
+diff -urNad zaptel-1.2.17.1.xpp.r3965~/zaptel-base.c zaptel-1.2.17.1.xpp.r3965/zaptel-base.c
+--- zaptel-1.2.17.1.xpp.r3965~/zaptel-base.c	2007-06-16 07:10:17.000000000 +0300
++++ zaptel-1.2.17.1.xpp.r3965/zaptel-base.c	2007-06-16 07:55:33.000000000 +0300
+@@ -5708,6 +5708,74 @@
+ 	spin_unlock_irqrestore(&chan->lock, flags);
+ }
+ 
++#ifdef USE_ZAPTAP
++/* Zaptap code -----------------------------------------------------------*/
++
++#define SAMPLE_BUF_SZ  1000 
++#define SAMPLE_IDLE    0
++#define SAMPLE_PING    1
++#define SAMPLE_PONG    2
++
++DECLARE_WAIT_QUEUE_HEAD(sample_wait);
++static int sample_state = 0;
++static int samples = 0;
++static short *psample;
++static short ping[3*SAMPLE_BUF_SZ];
++static short pong[3*SAMPLE_BUF_SZ];
++static int sample_ch = 1;
++static int sample_impulse = 0;
++static int tmp1,tmp2;
++
++static inline void sample_echo_before(int channo, short rxlin, short txlin) {
++	/* Sample echo canceller signals
++	 * Notes:
++	 *   1. Samples are multiplexed in buffer:
++	 *        tx sample
++	 *        rx sample
++	 *        ec sample
++	 *   2. We needs to sample rx here before echo can as it is
++	 *      overwritten.
++	 */
++	tmp1++;
++	tmp2 = channo;
++	if ((sample_state != SAMPLE_IDLE) && (channo == sample_ch)) {
++		*psample++ = txlin;
++		*psample++ = rxlin;
++	}
++}
++
++static inline void sample_echo_after(int channo, short rxlin) {
++
++	if ((sample_state != SAMPLE_IDLE) && (channo == sample_ch)) {
++
++		*psample++ = rxlin;
++
++		/* sample collection ping-pong buffer logic */
++
++		samples++;
++		if (samples >= SAMPLE_BUF_SZ) {
++			/* time to swap buffers */
++			samples = 0;
++
++			if (sample_state == SAMPLE_PING) {
++				sample_state = SAMPLE_PONG;
++				psample = pong;
++			}
++			else {
++				sample_state = SAMPLE_PING;
++				psample = ping;
++			}
++			wake_up_interruptible(&sample_wait);
++		}
++	}
++}
++
++/* end Zaptap code -----------------------------------------------------*/
++#else /* USE_ZAPTAP */
++#define sample_echo_before(a,b,c)
++#define sample_echo_after(a,b)
++#endif /* USE_ZAPTAP */
++
+ static inline void __zt_ec_chunk(struct zt_chan *ss, unsigned char *rxchunk, const unsigned char *txchunk)
+ {
+ 	short rxlin, txlin;
+@@ -5758,7 +5826,9 @@
+ #if !defined(ZT_EC_ARRAY_UPDATE)
+ 			for (x=0;x<ZT_CHUNKSIZE;x++) {
+ 				rxlin = ZT_XLAW(rxchunk[x], ss);
++				sample_echo_before(ss->channo, rxlin, ZT_XLAW(txchunk[x], ss)); /* Zaptap code */
+ 				rxlin = echo_can_update(ss->ec, ZT_XLAW(txchunk[x], ss), rxlin);
++				sample_echo_after(ss->channo, rxlin);                           /* Zaptap code */
+ 				rxchunk[x] = ZT_LIN2X((int)rxlin, ss);
+ 			}
+ #else /* defined(ZT_EC_ARRAY_UPDATE) */
+@@ -6505,6 +6575,10 @@
+ static void __zt_transmit_chunk(struct zt_chan *chan, unsigned char *buf)
+ {
+ 	unsigned char silly[ZT_CHUNKSIZE];
++#ifdef USE_ZAPTAP
++	int x;
++#endif
++
+ 	/* Called with chan->lock locked */
+ 	if (!buf)
+ 		buf = silly;
+@@ -6519,6 +6593,22 @@
+ 		kernel_fpu_end();
+ #endif
+ 	}
++
++#ifdef USE_ZAPTAP
++	/* Start Zaptap code -----------------------------------------*/
++	if (sample_impulse && (samples == 0)) {
++
++		/* option impulse insertion, tx stream becomes one */
++                /* impulse followed by SAMPLE_BUF_SZ-1 0's         */
++
++		buf[0] = ZT_LIN2MU(10000);
++		for (x=1;x<ZT_CHUNKSIZE;x++) {
++		    buf[x] = ZT_LIN2MU(0);
++		}
++	}
++
++	/* End Zaptap code -----------------------------------------*/
++#endif USE_ZAPTAP
+ }
+ 
+ static inline void __zt_real_transmit(struct zt_chan *chan)
+@@ -6931,6 +7021,108 @@
+ 
+ #endif
+ 
++#ifdef USE_ZAPTAP
++/* Zaptap code -----------------------------------------------------*/
++
++static int sample_open (struct inode *inode, struct file *file) {
++	printk("sample_open:\n");
++	tmp1 = tmp2 = -1;
++
++	psample = ping;
++	samples = 0;
++	sample_state = SAMPLE_PING;
++
++	return 0;
++}
++
++static int sample_release (struct inode *inode, struct file *file) {
++	printk("sample_release: tmp1 = %d tmp2 = %d\n", tmp1, tmp2);
++
++	sample_state = SAMPLE_IDLE;
++	sample_impulse = 0;
++	samples = 0;
++
++	return 0;
++}
++
++static ssize_t sample_read(struct file *file, char *buf,
++		size_t count, loff_t *ppos) {
++	int    err, len;
++	short *pread;
++
++	/* wait for next buffer to be prepared by ISR, we read
++           alternate buffer just after transition.
++         */
++	interruptible_sleep_on(&sample_wait);
++
++	if (sample_state == SAMPLE_PING) {
++	  pread = pong;
++	}
++	else {
++	  pread = ping;
++	}
++
++	len = 3*sizeof(short)*SAMPLE_BUF_SZ;
++	err = copy_to_user(buf, pread, len);
++
++	if (err != 0)
++		return -EFAULT;
++
++	return len;
++}
++
++/* ioctls for sample */
++
++#define SAMPLE_SET_CHANNEL 0
++#define SAMPLE_TX_IMPULSE  1
++
++static int sample_ioctl(struct inode *inode, struct file *file,
++		unsigned int cmd, unsigned long arg) {
++	int retval = 0;
++
++	switch ( cmd ) {
++		case SAMPLE_SET_CHANNEL:
++		  if (copy_from_user(&sample_ch, (int *)arg, sizeof(int)))
++		    return -EFAULT;
++	          printk("sample_ioctl: sample_ch = %d\n", sample_ch);
++		  break;
++		case SAMPLE_TX_IMPULSE:
++		  sample_impulse = 1;
++		  printk("sample_ioctl: under impulse power\n");
++		  break;
++		default:
++		  retval = -EINVAL;
++        }
++
++	return retval;
++}
++
++// define which file operations are supported
++struct file_operations sample_fops = {
++	.owner	=	THIS_MODULE,
++	.llseek	=	NULL,
++	.read	=	sample_read,
++	.write	=	NULL,
++	.readdir=	NULL,
++	.poll	=	NULL,
++	.ioctl	=	sample_ioctl,
++	.mmap	=	NULL,
++	.open	=	sample_open,
++	.flush	=	NULL,
++	.release=	sample_release,
++	.fsync	=	NULL,
++	.fasync	=	NULL,
++	.lock	=	NULL,
++	.readv	=	NULL,
++	.writev	=	NULL,
++};
++
++#define SAMPLE_NAME  "sample"
++#define SAMPLE_MAJOR 33
++
++/* end Zaptap code -----------------------------------------------------*/
++#endif USE_ZAPTAP
++
+ static int __init zt_init(void) {
+ 	int res = 0;
+ 
+@@ -6977,12 +7169,28 @@
+ #ifdef CONFIG_ZAPTEL_WATCHDOG
+ 	watchdog_init();
+ #endif	
++
++#ifdef USE_ZAPTAP
++	/* start Zaptap code ----------------------------------------*/
++	sample_state = SAMPLE_IDLE;
++	sample_impulse = 0;
++	if ((res = register_chrdev (SAMPLE_MAJOR, SAMPLE_NAME, &sample_fops))) {
++	  printk(KERN_ERR "Zaptap unable to register 'sample' char driver on %d\n", SAMPLE_MAJOR);
++	  return res;
++	}
++	printk("Zaptap registered 'sample' char driver on major %d\n", SAMPLE_MAJOR);
++	/* end Zaptap code ------------------------------------------*/
++#endif /* USE_ZAPTAP */
++
+ 	return res;
+ }
+ 
+ static void __exit zt_cleanup(void) {
+ 	int x;
+ 
++#ifdef USE_ZAPTAP
++	unregister_chrdev (SAMPLE_MAJOR, SAMPLE_NAME); /* Zaptap code */
++#endif
+ #ifdef CONFIG_PROC_FS
+ 	remove_proc_entry("zaptel", NULL);
+ #endif


Property changes on: zaptel/trunk/debian/patches/oslec_zaptap.dpatch
___________________________________________________________________
Name: svn:executable
   + *

Added: zaptel/trunk/debian/patches/oslec_zaptel.dpatch
===================================================================
--- zaptel/trunk/debian/patches/oslec_zaptel.dpatch	                        (rev 0)
+++ zaptel/trunk/debian/patches/oslec_zaptel.dpatch	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,37 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## oslec_zaptel.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: A minimal patch to zaptel-base.c to integrate the oslec echo 
+## DP: canceller. The zaptap device is not included.
+
+ at DPATCH@
+diff -urNad zaptel-1.4.3~dfsg~/Makefile.kernel26 zaptel-1.4.3~dfsg/Makefile.kernel26
+--- zaptel-1.4.3~dfsg~/Makefile.kernel26	2007-06-16 21:33:45.000000000 +0300
++++ zaptel-1.4.3~dfsg/Makefile.kernel26	2007-06-16 21:36:02.000000000 +0300
+@@ -6,6 +6,8 @@
+ EXTRA_CFLAGS := -I$(src)
+ EXTRA_CFLAGS += $(ECHO_CAN_CFLAGS)
+ 
++obj-m		+= oslec/
++
+ zaptel-objs := zaptel-base.o
+ 
+ ifeq ($(HPEC_PRESENT),yes)
+diff -urNad zaptel-1.4.3~dfsg~/zaptel-base.c zaptel-1.4.3~dfsg/zaptel-base.c
+--- zaptel-1.4.3~dfsg~/zaptel-base.c	2007-06-16 21:33:45.000000000 +0300
++++ zaptel-1.4.3~dfsg/zaptel-base.c	2007-06-16 21:33:47.000000000 +0300
+@@ -424,6 +424,13 @@
+ #include "kb1ec.h"
+ #elif defined(ECHO_CAN_MG2)
+ #include "mg2ec.h"
++#elif defined(ECHO_CAN_OSLEC)
++#include "oslec/oslec.h"
++#define echo_can_create oslec_echo_can_create
++#define echo_can_free oslec_echo_can_free
++#define echo_can_update oslec_echo_can_update
++#define echo_can_traintap oslec_echo_can_traintap
++#define echo_can_identify oslec_echo_can_identify
+ #elif defined(ECHO_CAN_JP1)
+ #include "jpah.h"
+ #else


Property changes on: zaptel/trunk/debian/patches/oslec_zaptel.dpatch
___________________________________________________________________
Name: svn:executable
   + *

Modified: zaptel/trunk/debian/rules
===================================================================
--- zaptel/trunk/debian/rules	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/rules	2007-06-16 19:52:21 UTC (rev 3665)
@@ -143,7 +143,7 @@
 	# driver source code
 	mkdir -p $(TARDIR)/debian/generated
 	cp Makefile Makefile.kernel26 configure install-sh makeopts.in .version *.c *.h *.rbt $(TARDIR)/
-	for dir in build_tools firmware include vzaphfc oct612x wct4xxp wctc4xxp xpp; do \
+	for dir in build_tools firmware include vzaphfc oslec oct612x wct4xxp wctc4xxp xpp; do \
 	  if [ -d $$dir ]; then cp -r $$dir $(TARDIR); fi; \
 	done
 	cp -a $(GENERATED_SOURCES) $(TARDIR)/debian/generated/
@@ -151,7 +151,7 @@
 	dh_install -pzaptel-firmware xpp/firmwares/*.hex usr/share/zaptel/
 	
 	# Packaging infrastructure
-	cp -r debian/*-modules.* debian/rules debian/changelog debian/copyright\
+	cp -r debian/rules debian/changelog debian/copyright\
 	  debian/control debian/compat \
 	  debian/control.modules.in \
 	  $(TARDIR)/debian/
@@ -205,7 +205,7 @@
 	dh_installinit --update-rcd-params="defaults 15 30"
 	dh_installexamples -a zaptel.conf.sample 
 	
-	dh_installmodules -a
+	#dh_installmodules -a
 	dh_installchangelogs -a ChangeLog
 	dh_link -a
 	dh_strip -a

Deleted: zaptel/trunk/debian/zaptel-modules.modules
===================================================================
--- zaptel/trunk/debian/zaptel-modules.modules	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/zaptel-modules.modules	2007-06-16 19:52:21 UTC (rev 3665)
@@ -1,11 +0,0 @@
-options torisa base=0xd0000
-alias char-major-196 torisa
-post-install wcfxs /sbin/ztcfg
-post-install wcfxsusb /sbin/ztcfg
-post-install torisa /sbin/ztcfg
-post-install tor2 /sbin/ztcfg
-post-install wcfxo /sbin/ztcfg
-post-install wct1xxp /sbin/ztcfg
-post-install qozap /sbin/ztcfg
-post-install zaphfc /sbin/ztcfg
-post-install zaphfc-florz /sbin/ztcfg

Deleted: zaptel/trunk/debian/zaptel.modprobe.d
===================================================================
--- zaptel/trunk/debian/zaptel.modprobe.d	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/zaptel.modprobe.d	2007-06-16 19:52:21 UTC (rev 3665)
@@ -1,14 +0,0 @@
-options torisa base=0xd0000
-alias char-major-196 torisa
-install tor2 /sbin/modprobe --ignore-install tor2 && /sbin/ztcfg
-install torisa /sbin/modprobe --ignore-install torisa && /sbin/ztcfg
-install wcusb /sbin/modprobe --ignore-install wcusb && /sbin/ztcfg
-install wcfxo /sbin/modprobe --ignore-install wcfxo && /sbin/ztcfg
-install wcfxs /sbin/modprobe --ignore-install wcfxs && /sbin/ztcfg
-install ztdynamic /sbin/modprobe --ignore-install ztdynamic && /sbin/ztcfg
-install ztd-eth /sbin/modprobe --ignore-install ztd-eth && /sbin/ztcfg
-install wct1xxp /sbin/modprobe --ignore-install wct1xxp && /sbin/ztcfg
-install wct4xxp /sbin/modprobe --ignore-install wct4xxp && /sbin/ztcfg
-install wcte11xp /sbin/modprobe --ignore-install wcte11xp && /sbin/ztcfg
-install zaphfc /sbin/modprobe --ignore-install zaphfc && /sbin/ztcfg
-install qozap /sbin/modprobe --ignore-install qozap && /sbin/ztcfg

Deleted: zaptel/trunk/debian/zaptel.modules
===================================================================
--- zaptel/trunk/debian/zaptel.modules	2007-06-16 17:22:15 UTC (rev 3664)
+++ zaptel/trunk/debian/zaptel.modules	2007-06-16 19:52:21 UTC (rev 3665)
@@ -1,20 +0,0 @@
-# Uncomment the appropriate alias line, and change 'torisa' to the
-# driver for your card
-
-# DevFS
-#alias /dev/zap torisa
-
-# Non-DevFS
-#alias char-major-196 torisa
-
-options torisa base=0xd0000
-
-post-install wcfxs	ztcfg
-post-install wcfxsusb	ztcfg
-post-install torisa	ztcfg
-post-install tor2	ztcfg
-post-install wcfxo	ztcfg
-post-install wct1xxp	ztcfg
-post-install zaphfc	ztcfg
-post-install zaphfc-florz	ztcfg
-post-install qozap	ztcfg

Added: zaptel/trunk/oslec/Kbuild
===================================================================
--- zaptel/trunk/oslec/Kbuild	                        (rev 0)
+++ zaptel/trunk/oslec/Kbuild	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,4 @@
+obj-m		= oslec.o
+oslec-objs	= oslec_wrap.o echo.o
+
+

Added: zaptel/trunk/oslec/echo.c
===================================================================
--- zaptel/trunk/oslec/echo.c	                        (rev 0)
+++ zaptel/trunk/oslec/echo.c	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,630 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - A line echo canceller.  This code is being developed
+ *          against and partially complies with G168.
+ *
+ * Written by Steve Underwood <steveu at coppice.org> 
+ *         and David Rowe <david_at_rowetel_dot_com>
+ *
+ * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
+ *
+ * Based on a bit from here, a bit from there, eye of toad, ear of
+ * bat, 15 years of failed attempts by David and a few fried brain
+ * cells.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: echo.c,v 1.20 2006/12/01 18:00:48 steveu Exp $
+ */
+
+/*! \file */
+
+/* Implementation Notes
+   David Rowe
+   April 2007
+   
+   This code started life as Steve's NLMS algorithm with a tap
+   rotation algorithm to handle divergence during double talk.  I
+   added a Geigel Double Talk Detector (DTD) [2] and performed some
+   G168 tests.  However I had trouble meeting the G168 requirements,
+   especially for double talk - there were always cases where my DTD
+   failed, for example where near end speech was under the 6dB
+   threshold required for declaring double talk.
+
+   So I tried a two path algorithm [1], which has so far given better
+   results.  The original tap rotation/Geigel algorithm is available
+   in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit.
+   It's probably possible to make it work if some one wants to put some
+   serious work into it.
+   
+   At present no special treatment is provided for tones, which
+   generally cause NLMS algorithms to diverge.  Initial runs of a
+   subset of the G168 tests for tones (e.g ./echo_test 6) show the
+   current algorithm is passing OK, which is kind of surprising.  The
+   full set of tests needs to be performed to confirm this result.
+
+   One other interesting change is that I have managed to get the NLMS
+   code to work with 16 bit coefficients, rather than the original 32
+   bit coefficents.  This reduces the MIPs and storage required.
+   I evaulated the 16 bit port using g168_tests.sh and listening tests
+   on 4 real-world samples.
+
+   I also attempted the implementation of a block based NLMS update
+   [2] but although this passes g168_tests.sh it didn't converge well
+   on the real-world samples.  I have no idea why, perhaps a scaling
+   problem.  The block based code is also available in SVN
+   http://svn.rowetel.com/software/oslec/tags/before_16bit.  If this
+   code can be debugged, it will lead to further reduction in MIPS, as
+   the block update code maps nicely onto DSP instruction sets (it's a
+   dot product) compared to the current sample-by-sample update.
+
+   Steve also has some nice notes on echo cancellers in echo.h
+
+
+   References:
+
+   [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
+       Path Models", IEEE Transactions on communications, COM-25,
+       No. 6, June
+       1977. 
+       http://www.rowetel.com/images/echo/dual_path_paper.pdf
+
+   [2] The classic, very useful paper that tells you how to
+       actually build a real world echo canceller:
+         Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
+         Echo Canceller with a TMS320020, 
+         http://www.rowetel.com/images/echo/spra129.pdf
+
+   [3] I have written a series of blog posts on this work, here is
+       Part 1: http://www.rowetel.com/blog/?p=18
+
+   [4] The source code http://svn.rowetel.com/software/oslec/
+
+   [5] A nice reference on LMS filters:
+         http://en.wikipedia.org/wiki/Least_mean_squares_filter
+
+   Credits:
+
+   Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
+   Muthukrishnan for their suggestions and email discussions.  Thanks
+   also to those people who collected echo samples for me such as
+   Mark, Pawel, and Pavel.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef __KERNEL__
+#include <linux/kernel.h>       /* We're doing kernel work */
+#include <linux/module.h>     
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define malloc(a) kmalloc((a), GFP_KERNEL)
+#define free(a) kfree(a)
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#endif
+
+#include "spandsp/bit_operations.h"
+#include "spandsp/echo.h"
+
+#if !defined(NULL)
+#define NULL (void *) 0
+#endif
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+#define MIN_TX_POWER_FOR_ADAPTION   64
+#define MIN_RX_POWER_FOR_ADAPTION   64
+#define DTD_HANGOVER               600     /* 600 samples, or 75ms     */
+#define DC_LOG2BETA                  3     /* log2() of DC filter Beta */
+
+/*-----------------------------------------------------------------------*\
+
+                               FUNCTIONS
+
+\*-----------------------------------------------------------------------*/
+
+/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
+
+
+#ifdef __BLACKFIN_ASM__
+static void __inline__ lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+{
+    int i, j;
+    int offset1;
+    int offset2;
+    int factor;
+    int exp;
+    int16_t *phist;
+    int n;
+
+    if (shift > 0)
+	factor = clean << shift;
+    else
+	factor = clean >> -shift;
+
+    /* Update the FIR taps */
+
+    offset2 = ec->curr_pos;
+    offset1 = ec->taps - offset2;
+    phist = &ec->fir_state_bg.history[offset2];
+
+    /* st: and en: help us locate the assembler in echo.s */
+
+    //asm("st:");
+    n = ec->taps;
+    for (i = 0, j = offset2;  i < n;  i++, j++)
+    {
+       exp = *phist++ * factor;
+       ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+    }
+    //asm("en:");
+
+    /* Note the asm for the inner loop above generated by Blackfin gcc 
+       4.1.1 is pretty good (note even parallel instructions used):
+
+    	R0 = W [P0++] (X);
+	R0 *= R2;
+	R0 = R0 + R3 (NS) ||
+	R1 = W [P1] (X) ||
+	nop;
+	R0 >>>= 15;
+	R0 = R0 + R1;
+	W [P1++] = R0;
+
+	A block based update algorithm would be much faster but the
+	above can't be improved on much.  Every instruction saved in
+	the loop above is 2 MIPs/ch!  The for loop above is where the
+	Blackfin spends most of it's time - about 17 MIPs/ch measured
+	with speedtest.c with 256 taps (32ms).  Write-back and
+	Write-through cache gave about the same performance.
+    */
+}
+
+/*
+   IDEAS for further optimisation of lms_adapt_bg():
+
+   1/ The rounding is quite costly.  Could we keep as 32 bit coeffs
+   then make filter pluck the MS 16-bits of the coeffs when filtering?
+   However this would lower potential optimisation of filter, as I
+   think the dual-MAC architecture requires packed 16 bit coeffs.
+
+   2/ Block based update would be more efficient, as per comments above,
+   could use dual MAC architecture.
+
+   3/ Look for same sample Blackfin LMS code, see if we can get dual-MAC
+   packing.
+
+   4/ Execute the whole e/c in a block of say 20ms rather than sample
+   by sample.  Processing a few samples every ms is inefficient.
+*/
+
+#else
+static __inline__ void lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+{
+    int i;
+
+    int offset1;
+    int offset2;
+    int factor;
+    int exp;
+
+    if (shift > 0)
+	factor = clean << shift;
+    else
+	factor = clean >> -shift;
+
+    /* Update the FIR taps */
+
+    offset2 = ec->curr_pos;
+    offset1 = ec->taps - offset2;
+
+    for (i = ec->taps - 1;  i >= offset1;  i--)
+    {
+       exp = (ec->fir_state_bg.history[i - offset1]*factor);
+       ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+    }
+    for (  ;  i >= 0;  i--)
+    {
+       exp = (ec->fir_state_bg.history[i + offset2]*factor);
+       ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+    }
+}
+#endif
+
+/*- End of function --------------------------------------------------------*/
+
+echo_can_state_t *echo_can_create(int len, int adaption_mode)
+{
+    echo_can_state_t *ec;
+    int i;
+    int j;
+
+    ec = (echo_can_state_t *) malloc(sizeof(*ec));
+    if (ec == NULL)
+        return  NULL;
+    memset(ec, 0, sizeof(*ec));
+
+    ec->taps = len;
+    ec->log2taps = top_bit(len);
+    ec->curr_pos = ec->taps - 1;
+    
+    for (i = 0;  i < 2;  i++)
+    {
+        if ((ec->fir_taps16[i] = (int16_t *) malloc((ec->taps)*sizeof(int16_t))) == NULL)
+        {
+            for (j = 0;  j < i;  j++)
+                free(ec->fir_taps16[j]);
+            free(ec);
+            return  NULL;
+        }
+        memset(ec->fir_taps16[i], 0, (ec->taps)*sizeof(int16_t));
+    }
+    
+    fir16_create(&ec->fir_state,
+                 ec->fir_taps16[0],
+                 ec->taps);
+    fir16_create(&ec->fir_state_bg,
+                 ec->fir_taps16[1],
+                 ec->taps);
+
+    for(i=0; i<5; i++) {
+      ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
+    }
+
+    ec->cng_level = 1000;
+    echo_can_adaption_mode(ec, adaption_mode);
+
+    ec->snapshot = (int16_t*)malloc(ec->taps*sizeof(int16_t));
+    memset(ec->snapshot, 0, sizeof(int16_t)*ec->taps);
+
+    ec->cond_met = 0;
+    ec->Pstates = 0;
+    ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+    ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+    ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+    ec->Lbgn = ec->Lbgn_acc = 0;
+    ec->Lbgn_upper = 200;
+    ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+
+    return  ec;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_free(echo_can_state_t *ec)
+{
+    int i;
+    
+    fir16_free(&ec->fir_state);
+    for (i = 0;  i < 2;  i++)
+        free(ec->fir_taps16[i]);
+    free(ec->snapshot);
+    free(ec);
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode)
+{
+    ec->adaption_mode = adaption_mode;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_flush(echo_can_state_t *ec)
+{
+    int i;
+
+    ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+    ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+    ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+    
+    ec->Lbgn = ec->Lbgn_acc = 0;
+    ec->Lbgn_upper = 200;
+    ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+
+    ec->nonupdate_dwell = 0;
+
+    fir16_flush(&ec->fir_state);
+    fir16_flush(&ec->fir_state_bg);
+    ec->fir_state.curr_pos = ec->taps - 1;
+    ec->fir_state_bg.curr_pos = ec->taps - 1;
+    for (i = 0;  i < 2;  i++)
+        memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
+
+    ec->curr_pos = ec->taps - 1;
+    ec->Pstates = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_snapshot(echo_can_state_t *ec) {
+    memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Dual Path Echo Canceller ------------------------------------------------*/
+
+int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
+{
+    int32_t echo_value;
+    int clean_bg;
+    int tmp;
+
+    /* Input scaling was found be required to prevent problems when tx
+       starts clipping.  Another possible way to handle this would be the
+       filter coefficent scaling. */
+
+    ec->tx = tx; ec->rx = rx;
+    tx >>=1;
+    rx >>=1;
+
+    /* 
+       Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required
+       otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta)
+       only real axis.  Some chip sets (like Si labs) don't need
+       this, but something like a $10 X100P card does.  Any DC really slows
+       down convergence.
+
+       Note: removes some low frequency from the signal, this reduces
+       the speech quality when listening to samples through headphones
+       but may not be obvious through a telephone handset.
+                                                                    
+       Note that the 3dB frequency in radians is approx Beta, e.g. for
+       Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
+    */
+
+    if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
+      tmp = rx << 15;
+      ec->rx_1 += -(ec->rx_1>>DC_LOG2BETA) + tmp - ec->rx_2;
+      rx = ec->rx_1 >> 15;
+      ec->rx_2 = tmp;
+    }
+
+    /* Block average of power in the filter states.  Used for
+       adaption power calculation. */
+
+    {
+	int new, old;
+
+	/* efficient "out with the old and in with the new" algorithm so
+	   we don't have to recalculate over the whole block of
+	   samples. */
+	new = (int)tx * (int)tx;
+	old = (int)ec->fir_state.history[ec->fir_state.curr_pos] * 
+              (int)ec->fir_state.history[ec->fir_state.curr_pos];
+	ec->Pstates += ((new - old) + (1<<ec->log2taps)) >> ec->log2taps;
+	if (ec->Pstates < 0) ec->Pstates = 0;
+    }
+
+    /* Calculate short term average levels using simple single pole IIRs */
+    
+    ec->Ltxacc += abs(tx) - ec->Ltx;
+    ec->Ltx = (ec->Ltxacc + (1<<4)) >> 5;
+    ec->Lrxacc += abs(rx) - ec->Lrx;
+    ec->Lrx = (ec->Lrxacc + (1<<4)) >> 5;
+
+    /* Foreground filter ---------------------------------------------------*/
+
+    ec->fir_state.coeffs = ec->fir_taps16[0];
+    echo_value = fir16(&ec->fir_state, tx);
+    ec->clean = rx - echo_value;
+    ec->Lcleanacc += abs(ec->clean) - ec->Lclean;
+    ec->Lclean = (ec->Lcleanacc + (1<<4)) >> 5;
+
+    /* Background filter ---------------------------------------------------*/
+
+    echo_value = fir16(&ec->fir_state_bg, tx);
+    clean_bg = rx - echo_value;
+    ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg;
+    ec->Lclean_bg = (ec->Lclean_bgacc + (1<<4)) >> 5;
+
+    /* Background Filter adaption -----------------------------------------*/
+
+    /* Almost always adap bg filter, just simple DT and energy
+       detection to minimise adaption in cases of strong double talk.
+       However this is not critical for the dual path algorithm.
+    */
+    ec->factor = 0;
+    ec->shift = 0;
+    if ((ec->nonupdate_dwell == 0)) {
+	int   P, logP, shift;
+
+	/* Determine:
+
+	   f = Beta * clean_bg_rx/P ------ (1)
+
+	   where P is the total power in the filter states.
+	   
+	   The Boffins have shown that if we obey (1) we converge
+	   quickly and avoid instability.  
+	   
+	   The correct factor f must be in Q30, as this is the fixed
+	   point format required by the lms_adapt_bg() function,
+	   therefore the scaled version of (1) is:
+
+	   (2^30) * f  = (2^30) * Beta * clean_bg_rx/P    
+	       factor  = (2^30) * Beta * clean_bg_rx/P         ----- (2)
+
+	   We have chosen Beta = 0.25 by experiment, so:
+
+	       factor  = (2^30) * (2^-2) * clean_bg_rx/P  
+
+                                       (30 - 2 - log2(P))
+	       factor  = clean_bg_rx 2                         ----- (3)
+	   
+	   To avoid a divide we approximate log2(P) as top_bit(P),
+	   which returns the position of the highest non-zero bit in
+	   P.  This approximation introduces an error as large as a
+	   factor of 2, but the algorithm seems to handle it OK.
+
+	   Come to think of it a divide may not be a big deal on a 
+	   modern DSP, so its probably worth checking out the cycles
+	   for a divide versus a top_bit() implementation.
+	*/
+
+	P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates;
+	logP = top_bit(P) + ec->log2taps;
+	shift = 30 - 2 - logP;
+	ec->shift = shift;
+
+	lms_adapt_bg(ec, clean_bg, shift);
+    }
+
+    /* very simple DTD to make sure we dont try and adapt with strong
+       near end speech */
+
+    ec->adapt = 0;
+    if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx)) 
+	ec->nonupdate_dwell = DTD_HANGOVER;
+    if (ec->nonupdate_dwell)
+	ec->nonupdate_dwell--;
+
+    /* Transfer logic ------------------------------------------------------*/
+
+    /* These conditions are from the dual path paper [1], I messed with
+       them a bit to improve performance. */
+
+    if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
+	(ec->nonupdate_dwell == 0) && 
+	(8*ec->Lclean_bg < 7*ec->Lclean) /* (ec->Lclean_bg < 0.875*ec->Lclean) */ && 
+	(8*ec->Lclean_bg < ec->Ltx)      /* (ec->Lclean_bg < 0.125*ec->Ltx)    */ )       
+    {
+	if (ec->cond_met == 6) {
+	    /* BG filter has had better results for 6 consecutive samples */
+	    ec->adapt = 1;
+	    memcpy(ec->fir_taps16[0], ec->fir_taps16[1], ec->taps*sizeof(int16_t));
+	}
+	else
+	    ec->cond_met++;
+    }
+    else
+	ec->cond_met = 0;
+
+    /* Non-Linear Processing ---------------------------------------------------*/
+
+    ec->clean_nlp = ec->clean;
+    if (ec->adaption_mode & ECHO_CAN_USE_NLP)
+    {
+        /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+           residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+
+      if ((16*ec->Lclean < ec->Ltx))
+      {
+	/* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB,
+	   so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */
+        if (ec->adaption_mode & ECHO_CAN_USE_CNG)
+	{
+	    ec->cng_level = ec->Lbgn;
+
+	    /* Very elementary comfort noise generation.  Just random
+	       numbers rolled off very vaguely Hoth-like.  DR: This
+	       noise doesn't sound quite right to me - I suspect there
+	       are some overlfow issues in the filtering as it's too
+	       "crackly".  TODO: debug this, maybe just play noise at
+	       high level or look at spectrum.
+	    */
+
+	    ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U;
+	    ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3;
+	    ec->clean_nlp = (ec->cng_filter*ec->cng_level*8) >> 14;
+
+        }
+        else if (ec->adaption_mode & ECHO_CAN_USE_CLIP)
+	{
+	    /* This sounds much better than CNG */
+	    if (ec->clean_nlp > ec->Lbgn)
+	      ec->clean_nlp = ec->Lbgn;
+	    if (ec->clean_nlp < -ec->Lbgn)
+	      ec->clean_nlp = -ec->Lbgn;
+	}
+	else
+        {
+	  /* just mute the residual, doesn't sound very good, used mainly
+	     in G168 tests */
+          ec->clean_nlp = 0;
+        }
+      }
+      else {
+	  /* Background noise estimator.  I tried a few algorithms
+	     here without much luck.  This very simple one seems to
+	     work best, we just average the level using a slow (1 sec
+	     time const) filter if the current level is less than a
+	     (experimentally derived) constant.  This means we dont
+	     include high level signals like near end speech.  When
+	     combined with CNG or especially CLIP seems to work OK.
+	  */
+	  if (ec->Lclean < 40) {
+	      ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn;
+	      ec->Lbgn = (ec->Lbgn_acc + (1<<11)) >> 12;
+	  }
+       }
+    }
+
+    /* Roll around the taps buffer */
+    if (ec->curr_pos <= 0)
+        ec->curr_pos = ec->taps;
+    ec->curr_pos--;
+
+    if (ec->adaption_mode & ECHO_CAN_DISABLE)
+      ec->clean_nlp = rx;
+
+    /* Output scaled back up again to match input scaling */
+
+    return (int16_t) ec->clean_nlp << 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/* This function is seperated from the echo canceller is it is usually called
+   as part of the tx process.  See rx HP (DC blocking) filter above, it's
+   the same design.
+
+   Some soft phones send speech signals with a lot of low frequency
+   energy, e.g. down to 20Hz.  This can make the hybrid non-linear
+   which causes the echo canceller to fall over.  This filter can help
+   by removing any low frequency before it gets to the tx port of the
+   hybrid.
+
+   It can also help by removing and DC in the tx signal.  DC is bad
+   for LMS algorithms.   
+*/
+
+int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx) {
+    int tmp, tmp1;
+
+    if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
+        tmp = tx << 15;
+        ec->tx_1 += -(ec->tx_1>>DC_LOG2BETA) + tmp - ec->tx_2;
+        tmp1 = ec->tx_1 >> 15;
+	if (tmp1 > 32767) tmp1 = 32767;
+	if (tmp1 < -32767) tmp1 = -32767;
+	tx = tmp1;
+        ec->tx_2 = tmp;
+    }
+    
+    return tx;
+}
+
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/

Added: zaptel/trunk/oslec/oslec-ctrl-panel.sh
===================================================================
--- zaptel/trunk/oslec/oslec-ctrl-panel.sh	                        (rev 0)
+++ zaptel/trunk/oslec/oslec-ctrl-panel.sh	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,159 @@
+#!/bin/sh
+# ./oslec-ctrl-panel.sh
+#
+# David Rowe
+# Created February 2007
+#
+# cdialog based shell script to control Oslec echo canceller in real time
+# from a text mode GUI.  I am totally useless at shell scripting so please
+# feel free to improve on this.
+
+#
+#  Copyright (C) 2007 David Rowe
+# 
+#  All rights reserved.
+# 
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2, as
+#  published by the Free Software Foundation.
+# 
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+# 
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+nlp_off=off
+nlp_mute=off
+nlp_cng=off
+nlp_clip=on
+nlp_mode=1+2+8
+
+tmpfile=`mktemp /tmp/oslec_panel_XXXXXX` || exit 1
+
+nlp_menu()
+{
+  nlpstatus=0
+  while [ $nlpstatus -eq 0 ]
+  do
+  
+    dialog \
+      --radiolist "NLP Mode" 10 70 4 \
+          Off  "NLP disabled" $nlp_off  \
+          Mute "Simple mute" $nlp_mute  \
+          CNG  "Synthetic level-matched comfort noise" $nlp_cng \
+          Clip "Clip to background noise level" $nlp_clip \
+        2>$tmpfile 
+    nlpstatus=$?
+ 
+    if [ $nlpstatus -eq 0 ] ; then
+      nlpmenuitem=`cat $tmpfile` 
+      case $nlpmenuitem in
+	  "Off") nlp_off=on; nlp_mute=off; nlp_cng=off; nlp_clip=off; nlp_mode=0;;
+	  "Mute") nlp_off=off; nlp_mute=on; nlp_cng=off; nlp_clip=off; nlp_mode=2;;
+	  "CNG") nlp_off=off; nlp_mute=off; nlp_cng=on; nlp_clip=off; nlp_mode=`expr 2 + 4`;;
+	  "Clip") nlp_off=off; nlp_mute=off; nlp_cng=off; nlp_clip=on; nlp_mode=`expr 2 + 8`;;
+      esac
+      mode=`expr 1 + $nlp_mode`
+      echo $mode > /proc/oslec/mode
+    fi
+  done
+
+  return
+}
+
+filter_menu()
+{
+    
+  filterstatus=0
+  while [ $filterstatus -eq 0 ]
+  do
+  
+    # extract HPF state from $mode
+    mode=`cat /proc/oslec/mode`
+    tx_hpf=$(( $mode & 16 ))
+    if [ $tx_hpf -eq 16 ] ; then
+        tx_hpf=on
+    else
+        tx_hpf=off
+    fi
+    rx_hpf=$(( $mode & 32 ))
+    if [ $rx_hpf -eq 32 ] ; then
+      rx_hpf=on
+    else
+      rx_hpf=off
+    fi
+
+    dialog \
+      --checklist "High Pass Filters $mode" 10 70 4 \
+          Tx  "Tx HPF" $tx_hpf  \
+          Rx  "Rx HPF" $rx_hpf  \
+        2>$tmpfile 
+    filterstatus=$?
+ 
+    if [ $filterstatus -eq 0 ] ; then
+      filtermenuitem=`cat $tmpfile` 
+      if [ `expr match "$filtermenuitem" ".*Tx"` -ne 0 ] ; then
+	  mode=$(( $mode | 16 ))
+      else
+
+	  mode=$(( $mode & 239 ))
+      fi
+      
+      if [ `expr match "$filtermenuitem" ".*Rx"` -ne 0 ] ; then
+	  mode=$(( $mode | 32 ))
+      else
+	  mode=$(( $mode & 223 ))
+      fi
+      echo $mode > /proc/oslec/mode
+    fi
+  done
+
+  return
+}
+
+disable() {
+    mode=`cat /proc/oslec/mode`
+    mode=$(( $mode | 64 ))
+    echo $mode > /proc/oslec/mode
+}
+
+enable() {
+    mode=`cat /proc/oslec/mode`
+    mode=$(( $mode & 191 ))
+    echo $mode > /proc/oslec/mode
+}
+
+status=0
+menuitem=Info
+while [ $status -eq 0 ] 
+do
+  dialog  --cancel-label Finish --default-item $menuitem \
+    --menu "Oslec Control Panel" 12 60 6 \
+    Info      "Display echo canceller stats" \
+    NLP       "Configure Non Linear Processor" \
+    Filters   "Select High Pass Filters" \
+    Reset     "Reset echo canceller" \
+    Disable   "Disable echo canceller" \
+    Enable    "Enable echo canceller" \
+    2>$tmpfile 
+
+  status=$?
+ 
+  if [ $status -eq 0 ] ; then
+    menuitem=`cat $tmpfile` 
+    case $menuitem in
+	  "Info") cat /proc/oslec/info>$tmpfile; dialog --textbox $tmpfile 18 60;;
+	  "NLP") nlp_menu;;
+	  "Filters") filter_menu;;
+	  "Reset")   echo 1 > /proc/oslec/reset;;
+	  "Disable") disable;;
+	  "Enable") enable;;
+      esac
+    fi
+done
+
+rm $tmpfile


Property changes on: zaptel/trunk/oslec/oslec-ctrl-panel.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: zaptel/trunk/oslec/oslec.h
===================================================================
--- zaptel/trunk/oslec/oslec.h	                        (rev 0)
+++ zaptel/trunk/oslec/oslec.h	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,48 @@
+/*
+  oslec.h
+  David Rowe
+  7 Feb 2007
+
+  Interface for OSLEC module.
+*/
+
+/*
+  Copyright (C) 2007 David Rowe
+ 
+  All rights reserved.
+ 
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2, as
+  published by the Free Software Foundation.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __OSLEC__
+
+struct echo_can_state {
+  void *ec;
+};
+
+struct echo_can_state *oslec_echo_can_create(int len, int adaption_mode);
+void oslec_echo_can_free(struct echo_can_state *ec);
+short oslec_echo_can_update(struct echo_can_state *ec, short iref, short isig);
+int oslec_echo_can_traintap(struct echo_can_state *ec, int pos, short val);
+void oslec_echo_can_identify(char *buf, size_t len);
+static inline void echo_can_init(void) {}
+static inline void echo_can_shutdown(void) {}
+short oslec_hpf_tx(struct echo_can_state *ec, short txlin);
+
+#define ZAPTEL_ECHO_CANCELLER "OSLEC"
+
+#define USE_ZAPTAP
+
+#endif
+

Added: zaptel/trunk/oslec/oslec_wrap.c
===================================================================
--- zaptel/trunk/oslec/oslec_wrap.c	                        (rev 0)
+++ zaptel/trunk/oslec/oslec_wrap.c	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,413 @@
+/*
+  oslec_wrap.c
+  David Rowe
+  7 Feb 2007
+
+  Wrapper for OSLEC to turn it into a kernel module compatable with Zaptel.
+
+  The /proc/oslec interface points to the first echo canceller
+  instance created. Zaptel appears to create/destroy e/c on a call by
+  call basis, and with the current echo can function interface it is
+  difficult to tell which channel is assigned to which e/c.  So to
+  simply the /proc interface (at least in this first implementation)
+  we limit it to the first echo canceller created.
+
+  So if you only have one call up on a system, /proc/oslec will refer
+  to that.  That should be sufficient for debugging the echo canceller
+  algorithm, we can extend it to handle multiple simultaneous channels
+  later.
+*/
+
+/*
+  Copyright (C) 2007 David Rowe
+ 
+  All rights reserved.
+ 
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License version 2, as
+  published by the Free Software Foundation.
+   This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>       
+#include <linux/module.h>      
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <asm/delay.h>
+
+
+#define malloc(a) kmalloc((a), GFP_KERNEL)
+#define free(a) kfree(a)
+
+#include "oslec.h"
+#include "spandsp/echo.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+EXPORT_SYMBOL(oslec_echo_can_create);
+EXPORT_SYMBOL(oslec_echo_can_free);
+EXPORT_SYMBOL(oslec_echo_can_update);
+EXPORT_SYMBOL(oslec_echo_can_traintap);
+EXPORT_SYMBOL(oslec_hpf_tx);
+#endif
+
+/* constants for isr cycle averaging */
+
+#define LTC   5   /* base 2 log of TC */
+
+/* number of cycles we are using per call */
+
+static int cycles_last = 0;
+static int cycles_worst = 0;
+static int cycles_average = 0; 
+
+#ifdef __BLACKFIN__
+/* sample cycles register of Blackfin */
+
+static inline volatile unsigned int cycles(void) {
+  int ret;
+
+   __asm__ __volatile__
+   (
+   "%0 = CYCLES;\n\t"
+   : "=&d" (ret)
+   :
+   : "R1"
+   );
+
+   return ret;
+}
+#else
+static __inline__ uint64_t cycles(void) {
+  uint64_t x;
+  __asm__ volatile ("rdtsc\n\t" : "=A" (x));
+  return x;
+}
+
+#endif
+
+/* vars to help us with /proc interface */
+
+static echo_can_state_t *mon_ec;
+static int num_ec;
+static int len_ec;
+ 
+/* We need this lock as multiple threads may try to manipulate
+   the globals used for diagnostics at the same time */
+
+DECLARE_MUTEX(oslec_lock);
+
+/* Thread safety issues:
+
+  Due to the design of zaptel an e/c instance may be created and
+  destroyed at any time.  So monitoring and controlling a running e/c
+  instance through /proc/oslec has some special challenges:
+
+  1/ oslec_echo_can_create() might be interrupted part way through,
+     and called again by another thread.
+
+  2/ proc_* might be interrupted and the e/c instance pointed to
+     by mon_ec destroyed by another thread.
+
+  3/ Call 1 might be destroyed while Call 2 is still up, mon_ec will
+     then point to a destroyed instance.
+
+  4/ What happens if an e/c is destroyed while we are modifying it's
+     mode?
+
+  The goal is to allow monitoring and control of at least once
+  instance while maintaining stable multithreaded operation.  This is
+  tricky (at least for me) given zaptel design and the use of globals
+  here to monitor status.
+
+  Thanks Dmitry for helping point these problems out.....
+*/
+
+struct echo_can_state *oslec_echo_can_create(int len, int adaption_mode) {
+  struct echo_can_state *ec;
+
+  down(&oslec_lock);
+
+  ec = (struct echo_can_state *)malloc(sizeof(struct echo_can_state));
+  ec->ec = (void*)echo_can_create(len,   ECHO_CAN_USE_ADAPTION 
+				       | ECHO_CAN_USE_NLP 
+				       | ECHO_CAN_USE_CLIP
+				       | ECHO_CAN_USE_TX_HPF
+				       | ECHO_CAN_USE_RX_HPF);
+				   
+  num_ec++;
+
+  /* We monitor the first e/c created after mon_ec is set to NULL.  If
+     no other calls exist this will be the first call.  If a monitored
+     call hangs up, we will monitor the next call created, ignoring
+     any other current calls.  Not perfect I know, however this is
+     just meant to be a development tool.  Stability is more important
+     than comprehensive monitoring abilities.
+  */
+  if (mon_ec == NULL) {
+      mon_ec = (echo_can_state_t*)(ec->ec);
+      len_ec = len;
+  }
+
+  up(&oslec_lock);
+
+  return ec;
+}
+
+void oslec_echo_can_free(struct echo_can_state *ec) {
+  down(&oslec_lock);
+
+  /* if this is the e/c being monitored, disable monitoring */
+
+  if (mon_ec == ec->ec)
+    mon_ec = NULL;
+
+  echo_can_free((echo_can_state_t*)(ec->ec));
+  num_ec--;
+  free(ec);
+
+  up(&oslec_lock);
+}
+
+/* 
+   This code in re-entrant, and will run in the context of an ISR.  No
+   locking is required for cycles calculation, as only one thread will have
+   ec->ec == mon_ec at a given time, so there will only ever be one
+   writer to the cycles_* globals. 
+*/
+
+short oslec_echo_can_update(struct echo_can_state *ec, short iref, short isig) {
+    short clean;
+    u32   start_cycles = 0;
+
+    if (ec->ec == mon_ec) {
+      start_cycles = cycles();
+    }
+
+    clean = echo_can_update((echo_can_state_t*)(ec->ec), iref, isig);
+
+    /*
+      Simple IIR averager:
+
+                   -LTC           -LTC
+      y(n) = (1 - 2    )y(n-1) + 2    x(n)
+
+    */
+
+    if (ec->ec == mon_ec) {
+      cycles_last = cycles() - start_cycles;
+      cycles_average += (cycles_last - cycles_average) >> LTC;
+    
+      if (cycles_last > cycles_worst)
+	cycles_worst = cycles_last;
+    }
+
+    return clean;
+}
+
+int oslec_echo_can_traintap(struct echo_can_state *ec, int pos, short val)
+{
+	return 0;
+}
+
+void oslec_echo_can_identify(char *buf, size_t len)
+{
+	strncpy(buf, ZAPTEL_ECHO_CANCELLER, len);
+}
+
+
+static int proc_read_info(char *buf, char **start, off_t offset,
+                          int count, int *eof, void *data)
+{
+  int len;
+  char mode_str[80];
+
+  *eof = 1;
+
+  down(&oslec_lock);
+
+  if (mon_ec == NULL) {
+    len = sprintf(buf, "no echo canceller being monitored - make a new call\n");
+    up(&oslec_lock);
+    return len;
+  }
+
+  if (mon_ec->adaption_mode & ECHO_CAN_USE_ADAPTION)
+    sprintf(mode_str, "|ADAPTION");
+  else
+    sprintf(mode_str, "|        ");
+
+  if (mon_ec->adaption_mode & ECHO_CAN_USE_NLP)
+    strcat(mode_str, "|NLP");
+  else
+    strcat(mode_str, "|   ");
+
+  if (mon_ec->adaption_mode & ECHO_CAN_USE_CNG)
+    strcat(mode_str, "|CNG");
+  else if (mon_ec->adaption_mode & ECHO_CAN_USE_CLIP)
+    strcat(mode_str, "|CLIP");
+  else
+    strcat(mode_str, "|   ");		
+	
+  if (mon_ec->adaption_mode & ECHO_CAN_USE_TX_HPF)
+    strcat(mode_str, "|TXHPF");
+  else
+    strcat(mode_str, "|   ");		
+
+  if (mon_ec->adaption_mode & ECHO_CAN_USE_TX_HPF)
+    strcat(mode_str, "|RXHPF|");
+  else
+    strcat(mode_str, "|   |");		
+
+  len = sprintf(buf,
+		"channels.......: %d\n"
+		"length (taps)..: %d\n"
+		"mode...........: [%0d] %s\n"
+		"Ltx............: %d\n"
+		"Lrx............: %d\n"
+		"Lclean.........: %d\n"
+		"Lclean_bg......: %d\n"
+		"shift..........: %d\n"
+		"Double Talk....: %d\n"
+		"Lbgn...........: %d\n"
+		"MIPs (last)....: %d\n"
+		"MIPs (worst)...: %d\n"
+		"MIPs (avergage): %d\n",
+		num_ec,
+		len_ec,
+		mon_ec->adaption_mode, mode_str,
+		mon_ec->Ltx,
+		mon_ec->Lrx,
+		mon_ec->Lclean,
+		mon_ec->Lclean_bg,
+		mon_ec->shift,
+		(mon_ec->nonupdate_dwell != 0),
+		mon_ec->Lbgn,
+		8*cycles_last/1000,
+		8*cycles_worst/1000,
+		8*cycles_average/1000
+		);
+
+  up(&oslec_lock);
+
+  return len;
+}
+
+static int proc_read_mode(char *buf, char **start, off_t offset,
+                          int count, int *eof, void *data)
+{
+  int len;
+
+  *eof = 1;
+
+  down(&oslec_lock);
+
+  if (mon_ec == NULL) {
+    len = sprintf(buf, "%d\n", 0);
+    up(&oslec_lock);
+    return len;
+  }
+
+  len = sprintf(buf, "%d\n", mon_ec->adaption_mode);
+
+  up(&oslec_lock);
+
+  return len;
+}
+
+static int proc_write_mode(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+
+  int   new_mode;
+  char *endbuffer;
+
+  down(&oslec_lock);
+
+  if (mon_ec == NULL) {
+    printk("no echo canceller being monitored - make a new call\n");
+    up(&oslec_lock);
+    return count;
+  }
+
+  new_mode = simple_strtol (buffer, &endbuffer, 10);
+  mon_ec->adaption_mode = new_mode;
+
+  up(&oslec_lock);
+
+  return count;
+}
+
+static int proc_write_reset(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+  down(&oslec_lock);
+
+  if (mon_ec == NULL) {
+    printk("no echo canceller being monitored - make a new call\n");
+    up(&oslec_lock);
+    return count;
+  }
+
+  /* Not sure how thread safe this is, should be OKJ as its only resetting
+     same state variables.  There is a chance this will be interrupted
+     by ISR that calls oslec_echo_can_update() 
+  */
+  echo_can_flush(mon_ec);
+
+  up(&oslec_lock);
+
+  return count;
+}
+
+static int __init init_oslec(void)
+{
+    struct proc_dir_entry *proc_oslec, *proc_mode, *proc_reset;
+
+    printk("Open Source Line Echo Canceller Installed\n");
+
+    num_ec = 0;
+    mon_ec = NULL;
+
+    proc_oslec = proc_mkdir("oslec", 0);
+    create_proc_read_entry("oslec/info", 0, NULL, proc_read_info, NULL);
+    proc_mode = create_proc_read_entry("oslec/mode", 0, NULL, proc_read_mode, NULL);
+    proc_reset = create_proc_read_entry("oslec/reset", 0, NULL, NULL, NULL);
+
+    proc_mode->write_proc = proc_write_mode;
+    proc_reset->write_proc = proc_write_reset;
+
+    return 0;
+}
+
+static void __exit cleanup_oslec(void)
+{
+    remove_proc_entry("oslec/reset", NULL);
+    remove_proc_entry("oslec/info", NULL);
+    remove_proc_entry("oslec/mode", NULL);
+    remove_proc_entry("oslec", NULL);
+    printk("Open Source Line Echo Canceller Removed\n");
+}
+
+short oslec_hpf_tx(struct echo_can_state *ec, short txlin) {
+    if (ec != NULL) 
+        return echo_can_hpf_tx((echo_can_state_t*)(ec->ec), txlin);  
+    else
+        return txlin;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Rowe");
+MODULE_DESCRIPTION("Open Source Line Echo Canceller Zaptel Wrapper");
+
+module_init(init_oslec);
+module_exit(cleanup_oslec);
+

Added: zaptel/trunk/oslec/spandsp/bit_operations.h
===================================================================
--- zaptel/trunk/oslec/spandsp/bit_operations.h	                        (rev 0)
+++ zaptel/trunk/oslec/spandsp/bit_operations.h	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,253 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * bit_operations.h - Various bit level operations, such as bit reversal
+ *
+ * Written by Steve Underwood <steveu at coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: bit_operations.h,v 1.11 2006/11/28 15:37:03 steveu Exp $
+ */
+
+/*! \file */
+
+#if !defined(_BIT_OPERATIONS_H_)
+#define _BIT_OPERATIONS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__i386__)  ||  defined(__x86_64__)
+/*! \brief Find the bit position of the highest set bit in a word
+    \param bits The word to be searched
+    \return The bit number of the highest set bit, or -1 if the word is zero. */
+static __inline__ int top_bit(unsigned int bits)
+{
+    int res;
+    
+    __asm__ (" xorl %[res],%[res];\n"
+             " decl %[res];\n"
+             " bsrl %[bits],%[res]\n"
+             : [res] "=&r" (res)
+             : [bits] "rm" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the bit position of the lowest set bit in a word
+    \param bits The word to be searched
+    \return The bit number of the lowest set bit, or -1 if the word is zero. */
+static __inline__ int bottom_bit(unsigned int bits)
+{
+    int res;
+    
+    __asm__ (" xorl %[res],%[res];\n"
+             " decl %[res];\n"
+             " bsfl %[bits],%[res]\n"
+             : [res] "=&r" (res)
+             : [bits] "rm" (bits));
+    return res;
+}
+/*- End of function --------------------------------------------------------*/
+#else
+static __inline__ int top_bit(unsigned int bits)
+{
+    int i;
+    
+    if (bits == 0)
+        return -1;
+    i = 0;
+    if (bits & 0xFFFF0000)
+    {
+        bits &= 0xFFFF0000;
+        i += 16;
+    }
+    if (bits & 0xFF00FF00)
+    {
+        bits &= 0xFF00FF00;
+        i += 8;
+    }
+    if (bits & 0xF0F0F0F0)
+    {
+        bits &= 0xF0F0F0F0;
+        i += 4;
+    }
+    if (bits & 0xCCCCCCCC)
+    {
+        bits &= 0xCCCCCCCC;
+        i += 2;
+    }
+    if (bits & 0xAAAAAAAA)
+    {
+        bits &= 0xAAAAAAAA;
+        i += 1;
+    }
+    return i;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int bottom_bit(unsigned int bits)
+{
+    int i;
+    
+    if (bits == 0)
+        return -1;
+    i = 32;
+    if (bits & 0x0000FFFF)
+    {
+        bits &= 0x0000FFFF;
+        i -= 16;
+    }
+    if (bits & 0x00FF00FF)
+    {
+        bits &= 0x00FF00FF;
+        i -= 8;
+    }
+    if (bits & 0x0F0F0F0F)
+    {
+        bits &= 0x0F0F0F0F;
+        i -= 4;
+    }
+    if (bits & 0x33333333)
+    {
+        bits &= 0x33333333;
+        i -= 2;
+    }
+    if (bits & 0x55555555)
+    {
+        bits &= 0x55555555;
+        i -= 1;
+    }
+    return i;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+/*! \brief Bit reverse a byte.
+    \param data The byte to be reversed.
+    \return The bit reversed version of data. */
+static __inline__ uint8_t bit_reverse8(uint8_t x)
+{
+#if defined(__i386__)  ||  defined(__x86_64__)
+    /* If multiply is fast */
+    return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16;
+#else
+    /* If multiply is slow, but we have a barrel shifter */
+    x = (x >> 4) | (x << 4);
+    x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
+    return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a 16 bit word.
+    \param data The word to be reversed.
+    \return The bit reversed version of data. */
+uint16_t bit_reverse16(uint16_t data);
+
+/*! \brief Bit reverse a 32 bit word.
+    \param data The word to be reversed.
+    \return The bit reversed version of data. */
+uint32_t bit_reverse32(uint32_t data);
+
+/*! \brief Bit reverse each of the four bytes in a 32 bit word.
+    \param data The word to be reversed.
+    \return The bit reversed version of data. */
+uint32_t bit_reverse_4bytes(uint32_t data);
+
+/*! \brief Find the number of set bits in a 32 bit word.
+    \param x The word to be searched.
+    \return The number of set bits. */
+int one_bits32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 32 bit word.
+    \param x The word to be searched.
+    \return The mask. */
+uint32_t make_mask32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 16 bit word.
+    \param x The word to be searched.
+    \return The mask. */
+uint16_t make_mask16(uint16_t x);
+
+/*! \brief Find the least significant one in a word, and return a word
+           with just that bit set.
+    \param x The word to be searched.
+    \return The word with the single set bit. */
+static __inline__ uint32_t least_significant_one32(uint32_t x)
+{
+    return (x & (-(int32_t) x));
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the most significant one in a word, and return a word
+           with just that bit set.
+    \param x The word to be searched.
+    \return The word with the single set bit. */
+static __inline__ uint32_t most_significant_one32(uint32_t x)
+{
+#if defined(__i386__)  ||  defined(__x86_64__)
+    return 1 << top_bit(x);
+#else
+    x = make_mask32(x);
+    return (x ^ (x >> 1));
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a byte.
+    \param x The byte to be checked.
+    \return 1 for odd, or 0 for even. */
+static __inline__ int parity8(uint8_t x)
+{
+    x = (x ^ (x >> 4)) & 0x0F;
+    return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 16 bit word.
+    \param x The word to be checked.
+    \return 1 for odd, or 0 for even. */
+static __inline__ int parity16(uint16_t x)
+{
+    x ^= (x >> 8);
+    x = (x ^ (x >> 4)) & 0x0F;
+    return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 32 bit word.
+    \param x The word to be checked.
+    \return 1 for odd, or 0 for even. */
+static __inline__ int parity32(uint32_t x)
+{
+    x ^= (x >> 16);
+    x ^= (x >> 8);
+    x = (x ^ (x >> 4)) & 0x0F;
+    return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/

Added: zaptel/trunk/oslec/spandsp/echo.h
===================================================================
--- zaptel/trunk/oslec/spandsp/echo.h	                        (rev 0)
+++ zaptel/trunk/oslec/spandsp/echo.h	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,220 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - A line echo canceller.  This code is being developed
+ *          against and partially complies with G168.
+ *
+ * Written by Steve Underwood <steveu at coppice.org> 
+ *         and David Rowe <david_at_rowetel_dot_com>
+ *
+ * Copyright (C) 2001 Steve Underwood and 2007 David Rowe
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \file */
+
+#if !defined(_ECHO_H_)
+#define _ECHO_H_
+
+/*! \page echo_can_page Line echo cancellation for voice
+
+\section echo_can_page_sec_1 What does it do?
+This module aims to provide G.168-2002 compliant echo cancellation, to remove
+electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
+
+\section echo_can_page_sec_2 How does it work?
+The heart of the echo cancellor is FIR filter. This is adapted to match the echo
+impulse response of the telephone line. It must be long enough to adequately cover
+the duration of that impulse response. The signal transmitted to the telephone line
+is passed through the FIR filter. Once the FIR is properly adapted, the resulting
+output is an estimate of the echo signal received from the line. This is subtracted
+from the received signal. The result is an estimate of the signal which originated
+at the far end of the line, free from echos of our own transmitted signal. 
+
+The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was
+introduced in 1960. It is the commonest form of filter adaption used in things
+like modem line equalisers and line echo cancellers. There it works very well.
+However, it only works well for signals of constant amplitude. It works very poorly
+for things like speech echo cancellation, where the signal level varies widely.
+This is quite easy to fix. If the signal level is normalised - similar to applying
+AGC - LMS can work as well for a signal of varying amplitude as it does for a modem
+signal. This normalised least mean squares (NLMS) algorithm is the commonest one used
+for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially
+the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS.
+However, factors such as computational complexity and patents favour the use of NLMS.
+
+A simple refinement to NLMS can improve its performance with speech. NLMS tends
+to adapt best to the strongest parts of a signal. If the signal is white noise,
+the NLMS algorithm works very well. However, speech has more low frequency than
+high frequency content. Pre-whitening (i.e. filtering the signal to flatten
+its spectrum) the echo signal improves the adapt rate for speech, and ensures the
+final residual signal is not heavily biased towards high frequencies. A very low
+complexity filter is adequate for this, so pre-whitening adds little to the
+compute requirements of the echo canceller.
+
+An FIR filter adapted using pre-whitened NLMS performs well, provided certain
+conditions are met: 
+
+    - The transmitted signal has poor self-correlation.
+    - There is no signal being generated within the environment being cancelled.
+
+The difficulty is that neither of these can be guaranteed.
+
+If the adaption is performed while transmitting noise (or something fairly noise
+like, such as voice) the adaption works very well. If the adaption is performed
+while transmitting something highly correlative (typically narrow band energy
+such as signalling tones or DTMF), the adaption can go seriously wrong. The reason
+is there is only one solution for the adaption on a near random signal - the impulse
+response of the line. For a repetitive signal, there are any number of solutions
+which converge the adaption, and nothing guides the adaption to choose the generalised
+one. Allowing an untrained canceller to converge on this kind of narrowband
+energy probably a good thing, since at least it cancels the tones. Allowing a well
+converged canceller to continue converging on such energy is just a way to ruin
+its generalised adaption. A narrowband detector is needed, so adapation can be
+suspended at appropriate times.
+
+The adaption process is based on trying to eliminate the received signal. When
+there is any signal from within the environment being cancelled it may upset the
+adaption process. Similarly, if the signal we are transmitting is small, noise
+may dominate and disturb the adaption process. If we can ensure that the
+adaption is only performed when we are transmitting a significant signal level,
+and the environment is not, things will be OK. Clearly, it is easy to tell when
+we are sending a significant signal. Telling, if the environment is generating a
+significant signal, and doing it with sufficient speed that the adaption will
+not have diverged too much more we stop it, is a little harder. 
+
+The key problem in detecting when the environment is sourcing significant energy
+is that we must do this very quickly. Given a reasonably long sample of the
+received signal, there are a number of strategies which may be used to assess
+whether that signal contains a strong far end component. However, by the time
+that assessment is complete the far end signal will have already caused major
+mis-convergence in the adaption process. An assessment algorithm is needed which
+produces a fairly accurate result from a very short burst of far end energy. 
+
+\section echo_can_page_sec_3 How do I use it?
+The echo cancellor processes both the transmit and receive streams sample by
+sample. The processing function is not declared inline. Unfortunately,
+cancellation requires many operations per sample, so the call overhead is only a
+minor burden. 
+*/
+
+#include "fir.h"
+
+/* Mask bits for the adaption mode */
+
+#define ECHO_CAN_USE_ADAPTION       0x01
+#define ECHO_CAN_USE_NLP            0x02
+#define ECHO_CAN_USE_CNG            0x04
+#define ECHO_CAN_USE_CLIP           0x08
+#define ECHO_CAN_USE_TX_HPF         0x10
+#define ECHO_CAN_USE_RX_HPF         0x20
+#define ECHO_CAN_DISABLE            0x40
+
+/*!
+    G.168 echo canceller descriptor. This defines the working state for a line
+    echo canceller.
+*/
+typedef struct
+{
+    int16_t tx,rx;
+    int16_t clean;
+    int16_t clean_nlp;
+
+    int nonupdate_dwell;
+    int curr_pos;	
+    int taps;
+    int log2taps;
+    int adaption_mode;
+
+    int cond_met;
+    int32_t Pstates;
+    int16_t adapt;
+    int32_t factor;
+    int16_t shift;
+
+    /* Average levels and averaging filter states */ 
+    int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc;
+    int Ltx, Lrx;
+    int Lclean;
+    int Lclean_bg;
+    int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc;
+
+    /* foreground and background filter states */
+    fir16_state_t fir_state;
+    fir16_state_t fir_state_bg;
+    int16_t *fir_taps16[2];
+    
+    /* DC blocking filter states */
+    int tx_1, tx_2, rx_1, rx_2;
+   
+    /* optional High Pass Filter states */
+    int32_t xvtx[5], yvtx[5];
+    int32_t xvrx[5], yvrx[5];
+   
+    /* Parameters for the optional Hoth noise generator */
+    int cng_level;
+    int cng_rndnum;
+    int cng_filter;
+    
+    /* snapshot sample of coeffs used for development */
+    int16_t *snapshot;       
+
+} echo_can_state_t;
+
+/*! Create a voice echo canceller context.
+    \param len The length of the canceller, in samples.
+    \return The new canceller context, or NULL if the canceller could not be created.
+*/
+echo_can_state_t *echo_can_create(int len, int adaption_mode);
+
+/*! Free a voice echo canceller context.
+    \param ec The echo canceller context.
+*/
+void echo_can_free(echo_can_state_t *ec);
+
+/*! Flush (reinitialise) a voice echo canceller context.
+    \param ec The echo canceller context.
+*/
+void echo_can_flush(echo_can_state_t *ec);
+
+/*! Set the adaption mode of a voice echo canceller context.
+    \param ec The echo canceller context.
+    \param adapt The mode.
+*/
+void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode);
+
+void echo_can_snapshot(echo_can_state_t *ec);
+
+/*! Process a sample through a voice echo canceller.
+    \param ec The echo canceller context.
+    \param tx The transmitted audio sample.
+    \param rx The received audio sample.
+    \return The clean (echo cancelled) received sample.
+*/
+int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx);
+
+/*! Process to high pass filter the tx signal.
+    \param ec The echo canceller context.
+    \param tx The transmitted auio sample.
+    \return The HP filtered transmit sample, send this to your D/A.
+*/
+int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx);
+
+#endif
+/*- End of file ------------------------------------------------------------*/

Added: zaptel/trunk/oslec/spandsp/fir.h
===================================================================
--- zaptel/trunk/oslec/spandsp/fir.h	                        (rev 0)
+++ zaptel/trunk/oslec/spandsp/fir.h	2007-06-16 19:52:21 UTC (rev 3665)
@@ -0,0 +1,367 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * fir.h - General telephony FIR routines
+ *
+ * Written by Steve Underwood <steveu at coppice.org>
+ *
+ * Copyright (C) 2002 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: fir.h,v 1.8 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \page fir_page FIR filtering
+\section fir_page_sec_1 What does it do?
+???.
+
+\section fir_page_sec_2 How does it work?
+???.
+*/
+
+#if !defined(_FIR_H_)
+#define _FIR_H_
+
+/* 
+   Blackfin NOTES & IDEAS:
+
+   A simple dot product function is used to implement the filter.  This performs
+   just one MAC/cycle which is inefficient but was easy to implement as a first
+   pass.  The current Blackfin code also uses an unrolled form of the filter
+   history to avoid 0 length hardware loop issues.  This is wasteful of 
+   memory.
+
+   Ideas for improvement:
+
+   1/ Rewrite filter for dual MAC inner loop.  The issue here is handling
+   history sample offsets that are 16 bit aligned - the dual MAC needs
+   32 bit aligmnent.  There are some good examples in libbfdsp.
+
+   2/ Use the hardware circular buffer facility tohalve memory usage.
+
+   3/ Consider using internal memory.
+
+   Using less memory might also improve speed as cache misses will be
+   reduced. A drop in MIPs and memory approaching 50% should be
+   possible.
+
+   The foreground and background filters currenlty use a total of
+   about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
+   can.
+*/
+
+#if defined(USE_MMX)  ||  defined(USE_SSE2)
+#include "mmx.h"
+#endif
+
+/*!
+    16 bit integer FIR descriptor. This defines the working state for a single
+    instance of an FIR filter using 16 bit integer coefficients.
+*/
+typedef struct
+{
+    int taps;
+    int curr_pos;
+    const int16_t *coeffs;
+    int16_t *history;
+} fir16_state_t;
+
+/*!
+    32 bit integer FIR descriptor. This defines the working state for a single
+    instance of an FIR filter using 32 bit integer coefficients, and filtering
+    16 bit integer data.
+*/
+typedef struct
+{
+    int taps;
+    int curr_pos;
+    const int32_t *coeffs;
+    int16_t *history;
+} fir32_state_t;
+
+/*!
+    Floating point FIR descriptor. This defines the working state for a single
+    instance of an FIR filter using floating point coefficients and data.
+*/
+typedef struct
+{
+    int taps;
+    int curr_pos;
+    const float *coeffs;
+    float *history;
+} fir_float_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static __inline__ const int16_t *fir16_create(fir16_state_t *fir,
+                                              const int16_t *coeffs,
+                                              int taps)
+{
+    fir->taps = taps;
+    fir->curr_pos = taps - 1;
+    fir->coeffs = coeffs;
+#if defined(USE_MMX)  ||  defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
+    if ((fir->history = malloc(2*taps*sizeof(int16_t))))
+        memset(fir->history, 0, 2*taps*sizeof(int16_t));
+#else
+    if ((fir->history = (int16_t *) malloc(taps*sizeof(int16_t))))
+        memset(fir->history, 0, taps*sizeof(int16_t));
+#endif
+    return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_flush(fir16_state_t *fir)
+{
+#if defined(USE_MMX)  ||  defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
+    memset(fir->history, 0, 2*fir->taps*sizeof(int16_t));
+#else
+    memset(fir->history, 0, fir->taps*sizeof(int16_t));
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_free(fir16_state_t *fir)
+{
+    free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifdef __BLACKFIN_ASM__
+static inline int32_t dot_asm(short *x, short *y, int len)
+{
+   int dot;
+
+   len--;
+
+   __asm__ 
+   (
+   "I0 = %1;\n\t"
+   "I1 = %2;\n\t"
+   "A0 = 0;\n\t"
+   "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+   "LOOP dot%= LC0 = %3;\n\t"
+   "LOOP_BEGIN dot%=;\n\t"
+      "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+   "LOOP_END dot%=;\n\t"
+   "A0 += R0.L*R1.L (IS);\n\t"
+   "R0 = A0;\n\t"
+   "%0 = R0;\n\t"
+   : "=&d" (dot)
+   : "a" (x), "a" (y), "a" (len)
+   : "I0", "I1", "A1", "A0", "R0", "R1"
+   );
+
+   return dot;
+}
+#endif
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample)
+{
+    int32_t y;
+#if defined(USE_MMX)
+    int i;
+    mmx_t *mmx_coeffs;
+    mmx_t *mmx_hist;
+
+    fir->history[fir->curr_pos] = sample;
+    fir->history[fir->curr_pos + fir->taps] = sample;
+
+    mmx_coeffs = (mmx_t *) fir->coeffs;
+    mmx_hist = (mmx_t *) &fir->history[fir->curr_pos];
+    i = fir->taps;
+    pxor_r2r(mm4, mm4);
+    /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
+    while (i > 0)
+    {
+        movq_m2r(mmx_coeffs[0], mm0);
+        movq_m2r(mmx_coeffs[1], mm2);
+        movq_m2r(mmx_hist[0], mm1);
+        movq_m2r(mmx_hist[1], mm3);
+        mmx_coeffs += 2;
+        mmx_hist += 2;
+        pmaddwd_r2r(mm1, mm0);
+        pmaddwd_r2r(mm3, mm2);
+        paddd_r2r(mm0, mm4);
+        paddd_r2r(mm2, mm4);
+        i -= 8;
+    }
+    movq_r2r(mm4, mm0);
+    psrlq_i2r(32, mm0);
+    paddd_r2r(mm0, mm4);
+    movd_r2m(mm4, y);
+    emms();
+#elif defined(USE_SSE2)
+    int i;
+    xmm_t *xmm_coeffs;
+    xmm_t *xmm_hist;
+
+    fir->history[fir->curr_pos] = sample;
+    fir->history[fir->curr_pos + fir->taps] = sample;
+
+    xmm_coeffs = (xmm_t *) fir->coeffs;
+    xmm_hist = (xmm_t *) &fir->history[fir->curr_pos];
+    i = fir->taps;
+    pxor_r2r(xmm4, xmm4);
+    /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
+    while (i > 0)
+    {
+        movdqu_m2r(xmm_coeffs[0], xmm0);
+        movdqu_m2r(xmm_coeffs[1], xmm2);
+        movdqu_m2r(xmm_hist[0], xmm1);
+        movdqu_m2r(xmm_hist[1], xmm3);
+        xmm_coeffs += 2;
+        xmm_hist += 2;
+        pmaddwd_r2r(xmm1, xmm0);
+        pmaddwd_r2r(xmm3, xmm2);
+        paddd_r2r(xmm0, xmm4);
+        paddd_r2r(xmm2, xmm4);
+        i -= 16;
+    }
+    movdqa_r2r(xmm4, xmm0);
+    psrldq_i2r(8, xmm0);
+    paddd_r2r(xmm0, xmm4);
+    movdqa_r2r(xmm4, xmm0);
+    psrldq_i2r(4, xmm0);
+    paddd_r2r(xmm0, xmm4);
+    movd_r2m(xmm4, y);
+#elif defined(__BLACKFIN_ASM__)
+    fir->history[fir->curr_pos] = sample;
+    fir->history[fir->curr_pos + fir->taps] = sample;
+    y = dot_asm((int16_t*)fir->coeffs, &fir->history[fir->curr_pos], fir->taps);
+#else
+    int i;
+    int offset1;
+    int offset2;
+
+    fir->history[fir->curr_pos] = sample;
+
+    offset2 = fir->curr_pos;
+    offset1 = fir->taps - offset2;
+    y = 0;
+    for (i = fir->taps - 1;  i >= offset1;  i--)
+        y += fir->coeffs[i]*fir->history[i - offset1];
+    for (  ;  i >= 0;  i--)
+        y += fir->coeffs[i]*fir->history[i + offset2];
+#endif
+    if (fir->curr_pos <= 0)
+    	fir->curr_pos = fir->taps;
+    fir->curr_pos--;
+    return (int16_t) (y >> 15);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const int16_t *fir32_create(fir32_state_t *fir,
+                                              const int32_t *coeffs,
+                                              int taps)
+{
+    fir->taps = taps;
+    fir->curr_pos = taps - 1;
+    fir->coeffs = coeffs;
+    fir->history = (int16_t *) malloc(taps*sizeof(int16_t));
+    if (fir->history)
+    	memset(fir->history, '\0', taps*sizeof(int16_t));
+    return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_flush(fir32_state_t *fir)
+{
+    memset(fir->history, 0, fir->taps*sizeof(int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_free(fir32_state_t *fir)
+{
+    free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample)
+{
+    int i;
+    int32_t y;
+    int offset1;
+    int offset2;
+
+    fir->history[fir->curr_pos] = sample;
+    offset2 = fir->curr_pos;
+    offset1 = fir->taps - offset2;
+    y = 0;
+    for (i = fir->taps - 1;  i >= offset1;  i--)
+        y += fir->coeffs[i]*fir->history[i - offset1];
+    for (  ;  i >= 0;  i--)
+        y += fir->coeffs[i]*fir->history[i + offset2];
+    if (fir->curr_pos <= 0)
+    	fir->curr_pos = fir->taps;
+    fir->curr_pos--;
+    return (int16_t) (y >> 15);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const float *fir_float_create(fir_float_state_t *fir,
+                                                const float *coeffs,
+    	    	    	                        int taps)
+{
+    fir->taps = taps;
+    fir->curr_pos = taps - 1;
+    fir->coeffs = coeffs;
+    fir->history = (float *) malloc(taps*sizeof(float));
+    if (fir->history)
+        memset(fir->history, '\0', taps*sizeof(float));
+    return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+    
+static __inline__ void fir_float_free(fir_float_state_t *fir)
+{
+    free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample)
+{
+    int i;
+    float y;
+    int offset1;
+    int offset2;
+
+    fir->history[fir->curr_pos] = sample;
+
+    offset2 = fir->curr_pos;
+    offset1 = fir->taps - offset2;
+    y = 0;
+    for (i = fir->taps - 1;  i >= offset1;  i--)
+        y += fir->coeffs[i]*fir->history[i - offset1];
+    for (  ;  i >= 0;  i--)
+        y += fir->coeffs[i]*fir->history[i + offset2];
+    if (fir->curr_pos <= 0)
+    	fir->curr_pos = fir->taps;
+    fir->curr_pos--;
+    return  (int16_t) y;
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/




More information about the Pkg-voip-commits mailing list