www.pudn.com > lpc10-15.zip > onset.f


*******************************************************************
*
*	ONSET Version 49
*
* $Log: onset.f,v $
* Revision 1.5  1996/03/15  16:41:01  jaf
* Just rearranged INITONSET assignment orders to be consistent with
* order of DATA statements in ONSET.
*
* Revision 1.4  1996/03/15  15:48:27  jaf
* Changed some comments, and only reordered the DATA statements (their
* meaning wasn't changed).
*
* Revision 1.3  1996/03/14  23:53:06  jaf
* Added an entry INITONSET that reinitializes the local state variables
* of subroutine ONSET.
*
* Rearranged quite a few comments, adding more explaining which
* arguments were inputs, and how the modified ones can be changed.
*
* Revision 1.2  1996/03/12  23:53:00  jaf
* Lots of comments added about the local state of this subroutine that
* must be saved from one invocation to the next.
*
* One constant 180 replaced with LFRAME, which should be "more general",
* even though it would probably require many more changes than this to
* get this coder to work for other frame sizes.
*
* Revision 1.1  1996/02/07 14:48:09  jaf
* Initial revision
*
*
*******************************************************************
*
*	Floating point version
*
*
*   Detection of onsets in (or slightly preceding) the futuremost frame
*   of speech.
*
*
* Input:
*  PEBUF(SBUFL:SBUFH)  - Preemphasized speech
*                        Indices SBUFH-LFRAME through SBUFH are read.
*  OSLEN  - Maximum number of onsets that can be stored in OSBUF.
*  SBUFL, SBUFH        - Range of PEBUF
*  LFRAME              - length of a frame, in samples
* Input/Output:
*  OSBUF(OSLEN) - Buffer which holds sorted indexes of onsets
*                 Indices A through B are modified, where A
*                 is the original value of OSPTR, and B is the final
*                 value of OSPTR-1.  B is at most OSLEN.
*  OSPTR        - Free pointer into OSBUF
*                 Initial value should be .LE. OSLEN+1.
*                 If so, final value grows by one for each new onset
*                 found, and final value will be .LE. OSLEN+1.
* 
* This subroutine maintains local state from one call to the next.  If
* you want to switch to using a new audio stream for this subroutine, or
* reinitialize its state for any other reason, call the ENTRY INITONSET.
*

	SUBROUTINE ONSET( PEBUF, OSBUF, OSPTR, OSLEN,
     1                   SBUFL, SBUFH, LFRAME )
	INCLUDE 'config.fh'

*       Arguments

	INTEGER OSLEN, SBUFL, SBUFH, LFRAME
	REAL PEBUF(SBUFL:SBUFH)
	INTEGER OSBUF(OSLEN), OSPTR

*       Parameters/constants

*   Parameters for onset detection algorithm:
*    L2		Threshold for filtered slope of FPC (function of L2WID!)
*    L2LAG	Lag due to both filters which compute filtered slope of FPC
*    L2WID	Width of the filter which computes the slope of FPC
*    OSHYST	The number of samples of slope(FPC) which must be below
*	        the threshold before a new onset may be declared.

	INTEGER L2LAG, L2WID, OSHYST, TEMP
	REAL L2
	PARAMETER (L2=1.7, L2LAG=9, L2WID=16, OSHYST=10)
	PARAMETER (TEMP=1+L2WID/2)

*       Local variables that need not be saved

	INTEGER I
	REAL L2SUM2

*       Local state

*   Variables
*    N, D       Numerator and denominator of prediction filters
*    FPC        Current prediction coefs
*    L2BUF, L2SUM1, L2SUM2    State of slope filter

*       The only "significant" change I've made is to change L2SUM2 out
*       of the list of local variables that need to be saved, since it
*       didn't need to be.

*       L2SUM1 need not be, but avoiding saving it would require a small
*       change to the body of the code.  See comments below for an
*       example of how the code could be changed to avoid saving L2SUM1.

*       FPC and LASTI are saved from one invocation to the next, but
*       they are not given initial values.  This is acceptable, because
*       FPC will be assigned a value the first time that this function
*       is called after D is initialized to 1, since the formula to
*       change D will not change it to 0 in one step, and the IF (D
*       .NE. 0) statement will execute its THEN part, initializing FPC.
*       
*       LASTI's value will not be used until HYST is .TRUE., and
*       whenever HYST is changed from its initial value of .FALSE.,
*       LASTI is assigned a value.

*       In a C version of this coder, it would be nice if all of these
*       saved things, in this and all other subroutines, could be stored
*       in a single struct lpc10_coder_state_t, initialized with a call
*       to a function like lpc10_init(&lpc10_coder_state).  In this way,
*       a program that used these functions could conveniently alternate
*       coding more than one distinct audio stream.

	REAL N, D, FPC
	REAL L2BUF(L2WID), L2SUM1
	INTEGER L2PTR1, L2PTR2, LASTI
	LOGICAL HYST

	DATA N/0./, D/1./
	DATA L2BUF/L2WID*0./, L2SUM1/0./
	DATA L2PTR1/1/, L2PTR2/TEMP/
	DATA HYST/.FALSE./

	SAVE N, D, FPC
	SAVE L2BUF, L2SUM1
	SAVE L2PTR1, L2PTR2, LASTI
	SAVE HYST

*       The following line subtracted a hard-coded "180" from LASTI,
*       instead of using a variable like LFRAME or a constant like
*       MAXFRM.  I changed it to LFRAME, for "generality".

	IF (HYST) LASTI = LASTI - LFRAME
	DO I = SBUFH-LFRAME+1, SBUFH

*   Compute FPC; Use old FPC on divide by zero; Clamp FPC to +/- 1.
	   N=(PEBUF(I)*PEBUF(I-1)+63.*N) / 64.
	   D=(PEBUF(I-1)**2+63.*D) / 64.
	   IF (D .NE. 0.) THEN
	      IF (ABS(N) .GT. D) THEN
	         FPC = SIGN (1., N)
	      ELSE
	         FPC=N/D
	      END IF
	   END IF
*   Filter FPC

*       In order to allow L2SUM1 not to be saved from one invocation of
*       this subroutine to the next, one could change the sequence of
*       assignments below, up to the IF statement, to the following.  In
*       addition, the initial value of L2PTR2 should be changed to
*       L2WID/2 instead of L2WID/2+1.
*       
*       L2SUM1 = L2BUF(L2PTR2)
*       L2PTR2 = MOD(L2PTR2,L2WID)+1
*       L2SUM1 = L2SUM1 - L2BUF(L2PTR2) + FPC
*       L2BUF(L2PTR2) = L2SUM1
*       
**       The following lines didn't change from the original:
*       L2SUM2 = L2BUF(L2PTR1)
*       L2BUF(L2PTR1) = FPC
*       L2PTR1 = MOD(L2PTR1,L2WID)+1
*       

	   L2SUM2 = L2BUF(L2PTR1)
	   L2SUM1 = L2SUM1 - L2BUF(L2PTR2) + FPC
	   L2BUF(L2PTR2) = L2SUM1
	   L2BUF(L2PTR1) = FPC
	   L2PTR1 = MOD(L2PTR1,L2WID)+1
	   L2PTR2 = MOD(L2PTR2,L2WID)+1
	   IF (ABS(L2SUM1-L2SUM2) .GT. L2) THEN
	      IF (.NOT. HYST) THEN
*   Ignore if buffer full
	         IF (OSPTR .LE. OSLEN) THEN
	            OSBUF (OSPTR) = I - L2LAG
	            OSPTR = OSPTR + 1
	         END IF
	         HYST = .TRUE.
	      END IF
	      LASTI = I

*       After one onset detection, at least OSHYST sample times must go
*       by before another is allowed to occur.

	   ELSE IF (HYST .AND. I - LASTI .GE. OSHYST) THEN
	      HYST = .FALSE.
	   END IF
	END DO
	RETURN


	ENTRY INITONSET ()

	N = 0.
	D = 1.
	DO I = 1, L2WID
	   L2BUF(I) = 0.
	END DO
	L2SUM1 = 0.
	L2PTR1 = 1
	L2PTR2 = TEMP
	HYST = .FALSE.

	RETURN

	END