Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/super_tone_tx.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * super_tone_tx.c - Flexible telephony supervisory tone generation. | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2003 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License version 2, as | |
14 * published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: super_tone_tx.c,v 1.15 2006/11/19 14:07:25 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #ifdef HAVE_CONFIG_H | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 #include <stdlib.h> | |
35 #include <string.h> | |
36 #include <stdio.h> | |
37 #include <fcntl.h> | |
38 #include <ctype.h> | |
39 #include <time.h> | |
40 #include <inttypes.h> | |
41 #if defined(HAVE_TGMATH_H) | |
42 #include <tgmath.h> | |
43 #endif | |
44 #if defined(HAVE_MATH_H) | |
45 #include <math.h> | |
46 #endif | |
47 | |
48 #include "spandsp/telephony.h" | |
49 #include "spandsp/complex.h" | |
50 #include "spandsp/dds.h" | |
51 #include "spandsp/super_tone_tx.h" | |
52 | |
53 super_tone_tx_step_t *super_tone_tx_make_step(super_tone_tx_step_t *s, | |
54 float f1, | |
55 float l1, | |
56 float f2, | |
57 float l2, | |
58 int length, | |
59 int cycles) | |
60 { | |
61 if (s == NULL) | |
62 { | |
63 s = (super_tone_tx_step_t *) malloc(sizeof(super_tone_tx_step_t)); | |
64 if (s == NULL) | |
65 return NULL; | |
66 } | |
67 if (f1 >= 1.0) | |
68 { | |
69 s->phase_rate[0] = dds_phase_ratef(f1); | |
70 s->gain[0] = dds_scaling_dbm0f(l1); | |
71 } | |
72 else | |
73 { | |
74 s->phase_rate[0] = 0; | |
75 s->gain[0] = 0; | |
76 } | |
77 if (f2 >= 1.0) | |
78 { | |
79 s->phase_rate[1] = dds_phase_ratef(f2); | |
80 s->gain[1] = dds_scaling_dbm0f(l2); | |
81 } | |
82 else | |
83 { | |
84 s->phase_rate[1] = 0; | |
85 s->gain[1] = 0; | |
86 } | |
87 s->tone = (f1 > 0.0); | |
88 s->length = length*8; | |
89 s->cycles = cycles; | |
90 s->next = NULL; | |
91 s->nest = NULL; | |
92 return s; | |
93 } | |
94 /*- End of function --------------------------------------------------------*/ | |
95 | |
96 void super_tone_tx_free(super_tone_tx_step_t *s) | |
97 { | |
98 super_tone_tx_step_t *t; | |
99 | |
100 while (s) | |
101 { | |
102 /* Follow nesting... */ | |
103 if (s->nest) | |
104 super_tone_tx_free(s->nest); | |
105 t = s; | |
106 s = s->next; | |
107 free(t); | |
108 } | |
109 } | |
110 /*- End of function --------------------------------------------------------*/ | |
111 | |
112 super_tone_tx_state_t *super_tone_tx_init(super_tone_tx_state_t *s, super_tone_tx_step_t *tree) | |
113 { | |
114 if (tree == NULL) | |
115 return NULL; | |
116 memset(s, 0, sizeof(*s)); | |
117 s->level = 0; | |
118 s->levels[0] = tree; | |
119 s->cycles[0] = tree->cycles; | |
120 | |
121 s->current_position = 0; | |
122 return s; | |
123 } | |
124 /*- End of function --------------------------------------------------------*/ | |
125 | |
126 int super_tone_tx(super_tone_tx_state_t *s, int16_t amp[], int max_samples) | |
127 { | |
128 int samples; | |
129 int limit; | |
130 int len; | |
131 float xamp; | |
132 super_tone_tx_step_t *tree; | |
133 | |
134 if (s->level < 0 || s->level > 3) | |
135 return 0; | |
136 samples = 0; | |
137 tree = s->levels[s->level]; | |
138 while (tree && samples < max_samples) | |
139 { | |
140 if (tree->tone) | |
141 { | |
142 /* A period of tone. A length of zero means infinite | |
143 length. */ | |
144 if (s->current_position == 0) | |
145 { | |
146 /* New step - prepare the tone generator */ | |
147 s->phase_rate[0] = tree->phase_rate[0]; | |
148 s->gain[0] = tree->gain[0]; | |
149 s->phase_rate[1] = tree->phase_rate[1]; | |
150 s->gain[1] = tree->gain[1]; | |
151 } | |
152 len = tree->length - s->current_position; | |
153 if (tree->length == 0) | |
154 { | |
155 len = max_samples - samples; | |
156 /* We just need to make current position non-zero */ | |
157 s->current_position = 1; | |
158 } | |
159 else if (len > max_samples - samples) | |
160 { | |
161 len = max_samples - samples; | |
162 s->current_position += len; | |
163 } | |
164 else | |
165 { | |
166 s->current_position = 0; | |
167 } | |
168 for (limit = len + samples; samples < limit; samples++) | |
169 { | |
170 xamp = 0.0; | |
171 if (s->phase_rate[0]) | |
172 xamp += dds_modf(&(s->phase[0]), s->phase_rate[0], s->gain[0], 0); | |
173 if (s->phase_rate[1]) | |
174 xamp += dds_modf(&(s->phase[1]), s->phase_rate[1], s->gain[1], 0); | |
175 amp[samples] = (int16_t) lrintf(xamp); | |
176 } | |
177 if (s->current_position) | |
178 return samples; | |
179 } | |
180 else if (tree->length) | |
181 { | |
182 /* A period of silence. The length must always | |
183 be explicitly stated. A length of zero does | |
184 not give infinite silence. */ | |
185 len = tree->length - s->current_position; | |
186 if (len > max_samples - samples) | |
187 { | |
188 len = max_samples - samples; | |
189 s->current_position += len; | |
190 } | |
191 else | |
192 { | |
193 s->current_position = 0; | |
194 } | |
195 memset(amp + samples, 0, sizeof(uint16_t)*len); | |
196 samples += len; | |
197 if (s->current_position) | |
198 return samples; | |
199 } | |
200 /* Nesting has priority... */ | |
201 if (tree->nest) | |
202 { | |
203 tree = tree->nest; | |
204 s->levels[++s->level] = tree; | |
205 s->cycles[s->level] = tree->cycles; | |
206 } | |
207 else | |
208 { | |
209 /* ...Next comes repeating, and finally moving forward a step. */ | |
210 /* When repeating, note that zero cycles really means endless cycles. */ | |
211 while (tree->cycles && --s->cycles[s->level] <= 0) | |
212 { | |
213 tree = tree->next; | |
214 if (tree) | |
215 { | |
216 /* A fresh new step. */ | |
217 s->levels[s->level] = tree; | |
218 s->cycles[s->level] = tree->cycles; | |
219 break; | |
220 } | |
221 /* If we are nested we need to pop, otherwise this is the end. */ | |
222 if (s->level <= 0) | |
223 { | |
224 /* Mark the tone as completed */ | |
225 s->levels[0] = NULL; | |
226 break; | |
227 } | |
228 tree = s->levels[--s->level]; | |
229 } | |
230 } | |
231 | |
232 } | |
233 return samples; | |
234 } | |
235 /*- End of function --------------------------------------------------------*/ | |
236 /*- End of file ------------------------------------------------------------*/ |