|
Packit |
cb6d3d |
/*
|
|
Packit |
cb6d3d |
Copyright (C) 2004, 2005, 2008, 2011, 2017 Rocky Bernstein <rocky@gnu.org>
|
|
Packit |
cb6d3d |
Copyright (C) 1998 Monty xiphmont@mit.edu
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
This program is free software: you can redistribute it and/or modify
|
|
Packit |
cb6d3d |
it under the terms of the GNU General Public License as published by
|
|
Packit |
cb6d3d |
the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
cb6d3d |
(at your option) any later version.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
This program is distributed in the hope that it will be useful,
|
|
Packit |
cb6d3d |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
cb6d3d |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
cb6d3d |
GNU General Public License for more details.
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
You should have received a copy of the GNU General Public License
|
|
Packit |
cb6d3d |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/***
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Statistic code and cache management for overlap settings
|
|
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 <stdio.h>
|
|
Packit |
cb6d3d |
#ifdef HAVE_STRING_H
|
|
Packit |
cb6d3d |
#include <string.h>
|
|
Packit |
cb6d3d |
#endif
|
|
Packit |
cb6d3d |
#include <cdio/paranoia/paranoia.h>
|
|
Packit |
cb6d3d |
#include "p_block.h"
|
|
Packit |
cb6d3d |
#include "overlap.h"
|
|
Packit |
cb6d3d |
#include "isort.h"
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/**** Internal cache management *****************************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
paranoia_resetcache(cdrom_paranoia_t *p)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
c_block_t *c=c_first(p);
|
|
Packit |
cb6d3d |
v_fragment_t *v;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while(c){
|
|
Packit |
cb6d3d |
free_c_block(c);
|
|
Packit |
cb6d3d |
c=c_first(p);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
v=v_first(p);
|
|
Packit |
cb6d3d |
while(v){
|
|
Packit |
cb6d3d |
free_v_fragment(v);
|
|
Packit |
cb6d3d |
v=v_first(p);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
paranoia_resetall(cdrom_paranoia_t *p)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
p->root.returnedlimit=0;
|
|
Packit |
cb6d3d |
p->dyndrift=0;
|
|
Packit |
cb6d3d |
p->root.lastsector=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->root.vector){
|
|
Packit |
cb6d3d |
i_cblock_destructor(p->root.vector);
|
|
Packit |
cb6d3d |
p->root.vector=NULL;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
paranoia_resetcache(p);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
i_paranoia_trim(cdrom_paranoia_t *p, long int beginword, long int endword)
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
root_block *root=&(p->root);
|
|
Packit |
cb6d3d |
if(root->vector!=NULL){
|
|
Packit |
cb6d3d |
long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
long rbegin=cb(root->vector);
|
|
Packit |
cb6d3d |
long rend=ce(root->vector);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(rbegin>beginword)
|
|
Packit |
cb6d3d |
goto rootfree;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDS
|
|
Packit |
cb6d3d |
if(target+MIN_WORDS_OVERLAP>rend)
|
|
Packit |
cb6d3d |
goto rootfree;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
long int offset=target-rbegin;
|
|
Packit |
cb6d3d |
c_removef(root->vector,offset);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
c_block_t *c=c_first(p);
|
|
Packit |
cb6d3d |
while(c){
|
|
Packit |
cb6d3d |
c_block_t *next=c_next(c);
|
|
Packit |
cb6d3d |
if(ce(c)
|
|
Packit |
cb6d3d |
free_c_block(c);
|
|
Packit |
cb6d3d |
c=next;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
return;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
rootfree:
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
i_cblock_destructor(root->vector);
|
|
Packit |
cb6d3d |
root->vector=NULL;
|
|
Packit |
cb6d3d |
root->returnedlimit=-1;
|
|
Packit |
cb6d3d |
root->lastsector=0;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/**** Statistical and heuristic[al? :-] management ************************/
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* offset_adjust_settings (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function is called by offset_add_value() every time 10 samples have
|
|
Packit |
cb6d3d |
* been accumulated. This function updates the internal statistics for
|
|
Packit |
cb6d3d |
* paranoia (dynoverlap, dyndrift) that compensate for jitter and drift.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* (dynoverlap) influences how far stage 1 and stage 2 search for matching
|
|
Packit |
cb6d3d |
* runs. In low-jitter conditions, it will be very small (or even 0),
|
|
Packit |
cb6d3d |
* narrowing our search. In high-jitter conditions, it will be much larger,
|
|
Packit |
cb6d3d |
* widening our search at the cost of speed.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* ???: To be studied further.
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
offset_adjust_settings(cdrom_paranoia_t *p,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if(p->stage2.offpoints>=10){
|
|
Packit |
cb6d3d |
/* drift: look at the average offset value. If it's over one
|
|
Packit |
cb6d3d |
sector, frob it. We just want a little hysteresis [sp?]*/
|
|
Packit |
cb6d3d |
long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(labs(av)>p->dynoverlap/4){
|
|
Packit |
cb6d3d |
av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT);
|
|
Packit |
cb6d3d |
p->dyndrift+=av;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Adjust all the values in the cache otherwise we get a
|
|
Packit |
cb6d3d |
(potentially unstable) feedback loop */
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
c_block_t *c=c_first(p);
|
|
Packit |
cb6d3d |
v_fragment_t *v=v_first(p);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
while(v && v->one){
|
|
Packit |
cb6d3d |
/* safeguard beginning bounds case with a hammer */
|
|
Packit |
cb6d3d |
if(fb(v)<av || cb(v->one)
|
|
Packit |
cb6d3d |
v->one=NULL;
|
|
Packit |
cb6d3d |
}else{
|
|
Packit |
cb6d3d |
fb(v)-=av;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
v=v_next(v);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
while(c){
|
|
Packit |
cb6d3d |
long adj=min(av,cb(c));
|
|
Packit |
cb6d3d |
c_set(c,cb(c)-adj);
|
|
Packit |
cb6d3d |
c=c_next(c);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
p->stage2.offaccum=0;
|
|
Packit |
cb6d3d |
p->stage2.offmin=0;
|
|
Packit |
cb6d3d |
p->stage2.offmax=0;
|
|
Packit |
cb6d3d |
p->stage2.offpoints=0;
|
|
Packit |
cb6d3d |
p->stage2.newpoints=0;
|
|
Packit |
cb6d3d |
p->stage2.offdiff=0;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->stage1.offpoints>=10){
|
|
Packit |
cb6d3d |
/* dynoverlap: we arbitrarily set it to 4x the running difference
|
|
Packit |
cb6d3d |
value, unless min/max are more */
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/
|
|
Packit |
cb6d3d |
p->stage1.offpoints*3:CD_FRAMEWORDS);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->dynoverlap<-p->stage1.offmin*1.5)
|
|
Packit |
cb6d3d |
p->dynoverlap=-p->stage1.offmin*1.5;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->dynoverlap<p->stage1.offmax*1.5)
|
|
Packit |
cb6d3d |
p->dynoverlap=p->stage1.offmax*1.5;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->dynoverlap<MIN_SECTOR_EPSILON)p->dynoverlap=MIN_SECTOR_EPSILON;
|
|
Packit |
cb6d3d |
if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
|
|
Packit |
cb6d3d |
p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
if(p->stage1.offpoints>600){ /* bit of a bug; this routine is
|
|
Packit |
cb6d3d |
called too often due to the overlap
|
|
Packit |
cb6d3d |
mesh alg we use in stage 1 */
|
|
Packit |
cb6d3d |
p->stage1.offpoints/=1.2;
|
|
Packit |
cb6d3d |
p->stage1.offaccum/=1.2;
|
|
Packit |
cb6d3d |
p->stage1.offdiff/=1.2;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
p->stage1.offmin=0;
|
|
Packit |
cb6d3d |
p->stage1.offmax=0;
|
|
Packit |
cb6d3d |
p->stage1.newpoints=0;
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* ===========================================================================
|
|
Packit |
cb6d3d |
* offset_add_value (internal)
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* This function adds the given jitter detected (value) to the statistics
|
|
Packit |
cb6d3d |
* for the given stage (o). It is called whenever jitter has been identified
|
|
Packit |
cb6d3d |
* by stage 1 or 2. After every 10 samples, we update the overall jitter-
|
|
Packit |
cb6d3d |
* compensation settings (e.g. dynoverlap). This allows us to narrow our
|
|
Packit |
cb6d3d |
* search for matching runs (in both stages) in low-jitter conditions
|
|
Packit |
cb6d3d |
* and also widen our search appropriately when there is jitter.
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* "???BUG???:
|
|
Packit |
cb6d3d |
* Note that there is a bug in the way that this is called by try_sort_sync().
|
|
Packit |
cb6d3d |
* Silence looks like zero jitter, and dynoverlap may be incorrectly reduced
|
|
Packit |
cb6d3d |
* when there's lots of silence but also jitter."
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
* Strictly speaking, this is only sort-of true. The silence will
|
|
Packit |
cb6d3d |
* incorrectly somewhat reduce dynoverlap. However, it will increase
|
|
Packit |
cb6d3d |
* again once past the silence (even if reduced to zero, it will be
|
|
Packit |
cb6d3d |
* increased by the block read loop if we're not getting matches).
|
|
Packit |
cb6d3d |
* In reality, silence usually passes rapidly. Anyway, long streaks
|
|
Packit |
cb6d3d |
* of silence benefit performance-wise from having dynoverlap decrease
|
|
Packit |
cb6d3d |
* momentarily. There is no correctness bug. --Monty
|
|
Packit |
cb6d3d |
*
|
|
Packit |
cb6d3d |
*/
|
|
Packit |
cb6d3d |
void
|
|
Packit |
cb6d3d |
offset_add_value(cdrom_paranoia_t *p,offsets *o,long value,
|
|
Packit |
cb6d3d |
void(*callback)(long int, paranoia_cb_mode_t))
|
|
Packit |
cb6d3d |
{
|
|
Packit |
cb6d3d |
if(o->offpoints!=-1){
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Track the average magnitude of jitter (in either direction) */
|
|
Packit |
cb6d3d |
o->offdiff += labs(value);
|
|
Packit |
cb6d3d |
o->offpoints++;
|
|
Packit |
cb6d3d |
o->newpoints++;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Track the net value of the jitter (to track drift) */
|
|
Packit |
cb6d3d |
o->offaccum+=value;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* Track the largest jitter we've encountered in each direction */
|
|
Packit |
cb6d3d |
if(value<o->offmin)o->offmin=value;
|
|
Packit |
cb6d3d |
if(value>o->offmax)o->offmax=value;
|
|
Packit |
cb6d3d |
|
|
Packit |
cb6d3d |
/* After 10 samples, update dynoverlap, etc. */
|
|
Packit |
cb6d3d |
if(o->newpoints>=10)offset_adjust_settings(p,callback);
|
|
Packit |
cb6d3d |
}
|
|
Packit |
cb6d3d |
}
|