diff --git a/lib/paranoia/gap.c b/lib/paranoia/gap.c index ba4f8733..8c74dcfd 100644 --- a/lib/paranoia/gap.c +++ b/lib/paranoia/gap.c @@ -1,5 +1,5 @@ /* - $Id: gap.c,v 1.2 2005/11/07 20:06:45 pjcreath Exp $ + $Id: gap.c,v 1.3 2005/11/08 23:21:40 pjcreath Exp $ Copyright (C) 2004 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu @@ -484,7 +484,29 @@ i_analyze_rift_r(int16_t *A,int16_t *B, } -/* ??? To be studied. */ +/* =========================================================================== + * analyze_rift_silence_f (internal) + * + * This function examines the fragment and root from the rift onward to + * see if they have a rift's worth of silence (or if they end with silence). + * It sets (*matchA) to -1 if A's rift is silence, (*matchB) to -1 if B's + * rift is silence, and sets them to 0 otherwise. + * + * Note that, unlike every other function in cdparanoia, this function + * considers any repeated value to be silence (which, in effect, it is). + * All other functions only consider repeated zeroes to be silence. + * + * ??? Is this function name just a misnomer, as it's really looking for + * repeated garbage? + * + * This function is called by i_stage2_each() if it runs into a trailing rift + * that i_analyze_rift_f couldn't diagnose. This checks for another variant: + * where one vector has silence and the other doesn't. We then assume + * that the silence (and anything following it) is garbage. + * + * Note that while this function checks both A and B for silence, the caller + * assumes that only one or the other has silence. + */ void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, long aoffset, long boffset, @@ -493,12 +515,18 @@ analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, *matchA=-1; *matchB=-1; + /* Search for MIN_WORDS_RIFT samples, or to the end of the vector, + * whichever comes first. + */ sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT); sizeB=min(sizeB,boffset+MIN_WORDS_RIFT); aoffset++; boffset++; + /* Check whether A has only "silence" within the search range. Note + * that "silence" here is a single, repeated value (zero or not). + */ while(aoffset Copyright (C) 1998 Monty xiphmont@mit.edu @@ -63,6 +63,30 @@ **************************************************************/ +/* =========================================================================== + * Let's translate the above vivid metaphor into something a mere mortal + * can understand: + * + * Non-silent audio is "solid." Silent audio is "wet" and fluid. The reason + * to treat silence as fluid is that if there's a long enough span of + * silence, we can't reliably detect jitter or dropped samples within that + * span (since all silence looks alike). Non-silent audio, on the other + * hand, is distinctive and can be reliably reassembled. + * + * So we treat long spans of silence specially. We only consider an edge + * of a non-silent region ("continent" or "island") to be "wet" if it borders + * a long span of silence. Short spans of silence are merely damp and can + * be reliably placed within a continent. + * + * We position ("anchor") the non-silent regions somewhat arbitrarily (since + * they may be jittered and we have no way to verify their exact position), + * and fill the intervening space with silence. + * + * See i_silence_match() for the gory details. + * =========================================================================== + */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -1034,15 +1058,17 @@ i_iterate_stage2(cdrom_paranoia_t *p, } -/* simple test for a root vector that ends in silence*/ /* =========================================================================== * i_silence_test() (internal) * * If the entire root is silent, or there's enough trailing silence * to be significant (MIN_SILENCE_BOUNDARY samples), mark the beginning - * of the silence and "light" the silence flag. + * of the silence and "light" the silence flag. This flag will remain lit + * until i_silence_match() appends some non-silent samples to the root. * - * ???: Why? + * We do this because if there's a long enough span of silence, we can't + * reliably detect jitter or dropped samples within that span. See + * i_silence_match() for details on how we recover from this situation. */ static void i_silence_test(root_block *root) @@ -1085,9 +1111,31 @@ i_silence_test(root_block *root) } -/* match into silence vectors at offset zero if at all possible. This - also must be called with vectors in ascending begin order in case - there are nonzero islands */ +/* =========================================================================== + * i_silence_match() (internal) + * + * This function is merges verified fragments into the verified root in cases + * where there is a problematic amount of silence (MIN_SILENCE_BOUNDARY + * samples) at the end of the root. + * + * We need a special approach because if there's a long enough span of + * silence, we can't reliably detect jitter or dropped samples within that + * span (since all silence looks alike). + * + * Only fragments that begin with MIN_SILENCE_BOUNDARY samples are eligible + * to be merged in this case. Fragments that are too far beyond the edge + * of the root to possibly overlap are also disregarded. + * + * Our first approach is to assume that such fragments have no jitter (since + * we can't establish otherwise) and merge them. However, if it's clear + * that there must be jitter (i.e. because non-silent samples overlap when + * we assume no jitter), we assume the fragment has the minimum possible + * jitter and then merge it. + * + * This function extends silence fairly aggressively, so it must be called + * with fragments in ascending order (beginning position) in case there are + * small non-silent regions within the silence. + */ static long int i_silence_match(root_block *root, v_fragment_t *v, void(*callback)(long int, paranoia_cb_mode_t)) @@ -1104,75 +1152,170 @@ i_silence_match(root_block *root, v_fragment_t *v, fb(v), fe(v), rb(root), re(root), root->silencebegin); #endif - /* does this vector begin wet? */ + /* See how much leading silence this fragment has. If there are fewer than + * MIN_SILENCE_BOUNDARY leading silent samples, we don't do this special + * silence matching. + * + * This fragment could actually belong here, but we can't be sure unless + * it has enough silence on its leading edge. This fragment will likely + * stick around until we do successfully extend the root, at which point + * it will be merged using the usual method. + */ if (enddynoverlap? */ + /* If this fragment is ahead of the root, see if that could just be due + * to jitter (if it's within p->dynoverlap samples of the end of root). + */ if (fb(v)>=re(root) && fb(v)-p->dynoverlapsilencebegin); end = min(j,re(root)); - + + /* If there is an overlap, we assume that both the root and the fragment + * are jitter-free (since there's no way for us to tell otherwise). + */ if (beginre(root)){ long int voff = begin-fb(v); - + + /* Truncate the overlapping silence from the end of the root. + */ c_remove(rc(root),begin-rb(root),-1); + + /* Append the fragment to the root, starting from the point of overlap. + */ c_append(rc(root),vec+voff,fs(v)-voff); + #if TRACE_PARANOIA & 2 - fprintf(stderr, "* Adding [%ld-%ld] to root (easy)\n", + fprintf(stderr, "* Adding [%ld-%ld] to root (no jitter)\n", begin, re(root)); #endif } + + /* Record the fact that we merged this fragment assuming zero jitter. + */ offset_add_value(p,&p->stage2,0,callback); } else { + + /* We weren't able to merge the fragment assuming zero jitter. + * + * Check whether the fragment's leading silence ends before the root's + * trailing silence begins. If it does, we assume that the root is + * jittered forward. + */ if (jre(root)) { + + /* Truncate the trailing silence from the root. + */ c_remove(rc(root),root->silencebegin-rb(root),-1); + + /* Append the non-silent tail of the fragment to the root. + */ c_append(rc(root),vec+voff,fs(v)-voff); + #if TRACE_PARANOIA & 2 - fprintf(stderr, "* Adding [%ld-%ld] to root (force)\n", - root->silencebegin, re(root)); + fprintf(stderr, "* Adding [%ld-%ld] to root (jitter=%ld)\n", + root->silencebegin, re(root), end-begin); #endif } + + /* Record the fact that we merged this fragment assuming (end-begin) + * jitter. + */ offset_add_value(p,&p->stage2,end-begin,callback); + } else + + /* We only get here if the fragment is past the end of the root, + * which means it must be farther than (dynoverlap) away, due to our + * root extension above. + */ + + /* We weren't able to merge this fragment into the root after all. + */ return(0); } - /* test the new root vector for ending in silence */ + + /* We only get here if we merged the fragment into the root. Update + * the root's silence flag. + * + * Note that this is the only place silenceflag is reset. In other words, + * once i_silence_test() lights the silence flag, it can only be reset + * by i_silence_match(). + */ root->silenceflag = 0; + + /* Now see if the new, extended root ends in silence. + */ i_silence_test(root); + + /* Since we merged the fragment, we can free it now. But first we propagate + * its lastsector flag. + */ if (v->lastsector) root->lastsector=1; free_v_fragment(v); return(1); @@ -1476,8 +1619,10 @@ i_stage2_each(root_block *root, v_fragment_t *v, /* We may have had a mismatch because we ran into leading silence. * * ??? To be studied: why would this cause a mismatch? Neither - * i_analyze_rift_f nor i_iterate_stage2() nor i_paranoia_overlap() + * i_analyze_rift_r nor i_iterate_stage2() nor i_paranoia_overlap() * appear to take silence into consideration in this regard. + * It could be due to our skipping of silence when searching for + * a match. * * Since we don't extend the root in that direction, we don't * do anything, just move on to trailing rifts. @@ -1696,23 +1841,51 @@ i_stage2_each(root_block *root, v_fragment_t *v, * ??? To be studied: why would this cause a mismatch? Neither * i_analyze_rift_f nor i_iterate_stage2() nor i_paranoia_overlap() * appear to take silence into consideration in this regard. - * - * ??? To be studied: why do we drop the silence? + * It could be due to our skipping of silence when searching for + * a match. + */ + + /* At this point we have a trailing rift. We check whether + * one of the vectors (fragment or root) has trailing silence. */ analyze_rift_silence_f(rv(root),cv(l), rs(root),cs(l), end,endL, &matchA,&matchB); if (matchA){ - /* silence in root */ + + /* The contents of the root's trailing rift are silence. The + * fragment's are not (otherwise there wouldn't be a rift). + * We therefore assume that the root has garbage from this + * point forward and truncate it. + * + * This will have the effect of eliminating the trailing + * rift, causing the fragment's samples to be appended to + * the root. + * + * ??? Does this have any negative side effects? Why is this + * a good idea? + */ + /* ??? TODO: returnedlimit */ /* Can only do this if we haven't already returned data */ if (end+rb(root)>=p->root.returnedlimit){ c_remove(rc(root),end,-1); } } else if (matchB){ - /* silence in fragment; lose it */ - + + /* The contents of the fragment's trailing rift are silence. + * The root's are not (otherwise there wouldn't be a rift). + * We therefore assume that the fragment has garbage from this + * point forward. + * + * We needn't actually truncate the fragment, because the root + * has already been fixed up from this fragment as much as + * possible, and the truncated fragment wouldn't extend the + * root. Therefore, we can consider this (truncated) fragment + * to be already merged into the root. So we dispose of it and + * return a success. + */ if (l)i_cblock_destructor(l); free_v_fragment(v); return(1); @@ -1814,7 +1987,9 @@ i_stage2_each(root_block *root, v_fragment_t *v, rb(root)+end, re(root)); #endif - /* ???TODO??? */ + /* Any time we update the root we need to check whether it ends + * with a large span of silence. + */ i_silence_test(root); /* Add the offset into our stage 2 statistics. @@ -1841,7 +2016,23 @@ i_stage2_each(root_block *root, v_fragment_t *v, #if TRACE_PARANOIA & 2 fprintf(stderr, "no match"); #endif - /* D'oh. No match. What to do with the fragment? */ + + /* We were unable to merge this fragment into the root. + * + * Check whether the fragment should have overlapped with the root, + * even taking possible jitter into account. (I.e., If the fragment + * ends so far before the end of the root that even (dynoverlap) + * samples of jitter couldn't push it beyond the end of the root, + * it should have overlapped.) + * + * It is, however, possible that we failed to match using the normal + * tests because we're dealing with silence, which we handle + * separately. + * + * If the fragment should have overlapped, and we're not dealing + * with the special silence case, we don't know what to make of + * this fragment, and we just discard it. + */ if (fe(v)+dynoverlapsilenceflag){ /* It *should* have matched. No good; free it. */ free_v_fragment(v); @@ -1849,6 +2040,7 @@ i_stage2_each(root_block *root, v_fragment_t *v, fprintf(stderr, ", discarding fragment."); #endif } + #if TRACE_PARANOIA & 2 fprintf(stderr, "\n"); #endif @@ -1881,6 +2073,8 @@ i_init_root(root_block *root, v_fragment_t *v,long int begin, root->vector=c_alloc(buff,fb(v),fs(v)); } + /* Check whether the new root has a long span of trailing silence. + */ i_silence_test(root); #if TRACE_PARANOIA & 2 @@ -1916,7 +2110,12 @@ vsort(const void *a,const void *b) * will then read the device again to try and establish more verified * fragments. * - * ??? TODO: Silence matching ??? + * We first try to merge all the fragments in ascending order using the + * standard method (i_stage2_each()), and then we try to merge the + * remaining fragments using silence matching (i_silence_match()) + * if the root has a long span of trailing silence. See the initial + * comments on silence and i_silence_match() for an explanation of this + * distinction. * * This function returns the number of verified fragments successfully * merged into the verified root. @@ -2030,8 +2229,9 @@ i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword, } } - /* If the verified root ends in silence, iterate through the - * remaining unmerged fragments to ... TODO??? + /* If the verified root ends in a long span of silence, iterate + * through the remaining unmerged fragments to see if they can be + * merged using our special silence matching. */ if (!flag && p->root.silenceflag){ for(count=0;countone){ if (rv(root)!=NULL){ - /* ???TODO??? */ + /* Try to merge the fragment into the root. This will only + * succeed if the fragment overlaps and begins with sufficient + * silence to be a presumed match. + * + * Note that the fragments must be passed to i_silence_match() + * in ascending order, as they are here. + */ if (i_silence_match(root,first,callback)){ /* If we successfully merged the fragment, set the flag @@ -2053,7 +2259,7 @@ i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword, } } } - } + } /* end for */ } } /* end if(count) */ free(list);