📄 voicin.c
字号:
/* SYNTHS and sends it to an audio device. It could be optionally *//* displayed, for those that might want to know what it is. *//* maxosp is never initialized to 0 in SETUP, although it probably should *//* be, and it is updated in subroutine ANALYS. I doubt that its value *//* would be of much interest to an application in which LPC10 is *//* embedded. *//* listl and lincnt are not needed for an embedded LPC10 at all. *//* integer nframe, nunsfm, iclip, maxosp, listl, lincnt *//* common /contrl/ fsi, fso, fpi, fpo, fbi, fbo, pbin, fmsg, fdebug *//* common /contrl/ quant, nbits *//* common /contrl/ nframe, nunsfm, iclip, maxosp, listl, lincnt *//* Parameters/constants *//* Voicing coefficient and Linear Discriminant Analysis variables: *//* Max number of VDC's and VDC levels *//* The following are not Fortran PARAMETER's, but they are *//* initialized with DATA statements, and never modified. *//* Actual number of VDC's and levels *//* Local variables that need not be saved *//* Note: *//* VALUE(1) through VALUE(8) are assigned values, but VALUE(9) *//* never is. Yet VALUE(9) is read in the loop that begins "DO I = *//* 1, 9" below. I believe that this doesn't cause any problems in *//* this subroutine, because all VDC(9,*) array elements are 0, and *//* this is what is multiplied by VALUE(9) in all cases. Still, it *//* would save a multiplication to change the loop to "DO I = 1, 8". *//* Local state *//* WARNING! *//* VOICE, SFBUE, and SLBUE should be saved from one invocation to *//* the next, but they are never given an initial value. *//* Does Fortran 77 specify some default initial value, like 0, or *//* is it undefined? If it is undefined, then this code should be *//* corrected to specify an initial value. *//* For VOICE, note that it is "shifted" in the statement that *//* begins "IF (HALF .EQ. 1) THEN" below. Also, uninitialized *//* values in the VOICE array can only affect entries in the VOIBUF *//* array that are for the same frame, or for an older frame. Thus *//* the effects of uninitialized values in VOICE cannot linger on *//* for more than 2 or 3 frame times. *//* For SFBUE and SLBUE, the effects of uninitialized values can *//* linger on for many frame times, because their previous values *//* are exponentially decayed. Thus it is more important to choose *//* initial values for these variables. I would guess that a *//* reasonable initial value for SFBUE is REF/16, the same as used *//* for FBUE and OFBUE. Similarly, SLBUE can be initialized to *//* REF/32, the same as for LBUE and OLBUE. *//* These guessed initial values should be validated by re-running *//* the modified program on some audio samples. *//* Declare and initialize filters: */ dither = (&st->dither); snr = (&st->snr); maxmin = (&st->maxmin); voice = (&st->voice[0]); lbve = (&st->lbve); lbue = (&st->lbue); fbve = (&st->fbve); fbue = (&st->fbue); ofbue = (&st->ofbue); olbue = (&st->olbue); sfbue = (&st->sfbue); slbue = (&st->slbue); /* Parameter adjustments */ if (vwin) { --vwin; } if (buflim) { --buflim; } if (inbuf) { inbuf_offset = buflim[1]; inbuf -= inbuf_offset; } if (lpbuf) { lpbuf_offset = buflim[3]; lpbuf -= lpbuf_offset; } if (ivrc) { --ivrc; } if (obound) { --obound; } if (voibuf) { --voibuf; } /* Function Body *//* The following variables are saved from one invocation to the *//* next, but are not initialized with DATA statements. This is *//* acceptable, because FIRST is initialized ot .TRUE., and the *//* first time that this subroutine is then called, they are all *//* given initial values. *//* SNR *//* LBVE, LBUE, FBVE, FBUE, OFBUE, OLBUE *//* MAXMIN is initialized on the first call, assuming that HALF *//* .EQ. 1 on first call. This is how ANALYS calls this subroutine. *//* Voicing Decision Parameter vector (* denotes zero coefficient): *//* * MAXMIN *//* LBE/LBVE *//* ZC *//* RC1 *//* QS *//* IVRC2 *//* aR_B *//* aR_F *//* * LOG(LBE/LBVE) *//* Define 2-D voicing decision coefficient vector according to the voicing*//* parameter order above. Each row (VDC vector) is optimized for a specific*//* SNR. The last element of the vector is the constant. *//* E ZC RC1 Qs IVRC2 aRb aRf c *//* The VOICE array contains the result of the linear discriminant function*//* (analog values). The VOIBUF array contains the hard-limited binary *//* voicing decisions. The VOICE and VOIBUF arrays, according to FORTRAN *//* memory allocation, are addressed as: *//* (half-frame number, future-frame number) *//* | Past | Present | Future1 | Future2 | *//* | 1,0 | 2,0 | 1,1 | 2,1 | 1,2 | 2,2 | 1,3 | 2,3 | ---> time *//* Update linear discriminant function history each frame: */ if (*half == 1) { voice[0] = voice[2]; voice[1] = voice[3]; voice[2] = voice[4]; voice[3] = voice[5]; *maxmin = *maxamd / max(*minamd,1.f); }/* Calculate voicing parameters twice per frame: */ vparms_(&vwin[1], &inbuf[inbuf_offset], &lpbuf[lpbuf_offset], &buflim[1], half, dither, mintau, &zc, &lbe, &fbe, &qs, &rc1, &ar_b__, & ar_f__);/* Estimate signal-to-noise ratio to select the appropriate VDC vector. *//* The SNR is estimated as the running average of the ratio of the *//* running average full-band voiced energy to the running average *//* full-band unvoiced energy. SNR filter has gain of 63. */ r__1 = (*snr + *fbve / (real) max(*fbue,1)) * 63 / 64.f; *snr = (real) i_nint(&r__1); snr2 = *snr * *fbue / max(*lbue,1);/* Quantize SNR to SNRL according to VDCL thresholds. */ snrl = 1; i__1 = nvdcl - 1; for (snrl = 1; snrl <= i__1; ++snrl) { if (snr2 > vdcl[snrl - 1]) { goto L69; } }/* (Note: SNRL = NVDCL here) */L69:/* Linear discriminant voicing parameters: */ value[0] = *maxmin; value[1] = (real) lbe / max(*lbve,1); value[2] = (real) zc; value[3] = rc1; value[4] = qs; value[5] = ivrc[2]; value[6] = ar_b__; value[7] = ar_f__;/* Evaluation of linear discriminant function: */ voice[*half + 3] = vdc[snrl * 10 - 1]; for (i__ = 1; i__ <= 8; ++i__) { voice[*half + 3] += vdc[i__ + snrl * 10 - 11] * value[i__ - 1]; }/* Classify as voiced if discriminant > 0, otherwise unvoiced *//* Voicing decision for current half-frame: 1 = Voiced; 0 = Unvoiced */ if (voice[*half + 3] > 0.f) { voibuf[*half + 6] = 1; } else { voibuf[*half + 6] = 0; }/* Skip voicing decision smoothing in first half-frame: *//* Give a value to VSTATE, so that trace statements below will print *//* a consistent value from one call to the next when HALF .EQ. 1. *//* The value of VSTATE is not used for any other purpose when this is *//* true. */ vstate = -1; if (*half == 1) { goto L99; }/* Voicing decision smoothing rules (override of linear combination): *//* Unvoiced half-frames: At least two in a row. *//* -------------------- *//* Voiced half-frames: At least two in a row in one frame. *//* ------------------- Otherwise at least three in a row. *//* (Due to the way transition frames are encoded) *//* In many cases, the discriminant function determines how to smooth. *//* In the following chart, the decisions marked with a * may be overridden.*//* Voicing override of transitions at onsets: *//* If a V/UV or UV/V voicing decision transition occurs within one-half *//* frame of an onset bounding a voicing window, then the transition is *//* moved to occur at the onset. *//* P 1F *//* ----- ----- *//* 0 0 0 0 *//* 0 0 0* 1 (If there is an onset there) *//* 0 0 1* 0* (Based on 2F and discriminant distance) *//* 0 0 1 1 *//* 0 1* 0 0 (Always) *//* 0 1* 0* 1 (Based on discriminant distance) *//* 0* 1 1 0* (Based on past, 2F, and discriminant distance) *//* 0 1* 1 1 (If there is an onset there) *//* 1 0* 0 0 (If there is an onset there) *//* 1 0 0 1 *//* 1 0* 1* 0 (Based on discriminant distance) *//* 1 0* 1 1 (Always) *//* 1 1 0 0 *//* 1 1 0* 1* (Based on 2F and discriminant distance) *//* 1 1 1* 0 (If there is an onset there) *//* 1 1 1 1 *//* Determine if there is an onset transition between P and 1F. *//* OT (Onset Transition) is true if there is an onset between *//* P and 1F but not after 1F. */ ot = ((obound[1] & 2) != 0 || obound[2] == 1) && (obound[3] & 1) == 0;/* Multi-way dispatch on voicing decision history: */ vstate = (voibuf[3] << 3) + (voibuf[4] << 2) + (voibuf[5] << 1) + voibuf[ 6]; switch (vstate + 1) { case 1: goto L99; case 2: goto L1; case 3: goto L2; case 4: goto L99; case 5: goto L4; case 6: goto L5; case 7: goto L6; case 8: goto L7; case 9: goto L8; case 10: goto L99; case 11: goto L10; case 12: goto L11; case 13: goto L99; case 14: goto L13; case 15: goto L14; case 16: goto L99; }L1: if (ot && voibuf[7] == 1) { voibuf[5] = 1; } goto L99;L2: if (voibuf[7] == 0 || voice[2] < -voice[3]) { voibuf[5] = 0; } else { voibuf[6] = 1; } goto L99;L4: voibuf[4] = 0; goto L99;L5: if (voice[1] < -voice[2]) { voibuf[4] = 0; } else { voibuf[5] = 1; } goto L99;/* VOIBUF(2,0) must be 0 */L6: if (voibuf[1] == 1 || voibuf[7] == 1 || voice[3] > voice[0]) { voibuf[6] = 1; } else { voibuf[3] = 1; } goto L99;L7: if (ot) { voibuf[4] = 0; } goto L99;L8: if (ot) { voibuf[4] = 1; } goto L99;L10: if (voice[2] < -voice[1]) { voibuf[5] = 0; } else { voibuf[4] = 1; } goto L99;L11: voibuf[4] = 1; goto L99;L13: if (voibuf[7] == 0 && voice[3] < -voice[2]) { voibuf[6] = 0; } else { voibuf[5] = 1; } goto L99;L14: if (ot && voibuf[7] == 0) { voibuf[5] = 0; }/* GOTO 99 */L99:/* Now update parameters: *//* ---------------------- *//* During unvoiced half-frames, update the low band and full band unvoiced*//* energy estimates (LBUE and FBUE) and also the zero crossing *//* threshold (DITHER). (The input to the unvoiced energy filters is *//* restricted to be less than 10dB above the previous inputs of the *//* filters.) *//* During voiced half-frames, update the low-pass (LBVE) and all-pass *//* (FBVE) voiced energy estimates. */ if (voibuf[*half + 6] == 0) {/* Computing MIN */ i__1 = fbe, i__2 = *ofbue * 3; r__1 = (*sfbue * 63 + (min(i__1,i__2) << 3)) / 64.f; *sfbue = i_nint(&r__1); *fbue = *sfbue / 8; *ofbue = fbe;/* Computing MIN */ i__1 = lbe, i__2 = *olbue * 3; r__1 = (*slbue * 63 + (min(i__1,i__2) << 3)) / 64.f; *slbue = i_nint(&r__1); *lbue = *slbue / 8; *olbue = lbe; } else { r__1 = (*lbve * 63 + lbe) / 64.f; *lbve = i_nint(&r__1); r__1 = (*fbve * 63 + fbe) / 64.f; *fbve = i_nint(&r__1); }/* Set dither threshold to yield proper zero crossing rates in the *//* presence of low frequency noise and low level signal input. *//* NOTE: The divisor is a function of REF, the expected energies. *//* Computing MIN *//* Computing MAX */ r__2 = sqrt((real) (*lbue * *lbve)) * 64 / 3000; r__1 = max(r__2,1.f); *dither = min(r__1,20.f);/* Voicing decisions are returned in VOIBUF. */ return 0;} /* voicin_ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -