www.pudn.com > lpc10-15.zip > pitsyn.f
******************************************************************
*
* PITSYN Version 53
*
* $Log: pitsyn.f,v $
* Revision 1.2 1996/03/25 18:49:07 jaf
* Added commments about which indices of array arguments are read or
* written.
*
* Rearranged local variable declarations to indicate which need to be
* saved from one invocation to the next. Added entry INITPITSYN to
* reinitialize local state variables, if desired.
*
* Added lots of comments about proving that the maximum number of pitch
* periods (NOUT) that can be returned is 16. The call to STOP that
* could happen if NOUT got too large was removed as a result.
*
* Also proved that the total number of samples returned from N calls,
* each with identical values of LFRAME, will always be in the range
* N*LFRAME-MAXPIT+1 to N*LFRAME.
*
* Revision 1.1 1996/02/07 14:48:18 jaf
* Initial revision
*
*
******************************************************************
*
* Synthesize a single pitch epoch
*
* Input:
* ORDER - Synthesis order (number of RC's)
* VOICE - Half frame voicing decisions
* Indices 1 through 2 read.
* LFRAME - Length of speech buffer
* Input/Output:
* PITCH - Pitch
* This value should be in the range MINPIT (20) to MAXPIT
* (156), inclusive.
* PITCH can be modified under some conditions.
* RMS - Energy (can be modified)
* RMS is changed to 1 if the value passed in is less than 1.
* RC - Reflection coefficients
* Indices 1 through ORDER can be temporarily overwritten with
* RCO, and then replaced with original values, under some
* conditions.
* Output:
* IVUV - Pitch epoch voicing decisions
* Indices (I) of IVUV, IPITI, and RMSI are written,
* and indices (J,I) of RCI are written,
* where I ranges from 1 to NOUT, and J ranges from 1 to ORDER.
* IPITI - Pitch epoch length
* RMSI - Pitch epoch energy
* RCI - Pitch epoch RC's
* NOUT - Number of pitch periods in this frame
* This is at least 0, at least 1 if MAXPIT .LT. LFRAME (this
* is currently true on every call), and can never be more than
* (LFRAME+MAXPIT-1)/PITCH, which is currently 16 with
* LFRAME=180, MAXPIT=156, and PITCH .GE. 20, as SYNTHS
* guarantees when it calls this subroutine.
* RATIO - Previous to present energy ratio
* Always assigned a value.
*
SUBROUTINE PITSYN( ORDER, VOICE, PITCH, RMS, RC, LFRAME,
1 IVUV, IPITI, RMSI, RCI, NOUT, RATIO )
INCLUDE 'config.fh'
* Arguments
INTEGER ORDER, VOICE(2), PITCH
REAL RMS, RC(ORDER)
INTEGER LFRAME
INTEGER IVUV(16), IPITI(16)
REAL RMSI(16), RCI(ORDER,16)
INTEGER NOUT
REAL RATIO
* Local variables that need not be saved
* LSAMP is initialized in the IF (FIRST) THEN clause, but it is
* not used the first time through, and it is given a value before
* use whenever FIRST is .FALSE., so it appears unnecessary to
* assign it a value when FIRST is .TRUE.
INTEGER I, J, LSAMP, IP, ISTART, IVOICE
INTEGER JUSED, NL
REAL ALRN, ALRO, PROP
REAL SLOPE, UVPIT, XXY
INTEGER VFLAG
REAL YARC(MAXORD)
* Local state
* FIRST - .TRUE. only on first call to PITSYN.
* IVOICO - Previous VOICE(2) value.
* IPITO - Previous PITCH value.
* RMSO - Previous RMS value.
* RCO - Previous RC values.
*
* JSAMP - If this routine is called N times with identical values of
* LFRAME, then the total length of all pitch periods returned
* is always N*LFRAME-JSAMP, and JSAMP is always in the range 0
* to MAXPIT-1 (see below for why this is so). Thus JSAMP is
* the number of samples "left over" from the previous call to
* PITSYN, that haven't been "used" in a pitch period returned
* from this subroutine. Every time this subroutine is called,
* it returns pitch periods with a total length of at most
* LFRAME+JSAMP.
*
* IVOICO, IPITO, RCO, and JSAMP need not be assigned an initial value
* with a DATA statement, because they are always initialized on the
* first call to PITSYN.
*
* FIRST and RMSO should be initialized with DATA statements, because
* even on the first call, they are used before being initialized.
INTEGER IVOICO, IPITO
REAL RMSO
REAL RCO(MAXORD)
INTEGER JSAMP
LOGICAL FIRST
SAVE IVOICO, IPITO, RMSO, RCO, JSAMP, FIRST
DATA RMSO /1./
DATA FIRST /.TRUE./
IF (RMS .LT. 1) RMS = 1
IF (RMSO .LT. 1) RMSO = 1
UVPIT = 0.0
RATIO = RMS/(RMSO+8.)
IF (FIRST) THEN
LSAMP = 0
IVOICE = VOICE(2)
IF (IVOICE .EQ. 0) PITCH = LFRAME/4
NOUT = LFRAME/PITCH
JSAMP = LFRAME - NOUT*PITCH
*
* SYNTHS only calls this subroutine with PITCH in the range 20
* to 156. LFRAME = MAXFRM = 180, so NOUT is somewhere in the
* range 1 to 9.
*
* JSAMP is "LFRAME mod PITCH", so it is in the range 0 to
* (PITCH-1), or 0 to MAXPIT-1=155, after the first call.
*
DO I = 1,NOUT
DO J = 1,ORDER
RCI(J,I) = RC(J)
END DO
IVUV(I) = IVOICE
IPITI(I) = PITCH
RMSI(I) = RMS
END DO
FIRST = .FALSE.
ELSE
VFLAG = 0
LSAMP = LFRAME + JSAMP
SLOPE = (PITCH-IPITO)/FLOAT(LSAMP)
NOUT = 0
JUSED = 0
ISTART = 1
IF ((VOICE(1) .EQ. IVOICO) .AND. (VOICE(2) .EQ. VOICE(1))) THEN
IF (VOICE(2) .EQ. 0) THEN
* SSUV - - 0 , 0 , 0
PITCH = LFRAME/4
IPITO = PITCH
IF (RATIO .GT. 8) RMSO = RMS
END IF
* SSVC - - 1 , 1 , 1
SLOPE = (PITCH-IPITO)/FLOAT(LSAMP)
IVOICE = VOICE(2)
ELSE
IF (IVOICO .NE. 1) THEN
IF (IVOICO .EQ. VOICE(1)) THEN
* UV2VC2 - - 0 , 0 , 1
NL = LSAMP - LFRAME/4
ELSE
* UV2VC1 - - 0 , 1 , 1
NL = LSAMP - 3*LFRAME/4
ENDIF
IPITI(1) = NL/2
IPITI(2) = NL - IPITI(1)
IVUV(1) = 0
IVUV(2) = 0
RMSI(1) = RMSO
RMSI(2) = RMSO
DO I = 1,ORDER
RCI(I,1) = RCO(I)
RCI(I,2) = RCO(I)
RCO(I) = RC(I)
END DO
SLOPE = 0
NOUT = 2
IPITO = PITCH
JUSED = NL
ISTART = NL + 1
IVOICE = 1
ELSE
IF (IVOICO .NE. VOICE(1)) THEN
* VC2UV1 - - 1 , 0 , 0
LSAMP = LFRAME/4 + JSAMP
ELSE
* VC2UV2 - - 1 , 1 , 0
LSAMP = 3*LFRAME/4 + JSAMP
END IF
DO I = 1,ORDER
YARC(I) = RC(I)
RC(I) = RCO(I)
END DO
IVOICE = 1
SLOPE = 0.
VFLAG = 1
END IF
END IF
* Here is the value of most variables that are used below, depending on
* the values of IVOICO, VOICE(1), and VOICE(2). VOICE(1) and VOICE(2)
* are input arguments, and IVOICO is the value of VOICE(2) on the
* previous call (see notes for the IF (NOUT .NE. 0) statement near the
* end). Each of these three values is either 0 or 1. These three
* values below are given as 3-bit long strings, in the order IVOICO,
* VOICE(1), and VOICE(2). It appears that the code above assumes that
* the bit sequences 010 and 101 never occur, but I wonder whether a
* large enough number of bit errors in the channel could cause such a
* thing to happen, and if so, could that cause NOUT to ever go over 11?
*
* Note that all of the 180 values in the table are really LFRAME, but
* 180 has fewer characters, and it makes the table a little more
* concrete. If LFRAME is ever changed, keep this in mind. Similarly,
* 135's are 3*LFRAME/4, and 45's are LFRAME/4. If LFRAME is not a
* multiple of 4, then the 135 for NL-JSAMP is actually LFRAME-LFRAME/4,
* and the 45 for NL-JSAMP is actually LFRAME-3*LFRAME/4.
*
* Note that LSAMP-JSAMP is given as the variable. This was just for
* brevity, to avoid adding "+JSAMP" to all of the column entries.
* Similarly for NL-JSAMP.
*
* Variable | 000 001 011,010 111 110 100,101
* ------------+--------------------------------------------------
* ISTART | 1 NL+1 NL+1 1 1 1
* LSAMP-JSAMP | 180 180 180 180 135 45
* IPITO | 45 PITCH PITCH oldPITCH oldPITCH oldPITCH
* SLOPE | 0 0 0 seebelow 0 0
* JUSED | 0 NL NL 0 0 0
* PITCH | 45 PITCH PITCH PITCH PITCH PITCH
* NL-JSAMP | -- 135 45 -- -- --
* VFLAG | 0 0 0 0 1 1
* NOUT | 0 2 2 0 0 0
* IVOICE | 0 1 1 1 1 1
*
* while_loop | once once once once twice twice
*
* ISTART | -- -- -- -- JUSED+1 JUSED+1
* LSAMP-JSAMP | -- -- -- -- 180 180
* IPITO | -- -- -- -- oldPITCH oldPITCH
* SLOPE | -- -- -- -- 0 0
* JUSED | -- -- -- -- ?? ??
* PITCH | -- -- -- -- PITCH PITCH
* NL-JSAMP | -- -- -- -- -- --
* VFLAG | -- -- -- -- 0 0
* NOUT | -- -- -- -- ?? ??
* IVOICE | -- -- -- -- 0 0
*
*
* UVPIT is always 0.0 on the first pass through the DO WHILE (.TRUE.)
* loop below.
*
* The only possible non-0 value of SLOPE (in column 111) is
* (PITCH-IPITO)/FLOAT(LSAMP)
*
* Column 101 is identical to 100. Any good properties we can prove
* for 100 will also hold for 101. Similarly for 010 and 011.
*
* SYNTHS calls this subroutine with PITCH restricted to the range 20 to
* 156. IPITO is similarly restricted to this range, after the first
* call. IP below is also restricted to this range, given the
* definitions of IPITO, SLOPE, UVPIT, and that I is in the range ISTART
* to LSAMP.
*
DO WHILE (.TRUE.)
*
* JUSED is the total length of all pitch periods currently
* in the output arrays, in samples.
*
* An invariant of the DO I = ISTART,LSAMP loop below, under
* the condition that IP is always in the range 1 through
* MAXPIT, is:
*
* (I - MAXPIT) .LE. JUSED .LE. (I-1)
*
* Note that the final value of I is LSAMP+1, so that after
* the DO loop is complete, we know:
*
* (LSAMP - MAXPIT + 1) .LE. JUSED .LE. LSAMP
*
DO I = ISTART,LSAMP
IP = IPITO + SLOPE*I + .5
IF (UVPIT .NE. 0.0) IP = UVPIT
IF (IP .LE. I-JUSED) THEN
NOUT = NOUT + 1
*
* The following check is no longer necessary, now that
* we can prove that NOUT will never go over 16.
*
* IF (NOUT .GT. 16) STOP 'PITSYN: too many epochs'
*
IPITI(NOUT) = IP
PITCH = IP
IVUV(NOUT) = IVOICE
JUSED = JUSED + IP
PROP = (JUSED-IP/2)/FLOAT(LSAMP)
DO J = 1,ORDER
ALRO = ALOG((1+RCO(J))/(1-RCO(J)))
ALRN = ALOG((1+RC(J))/(1-RC(J)))
XXY = ALRO + PROP*(ALRN-ALRO)
XXY = EXP(XXY)
RCI(J,NOUT) = (XXY-1)/(XXY+1)
END DO
RMSI(NOUT) = ALOG(RMSO) + PROP*(ALOG(RMS)-ALOG(RMSO))
RMSI(NOUT) = EXP(RMSI(NOUT))
END IF
END DO
IF (VFLAG .NE. 1) GOTO 100
*
* I want to prove what range UVPIT must lie in after the
* assignments to it below. To do this, I must determine
* what range (LSAMP-ISTART) must lie in, after the
* assignments to ISTART and LSAMP below.
*
* Let oldLSAMP be the value of LSAMP at this point in the
* execution. This is 135+JSAMP in state 110, or 45+JSAMP in
* states 100 or 101.
*
* Given the loop invariant on JUSED above, we know that:
*
* (oldLSAMP - MAXPIT + 1) .LE. JUSED .LE. oldLSAMP
*
* ISTART is one more than this.
*
* Let newLSAMP be the value assigned to LSAMP below. This
* is 180+JSAMP. Thus (newLSAMP-oldLSAMP) is either 45 or
* 135, depending on the state.
*
* Thus, the range of newLSAMP-ISTART is:
*
* (newLSAMP-(oldLSAMP+1)) .LE. newLSAMP-ISTART
* .LE. (newLSAMP-(oldLSAMP - MAXPIT + 2))
*
* or:
*
* 46 .LE. newLSAMP-ISTART .LE. 133+MAXPIT .EQ. 289
*
* Therefore, UVPIT is in the range 23 to 144 after the first
* assignment to UVPIT below, and after the conditional
* assignment, it is in the range 23 to 90.
*
* The important thing is that it is in the range 20 to 156,
* so that in the loop above, IP is always in this range.
*
VFLAG = 0
ISTART = JUSED + 1
LSAMP = LFRAME + JSAMP
SLOPE = 0
IVOICE = 0
UVPIT = (LSAMP-ISTART)/2
IF (UVPIT .GT. 90) UVPIT = UVPIT/2
RMSO = RMS
DO I = 1,ORDER
RC(I) = YARC(I)
RCO(I) = YARC(I)
END DO
END DO
100 JSAMP = LSAMP - JUSED
END IF
* Given that the maximum pitch period MAXPIT .LT. LFRAME (this is
* currently true on every call, since SYNTHS always sets
* LFRAME=180), NOUT will always be .GE. 1 at this point.
IF (NOUT .NE. 0) THEN
IVOICO = VOICE(2)
IPITO = PITCH
RMSO = RMS
DO I = 1,ORDER
RCO(I) = RC(I)
END DO
END IF
RETURN
ENTRY INITPITSYN ()
RMSO = 1.
FIRST = .TRUE.
RETURN
END