Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 960366cf authored by Karsten Keil's avatar Karsten Keil
Browse files

Add mISDN DSP



Enable support for digital audio processing capability.
This module may be used for special applications that require
cross connecting of bchannels, conferencing, dtmf decoding
echo cancelation, tone generation, and Blowfish encryption and
decryption.
It may use hardware features if available.

Signed-off-by: default avatarKarsten Keil <kkeil@suse.de>
parent 1b2b03f8
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -7,3 +7,21 @@ menuconfig MISDN
	help
	  Enable support for the modular ISDN driver.

if MISDN != n

config MISDN_DSP
	tristate "Digital Audio Processing of transparent data"
	depends on MISDN
	help
	  Enable support for digital audio processing capability.
	  This module may be used for special applications that require
	  cross connecting of bchannels, conferencing, dtmf decoding
	  echo cancelation, tone generation, and Blowfish encryption and
	  decryption.
	  It may use hardware features if available.
	  E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu
	  and get more informations about this module and it's usage.
	  If unsure, say 'N'.

	source "drivers/isdn/hardware/mISDN/Kconfig"
endif #MISDN
+2 −0
Original line number Diff line number Diff line
@@ -3,7 +3,9 @@
#

obj-$(CONFIG_MISDN) += mISDN_core.o
obj-$(CONFIG_MISDN_DSP) += mISDN_dsp.o

# multi objects

mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o
+263 −0
Original line number Diff line number Diff line
/*
 * Audio support data for ISDN4Linux.
 *
 * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#define DEBUG_DSP_CTRL		0x0001
#define DEBUG_DSP_CORE		0x0002
#define DEBUG_DSP_DTMF		0x0004
#define DEBUG_DSP_CMX		0x0010
#define DEBUG_DSP_TONE		0x0020
#define DEBUG_DSP_BLOWFISH	0x0040
#define DEBUG_DSP_DELAY		0x0100
#define DEBUG_DSP_DTMFCOEFF	0x8000 /* heavy output */

/* options may be:
 *
 * bit 0 = use ulaw instead of alaw
 * bit 1 = enable hfc hardware accelleration for all channels
 *
 */
#define DSP_OPT_ULAW		(1<<0)
#define DSP_OPT_NOHARDWARE	(1<<1)

#include <linux/timer.h>
#include <linux/workqueue.h>

#include "dsp_ecdis.h"

extern int dsp_options;
extern int dsp_debug;
extern int dsp_poll;
extern int dsp_tics;
extern spinlock_t dsp_lock;
extern struct work_struct dsp_workq;
extern u32 dsp_poll_diff; /* calculated fix-comma corrected poll value */

/***************
 * audio stuff *
 ***************/

extern s32 dsp_audio_alaw_to_s32[256];
extern s32 dsp_audio_ulaw_to_s32[256];
extern s32 *dsp_audio_law_to_s32;
extern u8 dsp_audio_s16_to_law[65536];
extern u8 dsp_audio_alaw_to_ulaw[256];
extern u8 dsp_audio_mix_law[65536];
extern u8 dsp_audio_seven2law[128];
extern u8 dsp_audio_law2seven[256];
extern void dsp_audio_generate_law_tables(void);
extern void dsp_audio_generate_s2law_table(void);
extern void dsp_audio_generate_seven(void);
extern void dsp_audio_generate_mix_table(void);
extern void dsp_audio_generate_ulaw_samples(void);
extern void dsp_audio_generate_volume_changes(void);
extern u8 dsp_silence;


/*************
 * cmx stuff *
 *************/

#define MAX_POLL	256	/* maximum number of send-chunks */

#define CMX_BUFF_SIZE	0x8000	/* must be 2**n (0x1000 about 1/2 second) */
#define CMX_BUFF_HALF	0x4000	/* CMX_BUFF_SIZE / 2 */
#define CMX_BUFF_MASK	0x7fff	/* CMX_BUFF_SIZE - 1 */

/* how many seconds will we check the lowest delay until the jitter buffer
   is reduced by that delay */
#define MAX_SECONDS_JITTER_CHECK 5

extern struct timer_list dsp_spl_tl;
extern u32 dsp_spl_jiffies;

/* the structure of conferences:
 *
 * each conference has a unique number, given by user space.
 * the conferences are linked in a chain.
 * each conference has members linked in a chain.
 * each dsplayer points to a member, each member points to a dsplayer.
 */

/* all members within a conference (this is linked 1:1 with the dsp) */
struct dsp;
struct dsp_conf_member {
	struct list_head	list;
	struct dsp		*dsp;
};

/* the list of all conferences */
struct dsp_conf {
	struct list_head	list;
	u32			id;
				/* all cmx stacks with the same ID are
				 connected */
	struct list_head	mlist;
	int			software; /* conf is processed by software */
	int			hardware; /* conf is processed by hardware */
				/* note: if both unset, has only one member */
};


/**************
 * DTMF stuff *
 **************/

#define DSP_DTMF_NPOINTS 102

#define ECHOCAN_BUFLEN (4*128)

struct dsp_dtmf {
	int		treshold; /* above this is dtmf (square of) */
	int		software; /* dtmf uses software decoding */
	int		hardware; /* dtmf uses hardware decoding */
	int		size; /* number of bytes in buffer */
	signed short	buffer[DSP_DTMF_NPOINTS];
		/* buffers one full dtmf frame */
	u8		lastwhat, lastdigit;
	int		count;
	u8		digits[16]; /* just the dtmf result */
};


/******************
 * pipeline stuff *
 ******************/
struct dsp_pipeline {
	rwlock_t  lock;
	struct list_head list;
	int inuse;
};

/***************
 * tones stuff *
 ***************/

struct dsp_tone {
	int		software; /* tones are generated by software */
	int		hardware; /* tones are generated by hardware */
	int		tone;
	void		*pattern;
	int		count;
	int		index;
	struct timer_list tl;
};

/*****************
 * general stuff *
 *****************/

struct dsp {
	struct list_head list;
	struct mISDNchannel	ch;
	struct mISDNchannel	*up;
	unsigned char	name[64];
	int		b_active;
	int		echo; /* echo is enabled */
	int		rx_disabled; /* what the user wants */
	int		rx_is_off; /* what the card is */
	int		tx_mix;
	struct dsp_tone	tone;
	struct dsp_dtmf	dtmf;
	int		tx_volume, rx_volume;

	/* queue for sending frames */
	struct work_struct	workq;
	struct sk_buff_head	sendq;
	int		hdlc;	/* if mode is hdlc */
	int		data_pending;	/* currently an unconfirmed frame */

	/* conference stuff */
	u32		conf_id;
	struct dsp_conf	*conf;
	struct dsp_conf_member
			*member;

	/* buffer stuff */
	int		rx_W; /* current write pos for data without timestamp */
	int		rx_R; /* current read pos for transmit clock */
	int		rx_init; /* if set, pointers will be adjusted first */
	int		tx_W; /* current write pos for transmit data */
	int		tx_R; /* current read pos for transmit clock */
	int		rx_delay[MAX_SECONDS_JITTER_CHECK];
	int		tx_delay[MAX_SECONDS_JITTER_CHECK];
	u8		tx_buff[CMX_BUFF_SIZE];
	u8		rx_buff[CMX_BUFF_SIZE];
	int		last_tx; /* if set, we transmitted last poll interval */
	int		cmx_delay; /* initial delay of buffers,
				or 0 for dynamic jitter buffer */
	int		tx_dejitter; /* if set, dejitter tx buffer */
	int		tx_data; /* enables tx-data of CMX to upper layer */

	/* hardware stuff */
	struct dsp_features features;
	int		features_rx_off; /* set if rx_off is featured */
	int		pcm_slot_rx; /* current PCM slot (or -1) */
	int		pcm_bank_rx;
	int		pcm_slot_tx;
	int		pcm_bank_tx;
	int		hfc_conf; /* unique id of current conference (or -1) */

	/* encryption stuff */
	int		bf_enable;
	u32		bf_p[18];
	u32		bf_s[1024];
	int		bf_crypt_pos;
	u8		bf_data_in[9];
	u8		bf_crypt_out[9];
	int		bf_decrypt_in_pos;
	int		bf_decrypt_out_pos;
	u8		bf_crypt_inring[16];
	u8		bf_data_out[9];
	int		bf_sync;

	struct dsp_pipeline
			pipeline;
};

/* functions */

extern void dsp_change_volume(struct sk_buff *skb, int volume);

extern struct list_head dsp_ilist;
extern struct list_head conf_ilist;
extern void dsp_cmx_debug(struct dsp *dsp);
extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp);
extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id);
extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb);
extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb);
extern void dsp_cmx_send(void *arg);
extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb);
extern int dsp_cmx_del_conf_member(struct dsp *dsp);
extern int dsp_cmx_del_conf(struct dsp_conf *conf);

extern void dsp_dtmf_goertzel_init(struct dsp *dsp);
extern void dsp_dtmf_hardware(struct dsp *dsp);
extern u8 *dsp_dtmf_goertzel_decode(struct dsp *dsp, u8 *data, int len,
		int fmt);

extern int dsp_tone(struct dsp *dsp, int tone);
extern void dsp_tone_copy(struct dsp *dsp, u8 *data, int len);
extern void dsp_tone_timeout(void *arg);

extern void dsp_bf_encrypt(struct dsp *dsp, u8 *data, int len);
extern void dsp_bf_decrypt(struct dsp *dsp, u8 *data, int len);
extern int dsp_bf_init(struct dsp *dsp, const u8 *key, unsigned int keylen);
extern void dsp_bf_cleanup(struct dsp *dsp);

extern int  dsp_pipeline_module_init(void);
extern void dsp_pipeline_module_exit(void);
extern int  dsp_pipeline_init(struct dsp_pipeline *pipeline);
extern void dsp_pipeline_destroy(struct dsp_pipeline *pipeline);
extern int  dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg);
extern void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data,
		int len);
extern void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data,
		int len);
+434 −0
Original line number Diff line number Diff line
/*
 * Audio support data for mISDN_dsp.
 *
 * Copyright 2002/2003 by Andreas Eversberg (jolly@eversberg.eu)
 * Rewritten by Peter
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#include <linux/delay.h>
#include <linux/mISDNif.h>
#include <linux/mISDNdsp.h>
#include "core.h"
#include "dsp.h"

/* ulaw[unsigned char] -> signed 16-bit */
s32 dsp_audio_ulaw_to_s32[256];
/* alaw[unsigned char] -> signed 16-bit */
s32 dsp_audio_alaw_to_s32[256];

s32 *dsp_audio_law_to_s32;
EXPORT_SYMBOL(dsp_audio_law_to_s32);

/* signed 16-bit -> law */
u8 dsp_audio_s16_to_law[65536];
EXPORT_SYMBOL(dsp_audio_s16_to_law);

/* alaw -> ulaw */
u8 dsp_audio_alaw_to_ulaw[256];
/* ulaw -> alaw */
u8 dsp_audio_ulaw_to_alaw[256];
u8 dsp_silence;


/*****************************************************
 * generate table for conversion of s16 to alaw/ulaw *
 *****************************************************/

#define AMI_MASK 0x55

static inline unsigned char linear2alaw(short int linear)
{
	int mask;
	int seg;
	int pcm_val;
	static int seg_end[8] = {
		0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
	};

	pcm_val = linear;
	if (pcm_val >= 0) {
		/* Sign (7th) bit = 1 */
		mask = AMI_MASK | 0x80;
	} else {
		/* Sign bit = 0 */
		mask = AMI_MASK;
		pcm_val = -pcm_val;
	}

	/* Convert the scaled magnitude to segment number. */
	for (seg = 0;  seg < 8;  seg++) {
		if (pcm_val <= seg_end[seg])
			break;
	}
	/* Combine the sign, segment, and quantization bits. */
	return  ((seg << 4) |
		 ((pcm_val >> ((seg)  ?  (seg + 3)  :  4)) & 0x0F)) ^ mask;
}


static inline short int alaw2linear(unsigned char alaw)
{
	int i;
	int seg;

	alaw ^= AMI_MASK;
	i = ((alaw & 0x0F) << 4) + 8 /* rounding error */;
	seg = (((int) alaw & 0x70) >> 4);
	if (seg)
		i = (i + 0x100) << (seg - 1);
	return (short int) ((alaw & 0x80)  ?  i  :  -i);
}

static inline short int ulaw2linear(unsigned char ulaw)
{
	short mu, e, f, y;
	static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764};

	mu = 255 - ulaw;
	e = (mu & 0x70) / 16;
	f = mu & 0x0f;
	y = f * (1 << (e + 3));
	y += etab[e];
	if (mu & 0x80)
		y = -y;
	return y;
}

#define BIAS 0x84   /*!< define the add-in bias for 16 bit samples */

static unsigned char linear2ulaw(short sample)
{
	static int exp_lut[256] = {
		0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
		4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
		5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
		6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
		7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
	int sign, exponent, mantissa;
	unsigned char ulawbyte;

	/* Get the sample into sign-magnitude. */
	sign = (sample >> 8) & 0x80;	  /* set aside the sign */
	if (sign != 0)
		sample = -sample;	      /* get magnitude */

	/* Convert from 16 bit linear to ulaw. */
	sample = sample + BIAS;
	exponent = exp_lut[(sample >> 7) & 0xFF];
	mantissa = (sample >> (exponent + 3)) & 0x0F;
	ulawbyte = ~(sign | (exponent << 4) | mantissa);

	return ulawbyte;
}

static int reverse_bits(int i)
{
	int z, j;
	z = 0;

	for (j = 0; j < 8; j++) {
		if ((i & (1 << j)) != 0)
			z |= 1 << (7 - j);
	}
	return z;
}


void dsp_audio_generate_law_tables(void)
{
	int i;
	for (i = 0; i < 256; i++)
		dsp_audio_alaw_to_s32[i] = alaw2linear(reverse_bits(i));

	for (i = 0; i < 256; i++)
		dsp_audio_ulaw_to_s32[i] = ulaw2linear(reverse_bits(i));

	for (i = 0; i < 256; i++) {
		dsp_audio_alaw_to_ulaw[i] =
			linear2ulaw(dsp_audio_alaw_to_s32[i]);
		dsp_audio_ulaw_to_alaw[i] =
			linear2alaw(dsp_audio_ulaw_to_s32[i]);
	}
}

void
dsp_audio_generate_s2law_table(void)
{
	int i;

	if (dsp_options & DSP_OPT_ULAW) {
		/* generating ulaw-table */
		for (i = -32768; i < 32768; i++) {
			dsp_audio_s16_to_law[i & 0xffff] =
				reverse_bits(linear2ulaw(i));
		}
	} else {
		/* generating alaw-table */
		for (i = -32768; i < 32768; i++) {
			dsp_audio_s16_to_law[i & 0xffff] =
				reverse_bits(linear2alaw(i));
		}
	}
}


/*
 * the seven bit sample is the number of every second alaw-sample ordered by
 * aplitude. 0x00 is negative, 0x7f is positive amplitude.
 */
u8 dsp_audio_seven2law[128];
u8 dsp_audio_law2seven[256];

/********************************************************************
 * generate table for conversion law from/to 7-bit alaw-like sample *
 ********************************************************************/

void
dsp_audio_generate_seven(void)
{
	int i, j, k;
	u8 spl;
	u8 sorted_alaw[256];

	/* generate alaw table, sorted by the linear value */
	for (i = 0; i < 256; i++) {
		j = 0;
		for (k = 0; k < 256; k++) {
			if (dsp_audio_alaw_to_s32[k]
				< dsp_audio_alaw_to_s32[i]) {
			j++;
			}
		}
		sorted_alaw[j] = i;
	}

	/* generate tabels */
	for (i = 0; i < 256; i++) {
		/* spl is the source: the law-sample (converted to alaw) */
		spl = i;
		if (dsp_options & DSP_OPT_ULAW)
			spl = dsp_audio_ulaw_to_alaw[i];
		/* find the 7-bit-sample */
		for (j = 0; j < 256; j++) {
			if (sorted_alaw[j] == spl)
				break;
		}
		/* write 7-bit audio value */
		dsp_audio_law2seven[i] = j >> 1;
	}
	for (i = 0; i < 128; i++) {
		spl = sorted_alaw[i << 1];
		if (dsp_options & DSP_OPT_ULAW)
			spl = dsp_audio_alaw_to_ulaw[spl];
		dsp_audio_seven2law[i] = spl;
	}
}


/* mix 2*law -> law */
u8 dsp_audio_mix_law[65536];

/******************************************************
 * generate mix table to mix two law samples into one *
 ******************************************************/

void
dsp_audio_generate_mix_table(void)
{
	int i, j;
	s32 sample;

	i = 0;
	while (i < 256) {
		j = 0;
		while (j < 256) {
			sample = dsp_audio_law_to_s32[i];
			sample += dsp_audio_law_to_s32[j];
			if (sample > 32767)
				sample = 32767;
			if (sample < -32768)
				sample = -32768;
			dsp_audio_mix_law[(i<<8)|j] =
				dsp_audio_s16_to_law[sample & 0xffff];
			j++;
		}
		i++;
	}
}


/*************************************
 * generate different volume changes *
 *************************************/

static u8 dsp_audio_reduce8[256];
static u8 dsp_audio_reduce7[256];
static u8 dsp_audio_reduce6[256];
static u8 dsp_audio_reduce5[256];
static u8 dsp_audio_reduce4[256];
static u8 dsp_audio_reduce3[256];
static u8 dsp_audio_reduce2[256];
static u8 dsp_audio_reduce1[256];
static u8 dsp_audio_increase1[256];
static u8 dsp_audio_increase2[256];
static u8 dsp_audio_increase3[256];
static u8 dsp_audio_increase4[256];
static u8 dsp_audio_increase5[256];
static u8 dsp_audio_increase6[256];
static u8 dsp_audio_increase7[256];
static u8 dsp_audio_increase8[256];

static u8 *dsp_audio_volume_change[16] = {
	dsp_audio_reduce8,
	dsp_audio_reduce7,
	dsp_audio_reduce6,
	dsp_audio_reduce5,
	dsp_audio_reduce4,
	dsp_audio_reduce3,
	dsp_audio_reduce2,
	dsp_audio_reduce1,
	dsp_audio_increase1,
	dsp_audio_increase2,
	dsp_audio_increase3,
	dsp_audio_increase4,
	dsp_audio_increase5,
	dsp_audio_increase6,
	dsp_audio_increase7,
	dsp_audio_increase8,
};

void
dsp_audio_generate_volume_changes(void)
{
	register s32 sample;
	int i;
	int num[]   = { 110, 125, 150, 175, 200, 300, 400, 500 };
	int denum[] = { 100, 100, 100, 100, 100, 100, 100, 100 };

	i = 0;
	while (i < 256) {
		dsp_audio_reduce8[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[7] / num[7]) & 0xffff];
		dsp_audio_reduce7[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[6] / num[6]) & 0xffff];
		dsp_audio_reduce6[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[5] / num[5]) & 0xffff];
		dsp_audio_reduce5[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[4] / num[4]) & 0xffff];
		dsp_audio_reduce4[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[3] / num[3]) & 0xffff];
		dsp_audio_reduce3[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[2] / num[2]) & 0xffff];
		dsp_audio_reduce2[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[1] / num[1]) & 0xffff];
		dsp_audio_reduce1[i] = dsp_audio_s16_to_law[
			(dsp_audio_law_to_s32[i] * denum[0] / num[0]) & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[0] / denum[0];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase1[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[1] / denum[1];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase2[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[2] / denum[2];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase3[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[3] / denum[3];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase4[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[4] / denum[4];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase5[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[5] / denum[5];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase6[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[6] / denum[6];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase7[i] = dsp_audio_s16_to_law[sample & 0xffff];
		sample = dsp_audio_law_to_s32[i] * num[7] / denum[7];
		if (sample < -32768)
			sample = -32768;
		else if (sample > 32767)
			sample = 32767;
		dsp_audio_increase8[i] = dsp_audio_s16_to_law[sample & 0xffff];

		i++;
	}
}


/**************************************
 * change the volume of the given skb *
 **************************************/

/* this is a helper function for changing volume of skb. the range may be
 * -8 to 8, which is a shift to the power of 2. 0 == no volume, 3 == volume*8
 */
void
dsp_change_volume(struct sk_buff *skb, int volume)
{
	u8 *volume_change;
	int i, ii;
	u8 *p;
	int shift;

	if (volume == 0)
		return;

	/* get correct conversion table */
	if (volume < 0) {
		shift = volume + 8;
		if (shift < 0)
			shift = 0;
	} else {
		shift = volume + 7;
		if (shift > 15)
			shift = 15;
	}
	volume_change = dsp_audio_volume_change[shift];
	i = 0;
	ii = skb->len;
	p = skb->data;
	/* change volume */
	while (i < ii) {
		*p = volume_change[*p];
		p++;
		i++;
	}
}
+65 −0
Original line number Diff line number Diff line
/*
 * SpanDSP - a series of DSP components for telephony
 *
 * biquad.h - General telephony bi-quad section routines (currently this just
 *            handles canonic/type 2 form)
 *
 * Written by Steve Underwood <steveu@coppice.org>
 *
 * Copyright (C) 2001 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 as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 */

struct biquad2_state {
	int32_t gain;
	int32_t a1;
	int32_t a2;
	int32_t b1;
	int32_t b2;

	int32_t z1;
	int32_t z2;
};

static inline void biquad2_init(struct biquad2_state *bq,
    int32_t gain, int32_t a1, int32_t a2, int32_t b1, int32_t b2)
{
	bq->gain = gain;
	bq->a1 = a1;
	bq->a2 = a2;
	bq->b1 = b1;
	bq->b2 = b2;

	bq->z1 = 0;
	bq->z2 = 0;
}

static inline int16_t biquad2(struct biquad2_state *bq, int16_t sample)
{
	int32_t y;
	int32_t z0;

	z0 = sample*bq->gain + bq->z1*bq->a1 + bq->z2*bq->a2;
	y = z0 + bq->z1*bq->b1 + bq->z2*bq->b2;

	bq->z2 = bq->z1;
	bq->z1 = z0 >> 15;
	y >>= 15;
	return  y;
}
Loading