|
Packit |
cb6d3d |
/*
|
|
Packit |
cb6d3d |
Copyright (C) 2004, 2005, 2006, 2008, 2011, 2017
|
|
Packit |
cb6d3d |
Rocky Bernstein <rocky@gnu.org>
|
|
Packit |
cb6d3d |
Copyright (C) 2014 Robert Kausch <robert.kausch@freac.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 |
* Toplevel file for the paranoia abstraction over the cdda lib
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
***/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* immediate todo:: */
|
|
Packit |
cb6d3d |
/* Allow disabling of root fixups? */
|
|
Packit |
cb6d3d |
/* Dupe bytes are creeping into cases that require greater overlap
|
|
Packit |
cb6d3d |
than a single fragment can provide. We need to check against a
|
|
Packit |
cb6d3d |
larger area* (+/-32 sectors of root?) to better eliminate
|
|
Packit |
cb6d3d |
dupes. Of course this leads to other problems... Is it actually a
|
|
Packit |
cb6d3d |
practically solvable problem? */
|
|
Packit |
cb6d3d |
/* Bimodal overlap distributions break us. */
|
|
Packit |
cb6d3d |
/* scratch detection/tolerance not implemented yet */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/***************************************************************
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
Da new shtick: verification now a two-step assymetric process.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
A single 'verified/reconstructed' data segment cache, and then the
|
|
Packit |
cb6d3d |
multiple fragment cache
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
verify a newly read block against previous blocks; do it only this
|
|
Packit |
cb6d3d |
once. We maintain a list of 'verified sections' from these matches.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
We then glom these verified areas into a new data buffer.
|
|
Packit |
cb6d3d |
Defragmentation fixups are allowed here alone.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
We also now track where read boundaries actually happened; do not
|
|
Packit |
cb6d3d |
verify across matching boundaries.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
**************************************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/***************************************************************
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
Silence. "It's BAAAAAAaaack."
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
audio is now treated as great continents of values floating on a
|
|
Packit |
cb6d3d |
mantle of molten silence. Silence is not handled by basic
|
|
Packit |
cb6d3d |
verification at all; we simply anchor sections of nonzero audio to a
|
|
Packit |
cb6d3d |
position and fill in everything else as silence. We also note the
|
|
Packit |
cb6d3d |
audio that interfaces with silence; an edge must be 'wet'.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
**************************************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* Let's translate the above vivid metaphor into something a mere mortal
|
|
Packit |
cb6d3d |
* can understand:
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Non-silent audio is "solid." Silent audio is "wet" and fluid. The reason
|
|
Packit |
cb6d3d |
* to treat silence as fluid is that if there's a long enough span of
|
|
Packit |
cb6d3d |
* silence, we can't reliably detect jitter or dropped samples within that
|
|
Packit |
cb6d3d |
* span (since all silence looks alike). Non-silent audio, on the other
|
|
Packit |
cb6d3d |
* hand, is distinctive and can be reliably reassembled.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* So we treat long spans of silence specially. We only consider an edge
|
|
Packit |
cb6d3d |
* of a non-silent region ("continent" or "island") to be "wet" if it borders
|
|
Packit |
cb6d3d |
* a long span of silence. Short spans of silence are merely damp and can
|
|
Packit |
cb6d3d |
* be reliably placed within a continent.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We position ("anchor") the non-silent regions somewhat arbitrarily (since
|
|
Packit |
cb6d3d |
* they may be jittered and we have no way to verify their exact position),
|
|
Packit |
cb6d3d |
* and fill the intervening space with silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* See i_silence_match() for the gory details.
|
|
Packit |
cb6d3d |
* ===========================================================================
|
|
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 |
|
|
Packit |
cb6d3d |
#ifdef HAVE_STDLIB_H
|
|
Packit |
cb6d3d |
#include <stdlib.h>
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
#include <unistd.h>
|
|
Packit |
cb6d3d |
#include <stdio.h>
|
|
Packit |
cb6d3d |
#include <limits.h>
|
|
Packit |
cb6d3d |
#ifdef HAVE_STRING_H
|
|
Packit |
cb6d3d |
#include <string.h>
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
#include <math.h>
|
|
Packit |
cb6d3d |
#include <cdio/paranoia/cdda.h>
|
|
Packit |
cb6d3d |
#include "../cdda_interface/smallft.h"
|
|
Packit |
cb6d3d |
#include <cdio/paranoia/version.h>
|
|
Packit |
cb6d3d |
#include "p_block.h"
|
|
Packit |
cb6d3d |
#include <cdio/paranoia/paranoia.h>
|
|
Packit |
cb6d3d |
#include "overlap.h"
|
|
Packit |
cb6d3d |
#include "gap.h"
|
|
Packit |
cb6d3d |
#include "isort.h"
|
|
Packit |
cb6d3d |
#include <errno.h>
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#define MIN_SEEK_MS 6
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
const char *paranoia_cb_mode2str[] = {
|
|
Packit |
cb6d3d |
"read",
|
|
Packit |
cb6d3d |
"verify",
|
|
Packit |
cb6d3d |
"fixup edge",
|
|
Packit |
cb6d3d |
"fixup atom",
|
|
Packit |
cb6d3d |
"scratch",
|
|
Packit |
cb6d3d |
"repair",
|
|
Packit |
cb6d3d |
"skip",
|
|
Packit |
cb6d3d |
"drift",
|
|
Packit |
cb6d3d |
"backoff",
|
|
Packit |
cb6d3d |
"overlap",
|
|
Packit |
cb6d3d |
"fixup dropped",
|
|
Packit |
cb6d3d |
"fixup duplicated",
|
|
Packit |
cb6d3d |
"read error"
|
|
Packit |
cb6d3d |
};
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/** The below variables are trickery to force the above enum symbol
|
|
Packit |
cb6d3d |
values to be recorded in debug symbol tables. They are used to
|
|
Packit |
cb6d3d |
allow one to refer to the enumeration value names in the typedefs
|
|
Packit |
cb6d3d |
above in a debugger and debugger expressions
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
paranoia_mode_t debug_paranoia_mode;
|
|
Packit |
cb6d3d |
paranoia_cb_mode_t debug_paranoia_cb_mode;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static inline long
|
|
Packit |
cb6d3d |
re(root_block *root)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if (!root)return(-1);
|
|
Packit |
cb6d3d |
if (!root->vector)return(-1);
|
|
Packit |
cb6d3d |
return(ce(root->vector));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static inline long
|
|
Packit |
cb6d3d |
rb(root_block *root)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if (!root)return(-1);
|
|
Packit |
cb6d3d |
if (!root->vector)return(-1);
|
|
Packit |
cb6d3d |
return(cb(root->vector));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static inline
|
|
Packit |
cb6d3d |
long rs(root_block *root)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if (!root)return(-1);
|
|
Packit |
cb6d3d |
if (!root->vector)return(-1);
|
|
Packit |
cb6d3d |
return(cs(root->vector));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static inline int16_t *
|
|
Packit |
cb6d3d |
rv(root_block *root){
|
|
Packit |
cb6d3d |
if (!root)return(NULL);
|
|
Packit |
cb6d3d |
if (!root->vector)return(NULL);
|
|
Packit |
cb6d3d |
return(cv(root->vector));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#define rc(r) (r->vector)
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/**
|
|
Packit |
cb6d3d |
Flags indicating the status of a read samples.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
Imagine the below enumeration values are \#defines to be used in a
|
|
Packit |
cb6d3d |
bitmask rather than distinct values of an enum.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
The variable part of the declaration is trickery to force the enum
|
|
Packit |
cb6d3d |
symbol values to be recorded in debug symbol tables. They are used
|
|
Packit |
cb6d3d |
to allow one refer to the enumeration value names in a debugger
|
|
Packit |
cb6d3d |
and in debugger expressions.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
enum {
|
|
Packit |
cb6d3d |
FLAGS_EDGE =0x1, /**< first/last N words of frame */
|
|
Packit |
cb6d3d |
FLAGS_UNREAD =0x2, /**< unread, hence missing and unmatchable */
|
|
Packit |
cb6d3d |
FLAGS_VERIFIED=0x4 /**< block read and verified */
|
|
Packit |
cb6d3d |
} paranoia_read_flags;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/**** matching and analysis code *****************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_paranoia_overlap() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called when buffA[offsetA] == buffB[offsetB]. This
|
|
Packit |
cb6d3d |
* function searches backward and forward to see how many consecutive
|
|
Packit |
cb6d3d |
* samples also match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by do_const_sync() when we're not doing any
|
|
Packit |
cb6d3d |
* verification. Its more complicated sibling is i_paranoia_overlap2.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the number of consecutive matching samples.
|
|
Packit |
cb6d3d |
* If (ret_begin) or (ret_end) are not NULL, it fills them with the
|
|
Packit |
cb6d3d |
* offsets of the first and last matching samples in A.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static inline long
|
|
Packit |
cb6d3d |
i_paranoia_overlap(int16_t *buffA,int16_t *buffB,
|
|
Packit |
cb6d3d |
long offsetA, long offsetB,
|
|
Packit |
cb6d3d |
long sizeA,long sizeB,
|
|
Packit |
cb6d3d |
long *ret_begin, long *ret_end)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long beginA=offsetA,endA=offsetA;
|
|
Packit |
cb6d3d |
long beginB=offsetB,endB=offsetB;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Scan backward to extend the matching run in that direction. */
|
|
Packit |
cb6d3d |
for(; beginA>=0 && beginB>=0; beginA--,beginB--)
|
|
Packit |
cb6d3d |
if (buffA[beginA] != buffB[beginB]) break;
|
|
Packit |
cb6d3d |
beginA++;
|
|
Packit |
cb6d3d |
beginB++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Scan forward to extend the matching run in that direction. */
|
|
Packit |
cb6d3d |
for(; endA
|
|
Packit |
cb6d3d |
if (buffA[endA] != buffB[endB]) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Return the result of our search. */
|
|
Packit |
cb6d3d |
if (ret_begin) *ret_begin = beginA;
|
|
Packit |
cb6d3d |
if (ret_end) *ret_end = endA;
|
|
Packit |
cb6d3d |
return (endA-beginA);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_paranoia_overlap2() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called when buffA[offsetA] == buffB[offsetB]. This
|
|
Packit |
cb6d3d |
* function searches backward and forward to see how many consecutive
|
|
Packit |
cb6d3d |
* samples also match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by do_const_sync() when we're verifying the
|
|
Packit |
cb6d3d |
* data coming off the CD. Its less complicated sibling is
|
|
Packit |
cb6d3d |
* i_paranoia_overlap, which is a good place to look to see the simplest
|
|
Packit |
cb6d3d |
* outline of how this function works.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the number of consecutive matching samples.
|
|
Packit |
cb6d3d |
* If (ret_begin) or (ret_end) are not NULL, it fills them with the
|
|
Packit |
cb6d3d |
* offsets of the first and last matching samples in A.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static inline long
|
|
Packit |
cb6d3d |
i_paranoia_overlap2(int16_t *buffA,int16_t *buffB,
|
|
Packit |
cb6d3d |
unsigned char *flagsA,
|
|
Packit |
cb6d3d |
unsigned char *flagsB,
|
|
Packit |
cb6d3d |
long offsetA, long offsetB,
|
|
Packit |
cb6d3d |
long sizeA,long sizeB,
|
|
Packit |
cb6d3d |
long *ret_begin, long *ret_end)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long beginA=offsetA, endA=offsetA;
|
|
Packit |
cb6d3d |
long beginB=offsetB, endB=offsetB;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Scan backward to extend the matching run in that direction. */
|
|
Packit |
cb6d3d |
for (; beginA>=0 && beginB>=0; beginA--,beginB--) {
|
|
Packit |
cb6d3d |
if (buffA[beginA] != buffB[beginB]) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* don't allow matching across matching sector boundaries. The
|
|
Packit |
cb6d3d |
liklihood of the drive skipping identically in two
|
|
Packit |
cb6d3d |
different reads with the same sector read boundary is actually
|
|
Packit |
cb6d3d |
relatively very high compared to the liklihood of it skipping
|
|
Packit |
cb6d3d |
when one read is continuous across the boundary and other was
|
|
Packit |
cb6d3d |
discontinuous */
|
|
Packit |
cb6d3d |
/* Stop if both samples were at the edges of a low-level read.
|
|
Packit |
cb6d3d |
* ???: What implications does this have?
|
|
Packit |
cb6d3d |
* ???: Why do we include the first sample for which this is true?
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ((flagsA[beginA]&flagsB[beginB]&FLAGS_EDGE)) {
|
|
Packit |
cb6d3d |
beginA--;
|
|
Packit |
cb6d3d |
beginB--;
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* don't allow matching through known missing data */
|
|
Packit |
cb6d3d |
if ((flagsA[beginA]&FLAGS_UNREAD) || (flagsB[beginB]&FLAGS_UNREAD))
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
beginA++;
|
|
Packit |
cb6d3d |
beginB++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Scan forward to extend the matching run in that direction. */
|
|
Packit |
cb6d3d |
for (; endA
|
|
Packit |
cb6d3d |
if (buffA[endA] != buffB[endB]) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* don't allow matching across matching sector boundaries */
|
|
Packit |
cb6d3d |
/* Stop if both samples were at the edges of a low-level read.
|
|
Packit |
cb6d3d |
* ???: What implications does this have?
|
|
Packit |
cb6d3d |
* ???: Why do we not stop if endA == beginA?
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ((flagsA[endA]&flagsB[endB]&FLAGS_EDGE) && endA!=beginA){
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* don't allow matching through known missing data */
|
|
Packit |
cb6d3d |
if ((flagsA[endA]&FLAGS_UNREAD) || (flagsB[endB]&FLAGS_UNREAD))
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Return the result of our search. */
|
|
Packit |
cb6d3d |
if (ret_begin) *ret_begin = beginA;
|
|
Packit |
cb6d3d |
if (ret_end) *ret_end = endA;
|
|
Packit |
cb6d3d |
return (endA-beginA);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* do_const_sync() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called when samples A[posA] == B[posB]. It tries to
|
|
Packit |
cb6d3d |
* build a matching run from that point, looking forward and backward to
|
|
Packit |
cb6d3d |
* see how many consecutive samples match. Since the starting samples
|
|
Packit |
cb6d3d |
* might only be coincidentally identical, we only consider the run to
|
|
Packit |
cb6d3d |
* be a true match if it's longer than MIN_WORDS_SEARCH.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the length of the run if a matching run was found,
|
|
Packit |
cb6d3d |
* or 0 otherwise. If a matching run was found, (begin) and (end) are set
|
|
Packit |
cb6d3d |
* to the absolute positions of the beginning and ending samples of the
|
|
Packit |
cb6d3d |
* run in A, and (offset) is set to the jitter between the c_blocks.
|
|
Packit |
cb6d3d |
* (I.e., offset indicates the distance between what A considers sample N
|
|
Packit |
cb6d3d |
* on the CD and what B considers sample N.)
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static inline long int
|
|
Packit |
cb6d3d |
do_const_sync(c_block_t *A,
|
|
Packit |
cb6d3d |
sort_info_t *B,
|
|
Packit |
cb6d3d |
unsigned char *flagB,
|
|
Packit |
cb6d3d |
long posA, long posB,
|
|
Packit |
cb6d3d |
long *begin, long *end, long *offset)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
unsigned char *flagA=A->flags;
|
|
Packit |
cb6d3d |
long ret=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we're doing any verification whatsoever, we have flags in stage
|
|
Packit |
cb6d3d |
* 1, and will take them into account. Otherwise (e.g. in stage 2),
|
|
Packit |
cb6d3d |
* we just do the simple equality test for samples on both sides of
|
|
Packit |
cb6d3d |
* the initial match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (flagB==NULL)
|
|
Packit |
cb6d3d |
ret=i_paranoia_overlap(cv(A), iv(B), posA, posB,
|
|
Packit |
cb6d3d |
cs(A), is(B), begin, end);
|
|
Packit |
cb6d3d |
else
|
|
Packit |
cb6d3d |
if ((flagB[posB]&FLAGS_UNREAD)==0)
|
|
Packit |
cb6d3d |
ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB,
|
|
Packit |
cb6d3d |
posA, posB, cs(A), is(B),
|
|
Packit |
cb6d3d |
begin, end);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Small matching runs could just be coincidental. We only consider this
|
|
Packit |
cb6d3d |
* a real match if it's long enough.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (ret > MIN_WORDS_SEARCH) {
|
|
Packit |
cb6d3d |
*offset=+(posA+cb(A))-(posB+ib(B));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Note that try_sort_sync()'s swaps A & B when it calls this function,
|
|
Packit |
cb6d3d |
* so while we adjust begin & end to be relative to A here, that means
|
|
Packit |
cb6d3d |
* it's relative to B in try_sort_sync().
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
*begin+=cb(A);
|
|
Packit |
cb6d3d |
*end+=cb(A);
|
|
Packit |
cb6d3d |
return(ret);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* try_sort_sync() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Starting from the sample in B with the absolute position (post), look
|
|
Packit |
cb6d3d |
* for a matching run in A. This search will look in A for a first
|
|
Packit |
cb6d3d |
* matching sample within (p->dynoverlap) samples around (post). If it
|
|
Packit |
cb6d3d |
* finds one, it will then determine how many consecutive samples match
|
|
Packit |
cb6d3d |
* both A and B from that point, looking backwards and forwards. If
|
|
Packit |
cb6d3d |
* this search produces a matching run longer than MIN_WORDS_SEARCH, we
|
|
Packit |
cb6d3d |
* consider it a match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* When used by stage 1, the "post" is planted with respect to the old
|
|
Packit |
cb6d3d |
* c_block being compare to the new c_block. In stage 2, the "post" is
|
|
Packit |
cb6d3d |
* planted with respect to the verified root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns 1 if a match is found and 0 if not. When a match
|
|
Packit |
cb6d3d |
* is found, (begin) and (end) are set to the boundaries of the run, and
|
|
Packit |
cb6d3d |
* (offset) is set to the difference in position of the run in A and B.
|
|
Packit |
cb6d3d |
* (begin) and (end) are the absolute positions of the samples in
|
|
Packit |
cb6d3d |
* B. (offset) transforms A to B's frame of reference. I.e., an offset of
|
|
Packit |
cb6d3d |
* 2 would mean that A's absolute 3 is equivalent to B's 5.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* post is w.r.t. B. in stage one, we post from old. In stage 2 we
|
|
Packit |
cb6d3d |
post from root. Begin, end, offset count from B's frame of
|
|
Packit |
cb6d3d |
reference */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static inline long int
|
|
Packit |
cb6d3d |
try_sort_sync(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
sort_info_t *A, unsigned char *Aflags,
|
|
Packit |
cb6d3d |
c_block_t *B,
|
|
Packit |
cb6d3d |
long int post,
|
|
Packit |
cb6d3d |
long int *begin,
|
|
Packit |
cb6d3d |
long int *end,
|
|
Packit |
cb6d3d |
long *offset,
|
|
Packit |
cb6d3d |
void (*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
long int dynoverlap=p->dynoverlap;
|
|
Packit |
cb6d3d |
sort_link_t *ptr=NULL;
|
|
Packit |
cb6d3d |
unsigned char *Bflags=B->flags;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* block flag matches FLAGS_UNREAD (and hence unmatchable) */
|
|
Packit |
cb6d3d |
if (Bflags==NULL || (Bflags[post-cb(B)]&FLAGS_UNREAD)==0){
|
|
Packit |
cb6d3d |
/* always try absolute offset zero first! */
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long zeropos=post-ib(A);
|
|
Packit |
cb6d3d |
if (zeropos>=0 && zeropos
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Before we bother with the search for a matching samples,
|
|
Packit |
cb6d3d |
* we check the simple case. If there's no jitter at all
|
|
Packit |
cb6d3d |
* (i.e. the absolute positions of A's and B's samples are
|
|
Packit |
cb6d3d |
* consistent), A's sample at (post) should be identical
|
|
Packit |
cb6d3d |
* to B's sample at the same position.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ( cv(B)[post-cb(B)] == iv(A)[zeropos] ) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The first sample matched, now try to grow the matching run
|
|
Packit |
cb6d3d |
* in both directions. We only consider it a match if more
|
|
Packit |
cb6d3d |
* than MIN_WORDS_SEARCH consecutive samples match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (do_const_sync(B, A, Aflags,
|
|
Packit |
cb6d3d |
post-cb(B), zeropos,
|
|
Packit |
cb6d3d |
begin, end, offset) ) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ???BUG??? Jitter cannot be accurately detected when there are
|
|
Packit |
cb6d3d |
* large regions of silence. Silence all looks alike, so if
|
|
Packit |
cb6d3d |
* there is actually jitter but lots of silence, jitter (offset)
|
|
Packit |
cb6d3d |
* will be incorrectly identified as 0. When the incorrect zero
|
|
Packit |
cb6d3d |
* jitter is passed to offset_add_value, it eventually reduces
|
|
Packit |
cb6d3d |
* dynoverlap so much that it's impossible for stage 2 to merge
|
|
Packit |
cb6d3d |
* jittered fragments into the root (it doesn't search far enough).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* A potential solution (tested, but not committed) is to check
|
|
Packit |
cb6d3d |
* for silence in do_const_sync and simply not call
|
|
Packit |
cb6d3d |
* offset_add_value if the match is all silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This bug is not fixed yet.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
/* ???: To be studied. */
|
|
Packit |
cb6d3d |
offset_add_value(p,&(p->stage1),*offset,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the samples with the same absolute position didn't match, it's
|
|
Packit |
cb6d3d |
* either a bad sample, or the two c_blocks are jittered with respect
|
|
Packit |
cb6d3d |
* to each other. Now we search through A for samples that do have
|
|
Packit |
cb6d3d |
* the same value as B's post. The search looks from first to last
|
|
Packit |
cb6d3d |
* occurrence witin (dynoverlap) samples of (post).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while (ptr){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We've found a matching sample, so try to grow the matching run in
|
|
Packit |
cb6d3d |
* both directions. If we find a long enough run (longer than
|
|
Packit |
cb6d3d |
* MIN_WORDS_SEARCH), we've found a match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (do_const_sync(B,A,Aflags,
|
|
Packit |
cb6d3d |
post-cb(B),ipos(A,ptr),
|
|
Packit |
cb6d3d |
begin,end,offset)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ???BUG??? Jitter cannot be accurately detected when there are
|
|
Packit |
cb6d3d |
* large regions of silence. Silence all looks alike, so if
|
|
Packit |
cb6d3d |
* there is actually jitter but lots of silence, jitter (offset)
|
|
Packit |
cb6d3d |
* will be incorrectly identified as 0. When the incorrect zero
|
|
Packit |
cb6d3d |
* jitter is passed to offset_add_value, it eventually reduces
|
|
Packit |
cb6d3d |
* dynoverlap so much that it's impossible for stage 2 to merge
|
|
Packit |
cb6d3d |
* jittered fragments into the root (it doesn't search far enough).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* A potential solution (tested, but not committed) is to check
|
|
Packit |
cb6d3d |
* for silence in do_const_sync and simply not call
|
|
Packit |
cb6d3d |
* offset_add_value if the match is all silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This bug is not fixed yet.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
/* ???: To be studied. */
|
|
Packit |
cb6d3d |
offset_add_value(p,&(p->stage1),*offset,callback);
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The matching sample was just a fluke -- there weren't enough adjacent
|
|
Packit |
cb6d3d |
* samples that matched to consider a matching run. So now we check
|
|
Packit |
cb6d3d |
* for the next occurrence of that value in A.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
ptr=sort_nextmatch(A,ptr);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We didn't find any matches. */
|
|
Packit |
cb6d3d |
*begin=-1;
|
|
Packit |
cb6d3d |
*end=-1;
|
|
Packit |
cb6d3d |
*offset=-1;
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* STAGE 1 MATCHING
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ???: Insert high-level explanation here.
|
|
Packit |
cb6d3d |
* ===========================================================================
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Top level of the first stage matcher */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We match each analysis point of new to the preexisting blocks
|
|
Packit |
cb6d3d |
recursively. We can also optionally maintain a list of fragments of
|
|
Packit |
cb6d3d |
the preexisting block that didn't match anything, and match them back
|
|
Packit |
cb6d3d |
afterward. */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#define OVERLAP_ADJ (MIN_WORDS_OVERLAP/2-1)
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* stage1_matched() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called whenever stage 1 verification finds two identical
|
|
Packit |
cb6d3d |
* runs of samples from different reads. The runs must be more than
|
|
Packit |
cb6d3d |
* MIN_WORDS_SEARCH samples long. They may be jittered (i.e. their absolute
|
|
Packit |
cb6d3d |
* positions on the CD may not match due to inaccurate seeking) with respect
|
|
Packit |
cb6d3d |
* to each other, but they have been verified to have no dropped samples
|
|
Packit |
cb6d3d |
* within them.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function provides feedback via the callback mechanism and marks the
|
|
Packit |
cb6d3d |
* runs as verified. The details of the marking are somehwat subtle and
|
|
Packit |
cb6d3d |
* are described near the relevant code.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Subsequent portions of the stage 1 code will build a verified fragment
|
|
Packit |
cb6d3d |
* from this run. The verified fragment will eventually be merged
|
|
Packit |
cb6d3d |
* into the verified root (and its absolute position determined) in
|
|
Packit |
cb6d3d |
* stage 2.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static inline void
|
|
Packit |
cb6d3d |
stage1_matched(c_block_t *old, c_block_t *new,
|
|
Packit |
cb6d3d |
long matchbegin,long matchend,
|
|
Packit |
cb6d3d |
long matchoffset,
|
|
Packit |
cb6d3d |
void (*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long i;
|
|
Packit |
cb6d3d |
long oldadjbegin=matchbegin-cb(old);
|
|
Packit |
cb6d3d |
long oldadjend=matchend-cb(old);
|
|
Packit |
cb6d3d |
long newadjbegin=matchbegin-matchoffset-cb(new);
|
|
Packit |
cb6d3d |
long newadjend=matchend-matchoffset-cb(new);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Provide feedback via the callback about the samples we've just
|
|
Packit |
cb6d3d |
* verified.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "???: How can matchbegin ever be < cb(old)?"
|
|
Packit |
cb6d3d |
* Sorry, old bulletproofing habit. I often use <= to mean "not >"
|
|
Packit |
cb6d3d |
* --Monty
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "???: Why do edge samples get logged only when there's jitter
|
|
Packit |
cb6d3d |
* between the matched runs (matchoffset != 0)?"
|
|
Packit |
cb6d3d |
* FIXUP_EDGE is actually logging a jitter event, not a rift--
|
|
Packit |
cb6d3d |
* a rift is FIXUP_ATOM --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ( matchbegin-matchoffset<=cb(new)
|
|
Packit |
cb6d3d |
|| matchbegin<=cb(old)
|
|
Packit |
cb6d3d |
|| (new->flags[newadjbegin]&FLAGS_EDGE)
|
|
Packit |
cb6d3d |
|| (old->flags[oldadjbegin]&FLAGS_EDGE) ) {
|
|
Packit |
cb6d3d |
if ( matchoffset && callback )
|
|
Packit |
cb6d3d |
(*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE);
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if ( matchend-matchoffset>=ce(new) ||
|
|
Packit |
cb6d3d |
(new->flags[newadjend]&FLAGS_EDGE) ||
|
|
Packit |
cb6d3d |
matchend>=ce(old) ||
|
|
Packit |
cb6d3d |
(old->flags[oldadjend]&FLAGS_EDGE) ) {
|
|
Packit |
cb6d3d |
if ( matchoffset && callback )
|
|
Packit |
cb6d3d |
(*callback)(matchend,PARANOIA_CB_FIXUP_EDGE);
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(matchend, PARANOIA_CB_FIXUP_ATOM);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 1
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Matched [%ld-%ld] against [%ld-%ld]\n",
|
|
Packit |
cb6d3d |
newadjbegin+cb(new), newadjend+cb(new),
|
|
Packit |
cb6d3d |
oldadjbegin+cb(old), oldadjend+cb(old));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Mark verified samples as "verified," but trim the verified region
|
|
Packit |
cb6d3d |
* by OVERLAP_ADJ samples on each side. There are several significant
|
|
Packit |
cb6d3d |
* implications of this trimming:
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* 1) Why we trim at all: We have to trim to distinguish between two
|
|
Packit |
cb6d3d |
* adjacent verified runs and one long verified run. We encounter this
|
|
Packit |
cb6d3d |
* situation when samples have been dropped:
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* matched portion of read 1 ....)(.... matched portion of read 1
|
|
Packit |
cb6d3d |
* read 2 adjacent run .....)(..... read 2 adjacent run
|
|
Packit |
cb6d3d |
* ||
|
|
Packit |
cb6d3d |
* dropped samples in read 2
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* So at this point, the fact that we have two adjacent runs means
|
|
Packit |
cb6d3d |
* that we have not yet verified that the two runs really are adjacent.
|
|
Packit |
cb6d3d |
* (In fact, just the opposite: there are two runs because they were
|
|
Packit |
cb6d3d |
* matched by separate runs, indicating that some samples didn't match
|
|
Packit |
cb6d3d |
* across the length of read 2.)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* If we verify that they are actually adjacent (e.g. if the two runs
|
|
Packit |
cb6d3d |
* are simply a result of matching runs from different reads, not from
|
|
Packit |
cb6d3d |
* dropped samples), we will indeed mark them as one long merged run.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* 2) Why we trim by this amount: We want to ensure that when we
|
|
Packit |
cb6d3d |
* verify the relationship between these two runs, we do so with
|
|
Packit |
cb6d3d |
* an overlapping fragment at least OVERLAP samples long. Following
|
|
Packit |
cb6d3d |
* from the above example:
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* (..... matched portion of read 3 .....)
|
|
Packit |
cb6d3d |
* read 2 adjacent run .....)(..... read 2 adjacent run
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Assuming there were no dropped samples between the adjacent runs,
|
|
Packit |
cb6d3d |
* the matching portion of read 3 will need to be at least OVERLAP
|
|
Packit |
cb6d3d |
* samples long to mark the two runs as one long verified run.
|
|
Packit |
cb6d3d |
* If there were dropped samples, read 3 wouldn't match across the
|
|
Packit |
cb6d3d |
* two runs, proving our caution worthwhile.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* 3) Why we partially discard the work we've done: We don't.
|
|
Packit |
cb6d3d |
* When subsequently creating verified fragments from this run,
|
|
Packit |
cb6d3d |
* we compensate for this trimming. Thus the verified fragment will
|
|
Packit |
cb6d3d |
* contain the full length of verified samples. Only the c_blocks
|
|
Packit |
cb6d3d |
* will reflect this trimming.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ???: The comment below indicates that the sort cache is updated in
|
|
Packit |
cb6d3d |
* some way, but this does not appear to be the case.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Mark the verification flags. Don't mark the first or
|
|
Packit |
cb6d3d |
last OVERLAP/2 elements so that overlapping fragments
|
|
Packit |
cb6d3d |
have to overlap by OVERLAP to actually merge. We also
|
|
Packit |
cb6d3d |
remove elements from the sort such that later sorts do
|
|
Packit |
cb6d3d |
not have to sift through already matched data */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
newadjbegin+=OVERLAP_ADJ;
|
|
Packit |
cb6d3d |
newadjend-=OVERLAP_ADJ;
|
|
Packit |
cb6d3d |
for(i=newadjbegin;i
|
|
Packit |
cb6d3d |
new->flags[i]|=FLAGS_VERIFIED; /* mark verified */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
oldadjbegin+=OVERLAP_ADJ;
|
|
Packit |
cb6d3d |
oldadjend-=OVERLAP_ADJ;
|
|
Packit |
cb6d3d |
for(i=oldadjbegin;i
|
|
Packit |
cb6d3d |
old->flags[i]|=FLAGS_VERIFIED; /* mark verified */
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_iterate_stage1 (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by i_stage1() to compare newly read samples with
|
|
Packit |
cb6d3d |
* previously read samples, searching for contiguous runs of identical
|
|
Packit |
cb6d3d |
* samples. Matching runs indicate that at least two reads of the CD
|
|
Packit |
cb6d3d |
* returned identical data, with no dropped samples in that run.
|
|
Packit |
cb6d3d |
* The runs may be jittered (i.e. their absolute positions on the CD may
|
|
Packit |
cb6d3d |
* not be accurate due to inaccurate seeking) at this point. Their
|
|
Packit |
cb6d3d |
* positions will be determined in stage 2.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function compares the new c_block (which has been indexed in
|
|
Packit |
cb6d3d |
* p->sortcache) to a previous c_block. It is called for each previous
|
|
Packit |
cb6d3d |
* c_block. It searches for runs of identical samples longer than
|
|
Packit |
cb6d3d |
* MIN_WORDS_SEARCH. Samples in matched runs are marked as verified.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Subsequent stage 1 code builds verified fragments from the runs of
|
|
Packit |
cb6d3d |
* verified samples. These fragments are merged into the verified root
|
|
Packit |
cb6d3d |
* in stage 2.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the number of distinct runs verified in the new
|
|
Packit |
cb6d3d |
* c_block when compared against this old c_block.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static long int
|
|
Packit |
cb6d3d |
i_iterate_stage1(cdrom_paranoia_t *p, c_block_t *old, c_block_t *new,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long matchbegin = -1;
|
|
Packit |
cb6d3d |
long matchend = -1;
|
|
Packit |
cb6d3d |
long matchoffset;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* "???: Why do we limit our search only to the samples with overlapping
|
|
Packit |
cb6d3d |
* absolute positions? It could be because it eliminates some further
|
|
Packit |
cb6d3d |
* bounds checking."
|
|
Packit |
cb6d3d |
* Short answer is yes --Monty
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "Why do we "no longer try to spread the ... search" as mentioned
|
|
Packit |
cb6d3d |
* below?"
|
|
Packit |
cb6d3d |
* The search is normally much faster without the spread,
|
|
Packit |
cb6d3d |
* even in heavy jitter. Dynoverlap tends to be a bigger deal in
|
|
Packit |
cb6d3d |
* stage 2. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* we no longer try to spread the stage one search area by dynoverlap */
|
|
Packit |
cb6d3d |
long searchend = min(ce(old), ce(new));
|
|
Packit |
cb6d3d |
long searchbegin = max(cb(old), cb(new));
|
|
Packit |
cb6d3d |
long searchsize = searchend-searchbegin;
|
|
Packit |
cb6d3d |
sort_info_t *i = p->sortcache;
|
|
Packit |
cb6d3d |
long ret = 0;
|
|
Packit |
cb6d3d |
long int j;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
long tried = 0;
|
|
Packit |
cb6d3d |
long matched = 0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (searchsize<=0)
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* match return values are in terms of the new vector, not old */
|
|
Packit |
cb6d3d |
/* "???: Why 23?" Odd, prime number --Monty */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
for (j=searchbegin; j
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Skip past any samples verified in previous comparisons to
|
|
Packit |
cb6d3d |
* other old c_blocks. Also, obviously, don't bother verifying
|
|
Packit |
cb6d3d |
* unread/unmatchable samples.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ((new->flags[j-cb(new)] & (FLAGS_VERIFIED|FLAGS_UNREAD)) == 0) {
|
|
Packit |
cb6d3d |
tried++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Starting from the sample in the old c_block with the absolute
|
|
Packit |
cb6d3d |
* position j, look for a matching run in the new c_block. This
|
|
Packit |
cb6d3d |
* search will look a certain distance around j, and if successful
|
|
Packit |
cb6d3d |
* will extend the matching run as far backward and forward as
|
|
Packit |
cb6d3d |
* it can.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The search will only return 1 if it finds a matching run long
|
|
Packit |
cb6d3d |
* enough to be deemed significant.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (try_sort_sync(p, i, new->flags, old, j,
|
|
Packit |
cb6d3d |
&matchbegin, &matchend, &matchoffset,
|
|
Packit |
cb6d3d |
callback) == 1) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
matched+=matchend-matchbegin;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* purely cosmetic: if we're matching zeros, don't use the
|
|
Packit |
cb6d3d |
callback because they will appear to be all skewed */
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long j = matchbegin-cb(old);
|
|
Packit |
cb6d3d |
long end = matchend-cb(old);
|
|
Packit |
cb6d3d |
for (; j
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Mark the matched samples in both c_blocks as verified.
|
|
Packit |
cb6d3d |
* In reality, not all the samples are marked. See
|
|
Packit |
cb6d3d |
* stage1_matched() for details.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (j
|
|
Packit |
cb6d3d |
stage1_matched(old,new,matchbegin,matchend,matchoffset,callback);
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
stage1_matched(old,new,matchbegin,matchend,matchoffset,NULL);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
ret++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Skip past this verified run to look for more matches. */
|
|
Packit |
cb6d3d |
if (matchend-1 > j)
|
|
Packit |
cb6d3d |
j = matchend-1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} /* end for */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n",
|
|
Packit |
cb6d3d |
searchsize,searchbegin,searchend,tried,matched,ret);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(ret);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_stage1() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Compare newly read samples against previously read samples, searching
|
|
Packit |
cb6d3d |
* for contiguous runs of identical samples. Matching runs indicate that
|
|
Packit |
cb6d3d |
* at least two reads of the CD returned identical data, with no dropped
|
|
Packit |
cb6d3d |
* samples in that run. The runs may be jittered (i.e. their absolute
|
|
Packit |
cb6d3d |
* positions on the CD may not be accurate due to inaccurate seeking) at
|
|
Packit |
cb6d3d |
* this point. Their positions will be determined in stage 2.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function compares a new c_block against all other c_blocks in memory,
|
|
Packit |
cb6d3d |
* searching for sufficiently long runs of identical samples. Since each
|
|
Packit |
cb6d3d |
* c_block represents a separate call to read_c_block, this ensures that
|
|
Packit |
cb6d3d |
* multiple reads have returned identical data. (Additionally, read_c_block
|
|
Packit |
cb6d3d |
* varies the reads so that multiple reads are unlikely to produce identical
|
|
Packit |
cb6d3d |
* errors, so any matches between reads are considered verified. See
|
|
Packit |
cb6d3d |
* i_read_c_block for more details.)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Each time we find such a run (longer than MIN_WORDS_SEARCH), we mark
|
|
Packit |
cb6d3d |
* the samples as "verified" in both c_blocks. Runs of verified samples in
|
|
Packit |
cb6d3d |
* the new c_block are promoted into verified fragments, which will later
|
|
Packit |
cb6d3d |
* be merged into the verified root in stage 2.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* In reality, not all the verified samples are marked as "verified."
|
|
Packit |
cb6d3d |
* See stage1_matched() for an explanation.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the number of verified fragments created by the
|
|
Packit |
cb6d3d |
* stage 1 matching.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static long int
|
|
Packit |
cb6d3d |
i_stage1(cdrom_paranoia_t *p, c_block_t *p_new,
|
|
Packit |
cb6d3d |
void (*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long size=cs(p_new);
|
|
Packit |
cb6d3d |
c_block_t *ptr=c_last(p);
|
|
Packit |
cb6d3d |
int ret=0;
|
|
Packit |
cb6d3d |
long int begin=0;
|
|
Packit |
cb6d3d |
long int end;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 1
|
|
Packit |
cb6d3d |
long int block_count = 0;
|
|
Packit |
cb6d3d |
fprintf(stderr,
|
|
Packit |
cb6d3d |
"Verifying block %ld:[%ld-%ld] against previously read blocks...\n",
|
|
Packit |
cb6d3d |
p->cache->active,
|
|
Packit |
cb6d3d |
cb(p_new), ce(p_new));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We're going to be comparing the new c_block against the other
|
|
Packit |
cb6d3d |
* c_blocks in memory. Initialize the "sort cache" index to allow
|
|
Packit |
cb6d3d |
* for fast searching through the new c_block. (The index will
|
|
Packit |
cb6d3d |
* actually be built the first time we search.)
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (ptr)
|
|
Packit |
cb6d3d |
sort_setup( p->sortcache, cv(p_new), &cb(p_new), cs(p_new), cb(p_new),
|
|
Packit |
cb6d3d |
ce(p_new) );
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Iterate from oldest to newest c_block, comparing the new c_block
|
|
Packit |
cb6d3d |
* to each, looking for a sufficiently long run of identical samples
|
|
Packit |
cb6d3d |
* (longer than MIN_WORDS_SEARCH), which will be marked as "verified"
|
|
Packit |
cb6d3d |
* in both c_blocks.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Since the new c_block is already in the list (at the head), don't
|
|
Packit |
cb6d3d |
* compare it against itself.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
while ( ptr && ptr != p_new ) {
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 1
|
|
Packit |
cb6d3d |
block_count++;
|
|
Packit |
cb6d3d |
fprintf(stderr,
|
|
Packit |
cb6d3d |
"- Verifying against block %ld:[%ld-%ld] dynoverlap=%ld\n",
|
|
Packit |
cb6d3d |
block_count, cb(ptr), ce(ptr), p->dynoverlap);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(cb(p_new), PARANOIA_CB_VERIFY);
|
|
Packit |
cb6d3d |
i_iterate_stage1(p,ptr,p_new,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
ptr=c_prev(ptr);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* parse the verified areas of p_new into v_fragments */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Find each run of contiguous verified samples in the new c_block
|
|
Packit |
cb6d3d |
* and create a verified fragment from each run.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
begin=0;
|
|
Packit |
cb6d3d |
while (begin
|
|
Packit |
cb6d3d |
for ( ; begin < size; begin++)
|
|
Packit |
cb6d3d |
if (p_new->flags[begin]&FLAGS_VERIFIED) break;
|
|
Packit |
cb6d3d |
for (end=begin; end < size; end++)
|
|
Packit |
cb6d3d |
if ((p_new->flags[end]&FLAGS_VERIFIED)==0) break;
|
|
Packit |
cb6d3d |
if (begin>=size) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
ret++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We create a new verified fragment from the contiguous run
|
|
Packit |
cb6d3d |
* of verified samples.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We expand the "verified" range by OVERLAP_ADJ on each side
|
|
Packit |
cb6d3d |
* to compensate for trimming done to the verified range by
|
|
Packit |
cb6d3d |
* stage1_matched(). The samples were actually verified, and
|
|
Packit |
cb6d3d |
* hence belong in the verified fragment. See stage1_matched()
|
|
Packit |
cb6d3d |
* for an explanation of the trimming.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
new_v_fragment(p,p_new,cb(p_new)+max(0,begin-OVERLAP_ADJ),
|
|
Packit |
cb6d3d |
cb(p_new)+min(size,end+OVERLAP_ADJ),
|
|
Packit |
cb6d3d |
(end+OVERLAP_ADJ>=size && p_new->lastsector));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
begin=end;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Return the number of distinct verified fragments we found with
|
|
Packit |
cb6d3d |
* stage 1 matching.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
return(ret);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* STAGE 2 MATCHING
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ???: Insert high-level explanation here.
|
|
Packit |
cb6d3d |
* ===========================================================================
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
typedef struct sync_result {
|
|
Packit |
cb6d3d |
long offset;
|
|
Packit |
cb6d3d |
long begin;
|
|
Packit |
cb6d3d |
long end;
|
|
Packit |
cb6d3d |
} sync_result_t;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Reconcile v_fragments to root buffer. Free if matched, fragment/fixup root
|
|
Packit |
cb6d3d |
if necessary.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
Do *not* match using zero posts
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_iterate_stage2 (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function searches for a sufficiently long run of identical samples
|
|
Packit |
cb6d3d |
* between the passed verified fragment and the verified root. The search
|
|
Packit |
cb6d3d |
* is similar to that performed by i_iterate_stage1. Of course, what we do
|
|
Packit |
cb6d3d |
* as a result of a match is different.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Our search is slightly different in that we refuse to match silence to
|
|
Packit |
cb6d3d |
* silence. All silence looks alike, and it would result in too many false
|
|
Packit |
cb6d3d |
* positives here, so we handle silence separately.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Also, because we're trying to determine whether this fragment as a whole
|
|
Packit |
cb6d3d |
* overlaps with the root at all, we narrow our search (since it should match
|
|
Packit |
cb6d3d |
* immediately or not at all). This is in contrast to stage 1, where we
|
|
Packit |
cb6d3d |
* search the entire vector looking for all possible matches.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns 0 if no match was found (including failure to find
|
|
Packit |
cb6d3d |
* one due to silence), or 1 if we found a match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* When a match is found, the sync_result_t is set to the boundaries of
|
|
Packit |
cb6d3d |
* matching run (begin/end, in terms of the root) and how far out of sync
|
|
Packit |
cb6d3d |
* the fragment is from the canonical root (offset). Note that this offset
|
|
Packit |
cb6d3d |
* is opposite in sign from the notion of offset used by try_sort_sync()
|
|
Packit |
cb6d3d |
* and stage 1 generally.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static long int
|
|
Packit |
cb6d3d |
i_iterate_stage2(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
v_fragment_t *v,
|
|
Packit |
cb6d3d |
sync_result_t *r,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
root_block *root=&(p->root);
|
|
Packit |
cb6d3d |
long matchbegin=-1,matchend=-1,offset;
|
|
Packit |
cb6d3d |
long fbv,fev;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Comparing fragment [%ld-%ld] to root [%ld-%ld]...",
|
|
Packit |
cb6d3d |
fb(v), fe(v), rb(root), re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Quickly check whether there could possibly be any overlap between
|
|
Packit |
cb6d3d |
* the verified fragment and the root. Our search will allow up to
|
|
Packit |
cb6d3d |
* (p->dynoverlap) jitter between the two, so we expand the fragment
|
|
Packit |
cb6d3d |
* search area by p->dynoverlap on both sides and see if that expanded
|
|
Packit |
cb6d3d |
* area overlaps with the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We could just as easily expand root's boundaries by p->dynoverlap
|
|
Packit |
cb6d3d |
* instead and achieve the same result.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (min(fe(v) + p->dynoverlap,re(root)) -
|
|
Packit |
cb6d3d |
max(fb(v) - p->dynoverlap,rb(root)) <= 0)
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(fb(v), PARANOIA_CB_VERIFY);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We're going to try to match the fragment to the root while allowing
|
|
Packit |
cb6d3d |
* for p->dynoverlap jitter, so we'll actually be looking at samples
|
|
Packit |
cb6d3d |
* in the fragment whose position claims to be up to p->dynoverlap
|
|
Packit |
cb6d3d |
* outside the boundaries of the root. But, of course, don't extend
|
|
Packit |
cb6d3d |
* past the edges of the fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
fbv = max(fb(v), rb(root)-p->dynoverlap);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Skip past leading zeroes in the fragment, and bail if there's nothing
|
|
Packit |
cb6d3d |
* but silence. We handle silence later separately.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
while (fbv
|
|
Packit |
cb6d3d |
fbv++;
|
|
Packit |
cb6d3d |
if (fbv == fe(v))
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* This is basically the same idea as the initial calculation for fbv
|
|
Packit |
cb6d3d |
* above. Look at samples up to p->dynoverlap outside the boundaries
|
|
Packit |
cb6d3d |
* of the root, but don't extend past the edges of the fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* However, we also limit the search to no more than 256 samples.
|
|
Packit |
cb6d3d |
* Unlike stage 1, we're not trying to find all possible matches within
|
|
Packit |
cb6d3d |
* two runs -- rather, we're trying to see if the fragment as a whole
|
|
Packit |
cb6d3d |
* overlaps with the root. If we can't find a match within 256 samples,
|
|
Packit |
cb6d3d |
* there's probably no match to be found (because this fragment doesn't
|
|
Packit |
cb6d3d |
* overlap with the root).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? Is this why? Why 256?" 256 is simply a 'large enough number'. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
fev = min(min(fbv+256, re(root)+p->dynoverlap), fe(v));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
/* Because we'll allow for up to (p->dynoverlap) jitter between the
|
|
Packit |
cb6d3d |
* fragment and the root, we expand the search area (fbv to fev) by
|
|
Packit |
cb6d3d |
* p->dynoverlap on both sides. But, because we're iterating through
|
|
Packit |
cb6d3d |
* root, we need to constrain the search area not to extend beyond
|
|
Packit |
cb6d3d |
* the root's boundaries.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long searchend=min(fev+p->dynoverlap,re(root));
|
|
Packit |
cb6d3d |
long searchbegin=max(fbv-p->dynoverlap,rb(root));
|
|
Packit |
cb6d3d |
sort_info_t *i=p->sortcache;
|
|
Packit |
cb6d3d |
long j;
|
|
Packit |
cb6d3d |
long min_matchbegin = -1;
|
|
Packit |
cb6d3d |
long min_matchend = -1;
|
|
Packit |
cb6d3d |
long min_offset = LONG_MAX;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Initialize the "sort cache" index to allow for fast searching
|
|
Packit |
cb6d3d |
* through the verified fragment between (fbv,fev). (The index will
|
|
Packit |
cb6d3d |
* actually be built the first time we search.)
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
sort_setup(i, fv(v), &fb(v), fs(v), fbv, fev);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ??? Why 23? */
|
|
Packit |
cb6d3d |
for(j=searchbegin; j
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Skip past silence in the root. If there are just a few silent
|
|
Packit |
cb6d3d |
* samples, the effect is minimal. The real reason we need this is
|
|
Packit |
cb6d3d |
* for large regions of silence. All silence looks alike, so you
|
|
Packit |
cb6d3d |
* could false-positive "match" two runs of silence that are either
|
|
Packit |
cb6d3d |
* unrelated or ought to be jittered, and try_sort_sync can't
|
|
Packit |
cb6d3d |
* accurately determine jitter (offset) from silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Therefore, we want to post on a non-zero sample. If there's
|
|
Packit |
cb6d3d |
* nothing but silence left in the root, bail. We don't want
|
|
Packit |
cb6d3d |
* to match it here.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
while (j
|
|
Packit |
cb6d3d |
if (j==searchend) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Starting from the (non-zero) sample in the root with the absolute
|
|
Packit |
cb6d3d |
* position j, look for a matching run in the verified fragment. This
|
|
Packit |
cb6d3d |
* search will look a certain distance around j, and if successful
|
|
Packit |
cb6d3d |
* will extend the matching run as far backward and forward as
|
|
Packit |
cb6d3d |
* it can.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The search will only return 1 if it finds a matching run long
|
|
Packit |
cb6d3d |
* enough to be deemed significant. Note that the search is limited
|
|
Packit |
cb6d3d |
* by the boundaries given to sort_setup() above.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note also that flags aren't used in stage 2 (since neither verified
|
|
Packit |
cb6d3d |
* fragments nor the root have them).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (try_sort_sync(p, i, NULL, rc(root), j, &matchbegin,&matchend,&offset,callback)){
|
|
Packit |
cb6d3d |
if(labs(offset) < labs(min_offset)) {
|
|
Packit |
cb6d3d |
min_matchbegin = matchbegin;
|
|
Packit |
cb6d3d |
min_matchend = matchend;
|
|
Packit |
cb6d3d |
min_offset = offset;
|
|
Packit |
cb6d3d |
if(min_offset >= 0) {
|
|
Packit |
cb6d3d |
/* We will never find a smaller offset by continuing */
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
/* If we found a matching run, we return the results of our match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that we flip the sign of (offset) because try_sort_sync()
|
|
Packit |
cb6d3d |
* returns it in terms of the fragment (i.e. what we add
|
|
Packit |
cb6d3d |
* to the fragment's position to yield the corresponding position
|
|
Packit |
cb6d3d |
* in the root), but here we consider the root to be canonical,
|
|
Packit |
cb6d3d |
* and so our returned "offset" reflects how the fragment is offset
|
|
Packit |
cb6d3d |
* from the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* E.g.: If the fragment's sample 10 corresponds to root's 12,
|
|
Packit |
cb6d3d |
* try_sort_sync() would return 2. But since root is canonical,
|
|
Packit |
cb6d3d |
* we say that the fragment is off by -2.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if(min_offset != LONG_MAX) {
|
|
Packit |
cb6d3d |
r->begin=min_matchbegin;
|
|
Packit |
cb6d3d |
r->end=min_matchend;
|
|
Packit |
cb6d3d |
r->offset=-min_offset;
|
|
Packit |
cb6d3d |
if(min_offset)if(callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE);
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_silence_test() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* If the entire root is silent, or there's enough trailing silence
|
|
Packit |
cb6d3d |
* to be significant (MIN_SILENCE_BOUNDARY samples), mark the beginning
|
|
Packit |
cb6d3d |
* of the silence and "light" the silence flag. This flag will remain lit
|
|
Packit |
cb6d3d |
* until i_silence_match() appends some non-silent samples to the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We do this because if there's a long enough span of silence, we can't
|
|
Packit |
cb6d3d |
* reliably detect jitter or dropped samples within that span. See
|
|
Packit |
cb6d3d |
* i_silence_match() for details on how we recover from this situation.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static void
|
|
Packit |
cb6d3d |
i_silence_test(root_block *root)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
int16_t *vec=rv(root);
|
|
Packit |
cb6d3d |
long end=re(root)-rb(root)-1;
|
|
Packit |
cb6d3d |
long j;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Look backward from the end of the root to find the first non-silent
|
|
Packit |
cb6d3d |
* sample.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
for(j=end-1;j>=0;j--)
|
|
Packit |
cb6d3d |
if (vec[j]!=0) break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the entire root is silent, or there's enough trailing silence
|
|
Packit |
cb6d3d |
* to be significant, mark the beginning of the silence and "light"
|
|
Packit |
cb6d3d |
* the silence flag.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (j<0 || end-j>MIN_SILENCE_BOUNDARY) {
|
|
Packit |
cb6d3d |
/* ???BUG???:
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The original code appears to have a bug, as it points to the
|
|
Packit |
cb6d3d |
* last non-zero sample, and silence matching appears to treat
|
|
Packit |
cb6d3d |
* silencebegin as the first silent sample. As a result, in certain
|
|
Packit |
cb6d3d |
* situations, the last non-zero sample can get clobbered.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This bug has been tentatively fixed, since it allows more regression
|
|
Packit |
cb6d3d |
* tests to pass. The original code was:
|
|
Packit |
cb6d3d |
* if (j<0)j=0;
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
j++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root->silenceflag=1;
|
|
Packit |
cb6d3d |
root->silencebegin=rb(root)+j;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ???: To be studied. */
|
|
Packit |
cb6d3d |
if (root->silencebegin<root->returnedlimit)
|
|
Packit |
cb6d3d |
root->silencebegin=root->returnedlimit;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_silence_match() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is merges verified fragments into the verified root in cases
|
|
Packit |
cb6d3d |
* where there is a problematic amount of silence (MIN_SILENCE_BOUNDARY
|
|
Packit |
cb6d3d |
* samples) at the end of the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We need a special approach because if there's a long enough span of
|
|
Packit |
cb6d3d |
* silence, we can't reliably detect jitter or dropped samples within that
|
|
Packit |
cb6d3d |
* span (since all silence looks alike).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Only fragments that begin with MIN_SILENCE_BOUNDARY samples are eligible
|
|
Packit |
cb6d3d |
* to be merged in this case. Fragments that are too far beyond the edge
|
|
Packit |
cb6d3d |
* of the root to possibly overlap are also disregarded.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Our first approach is to assume that such fragments have no jitter (since
|
|
Packit |
cb6d3d |
* we can't establish otherwise) and merge them. However, if it's clear
|
|
Packit |
cb6d3d |
* that there must be jitter (i.e. because non-silent samples overlap when
|
|
Packit |
cb6d3d |
* we assume no jitter), we assume the fragment has the minimum possible
|
|
Packit |
cb6d3d |
* jitter and then merge it.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function extends silence fairly aggressively, so it must be called
|
|
Packit |
cb6d3d |
* with fragments in ascending order (beginning position) in case there are
|
|
Packit |
cb6d3d |
* small non-silent regions within the silence.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static long int
|
|
Packit |
cb6d3d |
i_silence_match(root_block *root, v_fragment_t *v,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
cdrom_paranoia_t *p=v->p;
|
|
Packit |
cb6d3d |
int16_t *vec=fv(v);
|
|
Packit |
cb6d3d |
long end=fs(v),begin;
|
|
Packit |
cb6d3d |
long j;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Silence matching fragment [%ld-%ld] to root [%ld-%ld]"
|
|
Packit |
cb6d3d |
" silencebegin=%ld\n",
|
|
Packit |
cb6d3d |
fb(v), fe(v), rb(root), re(root), root->silencebegin);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* See how much leading silence this fragment has. If there are fewer than
|
|
Packit |
cb6d3d |
* MIN_SILENCE_BOUNDARY leading silent samples, we don't do this special
|
|
Packit |
cb6d3d |
* silence matching.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This fragment could actually belong here, but we can't be sure unless
|
|
Packit |
cb6d3d |
* it has enough silence on its leading edge. This fragment will likely
|
|
Packit |
cb6d3d |
* stick around until we do successfully extend the root, at which point
|
|
Packit |
cb6d3d |
* it will be merged using the usual method.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (end
|
|
Packit |
cb6d3d |
for(j=0;j
|
|
Packit |
cb6d3d |
if (vec[j]!=0) break;
|
|
Packit |
cb6d3d |
if (j
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Convert the offset of the first non-silent sample to an absolute
|
|
Packit |
cb6d3d |
* position. For the time being, we will assume that this position
|
|
Packit |
cb6d3d |
* is accurate, with no jitter.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
j+=fb(v);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Fragment begins with silence [%ld-%ld]\n", fb(v), j);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If this fragment is ahead of the root, see if that could just be due
|
|
Packit |
cb6d3d |
* to jitter (if it's within p->dynoverlap samples of the end of root).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (fb(v)>=re(root) && fb(v)-p->dynoverlap
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* This fragment is within jitter range of the root, so we extend the
|
|
Packit |
cb6d3d |
* root's silence so that it overlaps with this fragment. At this point
|
|
Packit |
cb6d3d |
* we know that the fragment has at least MIN_SILENCE_BOUNDARY silent
|
|
Packit |
cb6d3d |
* samples at the beginning, so we overlap by that amount.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long addto = fb(v) + MIN_SILENCE_BOUNDARY - re(root);
|
|
Packit |
cb6d3d |
int16_t *vec = calloc(addto, sizeof(int16_t));
|
|
Packit |
cb6d3d |
c_append(rc(root), vec, addto);
|
|
Packit |
cb6d3d |
free(vec);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "* Adding silence [%ld-%ld] to root\n",
|
|
Packit |
cb6d3d |
re(root)-addto, re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Calculate the overlap of the root's trailing silence and the fragment's
|
|
Packit |
cb6d3d |
* leading silence. (begin,end) are the boundaries of that overlap.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
begin = max(fb(v),root->silencebegin);
|
|
Packit |
cb6d3d |
end = min(j,re(root));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If there is an overlap, we assume that both the root and the fragment
|
|
Packit |
cb6d3d |
* are jitter-free (since there's no way for us to tell otherwise).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (begin
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the fragment will extend the root, then we append it to the root.
|
|
Packit |
cb6d3d |
* Otherwise, no merging is necessary, as the fragment should already
|
|
Packit |
cb6d3d |
* be contained within the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (fe(v)>re(root)){
|
|
Packit |
cb6d3d |
long int voff = begin-fb(v);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Truncate the overlapping silence from the end of the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(rc(root),begin-rb(root),-1);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Append the fragment to the root, starting from the point of overlap.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_append(rc(root),vec+voff,fs(v)-voff);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "* Adding [%ld-%ld] to root (no jitter)\n",
|
|
Packit |
cb6d3d |
begin, re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Record the fact that we merged this fragment assuming zero jitter.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset_add_value(p,&p->stage2,0,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We weren't able to merge the fragment assuming zero jitter.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Check whether the fragment's leading silence ends before the root's
|
|
Packit |
cb6d3d |
* trailing silence begins. If it does, we assume that the root is
|
|
Packit |
cb6d3d |
* jittered forward.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (j
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We're going to append the non-silent samples of the fragment
|
|
Packit |
cb6d3d |
* to the root where its silence begins.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? This seems to be a very strange approach. At this point
|
|
Packit |
cb6d3d |
* the root has a lot of trailing silence, and the fragment has
|
|
Packit |
cb6d3d |
* the lot of leading silence. This merge will drop the silence
|
|
Packit |
cb6d3d |
* and just splice the non-silence together.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* In theory, rift analysis will either confirm or fix this result.
|
|
Packit |
cb6d3d |
* What circumstances motivated this approach?"
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This is an 'all bets are off' situation and we choose to make
|
|
Packit |
cb6d3d |
* the best guess we can, based on absolute position being
|
|
Packit |
cb6d3d |
* returned by the most recent reads. There are drives that
|
|
Packit |
cb6d3d |
* will randomly lose what they're doing during a read and just
|
|
Packit |
cb6d3d |
* pad out the results with zeros and return no error. This at
|
|
Packit |
cb6d3d |
* least has a shot of addressing that situation. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Compute the amount of silence at the beginning of the fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long voff = j - fb(v);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If attaching the non-silent tail of the fragment to the end
|
|
Packit |
cb6d3d |
* of the non-silent portion of the root will extend the root,
|
|
Packit |
cb6d3d |
* then we'll append the samples to the root. Otherwise, no
|
|
Packit |
cb6d3d |
* merging is necessary, as the fragment should already be contained
|
|
Packit |
cb6d3d |
* within the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (begin+fs(v)-voff>re(root)) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Truncate the trailing silence from the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(rc(root),root->silencebegin-rb(root),-1);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Append the non-silent tail of the fragment to the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_append(rc(root),vec+voff,fs(v)-voff);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "* Adding [%ld-%ld] to root (jitter=%ld)\n",
|
|
Packit |
cb6d3d |
root->silencebegin, re(root), end-begin);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Record the fact that we merged this fragment assuming (end-begin)
|
|
Packit |
cb6d3d |
* jitter.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset_add_value(p,&p->stage2,end-begin,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We only get here if the fragment is past the end of the root,
|
|
Packit |
cb6d3d |
* which means it must be farther than (dynoverlap) away, due to our
|
|
Packit |
cb6d3d |
* root extension above.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We weren't able to merge this fragment into the root after all.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We only get here if we merged the fragment into the root. Update
|
|
Packit |
cb6d3d |
* the root's silence flag.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that this is the only place silenceflag is reset. In other words,
|
|
Packit |
cb6d3d |
* once i_silence_test() lights the silence flag, it can only be reset
|
|
Packit |
cb6d3d |
* by i_silence_match().
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
root->silenceflag = 0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Now see if the new, extended root ends in silence.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_silence_test(root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Since we merged the fragment, we can free it now. But first we propagate
|
|
Packit |
cb6d3d |
* its lastsector flag.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (v->lastsector) root->lastsector=1;
|
|
Packit |
cb6d3d |
free_v_fragment(v);
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_stage2_each (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function (which is entirely too long) attempts to merge the passed
|
|
Packit |
cb6d3d |
* verified fragment into the verified root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* First this function looks for a run of identical samples between
|
|
Packit |
cb6d3d |
* the root and the fragment. If it finds a long enough run, it then
|
|
Packit |
cb6d3d |
* checks for "rifts" (see below) and fixes the root and/or fragment as
|
|
Packit |
cb6d3d |
* necessary. Finally, if the fragment will extend the tail of the root,
|
|
Packit |
cb6d3d |
* we merge the fragment and extend the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Most of the ugliness in this function has to do with handling "rifts",
|
|
Packit |
cb6d3d |
* which are points of disagreement between the root and the verified
|
|
Packit |
cb6d3d |
* fragment. This can happen when a drive consistently drops a few samples
|
|
Packit |
cb6d3d |
* or stutters and repeats a few samples. It has to be consistent enough
|
|
Packit |
cb6d3d |
* to result in a verified fragment (i.e. it happens twice), but inconsistent
|
|
Packit |
cb6d3d |
* enough (e.g. due to the jiggled reads) not to happen every time.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns 1 if the fragment was successfully merged into the
|
|
Packit |
cb6d3d |
* root, and 0 if not.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static long int
|
|
Packit |
cb6d3d |
i_stage2_each(root_block *root, v_fragment_t *v,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If this fragment has already been merged & freed, abort. */
|
|
Packit |
cb6d3d |
if (!v || !v->one) return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
cdrom_paranoia_t *p=v->p;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* "??? Why do we round down to an even dynoverlap?" Dynoverlap is
|
|
Packit |
cb6d3d |
in samples, not stereo frames --Monty */
|
|
Packit |
cb6d3d |
long dynoverlap=p->dynoverlap/2*2;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If there's no verified root yet, abort. */
|
|
Packit |
cb6d3d |
if (!rv(root)){
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
sync_result_t r;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Search for a sufficiently long run of identical samples between
|
|
Packit |
cb6d3d |
* the verified fragment and the verified root. There's a little
|
|
Packit |
cb6d3d |
* bit of subtlety in the search when silence is involved.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (i_iterate_stage2(p,v,&r,callback)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Convert the results of the search to be relative to the root. */
|
|
Packit |
cb6d3d |
long int begin=r.begin-rb(root);
|
|
Packit |
cb6d3d |
long int end=r.end-rb(root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Convert offset into a value that will transform a relative
|
|
Packit |
cb6d3d |
* position in the root to the corresponding relative position in
|
|
Packit |
cb6d3d |
* the fragment. I.e., if offset = -2, then the sample at relative
|
|
Packit |
cb6d3d |
* position 2 in the root is at relative position 0 in the fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* While a bit opaque, this does reduce the number of calculations
|
|
Packit |
cb6d3d |
* below.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long int offset=r.begin+r.offset-fb(v)-begin;
|
|
Packit |
cb6d3d |
long int temp;
|
|
Packit |
cb6d3d |
c_block_t *l=NULL;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* we have a match! We don't rematch off rift, we chase the
|
|
Packit |
cb6d3d |
match all the way to both extremes doing rift analysis. */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "matched [%ld-%ld], offset=%ld\n",
|
|
Packit |
cb6d3d |
r.begin, r.end, r.offset);
|
|
Packit |
cb6d3d |
int traced = 0;
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"Stage 2 match\n");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Now that we've found a sufficiently long run of identical samples
|
|
Packit |
cb6d3d |
* between the fragment and the root, we need to check for rifts.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* A "rift", as mentioned above, is a disagreement between the
|
|
Packit |
cb6d3d |
* fragment and the root. When there's a rift, the matching run
|
|
Packit |
cb6d3d |
* found by i_iterate_stage2() will obviously stop where the root
|
|
Packit |
cb6d3d |
* and the fragment disagree.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* So we detect rifts by checking whether the matching run extends
|
|
Packit |
cb6d3d |
* to the ends of the fragment and root. If the run does extend to
|
|
Packit |
cb6d3d |
* the ends of the fragment and root, then all overlapping samples
|
|
Packit |
cb6d3d |
* agreed, and there's no rift. If, however, the matching run
|
|
Packit |
cb6d3d |
* stops with samples left over in both the root and the fragment,
|
|
Packit |
cb6d3d |
* that means the root and fragment disagreed at that point.
|
|
Packit |
cb6d3d |
* Leftover samples at the beginning of the match indicate a
|
|
Packit |
cb6d3d |
* leading rift, and leftover samples at the end of the match indicate
|
|
Packit |
cb6d3d |
* a trailing rift.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Once we detect a rift, we attempt to fix it, depending on the
|
|
Packit |
cb6d3d |
* nature of the disagreement. See i_analyze_rift_[rf] for details
|
|
Packit |
cb6d3d |
* on how we determine what kind of rift it is. See below for
|
|
Packit |
cb6d3d |
* how we attempt to fix the rifts.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* First, check for a leading rift, fix it if possible, and then
|
|
Packit |
cb6d3d |
* extend the match forward until either we hit the limit of the
|
|
Packit |
cb6d3d |
* overlapping samples, or until we encounter another leading rift.
|
|
Packit |
cb6d3d |
* Keep doing this until we hit the beginning of the overlap.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that while we do fix up leading rifts, we don't extend
|
|
Packit |
cb6d3d |
* the root backward (earlier samples) -- only forward (later
|
|
Packit |
cb6d3d |
* samples).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the beginning of the match didn't reach the beginning of
|
|
Packit |
cb6d3d |
* either the fragment or the root, we have a leading rift to be
|
|
Packit |
cb6d3d |
* examined.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Remember that (begin) is the offset into the root, and (begin+offset)
|
|
Packit |
cb6d3d |
* is the equivalent offset into the fragment. If neither one is at
|
|
Packit |
cb6d3d |
* zero, then they both have samples before the match, and hence a
|
|
Packit |
cb6d3d |
* rift.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
while ((begin+offset>0 && begin>0)){
|
|
Packit |
cb6d3d |
long matchA=0,matchB=0,matchC=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* (begin) is the offset into the root of the first matching sample,
|
|
Packit |
cb6d3d |
* (beginL) is the offset into the fragment of the first matching
|
|
Packit |
cb6d3d |
* sample. These samples are at the edge of the rift.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long beginL=begin+offset;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
if ((traced & 1) == 0) {
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Analyzing leading rift...\n");
|
|
Packit |
cb6d3d |
traced |= 1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The first time we encounter a leading rift, allocate a
|
|
Packit |
cb6d3d |
* scratch copy of the verified fragment which we'll use if
|
|
Packit |
cb6d3d |
* we need to fix up the fragment before merging it into
|
|
Packit |
cb6d3d |
* the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (l==NULL){
|
|
Packit |
cb6d3d |
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
l=c_alloc(buff,fb(v),fs(v));
|
|
Packit |
cb6d3d |
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Starting at the first mismatching sample, see how far back the
|
|
Packit |
cb6d3d |
* rift goes, and determine what kind of rift it is. Note that
|
|
Packit |
cb6d3d |
* we're searching through the fixed up copy of the fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* matchA > 0 if there are samples missing from the root
|
|
Packit |
cb6d3d |
* matchA < 0 if there are duplicate samples (stuttering) in the root
|
|
Packit |
cb6d3d |
* matchB > 0 if there are samples missing from the fragment
|
|
Packit |
cb6d3d |
* matchB < 0 if there are duplicate samples in the fragment
|
|
Packit |
cb6d3d |
* matchC != 0 if there's a section of garbage, after which
|
|
Packit |
cb6d3d |
* the fragment and root agree and are in sync
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_analyze_rift_r(rv(root),cv(l),
|
|
Packit |
cb6d3d |
rs(root),cs(l),
|
|
Packit |
cb6d3d |
begin-1,beginL-1,
|
|
Packit |
cb6d3d |
&matchA,&matchB,&matchC);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n",
|
|
Packit |
cb6d3d |
matchA,matchB,matchC);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
/* "??? The root.returnedlimit checks below are presently a mystery." */
|
|
Packit |
cb6d3d |
/* Those are for the case where our backtracking wants to take
|
|
Packit |
cb6d3d |
us to back before bytes we've already returned to the
|
|
Packit |
cb6d3d |
application. In short, it's a "we're screwed"
|
|
Packit |
cb6d3d |
check. --Monty */
|
|
Packit |
cb6d3d |
if (matchA){
|
|
Packit |
cb6d3d |
/* There's a problem with the root */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (matchA>0){
|
|
Packit |
cb6d3d |
/* There were (matchA) samples dropped from the root. We'll add
|
|
Packit |
cb6d3d |
* them back from the fixed up fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
|
|
Packit |
cb6d3d |
if (rb(root)+begin<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
else{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* At the edge of the rift in the root, insert the missing
|
|
Packit |
cb6d3d |
* samples from the fixed up fragment. They're the (matchA)
|
|
Packit |
cb6d3d |
* samples immediately preceding the edge of the rift in the
|
|
Packit |
cb6d3d |
* fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_insert(rc(root),begin,cv(l)+beginL-matchA,
|
|
Packit |
cb6d3d |
matchA);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We just inserted (matchA) samples into the root, so update
|
|
Packit |
cb6d3d |
* our begin/end offsets accordingly. Also adjust the
|
|
Packit |
cb6d3d |
* (offset) to compensate (since we use it to find samples in
|
|
Packit |
cb6d3d |
* the fragment, and the fragment hasn't changed).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset-=matchA;
|
|
Packit |
cb6d3d |
begin+=matchA;
|
|
Packit |
cb6d3d |
end+=matchA;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* There were (-matchA) duplicate samples (stuttering) in the
|
|
Packit |
cb6d3d |
* root. We'll drop them.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
|
|
Packit |
cb6d3d |
if (rb(root)+begin+matchA<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
else{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Remove the (-matchA) samples immediately preceding the
|
|
Packit |
cb6d3d |
* edge of the rift in the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(rc(root),begin+matchA,-matchA);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We just removed (-matchA) samples from the root, so update
|
|
Packit |
cb6d3d |
* our begin/end offsets accordingly. Also adjust the offset
|
|
Packit |
cb6d3d |
* to compensate. Remember that matchA < 0, so we're actually
|
|
Packit |
cb6d3d |
* subtracting from begin/end.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset-=matchA;
|
|
Packit |
cb6d3d |
begin+=matchA;
|
|
Packit |
cb6d3d |
end+=matchA;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} else if (matchB){
|
|
Packit |
cb6d3d |
/* There's a problem with the fragment */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (matchB>0){
|
|
Packit |
cb6d3d |
/* There were (matchB) samples dropped from the fragment. We'll
|
|
Packit |
cb6d3d |
* add them back from the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* At the edge of the rift in the fragment, insert the missing
|
|
Packit |
cb6d3d |
* samples from the root. They're the (matchB) samples
|
|
Packit |
cb6d3d |
* immediately preceding the edge of the rift in the root.
|
|
Packit |
cb6d3d |
* Note that we're fixing up the scratch copy of the fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_insert(l,beginL,rv(root)+begin-matchB,
|
|
Packit |
cb6d3d |
matchB);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We just inserted (matchB) samples into the fixed up fragment,
|
|
Packit |
cb6d3d |
* so update (offset), since we use it to find samples in the
|
|
Packit |
cb6d3d |
* fragment based on the root's unchanged offsets.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset+=matchB;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* There were (-matchB) duplicate samples (stuttering) in the
|
|
Packit |
cb6d3d |
* fixed up fragment. We'll drop them.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Remove the (-matchB) samples immediately preceding the edge
|
|
Packit |
cb6d3d |
* of the rift in the fixed up fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(l,beginL+matchB,-matchB);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We just removed (-matchB) samples from the fixed up fragment,
|
|
Packit |
cb6d3d |
* so update (offset), since we use it to find samples in the
|
|
Packit |
cb6d3d |
* fragment based on the root's unchanged offsets.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset+=matchB;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else if (matchC){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* There are (matchC) samples that simply disagree between the
|
|
Packit |
cb6d3d |
* fragment and the root. On the other side of the mismatch, the
|
|
Packit |
cb6d3d |
* fragment and root agree again. We can't classify the mismatch
|
|
Packit |
cb6d3d |
* as either a stutter or dropped samples, and we have no way of
|
|
Packit |
cb6d3d |
* telling whether the fragment or the root is right.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "The original comment indicated that we set "disagree"
|
|
Packit |
cb6d3d |
* flags in the root, but it seems to be historical." The
|
|
Packit |
cb6d3d |
* disagree flags were from a time when we did interpolation
|
|
Packit |
cb6d3d |
* over samples we simply couldn't get to agree. Yes,
|
|
Packit |
cb6d3d |
* historical functionality that didn;t work well. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rb(root)+begin-matchC<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Overwrite the mismatching (matchC) samples in root with the
|
|
Packit |
cb6d3d |
* samples from the fixed up fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? Do we think the fragment is more likely correct, is this
|
|
Packit |
cb6d3d |
* just arbitrary, or is there some other reason for overwriting
|
|
Packit |
cb6d3d |
* the root?"
|
|
Packit |
cb6d3d |
* We think these samples are more likely to be correct --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_overwrite(rc(root),begin-matchC,
|
|
Packit |
cb6d3d |
cv(l)+beginL-matchC,matchC);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We may have had a mismatch because we ran into leading silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? To be studied: why would this cause a mismatch?
|
|
Packit |
cb6d3d |
* Neither i_analyze_rift_r nor i_iterate_stage2() nor
|
|
Packit |
cb6d3d |
* i_paranoia_overlap() appear to take silence into
|
|
Packit |
cb6d3d |
* consideration in this regard. It could be due to our
|
|
Packit |
cb6d3d |
* skipping of silence when searching for a match." Jitter
|
|
Packit |
cb6d3d |
* and or skipping in sections of silence could end up with
|
|
Packit |
cb6d3d |
* two sets of verified vectors that agree completely except
|
|
Packit |
cb6d3d |
* for the length of the silence. Silence is a huge bugaboo
|
|
Packit |
cb6d3d |
* in general because there's no entropy within it to base
|
|
Packit |
cb6d3d |
* verification on. --Monty
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Since we don't extend the root in that direction, we don't
|
|
Packit |
cb6d3d |
* do anything, just move on to trailing rifts.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the rift was too complex to fix (see i_analyze_rift_r),
|
|
Packit |
cb6d3d |
* we just stop and leave the leading edge where it is.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/*RRR(*callback)(post,PARANOIA_CB_XXX);*/
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Recalculate the offset of the edge of the rift in the fixed
|
|
Packit |
cb6d3d |
* up fragment, in case it changed.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? Why is this done here rather than in the (matchB) case above,
|
|
Packit |
cb6d3d |
* which should be the only time beginL will change."
|
|
Packit |
cb6d3d |
* Because there's no reason not to? --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
beginL=begin+offset;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Now that we've fixed up the root or fragment as necessary, see
|
|
Packit |
cb6d3d |
* how far we can extend the matching run. This function is
|
|
Packit |
cb6d3d |
* overkill, as it tries to extend the matching run in both
|
|
Packit |
cb6d3d |
* directions (and rematches what we already matched), but it works.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_paranoia_overlap(rv(root),cv(l),
|
|
Packit |
cb6d3d |
begin,beginL,
|
|
Packit |
cb6d3d |
rs(root),cs(l),
|
|
Packit |
cb6d3d |
&begin,&end;;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} /* end while (leading rift) */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Second, check for a trailing rift, fix it if possible, and then
|
|
Packit |
cb6d3d |
* extend the match forward until either we hit the limit of the
|
|
Packit |
cb6d3d |
* overlapping samples, or until we encounter another trailing rift.
|
|
Packit |
cb6d3d |
* Keep doing this until we hit the end of the overlap.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the end of the match didn't reach the end of either the fragment
|
|
Packit |
cb6d3d |
* or the root, we have a trailing rift to be examined.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Remember that (end) is the offset into the root, and (end+offset)
|
|
Packit |
cb6d3d |
* is the equivalent offset into the fragment. If neither one is
|
|
Packit |
cb6d3d |
* at the end of the vector, then they both have samples after the
|
|
Packit |
cb6d3d |
* match, and hence a rift.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* (temp) is the size of the (potentially fixed-up) fragment. If
|
|
Packit |
cb6d3d |
* there was a leading rift, (l) is the fixed up fragment, and
|
|
Packit |
cb6d3d |
* (offset) is now relative to it.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
temp=l ? cs(l) : fs(v);
|
|
Packit |
cb6d3d |
while (end+offset
|
|
Packit |
cb6d3d |
long matchA=0,matchB=0,matchC=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* (begin) is the offset into the root of the first matching sample,
|
|
Packit |
cb6d3d |
* (beginL) is the offset into the fragment of the first matching
|
|
Packit |
cb6d3d |
* sample. We know these samples match and will use these offsets
|
|
Packit |
cb6d3d |
* later when we try to extend the matching run.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long beginL=begin+offset;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* (end) is the offset into the root of the first mismatching sample
|
|
Packit |
cb6d3d |
* after the matching run, (endL) is the offset into the fragment of
|
|
Packit |
cb6d3d |
* the equivalent sample. These samples are at the edge of the rift.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
long endL=end+offset;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
if ((traced & 2) == 0) {
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Analyzing trailing rift...\n");
|
|
Packit |
cb6d3d |
traced |= 2;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The first time we encounter a rift, allocate a scratch copy of
|
|
Packit |
cb6d3d |
* the verified fragment which we'll use if we need to fix up the
|
|
Packit |
cb6d3d |
* fragment before merging it into the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that if there was a leading rift, we'll already have
|
|
Packit |
cb6d3d |
* this (potentially fixed-up) scratch copy allocated.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (l==NULL){
|
|
Packit |
cb6d3d |
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
l=c_alloc(buff,fb(v),fs(v));
|
|
Packit |
cb6d3d |
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Starting at the first mismatching sample, see how far forward the
|
|
Packit |
cb6d3d |
* rift goes, and determine what kind of rift it is. Note that we're
|
|
Packit |
cb6d3d |
* searching through the fixed up copy of the fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* matchA > 0 if there are samples missing from the root
|
|
Packit |
cb6d3d |
* matchA < 0 if there are duplicate samples (stuttering) in the root
|
|
Packit |
cb6d3d |
* matchB > 0 if there are samples missing from the fragment
|
|
Packit |
cb6d3d |
* matchB < 0 if there are duplicate samples in the fragment
|
|
Packit |
cb6d3d |
* matchC != 0 if there's a section of garbage, after which
|
|
Packit |
cb6d3d |
* the fragment and root agree and are in sync
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_analyze_rift_f(rv(root),cv(l),
|
|
Packit |
cb6d3d |
rs(root),cs(l),
|
|
Packit |
cb6d3d |
end,endL,
|
|
Packit |
cb6d3d |
&matchA,&matchB,&matchC);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"matching rootF: matchA:%ld matchB:%ld matchC:%ld\n",
|
|
Packit |
cb6d3d |
matchA,matchB,matchC);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ??? The root.returnedlimit checks below are presently a mystery. */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (matchA){
|
|
Packit |
cb6d3d |
/* There's a problem with the root */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (matchA>0){
|
|
Packit |
cb6d3d |
/* There were (matchA) samples dropped from the root. We'll add
|
|
Packit |
cb6d3d |
* them back from the fixed up fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
|
|
Packit |
cb6d3d |
if (end+rb(root)<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* At the edge of the rift in the root, insert the missing
|
|
Packit |
cb6d3d |
* samples from the fixed up fragment. They're the (matchA)
|
|
Packit |
cb6d3d |
* samples immediately preceding the edge of the rift in the
|
|
Packit |
cb6d3d |
* fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_insert(rc(root),end,cv(l)+endL,matchA);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Although we just inserted samples into the root, we did so
|
|
Packit |
cb6d3d |
* after (begin) and (end), so we needn't update those offsets.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* There were (-matchA) duplicate samples (stuttering) in the
|
|
Packit |
cb6d3d |
* root. We'll drop them.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
|
|
Packit |
cb6d3d |
if (end+rb(root)<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Remove the (-matchA) samples immediately following the edge
|
|
Packit |
cb6d3d |
* of the rift in the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(rc(root),end,-matchA);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Although we just removed samples from the root, we did so
|
|
Packit |
cb6d3d |
* after (begin) and (end), so we needn't update those offsets.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} else if (matchB){
|
|
Packit |
cb6d3d |
/* There's a problem with the fragment */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (matchB>0){
|
|
Packit |
cb6d3d |
/* There were (matchB) samples dropped from the fragment. We'll
|
|
Packit |
cb6d3d |
* add them back from the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* At the edge of the rift in the fragment, insert the missing
|
|
Packit |
cb6d3d |
* samples from the root. They're the (matchB) samples
|
|
Packit |
cb6d3d |
* immediately following the dge of the rift in the root.
|
|
Packit |
cb6d3d |
* Note that we're fixing up the scratch copy of the fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_insert(l,endL,rv(root)+end,matchB);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Although we just inserted samples into the fragment, we did so
|
|
Packit |
cb6d3d |
* after (begin) and (end), so (offset) hasn't changed either.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* There were (-matchB) duplicate samples (stuttering) in the
|
|
Packit |
cb6d3d |
* fixed up fragment. We'll drop them.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Remove the (-matchB) samples immediately following the edge
|
|
Packit |
cb6d3d |
* of the rift in the fixed up fragment.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_remove(l,endL,-matchB);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Although we just removed samples from the fragment, we did so
|
|
Packit |
cb6d3d |
* after (begin) and (end), so (offset) hasn't changed either.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} else if (matchC){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* There are (matchC) samples that simply disagree between the
|
|
Packit |
cb6d3d |
* fragment and the root. On the other side of the mismatch, the
|
|
Packit |
cb6d3d |
* fragment and root agree again. We can't classify the mismatch
|
|
Packit |
cb6d3d |
* as either a stutter or dropped samples, and we have no way of
|
|
Packit |
cb6d3d |
* telling whether the fragment or the root is right.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The original comment indicated that we set "disagree" flags
|
|
Packit |
cb6d3d |
* in the root, but it seems to be historical.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (end+rb(root)<p->root.returnedlimit)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Overwrite the mismatching (matchC) samples in root with the
|
|
Packit |
cb6d3d |
* samples from the fixed up fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ??? Do we think the fragment is more likely correct, is this
|
|
Packit |
cb6d3d |
* just arbitrary, or is there some other reason for overwriting
|
|
Packit |
cb6d3d |
* the root?
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_overwrite(rc(root),end,cv(l)+endL,matchC);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We may have had a mismatch because we ran into trailing silence.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ??? To be studied: why would this cause a mismatch? Neither
|
|
Packit |
cb6d3d |
* i_analyze_rift_f nor i_iterate_stage2() nor i_paranoia_overlap()
|
|
Packit |
cb6d3d |
* appear to take silence into consideration in this regard.
|
|
Packit |
cb6d3d |
* It could be due to our skipping of silence when searching for
|
|
Packit |
cb6d3d |
* a match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* At this point we have a trailing rift. We check whether
|
|
Packit |
cb6d3d |
* one of the vectors (fragment or root) has trailing silence.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
analyze_rift_silence_f(rv(root),cv(l),
|
|
Packit |
cb6d3d |
rs(root),cs(l),
|
|
Packit |
cb6d3d |
end,endL,
|
|
Packit |
cb6d3d |
&matchA,&matchB);
|
|
Packit |
cb6d3d |
if (matchA){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The contents of the root's trailing rift are silence. The
|
|
Packit |
cb6d3d |
* fragment's are not (otherwise there wouldn't be a rift).
|
|
Packit |
cb6d3d |
* We therefore assume that the root has garbage from this
|
|
Packit |
cb6d3d |
* point forward and truncate it.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This will have the effect of eliminating the trailing
|
|
Packit |
cb6d3d |
* rift, causing the fragment's samples to be appended to
|
|
Packit |
cb6d3d |
* the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ??? Does this have any negative side effects? Why is this
|
|
Packit |
cb6d3d |
* a good idea?
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
/* ??? TODO: returnedlimit */
|
|
Packit |
cb6d3d |
/* Can only do this if we haven't already returned data */
|
|
Packit |
cb6d3d |
if (end+rb(root)>=p->root.returnedlimit){
|
|
Packit |
cb6d3d |
c_remove(rc(root),end,-1);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else if (matchB){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The contents of the fragment's trailing rift are silence.
|
|
Packit |
cb6d3d |
* The root's are not (otherwise there wouldn't be a rift).
|
|
Packit |
cb6d3d |
* We therefore assume that the fragment has garbage from this
|
|
Packit |
cb6d3d |
* point forward.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We needn't actually truncate the fragment, because the root
|
|
Packit |
cb6d3d |
* has already been fixed up from this fragment as much as
|
|
Packit |
cb6d3d |
* possible, and the truncated fragment wouldn't extend the
|
|
Packit |
cb6d3d |
* root. Therefore, we can consider this (truncated) fragment
|
|
Packit |
cb6d3d |
* to be already merged into the root. So we dispose of it and
|
|
Packit |
cb6d3d |
* return a success.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (l)i_cblock_destructor(l);
|
|
Packit |
cb6d3d |
free_v_fragment(v);
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the rift was too complex to fix (see i_analyze_rift_f),
|
|
Packit |
cb6d3d |
* we just stop and leave the trailing edge where it is.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/*RRR(*callback)(post,PARANOIA_CB_XXX);*/
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Now that we've fixed up the root or fragment as necessary, see
|
|
Packit |
cb6d3d |
* how far we can extend the matching run. This function is
|
|
Packit |
cb6d3d |
* overkill, as it tries to extend the matching run in both
|
|
Packit |
cb6d3d |
* directions (and rematches what we already matched), but it works.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_paranoia_overlap(rv(root),cv(l),
|
|
Packit |
cb6d3d |
begin,beginL,
|
|
Packit |
cb6d3d |
rs(root),cs(l),
|
|
Packit |
cb6d3d |
NULL,&end;;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
temp=cs(l);
|
|
Packit |
cb6d3d |
} /* end while (trailing rift) */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Third and finally, if the overlapping verified fragment extends
|
|
Packit |
cb6d3d |
* our range forward (later samples), we append ("glom") the new
|
|
Packit |
cb6d3d |
* samples to the end of the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that while we did fix up leading rifts, we don't extend
|
|
Packit |
cb6d3d |
* the root backward (earlier samples) -- only forward (later
|
|
Packit |
cb6d3d |
* samples).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This is generally fine, since the verified root is supposed to
|
|
Packit |
cb6d3d |
* slide from earlier samples to later samples across multiple calls
|
|
Packit |
cb6d3d |
* to paranoia_read().
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? But, is this actually right? Because of this, we don't
|
|
Packit |
cb6d3d |
* extend the root to hold the earliest read sample, if we
|
|
Packit |
cb6d3d |
* happened to initialize the root with a later sample due to
|
|
Packit |
cb6d3d |
* jitter. There are probably some ugly side effects from
|
|
Packit |
cb6d3d |
* extending the root backward, in the general case, but it may
|
|
Packit |
cb6d3d |
* not be so dire if we're near sample 0. To be investigated."
|
|
Packit |
cb6d3d |
* In the begin case, any start position is arbitrary due to
|
|
Packit |
cb6d3d |
* inexact seeking. Later, we can't back-extend the root as the
|
|
Packit |
cb6d3d |
* samples preceeding the beginning have already been returned
|
|
Packit |
cb6d3d |
* to the application! --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long sizeA=rs(root);
|
|
Packit |
cb6d3d |
long sizeB;
|
|
Packit |
cb6d3d |
long vecbegin;
|
|
Packit |
cb6d3d |
int16_t *vector;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If there were any rifts, we'll use the fixed up fragment (l),
|
|
Packit |
cb6d3d |
* otherwise, we use the original fragment (v).
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (l){
|
|
Packit |
cb6d3d |
sizeB=cs(l);
|
|
Packit |
cb6d3d |
vector=cv(l);
|
|
Packit |
cb6d3d |
vecbegin=cb(l);
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
sizeB=fs(v);
|
|
Packit |
cb6d3d |
vector=fv(v);
|
|
Packit |
cb6d3d |
vecbegin=fb(v);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Convert the fragment-relative offset (sizeB) into an offset
|
|
Packit |
cb6d3d |
* relative to the root (A), and see if the offset is past the
|
|
Packit |
cb6d3d |
* end of the root (> sizeA). If it is, this fragment will extend
|
|
Packit |
cb6d3d |
* our root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? Why do we check for v->lastsector separately?" Because
|
|
Packit |
cb6d3d |
* of the case where root extends *too* far; if we never get a
|
|
Packit |
cb6d3d |
* read that accidentally extends that far again, we could
|
|
Packit |
cb6d3d |
* hang and loop forever. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (sizeB-offset>sizeA || v->lastsector){
|
|
Packit |
cb6d3d |
if (v->lastsector){
|
|
Packit |
cb6d3d |
root->lastsector=1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* "??? Why would end be < sizeA? Why do we truncate root?"
|
|
Packit |
cb6d3d |
Because it can happen (seeking is very very inexact) and
|
|
Packit |
cb6d3d |
end of disk tends to be very problematic in terms of
|
|
Packit |
cb6d3d |
stopping point. We also generally believe more recent
|
|
Packit |
cb6d3d |
information over previous information when they disagree
|
|
Packit |
cb6d3d |
and both are 'verified'. --Monty */
|
|
Packit |
cb6d3d |
if (end
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Extend the root with the samples from the end of the
|
|
Packit |
cb6d3d |
* (potentially fixed up) fragment.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ??? When would this condition not be true?
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (sizeB-offset-end)c_append(rc(root),vector+end+offset,
|
|
Packit |
cb6d3d |
sizeB-offset-end);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "* Adding [%ld-%ld] to root\n",
|
|
Packit |
cb6d3d |
rb(root)+end, re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Any time we update the root we need to check whether it ends
|
|
Packit |
cb6d3d |
* with a large span of silence.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_silence_test(root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Add the offset into our stage 2 statistics.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that we convert our peculiar offset (which is in terms of
|
|
Packit |
cb6d3d |
* the relative positions of samples within each vector) back into
|
|
Packit |
cb6d3d |
* the actual offset between what A considers sample N and what B
|
|
Packit |
cb6d3d |
* considers sample N.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We do this at the end of rift handling because any original
|
|
Packit |
cb6d3d |
* offset returned by i_iterate_stage2() might have been due to
|
|
Packit |
cb6d3d |
* dropped or duplicated samples. Once we've fixed up the root
|
|
Packit |
cb6d3d |
* and the fragment, we have an offset which more reliably
|
|
Packit |
cb6d3d |
* indicates jitter.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
offset_add_value(p,&p->stage2,offset+vecbegin-rb(root),callback);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
if (l)i_cblock_destructor(l);
|
|
Packit |
cb6d3d |
free_v_fragment(v);
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else { /* !i_iterate_stage2(...) */
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "no match");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We were unable to merge this fragment into the root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Check whether the fragment should have overlapped with the root,
|
|
Packit |
cb6d3d |
* even taking possible jitter into account. (I.e., If the fragment
|
|
Packit |
cb6d3d |
* ends so far before the end of the root that even (dynoverlap)
|
|
Packit |
cb6d3d |
* samples of jitter couldn't push it beyond the end of the root,
|
|
Packit |
cb6d3d |
* it should have overlapped.)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* It is, however, possible that we failed to match using the normal
|
|
Packit |
cb6d3d |
* tests because we're dealing with silence, which we handle
|
|
Packit |
cb6d3d |
* separately.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* If the fragment should have overlapped, and we're not dealing
|
|
Packit |
cb6d3d |
* with the special silence case, we don't know what to make of
|
|
Packit |
cb6d3d |
* this fragment, and we just discard it.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (fe(v)+dynoverlap<re(root) && !root->silenceflag){
|
|
Packit |
cb6d3d |
/* It *should* have matched. No good; free it. */
|
|
Packit |
cb6d3d |
free_v_fragment(v);
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, ", discarding fragment.");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr, "\n");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* otherwise, we likely want this for an upcoming match */
|
|
Packit |
cb6d3d |
/* we don't free the sort info (if it was collected) */
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} /* endif rv(root) */
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static int
|
|
Packit |
cb6d3d |
i_init_root(root_block *root, v_fragment_t *v,long int begin,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if (fb(v)<=begin && fe(v)>begin){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root->lastsector=v->lastsector;
|
|
Packit |
cb6d3d |
root->returnedlimit=begin;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rv(root)){
|
|
Packit |
cb6d3d |
i_cblock_destructor(rc(root));
|
|
Packit |
cb6d3d |
rc(root)=NULL;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
|
|
Packit |
cb6d3d |
root->vector=c_alloc(buff,fb(v),fs(v));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Check whether the new root has a long span of trailing silence.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_silence_test(root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
fprintf(stderr,
|
|
Packit |
cb6d3d |
"* Assigning fragment [%ld-%ld] to root, silencebegin=%ld\n",
|
|
Packit |
cb6d3d |
rb(root), re(root), root->silencebegin);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(1);
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
return(0);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static int
|
|
Packit |
cb6d3d |
vsort(const void *a,const void *b)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
return((*(v_fragment_t **)a)->begin-(*(v_fragment_t **)b)->begin);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* i_stage2 (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function attempts to extend the verified root by merging verified
|
|
Packit |
cb6d3d |
* fragments into it. It keeps extending the tail end of the root until
|
|
Packit |
cb6d3d |
* it runs out of matching fragments. See i_stage2_each (and
|
|
Packit |
cb6d3d |
* i_iterate_stage2) for details of fragment matching and merging.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by paranoia_read_limited when the verified root
|
|
Packit |
cb6d3d |
* doesn't contain sufficient data to satisfy the request for samples.
|
|
Packit |
cb6d3d |
* If this function fails to extend the verified root far enough (having
|
|
Packit |
cb6d3d |
* exhausted the currently available verified fragments), the caller
|
|
Packit |
cb6d3d |
* will then read the device again to try and establish more verified
|
|
Packit |
cb6d3d |
* fragments.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* We first try to merge all the fragments in ascending order using the
|
|
Packit |
cb6d3d |
* standard method (i_stage2_each()), and then we try to merge the
|
|
Packit |
cb6d3d |
* remaining fragments using silence matching (i_silence_match())
|
|
Packit |
cb6d3d |
* if the root has a long span of trailing silence. See the initial
|
|
Packit |
cb6d3d |
* comments on silence and i_silence_match() for an explanation of this
|
|
Packit |
cb6d3d |
* distinction.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the number of verified fragments successfully
|
|
Packit |
cb6d3d |
* merged into the verified root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
static int
|
|
Packit |
cb6d3d |
i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword,
|
|
Packit |
cb6d3d |
void (*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
int flag=1,ret=0;
|
|
Packit |
cb6d3d |
root_block *root=&(p->root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"Fragments:%ld\n",p->fragments->active);
|
|
Packit |
cb6d3d |
fflush(stderr);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* even when the 'silence flag' is lit, we try to do non-silence
|
|
Packit |
cb6d3d |
matching in the event that there are still audio vectors with
|
|
Packit |
cb6d3d |
content to be sunk before the silence */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* This flag is not the silence flag. Rather, it indicates whether
|
|
Packit |
cb6d3d |
* we succeeded in adding a verified fragment to the verified root.
|
|
Packit |
cb6d3d |
* In short, we keep adding fragments until we no longer find a
|
|
Packit |
cb6d3d |
* match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
while (flag) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Convert the linked list of verified fragments into an array,
|
|
Packit |
cb6d3d |
* to be sorted in order of beginning sample position
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
v_fragment_t *first=v_first(p);
|
|
Packit |
cb6d3d |
long active=p->fragments->active,count=0;
|
|
Packit |
cb6d3d |
v_fragment_t **list = calloc(active, sizeof(v_fragment_t *));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while (first){
|
|
Packit |
cb6d3d |
v_fragment_t *next=v_next(first);
|
|
Packit |
cb6d3d |
list[count++]=first;
|
|
Packit |
cb6d3d |
first=next;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Reset the flag so that if we don't match any fragments, we
|
|
Packit |
cb6d3d |
* stop looping. Then, proceed only if there are any fragments
|
|
Packit |
cb6d3d |
* to match.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
flag=0;
|
|
Packit |
cb6d3d |
if (count){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Sort the array of verified fragments in order of beginning
|
|
Packit |
cb6d3d |
* sample position.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
qsort(list,active,sizeof(v_fragment_t *),&vsort);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We don't check for the silence flag yet, because even if the
|
|
Packit |
cb6d3d |
* verified root ends in silence (and thus the silence flag is set),
|
|
Packit |
cb6d3d |
* there may be a non-silent region at the beginning of the verified
|
|
Packit |
cb6d3d |
* root, into which we can merge the verified fragments.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Iterate through the verified fragments, starting at the fragment
|
|
Packit |
cb6d3d |
* with the lowest beginning sample position.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
for(count=0;count
|
|
Packit |
cb6d3d |
first=list[count];
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Make sure this fragment hasn't already been merged (and
|
|
Packit |
cb6d3d |
* thus freed). */
|
|
Packit |
cb6d3d |
if (first->one){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we don't have a verified root yet, just promote the first
|
|
Packit |
cb6d3d |
* fragment (with lowest beginning sample) to be the verified
|
|
Packit |
cb6d3d |
* root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "??? It seems that this could be fairly arbitrary if jitter
|
|
Packit |
cb6d3d |
* is an issue. If we've verified two fragments allegedly
|
|
Packit |
cb6d3d |
* beginning at "0" (which are actually slightly offset due to
|
|
Packit |
cb6d3d |
* jitter), the root might not begin at the earliest read
|
|
Packit |
cb6d3d |
* sample. Additionally, because subsequent fragments are
|
|
Packit |
cb6d3d |
* only merged at the tail end of the root, this situation
|
|
Packit |
cb6d3d |
* won't be fixed by merging the earlier samples.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Practically, this ends up not being critical since most
|
|
Packit |
cb6d3d |
* drives insert some extra silent samples at the beginning
|
|
Packit |
cb6d3d |
* of the stream. Missing a few of them doesn't cause any
|
|
Packit |
cb6d3d |
* real lost data. But it is non-deterministic."
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* On such a drive, the entire act of CDDA read is highly
|
|
Packit |
cb6d3d |
* nondeterministic. All redbook says is +/- 75 sectors.
|
|
Packit |
cb6d3d |
* If you insist on the earliest possible sample, you can
|
|
Packit |
cb6d3d |
* get into a situation where the first read was far earlier
|
|
Packit |
cb6d3d |
* than all the others and no other read ever repeats the
|
|
Packit |
cb6d3d |
* early positioning. --Monty */
|
|
Packit |
cb6d3d |
if (rv(root)==NULL){
|
|
Packit |
cb6d3d |
if (i_init_root(&(p->root),first,beginword,callback)){
|
|
Packit |
cb6d3d |
free_v_fragment(first);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Consider this a merged fragment, so set the flag
|
|
Packit |
cb6d3d |
* to keep looping.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
flag=1;
|
|
Packit |
cb6d3d |
ret++;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Try to merge this fragment with the verified root,
|
|
Packit |
cb6d3d |
* extending the tail of the root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (i_stage2_each(root,first,callback)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we successfully merged the fragment, set the flag
|
|
Packit |
cb6d3d |
* to keep looping.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
ret++;
|
|
Packit |
cb6d3d |
flag=1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the verified root ends in a long span of silence, iterate
|
|
Packit |
cb6d3d |
* through the remaining unmerged fragments to see if they can be
|
|
Packit |
cb6d3d |
* merged using our special silence matching.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (!flag && p->root.silenceflag){
|
|
Packit |
cb6d3d |
for(count=0;count
|
|
Packit |
cb6d3d |
first=list[count];
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Make sure this fragment hasn't already been merged (and
|
|
Packit |
cb6d3d |
* thus freed). */
|
|
Packit |
cb6d3d |
if (first->one){
|
|
Packit |
cb6d3d |
if (rv(root)!=NULL){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Try to merge the fragment into the root. This will only
|
|
Packit |
cb6d3d |
* succeed if the fragment overlaps and begins with sufficient
|
|
Packit |
cb6d3d |
* silence to be a presumed match.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Note that the fragments must be passed to i_silence_match()
|
|
Packit |
cb6d3d |
* in ascending order, as they are here.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (i_silence_match(root,first,callback)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we successfully merged the fragment, set the flag
|
|
Packit |
cb6d3d |
* to keep looping.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
ret++;
|
|
Packit |
cb6d3d |
flag=1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} /* end for */
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
} /* end if(count) */
|
|
Packit |
cb6d3d |
free(list);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we were able to extend the verified root at all during this pass
|
|
Packit |
cb6d3d |
* through the loop, loop again to see if we can merge any remaining
|
|
Packit |
cb6d3d |
* fragments with the extended root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 2
|
|
Packit |
cb6d3d |
if (flag)
|
|
Packit |
cb6d3d |
fprintf(stderr,
|
|
Packit |
cb6d3d |
"- Root updated, comparing remaining fragments again.\n");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} /* end while */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Return the number of fragments we successfully merged into the
|
|
Packit |
cb6d3d |
* verified root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
return(ret);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static void
|
|
Packit |
cb6d3d |
i_end_case(cdrom_paranoia_t *p,long endword,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root_block *root=&p->root;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* have an 'end' flag; if we've just read in the last sector in a
|
|
Packit |
cb6d3d |
session, set the flag. If we verify to the end of a fragment
|
|
Packit |
cb6d3d |
which has the end flag set, we're done (set a done flag). Pad
|
|
Packit |
cb6d3d |
zeroes to the end of the read */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (root->lastsector==0)return;
|
|
Packit |
cb6d3d |
if (endword
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long addto=endword-re(root);
|
|
Packit |
cb6d3d |
char *temp=calloc(addto,sizeof(char)*2);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
c_append(rc(root),(void *)temp,addto);
|
|
Packit |
cb6d3d |
free(temp);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* trash da cache */
|
|
Packit |
cb6d3d |
paranoia_resetcache(p);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We want to add a sector. Look through the caches for something that
|
|
Packit |
cb6d3d |
spans. Also look at the flags on the c_block... if this is an
|
|
Packit |
cb6d3d |
obliterated sector, get a bit of a chunk past the obliteration. */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Not terribly smart right now, actually. We can probably find
|
|
Packit |
cb6d3d |
*some* match with a cache block somewhere. Take it and continue it
|
|
Packit |
cb6d3d |
through the skip */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static void
|
|
Packit |
cb6d3d |
verify_skip_case(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root_block *root=&(p->root);
|
|
Packit |
cb6d3d |
c_block_t *graft=NULL;
|
|
Packit |
cb6d3d |
int vflag=0;
|
|
Packit |
cb6d3d |
int gend=0;
|
|
Packit |
cb6d3d |
long post;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef NOISY
|
|
Packit |
cb6d3d |
fprintf(stderr,"\nskipping\n");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rv(root)==NULL){
|
|
Packit |
cb6d3d |
post=0;
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
post=re(root);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
if (post==-1)post=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (callback)(*callback)(post,PARANOIA_CB_SKIP);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "Skipping [%ld-", post);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We want to add a sector. Look for a c_block that spans,
|
|
Packit |
cb6d3d |
preferrably a verified area */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
c_block_t *c=c_first(p);
|
|
Packit |
cb6d3d |
while (c){
|
|
Packit |
cb6d3d |
long cbegin=cb(c);
|
|
Packit |
cb6d3d |
long cend=ce(c);
|
|
Packit |
cb6d3d |
if (cbegin<=post && cend>post){
|
|
Packit |
cb6d3d |
long vend=post;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (c->flags[post-cbegin]&FLAGS_VERIFIED){
|
|
Packit |
cb6d3d |
/* verified area! */
|
|
Packit |
cb6d3d |
while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED))vend++;
|
|
Packit |
cb6d3d |
if (!vflag || vend>vflag){
|
|
Packit |
cb6d3d |
graft=c;
|
|
Packit |
cb6d3d |
gend=vend;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
vflag=1;
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* not a verified area */
|
|
Packit |
cb6d3d |
if (!vflag){
|
|
Packit |
cb6d3d |
while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED)==0)vend++;
|
|
Packit |
cb6d3d |
if (graft==NULL || gend>vend){
|
|
Packit |
cb6d3d |
/* smallest unverified area */
|
|
Packit |
cb6d3d |
graft=c;
|
|
Packit |
cb6d3d |
gend=vend;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
c=c_next(c);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (graft){
|
|
Packit |
cb6d3d |
long cbegin=cb(graft);
|
|
Packit |
cb6d3d |
long cend=ce(graft);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while (gend<cend && (graft->flags[gend-cbegin]&FLAGS_VERIFIED))gend++;
|
|
Packit |
cb6d3d |
gend=min(gend+OVERLAP_ADJ,cend);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rv(root)==NULL){
|
|
Packit |
cb6d3d |
int16_t *buff=malloc(cs(graft));
|
|
Packit |
cb6d3d |
memcpy(buff,cv(graft),cs(graft));
|
|
Packit |
cb6d3d |
rc(root)=c_alloc(buff,cb(graft),cs(graft));
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
c_append(rc(root),cv(graft)+post-cbegin,
|
|
Packit |
cb6d3d |
gend-post);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "%d], filled with %s data from block [%ld-%ld]\n",
|
|
Packit |
cb6d3d |
gend, (graft->flags[post-cbegin]&FLAGS_VERIFIED)
|
|
Packit |
cb6d3d |
? "verified" : "unverified", cbegin, cend);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root->returnedlimit=re(root);
|
|
Packit |
cb6d3d |
return;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* No? Fine. Great. Write in some zeroes :-P */
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
void *temp=calloc(CDIO_CD_FRAMESIZE_RAW,sizeof(int16_t));
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rv(root)==NULL){
|
|
Packit |
cb6d3d |
rc(root)=c_alloc(temp,post,CDIO_CD_FRAMESIZE_RAW);
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
c_append(rc(root),temp,CDIO_CD_FRAMESIZE_RAW);
|
|
Packit |
cb6d3d |
free(temp);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "%ld], filled with zero\n", re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
root->returnedlimit=re(root);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/**** toplevel ****************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
paranoia_free(cdrom_paranoia_t *p)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
paranoia_resetall(p);
|
|
Packit |
cb6d3d |
sort_free(p->sortcache);
|
|
Packit |
cb6d3d |
free_list(p->cache, 1);
|
|
Packit |
cb6d3d |
free_list(p->fragments, 1);
|
|
Packit |
cb6d3d |
free(p);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/*!
|
|
Packit |
cb6d3d |
Set the kind of repair you want to on for reading.
|
|
Packit |
cb6d3d |
The modes are listed above
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
@param p paranoia type
|
|
Packit |
cb6d3d |
@param mode_flags paranoia mode flags built from values in paranoia_mode_t,
|
|
Packit |
cb6d3d |
e.g. PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
paranoia_modeset(cdrom_paranoia_t *p, int mode_flags)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
p->enable=mode_flags;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/*!
|
|
Packit |
cb6d3d |
reposition reading offset.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
@param p paranoia type
|
|
Packit |
cb6d3d |
@param seek byte offset to seek to
|
|
Packit |
cb6d3d |
@param whence like corresponding parameter in libc's lseek, e.g.
|
|
Packit |
cb6d3d |
SEEK_SET or SEEK_END.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
lsn_t
|
|
Packit |
cb6d3d |
paranoia_seek(cdrom_paranoia_t *p, int32_t seek, int whence)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long sector;
|
|
Packit |
cb6d3d |
long ret;
|
|
Packit |
cb6d3d |
switch(whence){
|
|
Packit |
cb6d3d |
case SEEK_SET:
|
|
Packit |
cb6d3d |
sector=seek;
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
case SEEK_END:
|
|
Packit |
cb6d3d |
sector=cdda_disc_lastsector(p->d)+seek;
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
default:
|
|
Packit |
cb6d3d |
sector=p->cursor+seek;
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (cdda_sector_gettrack(p->d,sector)==-1)return(-1);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
i_cblock_destructor(p->root.vector);
|
|
Packit |
cb6d3d |
p->root.vector=NULL;
|
|
Packit |
cb6d3d |
p->root.lastsector=0;
|
|
Packit |
cb6d3d |
p->root.returnedlimit=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
ret=p->cursor;
|
|
Packit |
cb6d3d |
p->cursor=sector;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
i_paranoia_firstlast(p);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */
|
|
Packit |
cb6d3d |
p->current_firstsector=sector;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
return(ret);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static void cdrom_cache_update(cdrom_paranoia_t *p, int lba, int sectors){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(lba+sectors > p->cdcache_size){
|
|
Packit |
cb6d3d |
int end = lba+sectors;
|
|
Packit |
cb6d3d |
lba=end-p->cdcache_size;
|
|
Packit |
cb6d3d |
sectors = end-lba;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(lba < p->cdcache_begin){
|
|
Packit |
cb6d3d |
/* a backseek flushes the cache */
|
|
Packit |
cb6d3d |
p->cdcache_begin=lba;
|
|
Packit |
cb6d3d |
p->cdcache_end=lba+sectors;
|
|
Packit |
cb6d3d |
}else{
|
|
Packit |
cb6d3d |
if(lba+sectors>p->cdcache_end)
|
|
Packit |
cb6d3d |
p->cdcache_end = lba+sectors;
|
|
Packit |
cb6d3d |
if(lba+sectors-p->cdcache_size > p->cdcache_begin){
|
|
Packit |
cb6d3d |
if(lba+sectors-p->cdcache_size < p->cdcache_end){
|
|
Packit |
cb6d3d |
p->cdcache_begin = lba+sectors-p->cdcache_size;
|
|
Packit |
cb6d3d |
}else{
|
|
Packit |
cb6d3d |
p->cdcache_begin = lba;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static void cdrom_cache_handler(cdrom_paranoia_t *p, int lba, void(*callback)(long, paranoia_cb_mode_t)){
|
|
Packit |
cb6d3d |
int seekpos;
|
|
Packit |
cb6d3d |
int ms;
|
|
Packit |
cb6d3d |
if(lba>=p->cdcache_end)return; /* nothing to do */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(lba<0)lba=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(lba<p->cdcache_begin){
|
|
Packit |
cb6d3d |
/* should always trigger a backseek so let's do that here and look for the timing */
|
|
Packit |
cb6d3d |
seekpos=(lba==0 || lba-1<cdda_disc_firstsector(p->d) ? lba : lba-1); /* keep reads linear when possible */
|
|
Packit |
cb6d3d |
}else{
|
|
Packit |
cb6d3d |
int pre = p->cdcache_begin-1;
|
|
Packit |
cb6d3d |
int post = lba+p->cdcache_size;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
seekpos = (pre<cdda_disc_firstsector(p->d) ? post : pre);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(cdda_read_timed(p->d,NULL,seekpos,1,&ms)==1)
|
|
Packit |
cb6d3d |
if(seekpos<p->cdcache_begin && ms
|
|
Packit |
cb6d3d |
if(cdio_get_driver_id(p->d->p_cdio)==cdio_os_driver)
|
|
Packit |
cb6d3d |
callback(seekpos*CD_FRAMEWORDS,PARANOIA_CB_CACHEERR);
|
|
Packit |
cb6d3d |
cdrom_cache_update(p,seekpos,1);
|
|
Packit |
cb6d3d |
return;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* read_c_block() (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This funtion reads many (p->readahead) sectors, encompassing at least
|
|
Packit |
cb6d3d |
* the requested words.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* It returns a c_block which encapsulates these sectors' data and sector
|
|
Packit |
cb6d3d |
* number. The sectors come come from multiple low-level read requests.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function reads many sectors in order to exhaust any caching on the
|
|
Packit |
cb6d3d |
* drive itself, as caching would simply return the same incorrect data
|
|
Packit |
cb6d3d |
* over and over. Paranoia depends on truly re-reading portions of the
|
|
Packit |
cb6d3d |
* disc to make sure the reads are accurate and correct any inaccuracies.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Which precise sectors are read varies ("jiggles") between calls to
|
|
Packit |
cb6d3d |
* read_c_block, to prevent consistent errors across multiple reads
|
|
Packit |
cb6d3d |
* from being misinterpreted as correct data.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The size of each low-level read is determined by the underlying driver
|
|
Packit |
cb6d3d |
* (p->d->nsectors), which allows the driver to specify how many sectors
|
|
Packit |
cb6d3d |
* can be read in a single request. Historically, the Linux kernel could
|
|
Packit |
cb6d3d |
* only read 8 sectors at a time, with likely dropped samples between each
|
|
Packit |
cb6d3d |
* read request. Other operating systems may have different limitations.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by paranoia_read_limited(), which breaks the
|
|
Packit |
cb6d3d |
* c_block of read data into runs of samples that are likely to be
|
|
Packit |
cb6d3d |
* contiguous, verifies them and stores them in verified fragments, and
|
|
Packit |
cb6d3d |
* eventually merges the fragments into the verified root.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function returns the last c_block read or NULL on error.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
static c_block_t *
|
|
Packit |
cb6d3d |
i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
|
|
Packit |
cb6d3d |
void(*callback)(long, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* why do it this way? We need to read lots of sectors to kludge
|
|
Packit |
cb6d3d |
around stupid read ahead buffers on cheap drives, as well as avoid
|
|
Packit |
cb6d3d |
expensive back-seeking. We also want to 'jiggle' the start address
|
|
Packit |
cb6d3d |
to try to break borderline drives more noticeably (and make broken
|
|
Packit |
cb6d3d |
drives with unaddressable sectors behave more often). */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
long readat,firstread;
|
|
Packit |
cb6d3d |
long totaltoread=p->cdcache_size;
|
|
Packit |
cb6d3d |
long sectatonce=p->d->nsectors;
|
|
Packit |
cb6d3d |
long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5;
|
|
Packit |
cb6d3d |
c_block_t *new=NULL;
|
|
Packit |
cb6d3d |
root_block *root=&p->root;
|
|
Packit |
cb6d3d |
int16_t *buffer=NULL;
|
|
Packit |
cb6d3d |
unsigned char *flags=NULL;
|
|
Packit |
cb6d3d |
long sofar;
|
|
Packit |
cb6d3d |
long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
long anyflag=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Calculate the first sector to read. This calculation takes
|
|
Packit |
cb6d3d |
* into account the need to jitter the starting point of the read
|
|
Packit |
cb6d3d |
* to reveal consistent errors as well as the low reliability of
|
|
Packit |
cb6d3d |
* the edge words of a read.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ???: Document more clearly how dynoverlap and MIN_SECTOR_BACKUP
|
|
Packit |
cb6d3d |
* are calculated and used.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* What is the first sector to read? want some pre-buffer if
|
|
Packit |
cb6d3d |
we're not at the extreme beginning of the disc */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
long target;
|
|
Packit |
cb6d3d |
if (rv(root)==NULL || rb(root)>beginword)
|
|
Packit |
cb6d3d |
target=p->cursor-dynoverlap;
|
|
Packit |
cb6d3d |
else
|
|
Packit |
cb6d3d |
target=re(root)/(CD_FRAMEWORDS)-dynoverlap;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* we want to jitter the read alignment boundary, as some
|
|
Packit |
cb6d3d |
drives, beginning from a specific point, will tend to
|
|
Packit |
cb6d3d |
lose bytes between sectors in the same place. Also, as
|
|
Packit |
cb6d3d |
our vectors are being made up of multiple reads, we want
|
|
Packit |
cb6d3d |
the overlap boundaries to move.... */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter;
|
|
Packit |
cb6d3d |
if (readat>target)readat-=JIGGLE_MODULO;
|
|
Packit |
cb6d3d |
p->jitter--;
|
|
Packit |
cb6d3d |
if (p->jitter<0)
|
|
Packit |
cb6d3d |
p->jitter+=JIGGLE_MODULO;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
readat=p->cursor;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
readat+=driftcomp;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Create a new, empty c_block and add it to the head of the
|
|
Packit |
cb6d3d |
* list of c_blocks in memory. It will be empty until the end of
|
|
Packit |
cb6d3d |
* this subroutine.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)) {
|
|
Packit |
cb6d3d |
flags=calloc(totaltoread*CD_FRAMEWORDS, 1);
|
|
Packit |
cb6d3d |
new=new_c_block(p);
|
|
Packit |
cb6d3d |
recover_cache(p);
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* in the case of root it's just the buffer */
|
|
Packit |
cb6d3d |
paranoia_resetall(p);
|
|
Packit |
cb6d3d |
new=new_c_block(p);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1);
|
|
Packit |
cb6d3d |
sofar=0;
|
|
Packit |
cb6d3d |
firstread=-1;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* we have a read span; flush the drive cache if needed */
|
|
Packit |
cb6d3d |
cdrom_cache_handler(p, readat, callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "Reading [%ld-%ld] from media\n",
|
|
Packit |
cb6d3d |
readat*CD_FRAMEWORDS, (readat+totaltoread)*CD_FRAMEWORDS);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Issue each of the low-level reads; the optimal read size is
|
|
Packit |
cb6d3d |
* approximately the cachemodel's cdrom cache size. The only reason
|
|
Packit |
cb6d3d |
* to read less would be memory considerations.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* p->readahead = total number of sectors to read
|
|
Packit |
cb6d3d |
* p->d->nsectors = number of sectors to read per request
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* actual read loop */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while (sofar
|
|
Packit |
cb6d3d |
long secread=sectatonce; /* number of sectors to read this request */
|
|
Packit |
cb6d3d |
long adjread=readat; /* first sector to read for this request */
|
|
Packit |
cb6d3d |
long thisread; /* how many sectors were read this request */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* don't under/overflow the audio session */
|
|
Packit |
cb6d3d |
if (adjread<p->current_firstsector){
|
|
Packit |
cb6d3d |
secread-=p->current_firstsector-adjread;
|
|
Packit |
cb6d3d |
adjread=p->current_firstsector;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
if (adjread+secread-1>p->current_lastsector)
|
|
Packit |
cb6d3d |
secread=p->current_lastsector-adjread+1;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (sofar+secread>totaltoread)secread=totaltoread-sofar;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (secread>0){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (firstread<0) firstread = adjread;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Issue the low-level read to the driver.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 1
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Read [%ld-%ld] (0x%04X...0x%04X)%s",
|
|
Packit |
cb6d3d |
adjread*CD_FRAMEWORDS, (adjread+thisread)*CD_FRAMEWORDS,
|
|
Packit |
cb6d3d |
buffer[sofar*CD_FRAMEWORDS] & 0xFFFF,
|
|
Packit |
cb6d3d |
buffer[(sofar+thisread)*CD_FRAMEWORDS - 1] & 0xFFFF,
|
|
Packit |
cb6d3d |
thisread < secread ? "" : "\n");
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If the low-level read returned too few sectors, pad the result
|
|
Packit |
cb6d3d |
* with null data and mark it as invalid (FLAGS_UNREAD). We pad
|
|
Packit |
cb6d3d |
* because we're going to be appending further reads to the current
|
|
Packit |
cb6d3d |
* c_block.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "???: Why not re-read? It might be to keep you from getting
|
|
Packit |
cb6d3d |
* hung up on a bad sector. Or it might be to avoid
|
|
Packit |
cb6d3d |
* interrupting the streaming as much as possible."
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* There are drives on which you will never get a full read in
|
|
Packit |
cb6d3d |
* some positions. They always abort out early due to firmware
|
|
Packit |
cb6d3d |
* boundary cases. Reread will cause exactly the same thing to
|
|
Packit |
cb6d3d |
* happen again. NEC MultiSpeed 4x is one such drive. In these
|
|
Packit |
cb6d3d |
* cases, you take what part of the read you know is good, and
|
|
Packit |
cb6d3d |
* you get substantially better performance. --Monty
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if ( thisread < secread) {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(thisread<0){
|
|
Packit |
cb6d3d |
#ifdef ENOMEDIUM
|
|
Packit |
cb6d3d |
if(errno==ENOMEDIUM){
|
|
Packit |
cb6d3d |
/* the one error we bail on immediately */
|
|
Packit |
cb6d3d |
if(new)free_c_block(new);
|
|
Packit |
cb6d3d |
if(buffer)free(buffer);
|
|
Packit |
cb6d3d |
if(flags)free(flags);
|
|
Packit |
cb6d3d |
return NULL;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
thisread=0;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA & 1
|
|
Packit |
cb6d3d |
fprintf(stderr, " -- couldn't read [%ld-%ld]\n",
|
|
Packit |
cb6d3d |
(adjread+thisread)*CD_FRAMEWORDS,
|
|
Packit |
cb6d3d |
(adjread+secread)*CD_FRAMEWORDS);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Uhhh... right. Make something up. But don't make us seek
|
|
Packit |
cb6d3d |
backward! */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)((adjread+thisread)*CD_FRAMEWORDS, PARANOIA_CB_READERR);
|
|
Packit |
cb6d3d |
memset(buffer+(sofar+thisread)*CD_FRAMEWORDS,0,
|
|
Packit |
cb6d3d |
CDIO_CD_FRAMESIZE_RAW*(secread-thisread));
|
|
Packit |
cb6d3d |
if (flags)
|
|
Packit |
cb6d3d |
memset(flags+(sofar+thisread)*CD_FRAMEWORDS, FLAGS_UNREAD,
|
|
Packit |
cb6d3d |
CD_FRAMEWORDS*(secread-thisread));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
if (thisread!=0)anyflag=1;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Because samples are likely to be dropped between read requests,
|
|
Packit |
cb6d3d |
* mark the samples near the the boundaries of the read requests
|
|
Packit |
cb6d3d |
* as suspicious (FLAGS_EDGE). This means that any span of samples
|
|
Packit |
cb6d3d |
* against which these adjacent read requests are compared must
|
|
Packit |
cb6d3d |
* overlap beyond the edges and into the more trustworthy data.
|
|
Packit |
cb6d3d |
* Such overlapping spans are accordingly at least MIN_WORDS_OVERLAP
|
|
Packit |
cb6d3d |
* words long (and naturally longer if any samples were dropped
|
|
Packit |
cb6d3d |
* between the read requests).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* (EEEEE...overlapping span...EEEEE)
|
|
Packit |
cb6d3d |
* (read 1 ...........EEEEE) (EEEEE...... read 2 ......EEEEE) ...
|
|
Packit |
cb6d3d |
* dropped samples --^
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (flags && sofar!=0){
|
|
Packit |
cb6d3d |
/* Don't verify across overlaps that are too close to one
|
|
Packit |
cb6d3d |
another */
|
|
Packit |
cb6d3d |
int i=0;
|
|
Packit |
cb6d3d |
for(i=-MIN_WORDS_OVERLAP/2;i
|
|
Packit |
cb6d3d |
flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (adjread+secread-1==p->current_lastsector)
|
|
Packit |
cb6d3d |
new->lastsector=-1;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
cdrom_cache_update(p,adjread,secread);
|
|
Packit |
cb6d3d |
sofar+=secread;
|
|
Packit |
cb6d3d |
readat=adjread+secread;
|
|
Packit |
cb6d3d |
} else /* secread <= 0 */
|
|
Packit |
cb6d3d |
if (readat<p->current_firstsector)
|
|
Packit |
cb6d3d |
readat+=sectatonce; /* due to being before the readable area */
|
|
Packit |
cb6d3d |
else
|
|
Packit |
cb6d3d |
break; /* due to being past the readable area */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Keep issuing read requests until we've read enough sectors to
|
|
Packit |
cb6d3d |
* exhaust the drive's cache.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} /* end while */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we managed to read any sectors at all (anyflag), fill in the
|
|
Packit |
cb6d3d |
* previously allocated c_block with the read data. Otherwise, free
|
|
Packit |
cb6d3d |
* our buffers, dispose of the c_block, and return NULL.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (anyflag) {
|
|
Packit |
cb6d3d |
new->vector=buffer;
|
|
Packit |
cb6d3d |
new->begin=firstread*CD_FRAMEWORDS-p->dyndrift;
|
|
Packit |
cb6d3d |
new->size=sofar*CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
new->flags=flags;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Read block %ld:[%ld-%ld] from media\n",
|
|
Packit |
cb6d3d |
p->cache->active, cb(new), ce(new));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
if (new)free_c_block(new);
|
|
Packit |
cb6d3d |
free(buffer);
|
|
Packit |
cb6d3d |
free(flags);
|
|
Packit |
cb6d3d |
new=NULL;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
return(new);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/** ==========================================================================
|
|
Packit |
cb6d3d |
* cdio_paranoia_read(), cdio_paranoia_read_limited()
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* These functions "read" the next sector of audio data and returns
|
|
Packit |
cb6d3d |
* a pointer to a full sector of verified samples (2352 bytes).
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The returned buffer is *not* to be freed by the caller. It will
|
|
Packit |
cb6d3d |
* persist only until the next call to paranoia_read() for this p
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
int16_t *
|
|
Packit |
cb6d3d |
cdio_paranoia_read(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
void(*callback)(long, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
return paranoia_read_limited(p, callback, 20);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* I added max_retry functionality this way in order to avoid
|
|
Packit |
cb6d3d |
breaking any old apps using the new libs. cdparanoia 9.8 will
|
|
Packit |
cb6d3d |
need the updated libs, but nothing else will require it. */
|
|
Packit |
cb6d3d |
int16_t *
|
|
Packit |
cb6d3d |
cdio_paranoia_read_limited(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t),
|
|
Packit |
cb6d3d |
int max_retries)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long int beginword = p->cursor*(CD_FRAMEWORDS);
|
|
Packit |
cb6d3d |
long int endword = beginword+CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
long int retry_count= 0;
|
|
Packit |
cb6d3d |
long int lastend = -2;
|
|
Packit |
cb6d3d |
root_block *root = &p->root;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->d->opened==0){
|
|
Packit |
cb6d3d |
errno=EBADF;
|
|
Packit |
cb6d3d |
return NULL;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (beginword > p->root.returnedlimit)
|
|
Packit |
cb6d3d |
p->root.returnedlimit=beginword;
|
|
Packit |
cb6d3d |
lastend=re(root);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Since paranoia reads and verifies chunks of data at a time
|
|
Packit |
cb6d3d |
* (which it needs to counteract dropped samples and inaccurate
|
|
Packit |
cb6d3d |
* seeking), the requested samples may already be in memory,
|
|
Packit |
cb6d3d |
* in the verified "root".
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The root is where paranoia stores samples that have been
|
|
Packit |
cb6d3d |
* verified and whose position has been accurately determined.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* First, is the sector we want already in the root? */
|
|
Packit |
cb6d3d |
while (rv(root)==NULL ||
|
|
Packit |
cb6d3d |
rb(root)>beginword ||
|
|
Packit |
cb6d3d |
(re(root)
|
|
Packit |
cb6d3d |
p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) ||
|
|
Packit |
cb6d3d |
re(root)
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Nope; we need to build or extend the root verified range */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "Trying to expand root [%ld-%ld]...\n",
|
|
Packit |
cb6d3d |
rb(root), re(root));
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We may have already read the necessary samples and placed
|
|
Packit |
cb6d3d |
* them into verified fragments, but not yet merged them into
|
|
Packit |
cb6d3d |
* the verified root. We'll check that before we actually
|
|
Packit |
cb6d3d |
* try to read data from the drive.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* We need to make sure our memory consumption doesn't grow
|
|
Packit |
cb6d3d |
* to the size of the whole CD. But at the same time, we
|
|
Packit |
cb6d3d |
* need to hang onto some of the verified data (even perhaps
|
|
Packit |
cb6d3d |
* data that's already been returned by paranoia_read()) in
|
|
Packit |
cb6d3d |
* order to verify and accurately position future samples.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Therefore, we free some of the verified data that we
|
|
Packit |
cb6d3d |
* no longer need.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_paranoia_trim(p,beginword,endword);
|
|
Packit |
cb6d3d |
recover_cache(p);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rb(root)!=-1 && p->root.lastsector)
|
|
Packit |
cb6d3d |
i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
|
|
Packit |
cb6d3d |
callback);
|
|
Packit |
cb6d3d |
else
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Merge as many verified fragments into the verified root
|
|
Packit |
cb6d3d |
* as we need to satisfy the pending request. We may
|
|
Packit |
cb6d3d |
* not have all the fragments we need, in which case we'll
|
|
Packit |
cb6d3d |
* read data from the CD further below.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
i_stage2(p, beginword,
|
|
Packit |
cb6d3d |
endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
|
|
Packit |
cb6d3d |
callback);
|
|
Packit |
cb6d3d |
} else
|
|
Packit |
cb6d3d |
i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
|
|
Packit |
cb6d3d |
callback); /* only trips if we're already done */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#if TRACE_PARANOIA
|
|
Packit |
cb6d3d |
fprintf(stderr, "- Root is now [%ld-%ld] silencebegin=%ld\n",
|
|
Packit |
cb6d3d |
rb(root), re(root), root->silencebegin);
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we were able to fill the verified root with data already
|
|
Packit |
cb6d3d |
* in memory, we don't need to read any more data from the drive.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (!(rb(root)==-1 || rb(root)>beginword ||
|
|
Packit |
cb6d3d |
re(root)
|
|
Packit |
cb6d3d |
break;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Hmm, need more. Read another block */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
/* Read many sectors, encompassing at least the requested words.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* The returned c_block encapsulates these sectors' data and
|
|
Packit |
cb6d3d |
* sector number. The sectors come come from multiple low-level
|
|
Packit |
cb6d3d |
* read requests, and words which were near the boundaries of
|
|
Packit |
cb6d3d |
* those read requests are marked with FLAGS_EDGE.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
c_block_t *new=i_read_c_block(p,beginword,endword,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (new){
|
|
Packit |
cb6d3d |
if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we need to verify these samples, send them to
|
|
Packit |
cb6d3d |
* stage 1 verification, which will add verified samples
|
|
Packit |
cb6d3d |
* to the set of verified fragments. Verified fragments
|
|
Packit |
cb6d3d |
* will be merged into the verified root during stage 2
|
|
Packit |
cb6d3d |
* overlap analysis.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
if (p->enable&PARANOIA_MODE_VERIFY)
|
|
Packit |
cb6d3d |
i_stage1(p,new,callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we're only doing overlapping reads (no stage 1
|
|
Packit |
cb6d3d |
* verification), consider each low-level read in the
|
|
Packit |
cb6d3d |
* c_block to be a verified fragment. We exclude the
|
|
Packit |
cb6d3d |
* edges from these fragments to enforce the requirement
|
|
Packit |
cb6d3d |
* that we overlap the reads by the minimum amount.
|
|
Packit |
cb6d3d |
* These fragments will be merged into the verified
|
|
Packit |
cb6d3d |
* root during stage 2 overlap analysis.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
else{
|
|
Packit |
cb6d3d |
/* just make v_fragments from the boundary information. */
|
|
Packit |
cb6d3d |
long begin=0,end=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while (begin
|
|
Packit |
cb6d3d |
while (begin<cs(new) && (new->flags[begin]&FLAGS_EDGE))begin++;
|
|
Packit |
cb6d3d |
end=begin+1;
|
|
Packit |
cb6d3d |
while (end<cs(new) && (new->flags[end]&FLAGS_EDGE)==0)end++;
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
new_v_fragment(p,new,begin+cb(new),
|
|
Packit |
cb6d3d |
end+cb(new),
|
|
Packit |
cb6d3d |
(new->lastsector && cb(new)+end==ce(new)));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
begin=end;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* If we're not doing any overlapping reads or verification
|
|
Packit |
cb6d3d |
* of data, skip over the stage 1 and stage 2 verification and
|
|
Packit |
cb6d3d |
* promote this c_block directly to the current "verified" root.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (p->root.vector)i_cblock_destructor(p->root.vector);
|
|
Packit |
cb6d3d |
free_elem(new->e,0);
|
|
Packit |
cb6d3d |
p->root.vector=new;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
|
|
Packit |
cb6d3d |
callback);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}else{
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
#ifdef ENOMEDIUM
|
|
Packit |
cb6d3d |
/* Was the medium removed or the device closed out from
|
|
Packit |
cb6d3d |
under us? */
|
|
Packit |
cb6d3d |
if(errno==ENOMEDIUM) return NULL;
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Are we doing lots of retries? **************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ???: To be studied
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Check unaddressable sectors first. There's no backoff here;
|
|
Packit |
cb6d3d |
jiggle and minimum backseek handle that for us */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (rb(root)!=-1 && lastend+588
|
|
Packit |
cb6d3d |
half a sector */
|
|
Packit |
cb6d3d |
lastend=re(root);
|
|
Packit |
cb6d3d |
retry_count=0;
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
/* increase overlap or bail */
|
|
Packit |
cb6d3d |
retry_count++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* The better way to do this is to look at how many actual
|
|
Packit |
cb6d3d |
matches we're getting and what kind of gap */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if (retry_count%5==0){
|
|
Packit |
cb6d3d |
if (p->dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS ||
|
|
Packit |
cb6d3d |
retry_count==max_retries){
|
|
Packit |
cb6d3d |
if (!(p->enable&PARANOIA_MODE_NEVERSKIP))
|
|
Packit |
cb6d3d |
verify_skip_case(p,callback);
|
|
Packit |
cb6d3d |
retry_count=0;
|
|
Packit |
cb6d3d |
} else {
|
|
Packit |
cb6d3d |
if (p->stage1.offpoints!=-1){ /* hack */
|
|
Packit |
cb6d3d |
p->dynoverlap*=1.5;
|
|
Packit |
cb6d3d |
if (p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
|
|
Packit |
cb6d3d |
p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
if (callback)
|
|
Packit |
cb6d3d |
(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Having read data from the drive and placed it into verified
|
|
Packit |
cb6d3d |
* fragments, we now loop back to try to extend the root with
|
|
Packit |
cb6d3d |
* the newly loaded data. Alternatively, if the root already
|
|
Packit |
cb6d3d |
* contains the needed data, we'll just fall through.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
} /* end while */
|
|
Packit |
cb6d3d |
p->cursor++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Return a pointer into the verified root. Thus, the caller
|
|
Packit |
cb6d3d |
* must NOT free the returned pointer!
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
return(rv(root)+(beginword-rb(root)));
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* a temporary hack */
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
cdio_paranoia_overlapset(cdrom_paranoia_t *p, long int overlap)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
p->dynoverlap=overlap*CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
p->stage1.offpoints=-1;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
extern const char *cdio_paranoia_version(void){
|
|
Packit |
cb6d3d |
return LIBCDIO_PARANOIA_VERSION;
|
|
Packit |
cb6d3d |
}
|