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