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 + -
显示快捷键?