提交 10c6a30a authored 作者: Eric des Courtis's avatar Eric des Courtis

Added new FreeSWITCH module mod_avmd or the Advanced Voicemail Detection Module.

It provides better detection than mod_vmd but is a little more CPU intensive than mod_vmd.

Perhaps someone would like to CUDAfy this code?
上级 596c0012
BASE=../../../..
MOD_CFLAGS= -march=core2 -g -O2 -malign-double -mtune=core2 -mmmx -msse -msse2 -msse3 -mssse3 -mfpmath=sse -ffast-math -funroll-loops -fprefetch-loop-arrays -funit-at-a-time -ftracer --save-temps
MOD_LDFLAGS= --save-temps
LOCAL_SOURCES=amplitude.c buffer.c desa2.c goertzel.c fast_acosf.c
LOCAL_OBJS=amplitude.o buffer.o desa2.o goertzel.o fast_acosf.o
include $(BASE)/build/modmake.rules
#compute_table: compute_table.o
# gcc -o compute_table compute_table.o -lm
#
#compute_table.o: compute_table.c
# gcc -c compute_table.c
#
#ifndef __AMPLITUDE_H__
#include <math.h>
#include "amplitude.h"
#include "psi.h"
/*! \brief
* @author Eric des Courtis
* @param b A circular audio sample buffer
* @param i Position in the buffer
* @param f Frequency estimate
* @return The amplitude at position i
*/
extern double amplitude(circ_buffer_t *b, size_t i, double f)
{
double result;
result = sqrt(PSI(b, i) / sin(f * f));
return result;
}
#endif
#ifndef __AMPLITUDE_H__
#define __AMPLITUDE_H__
#include "buffer.h"
extern double amplitude(circ_buffer_t *, size_t i, double f);
#endif
#ifndef __BUFFER_H__
#include "buffer.h"
#endif
extern size_t next_power_of_2(size_t v)
{
size_t prev;
size_t tmp = 1;
v++;
do{
prev = v;
v &= ~tmp;
tmp <<= 1;
}while(v != 0);
prev <<= 1;
return prev;
}
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <stdlib.h>
#include <assert.h>
#define BUFF_TYPE double
typedef struct {
size_t pos;
size_t lpos;
BUFF_TYPE *buf;
size_t buf_len;
size_t mask;
size_t i;
size_t backlog;
} circ_buffer_t;
extern size_t next_power_of_2(size_t v);
#define INC_POS(b) \
do{ \
(b)->pos++; \
(b)->pos &= (b)->mask; \
(b)->lpos++; \
if((b)->backlog < (b)->buf_len) (b)->backlog++; \
}while(0)
#define DEC_POS(b) \
do{ \
(b)->pos--; \
(b)->pos &= (b)->mask; \
(b)->lpos--; \
if(((b)->backlog - 1) < (b)->backlog) (b)->backlog--; \
}while(0)
#define GET_SAMPLE(b, i) ((b)->buf[(i) & (b)->mask])
#define SET_SAMPLE(b, i, v) ((b)->buf[(i) & (b)->mask] = (v))
#define INSERT_FRAME(b, f, l) \
do{ \
for((b)->i = 0; (b)->i < (l); (b)->i++){ \
SET_SAMPLE((b), ((b)->i + (b)->pos), (f)[(b)->i]); \
} \
(b)->pos += (l); \
(b)->lpos += (l); \
(b)->pos %= (b)->buf_len; \
(b)->backlog += (l); \
if((b)->backlog > (b)->buf_len) (b)->backlog = (b)->buf_len; \
}while(0)
#define INSERT_INT16_FRAME(b, f, l) \
do{ \
for((b)->i = 0; (b)->i < (l); (b)->i++){ \
SET_SAMPLE( \
(b), \
((b)->i + (b)->pos), \
( \
((f)[(b)->i] >= 0) ? \
((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MAX): \
(0.0 - ((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MIN)) \
) \
); \
} \
(b)->pos += (l); \
(b)->lpos += (l); \
(b)->pos &= (b)->mask; \
(b)->backlog += (l); \
if((b)->backlog > (b)->buf_len) (b)->backlog = (b)->buf_len; \
}while(0)
#define CALC_BUFF_LEN(fl, bl) (((fl) >= (bl))? next_power_of_2((fl) << 1): next_power_of_2((bl) << 1))
#define INIT_CIRC_BUFFER(bf, bl, fl) \
do{ \
(bf)->buf_len = CALC_BUFF_LEN((fl), (bl)); \
(bf)->mask = (bf)->buf_len - 1; \
(bf)->buf = (BUFF_TYPE *)calloc((bf)->buf_len, sizeof(BUFF_TYPE)); \
assert((bf)->buf != NULL); \
(bf)->pos = 0; \
(bf)->lpos = 0; \
(bf)->backlog = 0; \
}while(0)
#define DESTROY_CIRC_BUFFER(b) free((b)->buf)
#define GET_BACKLOG_POS(b) ((b)->lpos - (b)->backlog)
#define GET_CURRENT_POS(b) ((b)->lpos)
#define GET_CURRENT_SAMPLE(b) GET_SAMPLE((b), GET_CURRENT_POS((b)))
#define ADD_SAMPLE(b, s) \
do{ \
INC_POS((b)); \
SET_SAMPLE((b), GET_CURRENT_POS((b)), (s)); \
}while(0)
#endif
#ifndef __DESA2_H__
#include <stdio.h>
#ifdef WIN32
#include <float.h>
#define ISNAN(x) (!!(_isnan(x)))
#else
#define ISNAN(x) (isnan(x))
#endif
#include "buffer.h"
#include "desa2.h"
#include "options.h"
#ifdef FASTMATH
#include "fast_acosf.h"
#endif
extern double desa2(circ_buffer_t *b, size_t i)
{
double d;
double n;
double x0;
double x1;
double x2;
double x3;
double x4;
double x2sq;
double result;
x0 = GET_SAMPLE((b), (i));
x1 = GET_SAMPLE((b), ((i) + 1));
x2 = GET_SAMPLE((b), ((i) + 2));
x3 = GET_SAMPLE((b), ((i) + 3));
x4 = GET_SAMPLE((b), ((i) + 4));
x2sq = x2 * x2;
d = 2.0 * ((x2sq) - (x1 * x3));
if(d == 0.0) return 0.0;
n = ((x2sq) - (x0 * x4)) - ((x1 * x1) - (x0 * x2)) - ((x3 * x3) - (x2 * x4));
#ifdef FASTMATH
result = 0.5 * (double)fast_acosf((float)n/d);
#else
result = 0.5 * acos(n/d);
#endif
if(ISNAN(result)){
result = 0.0;
}
return result;
}
#endif
#ifndef __DESA2_H__
#define __DESA2_H__
#include <math.h>
#include "buffer.h"
extern double desa2(circ_buffer_t *b, size_t i);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include "fast_acosf.h"
#define SIGN_MASK (0x80000000)
#define DATA_MASK (0x07FFFFF8)
#define SIGN_UNPACK_MASK (0x01000000)
#define DATA_UNPACK_MASK (0x00FFFFFF)
#define VARIA_DATA_MASK (0x87FFFFF8)
#define CONST_DATA_MASK (0x38000000)
#define ACOS_TABLE_LENGTH (1<<25)
#define ACOS_TABLE_FILENAME "/tmp/acos_table.dat"
typedef union {
uint32_t i;
float f;
} float_conv_t;
#ifdef FAST_ACOSF_TESTING
static float strip_float(float f);
#endif
static uint32_t index_from_float(float f);
static float float_from_index(uint32_t d);
static float *acos_table = NULL;
static int acos_fd = -1;
#ifdef FAST_ACOSF_TESTING
static float strip_float(float f)
{
float_conv_t d;
d.i = d.i & (VARIA_DATA_MASK | CONST_DATA_MASK);
return d.i;
}
#endif
extern void compute_table(void)
{
uint32_t i;
float f;
FILE *acos_table_file;
size_t ret;
acos_table_file = fopen(ACOS_TABLE_FILENAME, "w");
for(i = 0; i < (1 << 25); i++){
f = acosf(float_from_index(i));
ret = fwrite(&f, sizeof(f), 1, acos_table_file);
assert(ret != 0);
}
ret = fclose(acos_table_file);
assert(ret != EOF);
}
extern void init_fast_acosf(void)
{
int ret;
if(acos_table == NULL){
ret = access(ACOS_TABLE_FILENAME, F_OK);
if(ret == 0) compute_table();
acos_fd = open(ACOS_TABLE_FILENAME, O_RDONLY);
if(acos_fd == -1) perror("Could not open file " ACOS_TABLE_FILENAME);
assert(acos_fd != -1);
acos_table = (float *)mmap(
NULL,
ACOS_TABLE_LENGTH * sizeof(float),
PROT_READ,
MAP_SHARED | MAP_POPULATE,
acos_fd,
0
);
}
}
extern void destroy_fast_acosf(void)
{
int ret;
ret = munmap(acos_table, ACOS_TABLE_LENGTH);
assert(ret != -1);
ret = close(acos_fd);
assert(ret != -1);
acos_table = NULL;
}
extern float fast_acosf(float x)
{
return acos_table[index_from_float(x)];
}
static uint32_t index_from_float(float f)
{
float_conv_t d;
d.f = f;
return ((d.i & SIGN_MASK) >> 7) | ((d.i & DATA_MASK) >> 3);
}
static float float_from_index(uint32_t d)
{
float_conv_t f;
f.i = ((d & SIGN_UNPACK_MASK) << 7) | ((d & DATA_UNPACK_MASK) << 3) | CONST_DATA_MASK;
return f.f;
}
#ifndef __FAST_ACOSF_H__
#define __FAST_ACOSF_H__
extern void init_fast_acosf(void);
extern float fast_acosf(float x);
extern void destroy_fast_acosf(void);
extern void compute_table(void);
#endif
#ifndef __GOERTZEL_H__
#include <math.h>
#include "goertzel.h"
#include "buffer.h"
/*! \brief Identify frequency components of a signal
* @author Eric des Courtis
* @param b A circular buffer
* @param pos Position in the buffer
* @param f Frequency to look at
* @param num Number of samples to look at
* @return A power estimate for frequency f at position pos in the stream
*/
extern double goertzel(circ_buffer_t *b, size_t pos, double f, size_t num)
{
double s = 0.0;
double p = 0.0;
double p2 = 0.0;
double coeff;
size_t i;
coeff = 2.0 * cos(2.0 * M_PI * f);
for(i = 0; i < num; i++){
/* TODO: optimize to avoid GET_SAMPLE when possible */
s = GET_SAMPLE(b, i + pos) + (coeff * p) - p2;
p2 = p;
p = s;
}
return (p2 * p2) + (p * p) - (coeff * p2 * p);
}
#endif
#ifndef __GOERTZEL_H__
#define __GOERTZEL_H__
#include <stdint.h>
#include "buffer.h"
extern double goertzel(circ_buffer_t *b, size_t pos, double f, size_t num);
#endif
差异被折叠。
#ifndef __OPTIONS_H__
#define __OPTIONS_H__
/* #define FASTMATH */
#endif
#ifndef __PSI_H__
#define __PSI_H__
#include "buffer.h"
#define PSI(b, i) (GET_SAMPLE((b), ((i) + 1))*GET_SAMPLE((b), ((i) + 1))-GET_SAMPLE((b), ((i) + 2))*GET_SAMPLE((b), ((i) + 0)))
#endif
#ifndef __SMA_BUFFER_H__
#define __SMA_BUFFER_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include "buffer.h"
typedef struct {
size_t len;
BUFF_TYPE *data;
BUFF_TYPE sma;
size_t pos;
size_t lpos;
} sma_buffer_t;
#define INIT_SMA_BUFFER(b, l, s) \
do{ \
(void)memset((b), 0, sizeof(sma_buffer_t)); \
(b)->len = (l); \
(b)->data = (BUFF_TYPE *)switch_core_session_alloc((s), sizeof(BUFF_TYPE) * (l)); \
assert((b)->data != NULL); \
(void)memset((b)->data, 0, sizeof(BUFF_TYPE) * (l)); \
(b)->sma = 0.0; \
(b)->pos = 0; \
(b)->lpos = 0; \
}while(0)
#define GET_SMA_SAMPLE(b, p) ((b)->data[(p) % (b)->len])
#define SET_SMA_SAMPLE(b, p, v) ((b)->data[(p) % (b)->len] = (v))
#define GET_CURRENT_SMA_POS(b) ((b)->lpos)
#define INC_SMA_POS(b) \
do { \
(b)->lpos++; \
(b)->pos = (b)->lpos % (b)->len; \
}while(0)
#define APPEND_SMA_VAL(b, v) \
do{ \
INC_SMA_POS(b); \
(b)->sma -= ((b)->data[(b)->pos] / (BUFF_TYPE)(b)->len); \
(b)->data[(b)->pos] = (v); \
(b)->sma += ((b)->data[(b)->pos] / (BUFF_TYPE)(b)->len); \
}while(0)
#define RESET_SMA_BUFFER(b) \
do{ \
(b)->sma = 0.0; \
(void)memset((b)->data, 0, sizeof(BUFF_TYPE) * (b)->len); \
}while(0)
/*
#define DESTROY_SMA_BUFFER(b) \
do{ \
free((b)->data); \
}while(0);
*/
#endif
/*
int main(void)
{
int i;
sma_buffer_t b;
INIT_SMA_BUFFER(&b, 100);
for(i = 0; i < 20; i++){
APPEND_SMA_VAL(&b, 100.0);
printf("SMA = %lf\n", b.sma);
}
DESTROY_SMA_BUFFER(&b);
return EXIT_SUCCESS;
}
*/
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论