Blame lib/paranoia/gap.c

Packit cb6d3d
/*
Packit cb6d3d
  Copyright (C) 2004, 2008, 2011 Rocky Bernstein <rocky@gnu.org>
Packit cb6d3d
  Copyright (C) 1998 Monty xiphmont@mit.edu
Packit cb6d3d
Packit cb6d3d
  This program is free software: you can redistribute it and/or modify
Packit cb6d3d
  it under the terms of the GNU General Public License as published by
Packit cb6d3d
  the Free Software Foundation, either version 3 of the License, or
Packit cb6d3d
  (at your option) any later version.
Packit cb6d3d
Packit cb6d3d
  This program is distributed in the hope that it will be useful,
Packit cb6d3d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cb6d3d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit cb6d3d
  GNU General Public License for more details.
Packit cb6d3d
Packit cb6d3d
  You should have received a copy of the GNU General Public License
Packit cb6d3d
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit cb6d3d
*/
Packit cb6d3d
/***
Packit cb6d3d
 * Gap analysis support code for paranoia
Packit cb6d3d
 *
Packit cb6d3d
 ***/
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_CONFIG_H
Packit cb6d3d
# include "config.h"
Packit cb6d3d
# define __CDIO_CONFIG_H__ 1
Packit cb6d3d
#endif
Packit cb6d3d
#include "p_block.h"
Packit cb6d3d
#include <cdio/paranoia/paranoia.h>
Packit cb6d3d
#include "gap.h"
Packit cb6d3d
#include <string.h>
Packit cb6d3d
Packit cb6d3d
/**** Gap analysis code ***************************************************/
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * i_paranoia_overlap_r (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function seeks backward through two vectors (starting at the given
Packit cb6d3d
 * offsets) to determine how many consecutive samples agree.  It returns
Packit cb6d3d
 * the number of matching samples, which may be 0.
Packit cb6d3d
 *
Packit cb6d3d
 * Unlike its sibling, i_paranoia_overlap_f, this function doesn't need to
Packit cb6d3d
 * be given the size of the vectors (all vectors stop at offset 0).
Packit cb6d3d
 *
Packit cb6d3d
 * This function is used by i_analyze_rift_r() below to find where a
Packit cb6d3d
 * leading rift ends.
Packit cb6d3d
 */
Packit cb6d3d
long int
Packit cb6d3d
i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB,
Packit cb6d3d
			  long offsetA, long offsetB)
Packit cb6d3d
{
Packit cb6d3d
  long beginA=offsetA;
Packit cb6d3d
  long beginB=offsetB;
Packit cb6d3d
Packit cb6d3d
  /* Start at the given offsets and work our way backwards until we hit
Packit cb6d3d
   * the beginning of one of the vectors.
Packit cb6d3d
   */
Packit cb6d3d
  for( ; beginA>=0 && beginB>=0; beginA--,beginB-- )
Packit cb6d3d
    if (buffA[beginA] != buffB[beginB]) break;
Packit cb6d3d
Packit cb6d3d
  return(offsetA-beginA);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * i_paranoia_overlap_f (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function seeks forward through two vectors (starting at the given
Packit cb6d3d
 * offsets) to determine how many consecutive samples agree.  It returns
Packit cb6d3d
 * the number of matching samples, which may be 0.
Packit cb6d3d
 *
Packit cb6d3d
 * Unlike its sibling, i_paranoia_overlap_r, this function needs to given
Packit cb6d3d
 * the size of the vectors.
Packit cb6d3d
 *
Packit cb6d3d
 * This function is used by i_analyze_rift_f() below to find where a
Packit cb6d3d
 * trailing rift ends.
Packit cb6d3d
 */
Packit cb6d3d
long int 
Packit cb6d3d
i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB,
Packit cb6d3d
		     long offsetA, long offsetB,
Packit cb6d3d
		     long sizeA,long sizeB)
Packit cb6d3d
{
Packit cb6d3d
  long endA=offsetA;
Packit cb6d3d
  long endB=offsetB;
Packit cb6d3d
  
Packit cb6d3d
  /* Start at the given offsets and work our way forward until we hit
Packit cb6d3d
   * the end of one of the vectors.
Packit cb6d3d
   */
Packit cb6d3d
  for(;endA
Packit cb6d3d
    if(buffA[endA]!=buffB[endB])break;
Packit cb6d3d
  
Packit cb6d3d
  return(endA-offsetA);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * i_stutter_or_gap (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function compares (gap) samples of two vectors at the given offsets.
Packit cb6d3d
 * It returns 0 if all the samples are identical, or nonzero if they differ.
Packit cb6d3d
 *
Packit cb6d3d
 * This is used by i_analyze_rift_[rf] below to determine whether a rift
Packit cb6d3d
 * contains samples dropped by the other vector (that should be inserted),
Packit cb6d3d
 * or whether the rift contains a stutter (that should be dropped).  See
Packit cb6d3d
 * i_analyze_rift_[rf] for more details.
Packit cb6d3d
 */
Packit cb6d3d
int 
Packit cb6d3d
i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB, long int gap)
Packit cb6d3d
{
Packit cb6d3d
  long a1=offA;
Packit cb6d3d
  long b1=offB;
Packit cb6d3d
  
Packit cb6d3d
  /* If the rift was so big that there aren't enough samples in the other
Packit cb6d3d
   * vector to compare against the full gap, then just compare what we
Packit cb6d3d
   * have available.  E.g.:
Packit cb6d3d
   *
Packit cb6d3d
   *            (5678)|(newly matching run ...)
Packit cb6d3d
   *    (... 12345678)| (345678) |(newly matching run ...)
Packit cb6d3d
   *
Packit cb6d3d
   * In this case, a1 would be -2, since we'd want to compare 6 samples
Packit cb6d3d
   * against a vector that had only 4.  So we start 2 samples later, and
Packit cb6d3d
   * compare the 4 available samples.
Packit cb6d3d
   *
Packit cb6d3d
   * Again, this approach to identifying stutters is simply a heuristic,
Packit cb6d3d
   * so this may not produce correct results in all cases.
Packit cb6d3d
   */
Packit cb6d3d
  if(a1<0){
Packit cb6d3d
    /* Note that a1 is negative, so we're increasing b1 and decreasing (gap).
Packit cb6d3d
     */
Packit cb6d3d
    b1-=a1;
Packit cb6d3d
    gap+=a1;
Packit cb6d3d
    a1=0;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* Note that we don't have an equivalent adjustment for leading rifts.
Packit cb6d3d
   * Thus, it's possible for the following memcmp() to run off the end
Packit cb6d3d
   * of A.  See the bug note in i_analyze_rift_r().
Packit cb6d3d
   */
Packit cb6d3d
  
Packit cb6d3d
  /* Multiply gap by 2 because samples are 2 bytes long and memcmp compares
Packit cb6d3d
   * at the byte level.
Packit cb6d3d
   */
Packit cb6d3d
  return(memcmp(A+a1,B+b1,gap*2));
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
/* riftv is the first value into the rift -> or <- */
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * i_analyze_rift_f (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function examines a trailing rift to see how far forward the rift goes
Packit cb6d3d
 * and to determine what kind of rift it is.  This function is called by
Packit cb6d3d
 * i_stage2_each() when a trailing rift is detected.  (aoffset,boffset) are
Packit cb6d3d
 * the offsets into (A,B) of the first mismatching sample.
Packit cb6d3d
 *
Packit cb6d3d
 * This function returns:
Packit cb6d3d
 *  matchA  > 0 if there are (matchA) samples missing from A
Packit cb6d3d
 *  matchA  < 0 if there are (-matchA) duplicate samples (stuttering) in A
Packit cb6d3d
 *  matchB  > 0 if there are (matchB) samples missing from B
Packit cb6d3d
 *  matchB  < 0 if there are (-matchB) duplicate samples in B
Packit cb6d3d
 *  matchC != 0 if there are (matchC) samples of garbage, after which
Packit cb6d3d
 *              both A and B are in sync again
Packit cb6d3d
 */
Packit cb6d3d
void 
Packit cb6d3d
i_analyze_rift_f(int16_t *A,int16_t *B,
Packit cb6d3d
		 long sizeA, long sizeB,
Packit cb6d3d
		 long aoffset, long boffset, 
Packit cb6d3d
		 long *matchA,long *matchB,long *matchC)
Packit cb6d3d
{
Packit cb6d3d
  
Packit cb6d3d
  long apast=sizeA-aoffset;
Packit cb6d3d
  long bpast=sizeB-boffset;
Packit cb6d3d
  long i;
Packit cb6d3d
  
Packit cb6d3d
  *matchA=0, *matchB=0, *matchC=0;
Packit cb6d3d
  
Packit cb6d3d
  /* Look forward to see where we regain agreement between vectors
Packit cb6d3d
   * A and B (of at least MIN_WORDS_RIFT samples).  We look for one of
Packit cb6d3d
   * the following possible matches:
Packit cb6d3d
   * 
Packit cb6d3d
   *                         edge
Packit cb6d3d
   *                          v
Packit cb6d3d
   * (1)  (... A matching run)|(aoffset matches ...)
Packit cb6d3d
   *      (... B matching run)| (rift) |(boffset+i matches ...)
Packit cb6d3d
   *
Packit cb6d3d
   * (2)  (... A matching run)| (rift) |(aoffset+i matches ...)
Packit cb6d3d
   *      (... B matching run)|(boffset matches ...)
Packit cb6d3d
   *
Packit cb6d3d
   * (3)  (... A matching run)| (rift) |(aoffset+i matches ...)
Packit cb6d3d
   *      (... B matching run)| (rift) |(boffset+i matches ...)
Packit cb6d3d
   *
Packit cb6d3d
   * Anything that doesn't match one of these three is too corrupt to
Packit cb6d3d
   * for us to recover from.  E.g.:
Packit cb6d3d
   *
Packit cb6d3d
   *      (... A matching run)| (rift) |(eventual match ...)
Packit cb6d3d
   *      (... B matching run)| (big rift) |(eventual match ...)
Packit cb6d3d
   *
Packit cb6d3d
   * We won't find the eventual match, since we wouldn't be sure how
Packit cb6d3d
   * to fix the rift.
Packit cb6d3d
   */
Packit cb6d3d
  
Packit cb6d3d
  for(i=1;;i++){
Packit cb6d3d
    /* Search for whatever case we hit first, so as to end up with the
Packit cb6d3d
     * smallest rift.
Packit cb6d3d
     */
Packit cb6d3d
Packit cb6d3d
    /* Don't search for (1) past the end of B */
Packit cb6d3d
    if (i
Packit cb6d3d
Packit cb6d3d
      /* See if we match case (1) above, which either means that A dropped
Packit cb6d3d
       * samples at the rift, or that B stuttered.
Packit cb6d3d
       */
Packit cb6d3d
      if(i_paranoia_overlap_f(A,B,aoffset,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
Packit cb6d3d
	*matchA=i;
Packit cb6d3d
	break;
Packit cb6d3d
      }
Packit cb6d3d
    
Packit cb6d3d
    /* Don't search for (2) or (3) past the end of A */
Packit cb6d3d
    if (i
Packit cb6d3d
Packit cb6d3d
      /* See if we match case (2) above, which either means that B dropped
Packit cb6d3d
       * samples at the rift, or that A stuttered.
Packit cb6d3d
       */
Packit cb6d3d
      if(i_paranoia_overlap_f(A,B,aoffset+i,boffset,sizeA,sizeB)>=MIN_WORDS_RIFT){
Packit cb6d3d
	*matchB=i;
Packit cb6d3d
	break;
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      /* Don't search for (3) past the end of B */
Packit cb6d3d
      if (i
Packit cb6d3d
Packit cb6d3d
        /* See if we match case (3) above, which means that a fixed-length
Packit cb6d3d
         * rift of samples is getting read unreliably.
Packit cb6d3d
         */
Packit cb6d3d
	if(i_paranoia_overlap_f(A,B,aoffset+i,boffset+i,sizeA,sizeB)>=MIN_WORDS_RIFT){
Packit cb6d3d
	  *matchC=i;
Packit cb6d3d
	  break;
Packit cb6d3d
	}
Packit cb6d3d
    }else
Packit cb6d3d
Packit cb6d3d
      /* Stop searching when we've reached the end of both vectors.
Packit cb6d3d
       * In theory we could stop when there aren't MIN_WORDS_RIFT samples
Packit cb6d3d
       * left in both vectors, but this case should happen fairly rarely.
Packit cb6d3d
       */
Packit cb6d3d
      if(i>=bpast)break;
Packit cb6d3d
    
Packit cb6d3d
    /* Try the search again with a larger tentative rift. */
Packit cb6d3d
  }
Packit cb6d3d
  
Packit cb6d3d
  if(*matchA==0 && *matchB==0 && *matchC==0)return;
Packit cb6d3d
  
Packit cb6d3d
  if(*matchC)return;
Packit cb6d3d
Packit cb6d3d
  /* For case (1) or (2), we need to determine whether the rift contains
Packit cb6d3d
   * samples dropped by the other vector (that should be inserted), or
Packit cb6d3d
   * whether the rift contains a stutter (that should be dropped).  To
Packit cb6d3d
   * distinguish, we check the contents of the rift against the good samples
Packit cb6d3d
   * just before the rift.  If the contents match, then the rift contains
Packit cb6d3d
   * a stutter.
Packit cb6d3d
   *
Packit cb6d3d
   * A stutter in the second vector:
Packit cb6d3d
   *     (...good samples... 1234)|(567 ...newly matched run...)
Packit cb6d3d
   *     (...good samples... 1234)| (1234) | (567 ...newly matched run)
Packit cb6d3d
   *
Packit cb6d3d
   * Samples missing from the first vector:
Packit cb6d3d
   *     (...good samples... 1234)|(901 ...newly matched run...)
Packit cb6d3d
   *     (...good samples... 1234)| (5678) |(901 ...newly matched run...)
Packit cb6d3d
   *
Packit cb6d3d
   * Of course, there's no theoretical guarantee that a non-stutter
Packit cb6d3d
   * truly represents missing samples, but given that we're dealing with
Packit cb6d3d
   * verified fragments in stage 2, we can have some confidence that this
Packit cb6d3d
   * is the case.
Packit cb6d3d
   */
Packit cb6d3d
  if(*matchA){
Packit cb6d3d
    /* For case (1), we need to determine whether A dropped samples at the
Packit cb6d3d
     * rift or whether B stuttered.
Packit cb6d3d
     *
Packit cb6d3d
     * If the rift doesn't match the good samples in A (and hence in B),
Packit cb6d3d
     * it's not a stutter, and the rift should be inserted into A.
Packit cb6d3d
     */
Packit cb6d3d
    if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA))
Packit cb6d3d
      return;
Packit cb6d3d
Packit cb6d3d
    /* It is a stutter, so we need to signal that we need to remove
Packit cb6d3d
     * (matchA) bytes from B.
Packit cb6d3d
     */
Packit cb6d3d
    *matchB = -*matchA;
Packit cb6d3d
    *matchA=0;
Packit cb6d3d
    return;
Packit cb6d3d
Packit cb6d3d
  }else{
Packit cb6d3d
    /* Case (2) is the inverse of case (1) above. */
Packit cb6d3d
    if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB))
Packit cb6d3d
      return;
Packit cb6d3d
Packit cb6d3d
    *matchA = -*matchB;
Packit cb6d3d
    *matchB=0;
Packit cb6d3d
    return;
Packit cb6d3d
  }
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
/* riftv must be first even val of rift moving back */
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * i_analyze_rift_r (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function examines a leading rift to see how far back the rift goes
Packit cb6d3d
 * and to determine what kind of rift it is.  This function is called by
Packit cb6d3d
 * i_stage2_each() when a leading rift is detected.  (aoffset,boffset) are
Packit cb6d3d
 * the offsets into (A,B) of the first mismatching sample.
Packit cb6d3d
 *
Packit cb6d3d
 * This function returns:
Packit cb6d3d
 *  matchA  > 0 if there are (matchA) samples missing from A
Packit cb6d3d
 *  matchA  < 0 if there are (-matchA) duplicate samples (stuttering) in A
Packit cb6d3d
 *  matchB  > 0 if there are (matchB) samples missing from B
Packit cb6d3d
 *  matchB  < 0 if there are (-matchB) duplicate samples in B
Packit cb6d3d
 *  matchC != 0 if there are (matchC) samples of garbage, after which
Packit cb6d3d
 *              both A and B are in sync again
Packit cb6d3d
 */
Packit cb6d3d
void 
Packit cb6d3d
i_analyze_rift_r(int16_t *A,int16_t *B,
Packit cb6d3d
		 long sizeA, long sizeB,
Packit cb6d3d
		 long aoffset, long boffset, 
Packit cb6d3d
		 long *matchA,long *matchB,long *matchC)
Packit cb6d3d
{
Packit cb6d3d
  
Packit cb6d3d
  long apast=aoffset+1;
Packit cb6d3d
  long bpast=boffset+1;
Packit cb6d3d
  long i;
Packit cb6d3d
  
Packit cb6d3d
  *matchA=0, *matchB=0, *matchC=0;
Packit cb6d3d
Packit cb6d3d
  /* Look backward to see where we regain agreement between vectors
Packit cb6d3d
   * A and B (of at least MIN_WORDS_RIFT samples).  We look for one of
Packit cb6d3d
   * the following possible matches:
Packit cb6d3d
   * 
Packit cb6d3d
   *                                    edge
Packit cb6d3d
   *                                      v
Packit cb6d3d
   * (1)             (... aoffset matches)|(A matching run ...)
Packit cb6d3d
   *      (... boffset-i matches)| (rift) |(B matching run ...)
Packit cb6d3d
   *
Packit cb6d3d
   * (2)  (... aoffset-i matches)| (rift) |(A matching run ...)
Packit cb6d3d
   *                (... boffset matches)|(B matching run ...)
Packit cb6d3d
   *
Packit cb6d3d
   * (3)  (... aoffset-i matches)| (rift) |(A matching run ...)
Packit cb6d3d
   *      (... boffset-i matches)| (rift) |(B matching run ...)
Packit cb6d3d
   *
Packit cb6d3d
   * Anything that doesn't match one of these three is too corrupt to
Packit cb6d3d
   * for us to recover from.  E.g.:
Packit cb6d3d
   *
Packit cb6d3d
   *         (... eventual match)| (rift) |(A matching run ...)
Packit cb6d3d
   *    (... eventual match) | (big rift) |(B matching run ...)
Packit cb6d3d
   *
Packit cb6d3d
   * We won't find the eventual match, since we wouldn't be sure how
Packit cb6d3d
   * to fix the rift.
Packit cb6d3d
   */
Packit cb6d3d
  
Packit cb6d3d
  for(i=1;;i++){
Packit cb6d3d
    /* Search for whatever case we hit first, so as to end up with the
Packit cb6d3d
     * smallest rift.
Packit cb6d3d
     */
Packit cb6d3d
Packit cb6d3d
    /* Don't search for (1) past the beginning of B */
Packit cb6d3d
    if (i
Packit cb6d3d
Packit cb6d3d
      /* See if we match case (1) above, which either means that A dropped
Packit cb6d3d
       * samples at the rift, or that B stuttered.
Packit cb6d3d
       */
Packit cb6d3d
      if(i_paranoia_overlap_r(A,B,aoffset,boffset-i)>=MIN_WORDS_RIFT){
Packit cb6d3d
	*matchA=i;
Packit cb6d3d
	break;
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
    /* Don't search for (2) or (3) past the beginning of A */
Packit cb6d3d
    if (i
Packit cb6d3d
Packit cb6d3d
      /* See if we match case (2) above, which either means that B dropped
Packit cb6d3d
       * samples at the rift, or that A stuttered.
Packit cb6d3d
       */
Packit cb6d3d
      if(i_paranoia_overlap_r(A,B,aoffset-i,boffset)>=MIN_WORDS_RIFT){
Packit cb6d3d
	*matchB=i;
Packit cb6d3d
	break;
Packit cb6d3d
      }
Packit cb6d3d
Packit cb6d3d
      /* Don't search for (3) past the beginning of B */
Packit cb6d3d
      if (i
Packit cb6d3d
Packit cb6d3d
	/* See if we match case (3) above, which means that a fixed-length
Packit cb6d3d
	 * rift of samples is getting read unreliably.
Packit cb6d3d
	 */
Packit cb6d3d
	if(i_paranoia_overlap_r(A,B,aoffset-i,boffset-i)>=MIN_WORDS_RIFT){
Packit cb6d3d
	  *matchC=i;
Packit cb6d3d
	  break;
Packit cb6d3d
	}
Packit cb6d3d
    }else
Packit cb6d3d
Packit cb6d3d
      /* Stop searching when we've reached the end of both vectors.
Packit cb6d3d
       * In theory we could stop when there aren't MIN_WORDS_RIFT samples
Packit cb6d3d
       * left in both vectors, but this case should happen fairly rarely.
Packit cb6d3d
       */
Packit cb6d3d
      if(i>=bpast)break;
Packit cb6d3d
Packit cb6d3d
    /* Try the search again with a larger tentative rift. */
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if(*matchA==0 && *matchB==0 && *matchC==0)return;
Packit cb6d3d
Packit cb6d3d
  if(*matchC)return;
Packit cb6d3d
Packit cb6d3d
  /* For case (1) or (2), we need to determine whether the rift contains
Packit cb6d3d
   * samples dropped by the other vector (that should be inserted), or
Packit cb6d3d
   * whether the rift contains a stutter (that should be dropped).  To
Packit cb6d3d
   * distinguish, we check the contents of the rift against the good samples
Packit cb6d3d
   * just after the rift.  If the contents match, then the rift contains
Packit cb6d3d
   * a stutter.
Packit cb6d3d
   *
Packit cb6d3d
   * A stutter in the second vector:
Packit cb6d3d
   *              (...newly matched run... 234)|(5678 ...good samples...)
Packit cb6d3d
   *     (...newly matched run... 234)| (5678) |(5678 ...good samples...)
Packit cb6d3d
   *
Packit cb6d3d
   * Samples missing from the first vector:
Packit cb6d3d
   *              (...newly matched run... 890)|(5678 ...good samples...)
Packit cb6d3d
   *     (...newly matched run... 890)| (1234) |(5678 ...good samples...)
Packit cb6d3d
   *
Packit cb6d3d
   * Of course, there's no theoretical guarantee that a non-stutter
Packit cb6d3d
   * truly represents missing samples, but given that we're dealing with
Packit cb6d3d
   * verified fragments in stage 2, we can have some confidence that this
Packit cb6d3d
   * is the case.
Packit cb6d3d
   */
Packit cb6d3d
Packit cb6d3d
  if(*matchA){
Packit cb6d3d
    /* For case (1), we need to determine whether A dropped samples at the
Packit cb6d3d
     * rift or whether B stuttered.
Packit cb6d3d
     *
Packit cb6d3d
     * If the rift doesn't match the good samples in A (and hence in B),
Packit cb6d3d
     * it's not a stutter, and the rift should be inserted into A.
Packit cb6d3d
     *
Packit cb6d3d
     * ???BUG??? It's possible for aoffset+1+*matchA to be > sizeA, in
Packit cb6d3d
     * which case the comparison in i_stutter_or_gap() will extend beyond
Packit cb6d3d
     * the bounds of A.  Thankfully, this isn't writing data and thus
Packit cb6d3d
     * trampling memory, but it's still a memory access error that should
Packit cb6d3d
     * be fixed.
Packit cb6d3d
     *
Packit cb6d3d
     * This bug is not fixed yet.
Packit cb6d3d
     */
Packit cb6d3d
    if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA))
Packit cb6d3d
      return;
Packit cb6d3d
Packit cb6d3d
    /* It is a stutter, so we need to signal that we need to remove
Packit cb6d3d
     * (matchA) bytes from B.
Packit cb6d3d
     */
Packit cb6d3d
    *matchB = -*matchA;
Packit cb6d3d
    *matchA=0;
Packit cb6d3d
    return;
Packit cb6d3d
Packit cb6d3d
  }else{
Packit cb6d3d
    /* Case (2) is the inverse of case (1) above. */
Packit cb6d3d
    if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB))
Packit cb6d3d
      return;
Packit cb6d3d
Packit cb6d3d
    *matchA = -*matchB;
Packit cb6d3d
    *matchB=0;
Packit cb6d3d
    return;
Packit cb6d3d
  }
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
Packit cb6d3d
/* ===========================================================================
Packit cb6d3d
 * analyze_rift_silence_f (internal)
Packit cb6d3d
 *
Packit cb6d3d
 * This function examines the fragment and root from the rift onward to
Packit cb6d3d
 * see if they have a rift's worth of silence (or if they end with silence).
Packit cb6d3d
 * It sets (*matchA) to -1 if A's rift is silence, (*matchB) to -1 if B's
Packit cb6d3d
 * rift is silence, and sets them to 0 otherwise.
Packit cb6d3d
 *
Packit cb6d3d
 * Note that, unlike every other function in cdparanoia, this function
Packit cb6d3d
 * considers any repeated value to be silence (which, in effect, it is).
Packit cb6d3d
 * All other functions only consider repeated zeroes to be silence.
Packit cb6d3d
 *
Packit cb6d3d
 * ??? Is this function name just a misnomer, as it's really looking for
Packit cb6d3d
 * repeated garbage?
Packit cb6d3d
 *
Packit cb6d3d
 * This function is called by i_stage2_each() if it runs into a trailing rift
Packit cb6d3d
 * that i_analyze_rift_f couldn't diagnose.  This checks for another variant:
Packit cb6d3d
 * where one vector has silence and the other doesn't.  We then assume
Packit cb6d3d
 * that the silence (and anything following it) is garbage.
Packit cb6d3d
 *
Packit cb6d3d
 * Note that while this function checks both A and B for silence, the caller
Packit cb6d3d
 * assumes that only one or the other has silence.
Packit cb6d3d
 */
Packit cb6d3d
void
Packit cb6d3d
analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB,
Packit cb6d3d
		       long aoffset, long boffset,
Packit cb6d3d
		       long *matchA, long *matchB)
Packit cb6d3d
{
Packit cb6d3d
  *matchA=-1;
Packit cb6d3d
  *matchB=-1;
Packit cb6d3d
Packit cb6d3d
  /* Search for MIN_WORDS_RIFT samples, or to the end of the vector,
Packit cb6d3d
   * whichever comes first.
Packit cb6d3d
   */
Packit cb6d3d
  sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT);
Packit cb6d3d
  sizeB=min(sizeB,boffset+MIN_WORDS_RIFT);
Packit cb6d3d
Packit cb6d3d
  aoffset++;
Packit cb6d3d
  boffset++;
Packit cb6d3d
Packit cb6d3d
  /* Check whether A has only "silence" within the search range.  Note
Packit cb6d3d
   * that "silence" here is a single, repeated value (zero or not).
Packit cb6d3d
   */
Packit cb6d3d
  while(aoffset
Packit cb6d3d
    if(A[aoffset]!=A[aoffset-1]){
Packit cb6d3d
      *matchA=0;
Packit cb6d3d
      break;
Packit cb6d3d
    }
Packit cb6d3d
    aoffset++;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  /* Check whether B has only "silence" within the search range.  Note
Packit cb6d3d
   * that "silence" here is a single, repeated value (zero or not).
Packit cb6d3d
   *
Packit cb6d3d
   * Also note that while the caller assumes that only matchA or matchB
Packit cb6d3d
   * is set, we check both vectors here.
Packit cb6d3d
   */
Packit cb6d3d
  while(boffset
Packit cb6d3d
    if(B[boffset]!=B[boffset-1]){
Packit cb6d3d
      *matchB=0;
Packit cb6d3d
      break;
Packit cb6d3d
    }
Packit cb6d3d
    boffset++;
Packit cb6d3d
  }
Packit cb6d3d
}