1f73bfad797937c259fa0effd95c88da53d8d6c5
[asterisk/asterisk.git] / codecs / lpc10 / onset.c
1 /*
2
3 $Log$
4 Revision 1.10  2000/01/05 08:20:39  markster
5 Version 0.1.11 from FTP
6
7 Revision 1.2  2000/01/05 08:20:39  markster
8 Some OSS fixes and a few lpc changes to make it actually work
9
10  * Revision 1.2  1996/08/20  20:37:55  jaf
11  * Removed all static local variables that were SAVE'd in the Fortran
12  * code, and put them in struct lpc10_encoder_state that is passed as an
13  * argument.
14  *
15  * Removed init function, since all initialization is now done in
16  * init_lpc10_encoder_state().
17  *
18  * Revision 1.1  1996/08/19  22:31:18  jaf
19  * Initial revision
20  *
21
22 */
23
24 #ifdef P_R_O_T_O_T_Y_P_E_S
25 extern int onset_(real *pebuf, integer *osbuf, integer *osptr, integer *oslen, integer *sbufl, integer *sbufh, integer *lframe, struct lpc10_encoder_state *st);
26 #endif
27
28 /*  -- translated by f2c (version 19951025).
29    You must link the resulting object file with the libraries:
30         -lf2c -lm   (in that order)
31 */
32
33 #include "f2c.h"
34
35 /* Table of constant values */
36
37 static real c_b2 = 1.f;
38
39 /* ****************************************************************** */
40
41 /*      ONSET Version 49 */
42
43 /* $Log$
44  * Revision 1.10  2000/01/05 08:20:39  markster
45  * Version 0.1.11 from FTP
46  *
47 /* Revision 1.2  2000/01/05 08:20:39  markster
48 /* Some OSS fixes and a few lpc changes to make it actually work
49 /*
50  * Revision 1.2  1996/08/20  20:37:55  jaf
51  * Removed all static local variables that were SAVE'd in the Fortran
52  * code, and put them in struct lpc10_encoder_state that is passed as an
53  * argument.
54  *
55  * Removed init function, since all initialization is now done in
56  * init_lpc10_encoder_state().
57  *
58  * Revision 1.1  1996/08/19  22:31:18  jaf
59  * Initial revision
60  * */
61 /* Revision 1.5  1996/03/15  16:41:01  jaf */
62 /* Just rearranged INITONSET assignment orders to be consistent with */
63 /* order of DATA statements in ONSET. */
64
65 /* Revision 1.4  1996/03/15  15:48:27  jaf */
66 /* Changed some comments, and only reordered the DATA statements (their */
67 /* meaning wasn't changed). */
68
69 /* Revision 1.3  1996/03/14  23:53:06  jaf */
70 /* Added an entry INITONSET that reinitializes the local state variables */
71 /* of subroutine ONSET. */
72
73 /* Rearranged quite a few comments, adding more explaining which */
74 /* arguments were inputs, and how the modified ones can be changed. */
75
76 /* Revision 1.2  1996/03/12  23:53:00  jaf */
77 /* Lots of comments added about the local state of this subroutine that */
78 /* must be saved from one invocation to the next. */
79
80 /* One constant 180 replaced with LFRAME, which should be "more general", */
81 /* even though it would probably require many more changes than this to */
82 /* get this coder to work for other frame sizes. */
83
84 /* Revision 1.1  1996/02/07 14:48:09  jaf */
85 /* Initial revision */
86
87
88 /* ****************************************************************** */
89
90 /*      Floating point version */
91
92
93 /*   Detection of onsets in (or slightly preceding) the futuremost frame */
94 /*   of speech. */
95
96
97 /* Input: */
98 /*  PEBUF(SBUFL:SBUFH)  - Preemphasized speech */
99 /*                        Indices SBUFH-LFRAME through SBUFH are read. */
100 /*  OSLEN  - Maximum number of onsets that can be stored in OSBUF. */
101 /*  SBUFL, SBUFH        - Range of PEBUF */
102 /*  LFRAME              - length of a frame, in samples */
103 /* Input/Output: */
104 /*  OSBUF(OSLEN) - Buffer which holds sorted indexes of onsets */
105 /*                 Indices A through B are modified, where A */
106 /*                 is the original value of OSPTR, and B is the final */
107 /*                 value of OSPTR-1.  B is at most OSLEN. */
108 /*  OSPTR        - Free pointer into OSBUF */
109 /*                 Initial value should be .LE. OSLEN+1. */
110 /*                 If so, final value grows by one for each new onset */
111 /*                 found, and final value will be .LE. OSLEN+1. */
112
113 /* This subroutine maintains local state from one call to the next.  If */
114 /* you want to switch to using a new audio stream for this subroutine, or */
115 /* reinitialize its state for any other reason, call the ENTRY INITONSET. */
116
117 /* Subroutine */ int onset_(real *pebuf, integer *osbuf, integer *
118         osptr, integer *oslen, integer *sbufl, integer *sbufh, integer *
119         lframe, struct lpc10_encoder_state *st)
120 {
121     /* Initialized data */
122
123     real *n;
124     real *d__;
125     real *l2buf;
126     real *l2sum1;
127     integer *l2ptr1;
128     integer *l2ptr2;
129     logical *hyst;
130
131     /* System generated locals */
132     integer pebuf_offset, i__1;
133     real r__1;
134
135     /* Builtin functions */
136     double r_sign(real *, real *);
137
138     /* Local variables */
139     integer i__;
140     integer *lasti;
141     real l2sum2;
142     real *fpc;
143
144 /*       Arguments */
145 /* $Log$
146  * Revision 1.10  2000/01/05 08:20:39  markster
147  * Version 0.1.11 from FTP
148  *
149 /* Revision 1.2  2000/01/05 08:20:39  markster
150 /* Some OSS fixes and a few lpc changes to make it actually work
151 /*
152  * Revision 1.2  1996/08/20  20:37:55  jaf
153  * Removed all static local variables that were SAVE'd in the Fortran
154  * code, and put them in struct lpc10_encoder_state that is passed as an
155  * argument.
156  *
157  * Removed init function, since all initialization is now done in
158  * init_lpc10_encoder_state().
159  *
160  * Revision 1.1  1996/08/19  22:31:18  jaf
161  * Initial revision
162  * */
163 /* Revision 1.3  1996/03/29  22:03:47  jaf */
164 /* Removed definitions for any constants that were no longer used. */
165
166 /* Revision 1.2  1996/03/26  19:34:33  jaf */
167 /* Added comments indicating which constants are not needed in an */
168 /* application that uses the LPC-10 coder. */
169
170 /* Revision 1.1  1996/02/07  14:43:51  jaf */
171 /* Initial revision */
172
173 /*   LPC Configuration parameters: */
174 /* Frame size, Prediction order, Pitch period */
175 /*       Parameters/constants */
176 /*   Parameters for onset detection algorithm: */
177 /*    L2                Threshold for filtered slope of FPC (function of L2WID!) */
178 /*    L2LAG     Lag due to both filters which compute filtered slope of FPC */
179 /*    L2WID     Width of the filter which computes the slope of FPC */
180 /*    OSHYST    The number of samples of slope(FPC) which must be below */
181 /*              the threshold before a new onset may be declared. */
182 /*       Local variables that need not be saved */
183 /*       Local state */
184 /*   Variables */
185 /*    N, D       Numerator and denominator of prediction filters */
186 /*    FPC        Current prediction coefs */
187 /*    L2BUF, L2SUM1, L2SUM2    State of slope filter */
188 /*       The only "significant" change I've made is to change L2SUM2 out 
189 */
190 /*       of the list of local variables that need to be saved, since it */
191 /*       didn't need to be. */
192 /*       L2SUM1 need not be, but avoiding saving it would require a small 
193 */
194 /*       change to the body of the code.  See comments below for an */
195 /*       example of how the code could be changed to avoid saving L2SUM1. 
196 */
197 /*       FPC and LASTI are saved from one invocation to the next, but */
198 /*       they are not given initial values.  This is acceptable, because 
199 */
200 /*       FPC will be assigned a value the first time that this function */
201 /*       is called after D is initialized to 1, since the formula to */
202 /*       change D will not change it to 0 in one step, and the IF (D */
203 /*       .NE. 0) statement will execute its THEN part, initializing FPC. 
204 */
205
206 /*       LASTI's value will not be used until HYST is .TRUE., and */
207 /*       whenever HYST is changed from its initial value of .FALSE., */
208 /*       LASTI is assigned a value. */
209 /*       In a C version of this coder, it would be nice if all of these */
210 /*       saved things, in this and all other subroutines, could be stored 
211 */
212 /*       in a single struct lpc10_coder_state_t, initialized with a call 
213 */
214 /*       to a function like lpc10_init(&lpc10_coder_state).  In this way, 
215 */
216 /*       a program that used these functions could conveniently alternate 
217 */
218 /*       coding more than one distinct audio stream. */
219
220     n = &(st->n);
221     d__ = &(st->d__);
222     fpc = &(st->fpc);
223     l2buf = &(st->l2buf[0]);
224     l2sum1 = &(st->l2sum1);
225     l2ptr1 = &(st->l2ptr1);
226     l2ptr2 = &(st->l2ptr2);
227     lasti = &(st->lasti);
228     hyst = &(st->hyst);
229
230     /* Parameter adjustments */
231     if (osbuf) {
232         --osbuf;
233         }
234     if (pebuf) {
235         pebuf_offset = *sbufl;
236         pebuf -= pebuf_offset;
237         }
238
239     /* Function Body */
240
241 /*       The following line subtracted a hard-coded "180" from LASTI, */
242 /*       instead of using a variable like LFRAME or a constant like */
243 /*       MAXFRM.  I changed it to LFRAME, for "generality". */
244     if (*hyst) {
245         *lasti -= *lframe;
246     }
247     i__1 = *sbufh;
248     for (i__ = *sbufh - *lframe + 1; i__ <= i__1; ++i__) {
249 /*   Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1. 
250 */
251         *n = (pebuf[i__] * pebuf[i__ - 1] + (*n) * 63.f) / 64.f;
252 /* Computing 2nd power */
253         r__1 = pebuf[i__ - 1];
254         *d__ = (r__1 * r__1 + (*d__) * 63.f) / 64.f;
255         if ((*d__) != 0.f) {
256             if (abs(*n) > (*d__)) {
257                 *fpc = r_sign(&c_b2, n);
258             } else {
259                 *fpc = (*n) / (*d__);
260             }
261         }
262 /*   Filter FPC */
263 /*       In order to allow L2SUM1 not to be saved from one invocation 
264 of */
265 /*       this subroutine to the next, one could change the sequence of
266  */
267 /*       assignments below, up to the IF statement, to the following. 
268  In */
269 /*       addition, the initial value of L2PTR2 should be changed to */
270 /*       L2WID/2 instead of L2WID/2+1. */
271
272 /*       L2SUM1 = L2BUF(L2PTR2) */
273 /*       L2PTR2 = MOD(L2PTR2,L2WID)+1 */
274 /*       L2SUM1 = L2SUM1 - L2BUF(L2PTR2) + FPC */
275 /*       L2BUF(L2PTR2) = L2SUM1 */
276
277 /* *       The following lines didn't change from the original: */
278 /*       L2SUM2 = L2BUF(L2PTR1) */
279 /*       L2BUF(L2PTR1) = FPC */
280 /*       L2PTR1 = MOD(L2PTR1,L2WID)+1 */
281
282         l2sum2 = l2buf[*l2ptr1 - 1];
283         *l2sum1 = *l2sum1 - l2buf[*l2ptr2 - 1] + *fpc;
284         l2buf[*l2ptr2 - 1] = *l2sum1;
285         l2buf[*l2ptr1 - 1] = *fpc;
286         *l2ptr1 = *l2ptr1 % 16 + 1;
287         *l2ptr2 = *l2ptr2 % 16 + 1;
288         if ((r__1 = *l2sum1 - l2sum2, abs(r__1)) > 1.7f) {
289             if (! (*hyst)) {
290 /*   Ignore if buffer full */
291                 if (*osptr <= *oslen) {
292                     osbuf[*osptr] = i__ - 9;
293                     ++(*osptr);
294                 }
295                 *hyst = TRUE_;
296             }
297             *lasti = i__;
298 /*       After one onset detection, at least OSHYST sample times m
299 ust go */
300 /*       by before another is allowed to occur. */
301         } else if ((*hyst) && i__ - *lasti >= 10) {
302             *hyst = FALSE_;
303         }
304     }
305     return 0;
306 } /* onset_ */