1 /*
2 
3  * Revision 1.2  1996/08/20  20:25:29  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:32:26  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 dyptrk_(real *amdf, integer *ltau, integer *minptr, integer *voice, integer *pitch, integer *midx, struct lpc10_encoder_state *st);
25 
26 /* Common Block Declarations */
27 
28 extern struct {
29     integer order, lframe;
30     logical corrp;
31 } contrl_;
32 
33 #define contrl_1 contrl_
34 
35 /* ********************************************************************* */
36 
37 /* 	DYPTRK Version 52 */
38 
39 /*
40  * Revision 1.2  1996/08/20  20:25:29  jaf
41  * Removed all static local variables that were SAVE'd in the Fortran
42  * code, and put them in struct lpc10_encoder_state that is passed as an
43  * argument.
44  *
45  * Removed init function, since all initialization is now done in
46  * init_lpc10_encoder_state().
47  *
48  * Revision 1.1  1996/08/19  22:32:26  jaf
49  * Initial revision
50  * */
51 /* Revision 1.5  1996/03/26  19:35:35  jaf */
52 /* Commented out trace statements. */
53 
54 /* Revision 1.4  1996/03/19  18:03:22  jaf */
55 /* Replaced the initialization "DATA P/60*DEPTH*0/" with "DATA P/120*0/", */
56 /* because apparently Fortran (or at least f2c) can't handle expressions */
57 /* like that. */
58 
59 /* Revision 1.3  1996/03/19  17:38:32  jaf */
60 /* Added comments about the local variables that should be saved from one */
61 /* invocation to the next.  None of them were given initial values in the */
62 /* original code, but from my testing, it appears that initializing them */
63 /* all to 0 works. */
64 
65 /* Added entry INITDYPTRK to reinitialize these local variables. */
66 
67 /* Revision 1.2  1996/03/13  16:32:17  jaf */
68 /* Comments added explaining which of the local variables of this */
69 /* subroutine need to be saved from one invocation to the next, and which */
70 /* do not. */
71 
72 /* WARNING!  Some of them that should are never given initial values in */
73 /* this code.  Hopefully, Fortran 77 defines initial values for them, but */
74 /* even so, giving them explicit initial values is preferable. */
75 
76 /* Revision 1.1  1996/02/07 14:45:14  jaf */
77 /* Initial revision */
78 
79 
80 /* ********************************************************************* */
81 
82 /*   Dynamic Pitch Tracker */
83 
84 /* Input: */
85 /*  AMDF   - Average Magnitude Difference Function array */
86 /*           Indices 1 through LTAU read, and MINPTR */
87 /*  LTAU   - Number of lags in AMDF */
88 /*  MINPTR - Location of minimum AMDF value */
89 /*  VOICE  - Voicing decision */
90 /* Output: */
91 /*  PITCH  - Smoothed pitch value, 2 frames delayed */
92 /*  MIDX   - Initial estimate of current frame pitch */
93 /* Compile time constant: */
94 /*  DEPTH  - Number of frames to trace back */
95 
96 /* This subroutine maintains local state from one call to the next.  If */
97 /* you want to switch to using a new audio stream for this filter, or */
98 /* reinitialize its state for any other reason, call the ENTRY */
99 /* INITDYPTRK. */
100 
dyptrk_(real * amdf,integer * ltau,integer * minptr,integer * voice,integer * pitch,integer * midx,struct lpc10_encoder_state * st)101 /* Subroutine */ int dyptrk_(real *amdf, integer *ltau, integer *
102 	minptr, integer *voice, integer *pitch, integer *midx,
103 			       struct lpc10_encoder_state *st)
104 {
105     /* Initialized data */
106 
107     real *s;
108     integer *p;
109     integer *ipoint;
110     real *alphax;
111 
112     /* System generated locals */
113     integer i__1;
114 
115     /* Local variables */
116     integer pbar;
117     real sbar;
118     integer iptr, i__, j;
119     real alpha, minsc, maxsc;
120 
121 /*       Arguments */
122 
123 /*   LPC Processing control variables: */
124 
125 /* *** Read-only: initialized in setup */
126 
127 /*  Files for Speech, Parameter, and Bitstream Input & Output, */
128 /*    and message and debug outputs. */
129 
130 /* Here are the only files which use these variables: */
131 
132 /* lpcsim.f setup.f trans.f error.f vqsetup.f */
133 
134 /* Many files which use fdebug are not listed, since it is only used in */
135 /* those other files conditionally, to print trace statements. */
136 /* 	integer fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */
137 /*  LPC order, Frame size, Quantization rate, Bits per frame, */
138 /*    Error correction */
139 /* Subroutine SETUP is the only place where order is assigned a value, */
140 /* and that value is 10.  It could increase efficiency 1% or so to */
141 /* declare order as a constant (i.e., a Fortran PARAMETER) instead of as
142 */
143 /* a variable in a COMMON block, since it is used in many places in the */
144 /* core of the coding and decoding routines.  Actually, I take that back.
145 */
146 /* At least when compiling with f2c, the upper bound of DO loops is */
147 /* stored in a local variable before the DO loop begins, and then that is
148 */
149 /* compared against on each iteration. */
150 /* Similarly for lframe, which is given a value of MAXFRM in SETUP. */
151 /* Similarly for quant, which is given a value of 2400 in SETUP.  quant */
152 /* is used in only a few places, and never in the core coding and */
153 /* decoding routines, so it could be eliminated entirely. */
154 /* nbits is similar to quant, and is given a value of 54 in SETUP. */
155 /* corrp is given a value of .TRUE. in SETUP, and is only used in the */
156 /* subroutines ENCODE and DECODE.  It doesn't affect the speed of the */
157 /* coder significantly whether it is .TRUE. or .FALSE., or whether it is
158 */
159 /* a constant or a variable, since it is only examined once per frame. */
160 /* Leaving it as a variable that is set to .TRUE.  seems like a good */
161 /* idea, since it does enable some error-correction capability for */
162 /* unvoiced frames, with no change in the coding rate, and no noticeable
163 */
164 /* quality difference in the decoded speech. */
165 /* 	integer quant, nbits */
166 /* *** Read/write: variables for debugging, not needed for LPC algorithm
167 */
168 
169 /*  Current frame, Unstable frames, Output clip count, Max onset buffer,
170 */
171 /*    Debug listing detail level, Line count on listing page */
172 
173 /* nframe is not needed for an embedded LPC10 at all. */
174 /* nunsfm is initialized to 0 in SETUP, and incremented in subroutine */
175 /* ERROR, which is only called from RCCHK.  When LPC10 is embedded into */
176 /* an application, I would recommend removing the call to ERROR in RCCHK,
177 */
178 /* and remove ERROR and nunsfm completely. */
179 /* iclip is initialized to 0 in SETUP, and incremented in entry SWRITE in
180 */
181 /* sread.f.  When LPC10 is embedded into an application, one might want */
182 /* to cause it to be incremented in a routine that takes the output of */
183 /* SYNTHS and sends it to an audio device.  It could be optionally */
184 /* displayed, for those that might want to know what it is. */
185 /* maxosp is never initialized to 0 in SETUP, although it probably should
186 */
187 /* be, and it is updated in subroutine ANALYS.  I doubt that its value */
188 /* would be of much interest to an application in which LPC10 is */
189 /* embedded. */
190 /* listl and lincnt are not needed for an embedded LPC10 at all. */
191 /* 	integer nframe, nunsfm, iclip, maxosp, listl, lincnt */
192 /* 	common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug */
193 /* 	common /contrl/ quant, nbits */
194 /* 	common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt */
195 /* 	Parameters/constants */
196 /*       Local variables that need not be saved */
197 /*       Note that PATH is only used for debugging purposes, and can be */
198 /*       removed. */
199 /*       Local state */
200 /*       It would be a bit more "general" to define S(LTAU), if Fortran */
201 /*       allows the argument of a function to be used as the dimension of
202 */
203 /*       a local array variable. */
204 /*       IPOINT is always in the range 0 to DEPTH-1. */
205 /*       WARNING! */
206 
207 /*       In the original version of this subroutine, IPOINT, ALPHAX, */
208 /*       every element of S, and potentially any element of P with the */
209 /*       second index value .NE. IPTR were read without being given */
210 /*       initial values (all indices of P with second index equal to */
211 /*       IPTR are all written before being read in this subroutine). */
212 
213 /*       From examining the code carefully, it appears that all of these
214 */
215 /*       should be saved from one invocation to the next. */
216 
217 /*       I've run lpcsim with the "-l 6" option to see all of the */
218 /*       debugging information that is printed out by this subroutine */
219 /*       below, and it appears that S, P, IPOINT, and ALPHAX are all */
220 /*       initialized to 0 (these initial values would likely be different
221 */
222 /*       on different platforms, compilers, etc.).  Given that the output
223 */
224 /*       of the coder sounds reasonable, I'm going to initialize these */
225 /*       variables to 0 explicitly. */
226 
227     s = &(st->s[0]);
228     p = &(st->p[0]);
229     ipoint = &(st->ipoint);
230     alphax = &(st->alphax);
231 
232 
233     /* Parameter adjustments */
234     if (amdf) {
235 	--amdf;
236 	}
237 
238     /* Function Body */
239 
240 /*   Calculate the confidence factor ALPHA, used as a threshold slope in
241 */
242 /*   SEESAW.  If unvoiced, set high slope so that every point in P array
243 */
244 /*  is marked as a potential pitch frequency.  A scaled up version (ALPHAX
245 )*/
246 /*   is used to maintain arithmetic precision. */
247     if (*voice == 1) {
248 	*alphax = *alphax * .75f + amdf[*minptr] / 2.f;
249     } else {
250 	*alphax *= .984375f;
251     }
252     alpha = *alphax / 16;
253     if (*voice == 0 && *alphax < 128.f) {
254 	alpha = 8.f;
255     }
256 /* SEESAW: Construct a pitch pointer array and intermediate winner functio
257 n*/
258 /*   Left to right pass: */
259     iptr = *ipoint + 1;
260     p[iptr * 60 - 60] = 1;
261     i__ = 1;
262     pbar = 1;
263     sbar = s[0];
264     i__1 = *ltau;
265     for (i__ = 1; i__ <= i__1; ++i__) {
266 	sbar += alpha;
267 	if (sbar < s[i__ - 1]) {
268 	    s[i__ - 1] = sbar;
269 	    p[i__ + iptr * 60 - 61] = pbar;
270 	} else {
271 	    sbar = s[i__ - 1];
272 	    p[i__ + iptr * 60 - 61] = i__;
273 	    pbar = i__;
274 	}
275     }
276 /*   Right to left pass: */
277     i__ = pbar - 1;
278     sbar = s[i__];
279     while(i__ >= 1) {
280 	sbar += alpha;
281 	if (sbar < s[i__ - 1]) {
282 	    s[i__ - 1] = sbar;
283 	    p[i__ + iptr * 60 - 61] = pbar;
284 	} else {
285 	    pbar = p[i__ + iptr * 60 - 61];
286 	    i__ = pbar;
287 	    sbar = s[i__ - 1];
288 	}
289 	--i__;
290     }
291 /*   Update S using AMDF */
292 /*   Find maximum, minimum, and location of minimum */
293     s[0] += amdf[1] / 2;
294     minsc = s[0];
295     maxsc = minsc;
296     *midx = 1;
297     i__1 = *ltau;
298     for (i__ = 2; i__ <= i__1; ++i__) {
299 	s[i__ - 1] += amdf[i__] / 2;
300 	if (s[i__ - 1] > maxsc) {
301 	    maxsc = s[i__ - 1];
302 	}
303 	if (s[i__ - 1] < minsc) {
304 	    *midx = i__;
305 	    minsc = s[i__ - 1];
306 	}
307     }
308 /*   Subtract MINSC from S to prevent overflow */
309     i__1 = *ltau;
310     for (i__ = 1; i__ <= i__1; ++i__) {
311 	s[i__ - 1] -= minsc;
312     }
313     maxsc -= minsc;
314 /*   Use higher octave pitch if significant null there */
315     j = 0;
316     for (i__ = 20; i__ <= 40; i__ += 10) {
317 	if (*midx > i__) {
318 	    if (s[*midx - i__ - 1] < maxsc / 4) {
319 		j = i__;
320 	    }
321 	}
322     }
323     *midx -= j;
324 /*   TRACE: look back two frames to find minimum cost pitch estimate */
325     j = *ipoint;
326     *pitch = *midx;
327     for (i__ = 1; i__ <= 2; ++i__) {
328 	j = j % 2 + 1;
329 	*pitch = p[*pitch + j * 60 - 61];
330     }
331 
332 /*       The following statement subtracts one from IPOINT, mod DEPTH.  I
333 */
334 /*       think the author chose to add DEPTH-1, instead of subtracting 1,
335 */
336 /*       because then it will work even if MOD doesn't work as desired on
337 */
338 /*       negative arguments. */
339 
340     *ipoint = (*ipoint + 1) % 2;
341     return 0;
342 } /* dyptrk_ */
343