tonegen.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 618 行 · 第 1/2 页

C
618
字号
/* $Id: tonegen.c 1010 2007-02-27 00:13:47Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjmedia/tonegen.h>#include <pjmedia/errno.h>#include <pj/assert.h>#include <pj/ctype.h>#include <pj/pool.h>/* float can be twice slower on i686! */#define DATA	double/* amplitude */#define AMP	8192#ifndef M_PI#   define M_PI  ((DATA)3.141592653589793238462643383279)#endif#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0    /*     * Default floating-point based tone generation using sine wave      * generation from:     *   http://www.musicdsp.org/showone.php?id=10.     * This produces good quality tone in relatively faster time than     * the normal sin() generator.     * Speed = 40.6 cycles per sample.     */#   include <math.h>    struct gen    {	DATA a, s0, s1;    };#   define GEN_INIT(var,R,F,A)	 var.a = (DATA) (2.0 * sin(M_PI * F / R)); \				 var.s0 = A; \				 var.s1 = 0#   define GEN_SAMP(val,var)	 var.s0 = var.s0 - var.a * var.s1; \				 var.s1 = var.s1 + var.a * var.s0; \				 val = (short) var.s0#elif !defined(PJ_HAS_FLOATING_POINT) || PJ_HAS_FLOATING_POINT==0    /*      * Fallback algorithm when floating point is disabled.     * This is a very fast fixed point tone generation using sine wave     * approximation from     *    http://www.audiomulch.com/~rossb/code/sinusoids/      * Quality wise not so good, but it's blazing fast!     * Speed:      *	- with volume adjustment: 14 cycles per sample      *  - without volume adjustment: 12.22 cycles per sample     */    PJ_INLINE(int) approximate_sin3(unsigned x)    {		    unsigned s=-(int)(x>>31);	    x+=x;	    x=x>>16;	    x*=x^0xffff;            // x=x*(2-x)	    x+=x;                   // optional	    return x^s;    }    struct gen    {	unsigned add;	unsigned c;	unsigned vol;    };#   define MAXI			((unsigned)0xFFFFFFFF)#   define SIN			approximate_sin3#   if 1    /* set this to 0 to disable volume adjustment */#	define VOL(var,v)	(((v) * var.vol) >> 16)#   else#	define VOL(var,v)	(v)#   endif#   define GEN_INIT(var,R,F,A)	var.add = MAXI/R * F, var.c=0, var.vol=A#   define GEN_SAMP(val,var)	val = (short) VOL(var,SIN(var.c)>>16);\				var.c += var.add#else#   error "Should never get to this part"#   include <math.h>    /*     * Should never really reach here, but anyway it's provided for reference.     * This is the good old tone generator using sin().     * Speed = 222.5 cycles per sample.     */    struct gen    {	DATA add;	DATA c;	DATA vol;    };#   define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A#   define GEN_SAMP(val,var)   val = (short)(sin(var.c * 2 * M_PI) * var.vol);\			       var.c += var.add#endifstruct gen_state{    struct gen tone1;    struct gen tone2;    pj_bool_t  has_tone2;};static void init_generate_single_tone(struct gen_state *state,				      unsigned clock_rate, 				      unsigned freq,				      unsigned vol){    GEN_INIT(state->tone1,clock_rate,freq,vol);    state->has_tone2 = PJ_FALSE;}static void generate_single_tone(struct gen_state *state,				 unsigned channel_count,				 unsigned samples,				 short buf[]) {    short *end = buf + samples;    if (channel_count==1) {	while (buf < end) {	    GEN_SAMP(*buf++, state->tone1);	}    } else if (channel_count == 2) {	while (buf < end) {	    GEN_SAMP(*buf, state->tone1);	    *(buf+1) = *buf;	    buf += 2;	}    }}static void init_generate_dual_tone(struct gen_state *state,				    unsigned clock_rate, 				    unsigned freq1,				    unsigned freq2,				    unsigned vol){    GEN_INIT(state->tone1,clock_rate,freq1,vol);    GEN_INIT(state->tone2,clock_rate,freq2,vol);    state->has_tone2 = PJ_TRUE;}static void generate_dual_tone(struct gen_state *state,			       unsigned channel_count,			       unsigned samples,			       short buf[]) {    short *end = buf + samples;    if (channel_count==1) {	int val, val2;	while (buf < end) {	    GEN_SAMP(val, state->tone1);	    GEN_SAMP(val2, state->tone2);	    *buf++ = (short)((val+val2) >> 1);	}    } else if (channel_count == 2) {	int val, val2;	while (buf < end) {	    GEN_SAMP(val, state->tone1);	    GEN_SAMP(val2, state->tone2);	    val = (val + val2) >> 1;	    *buf++ = (short)val;	    *buf++ = (short)val;	}    }}static void init_generate_tone(struct gen_state *state,			       unsigned clock_rate, 			       unsigned freq1,			       unsigned freq2,			       unsigned vol){    if (freq2)	init_generate_dual_tone(state, clock_rate, freq1, freq2 ,vol);    else	init_generate_single_tone(state, clock_rate, freq1,vol);}static void generate_tone(struct gen_state *state,			  unsigned channel_count,			  unsigned samples,			  short buf[]){    if (!state->has_tone2)	generate_single_tone(state, channel_count, samples, buf);    else	generate_dual_tone(state, channel_count, samples, buf);}/****************************************************************************/#define SIGNATURE   PJMEDIA_PORT_SIGNATURE('t', 'n', 'g', 'n')struct tonegen{    pjmedia_port	base;    /* options */    unsigned		options;    unsigned		playback_options;    /* Digit map */    pjmedia_tone_digit_map  *digit_map;    /* Tone generation state */    struct gen_state	state;    /* Currently played digits: */    unsigned		count;		    /* # of digits		*/    unsigned		cur_digit;	    /* currently played		*/    unsigned		dig_samples;	    /* sample pos in cur digit	*/    pjmedia_tone_desc	digits[PJMEDIA_TONEGEN_MAX_DIGITS];/* array of digits*/};/* Default digit map is DTMF */static pjmedia_tone_digit_map digit_map = {    16,    {	{ '0', 941,  1336 },	{ '1', 697,  1209 },	{ '2', 697,  1336 },	{ '3', 697,  1447 },	{ '4', 770,  1209 },	{ '5', 770,  1336 },	{ '6', 770,  1447 },	{ '7', 852,  1209 },	{ '8', 852,  1336 },	{ '9', 852,  1447 },	{ 'a', 697,  1633 },	{ 'b', 770,  1633 },	{ 'c', 852,  1633 },	{ 'd', 941,  1633 },	{ '*', 941,  1209 },	{ '#', 941,  1477 },    }};static pj_status_t tonegen_get_frame(pjmedia_port *this_port, 				     pjmedia_frame *frame);/* * Create an instance of tone generator with the specified parameters. * When the tone generator is first created, it will be loaded with the * default digit map. */PJ_DEF(pj_status_t) pjmedia_tonegen_create2(pj_pool_t *pool,					    const pj_str_t *name,					    unsigned clock_rate,					    unsigned channel_count,					    unsigned samples_per_frame,					    unsigned bits_per_sample,					    unsigned options,					    pjmedia_port **p_port){    const pj_str_t STR_TONE_GEN = pj_str("tone-gen");    struct tonegen  *tonegen;    pj_status_t status;    PJ_ASSERT_RETURN(pool && clock_rate && channel_count && 		     samples_per_frame && bits_per_sample == 16 && 		     p_port != NULL, PJ_EINVAL);    /* Only support mono and stereo */    PJ_ASSERT_RETURN(channel_count==1 || channel_count==2, PJ_EINVAL);    /* Create and initialize port */    tonegen = pj_pool_zalloc(pool, sizeof(struct tonegen));    if (name == NULL || name->slen == 0) name = &STR_TONE_GEN;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?