diff options
Diffstat (limited to 'libparanoia/overlap.c')
-rw-r--r-- | libparanoia/overlap.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/libparanoia/overlap.c b/libparanoia/overlap.c new file mode 100644 index 0000000..6f15baf --- /dev/null +++ b/libparanoia/overlap.c @@ -0,0 +1,228 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)overlap.c 1.11 04/02/20 J. Schilling from cdparanoia-III-alpha9.8 */ +/* + * Modifications to make the code portable Copyright (c) 2002 J. Schilling + */ +/* + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Monty (xiphmont@mit.edu) + * + * Statistic code and cache management for overlap settings + * + */ + +#include <mconfig.h> +#include <stdxlib.h> +#include <standard.h> +#include <utypes.h> +#include "p_block.h" +#include "cdda_paranoia.h" +#include "overlap.h" +#include "isort.h" + +void paranoia_resetcache(cdrom_paranoia *p); +void paranoia_resetall(cdrom_paranoia *p); +void i_paranoia_trim(cdrom_paranoia *p, long beginword, long endword); +void offset_adjust_settings(cdrom_paranoia *p, void (*callback)(long, int)); +void offset_add_value(cdrom_paranoia *p, offsets *o, long value, + void (*callback)(long, int)); + +/* + * Internal cache management + */ +void paranoia_resetcache(cdrom_paranoia *p) +{ + c_block *c = c_first(p); + v_fragment *v; + + while (c) { + free_c_block(c); + c = c_first(p); + } + + v = v_first(p); + while (v) { + free_v_fragment(v); + v = v_first(p); + } +} + +void paranoia_resetall(cdrom_paranoia *p) +{ + p->root.returnedlimit = 0; + p->dyndrift = 0; + p->root.lastsector = 0; + + if (p->root.vector) { + i_cblock_destructor(p->root.vector); + p->root.vector = NULL; + } + paranoia_resetcache(p); +} + +void i_paranoia_trim(cdrom_paranoia *p, long beginword, long endword) +{ + root_block *root = &(p->root); + + if (root->vector != NULL) { + long target = beginword - p->maxdynoverlap; + long rbegin = cb(root->vector); + long rend = ce(root->vector); + + if (rbegin > beginword) + goto rootfree; + + if (rbegin + p->maxdynoverlap < beginword) { + if (target + MIN_WORDS_OVERLAP > rend) + goto rootfree; + + { + long offset = target - rbegin; + + c_removef(root->vector, offset); + } + } { + c_block *c = c_first(p); + + while (c) { + c_block *next = c_next(c); + + if (ce(c) < beginword - p->maxdynoverlap) + free_c_block(c); + c = next; + } + } + + } + return; + +rootfree: + + i_cblock_destructor(root->vector); + root->vector = NULL; + root->returnedlimit = -1; + root->lastsector = 0; + +} + +/* + * Statistical and heuristic[al? :-] management + */ +void offset_adjust_settings(cdrom_paranoia *p, void (*callback)(long, int)) +{ + if (p->stage2.offpoints >= 10) { + /* + * drift: look at the average offset value. If it's over one + * sector, frob it. We just want a little hysteresis [sp?] + */ + long av = (p->stage2.offpoints ? p->stage2.offaccum / p->stage2.offpoints : 0); + + if (abs(av) > p->dynoverlap / 4) { + av = (av / MIN_SECTOR_EPSILON) * MIN_SECTOR_EPSILON; + + if (callback) + (*callback) (ce(p->root.vector), PARANOIA_CB_DRIFT); + p->dyndrift += av; + + /* + * Adjust all the values in the cache otherwise we get + * a (potentially unstable) feedback loop + */ + { + c_block *c = c_first(p); + v_fragment *v = v_first(p); + + while (v && v->one) { + /* + * safeguard beginning bounds case with + * a hammer + */ + if (fb(v) < av || cb(v->one) < av) { + v->one = NULL; + } else { + fb(v) -= av; + } + v = v_next(v); + } + while (c) { + long adj = min(av, cb(c)); + + c_set(c, cb(c) - adj); + c = c_next(c); + } + } + + p->stage2.offaccum = 0; + p->stage2.offmin = 0; + p->stage2.offmax = 0; + p->stage2.offpoints = 0; + p->stage2.newpoints = 0; + p->stage2.offdiff = 0; + } + } + if (p->stage1.offpoints >= 10) { + /* + * dynoverlap: we arbitrarily set it to 4x the running + * difference value, unless min/max are more + */ + p->dynoverlap = (p->stage1.offpoints ? p->stage1.offdiff / + p->stage1.offpoints * 3 : CD_FRAMEWORDS); + + if (p->dynoverlap < -p->stage1.offmin * 1.5) + p->dynoverlap = -p->stage1.offmin * 1.5; + + if (p->dynoverlap < p->stage1.offmax * 1.5) + p->dynoverlap = p->stage1.offmax * 1.5; + + if (p->dynoverlap < p->mindynoverlap) + p->dynoverlap = p->mindynoverlap; + if (p->dynoverlap > p->maxdynoverlap) + p->dynoverlap = p->maxdynoverlap; + + if (callback) + (*callback) (p->dynoverlap, PARANOIA_CB_OVERLAP); + + if (p->stage1.offpoints > 600) { + /* + * bit of a bug; this routine is called too often + * due to the overlap mesh alg we use in stage 1 + */ + p->stage1.offpoints /= 1.2; + p->stage1.offaccum /= 1.2; + p->stage1.offdiff /= 1.2; + } + p->stage1.offmin = 0; + p->stage1.offmax = 0; + p->stage1.newpoints = 0; + } +} + +void offset_add_value(cdrom_paranoia *p, offsets *o, long value, + void (*callback)(long, int)) +{ + if (o->offpoints != -1) { + + o->offdiff += abs(value); + o->offpoints++; + o->newpoints++; + o->offaccum += value; + if (value < o->offmin) + o->offmin = value; + if (value > o->offmax) + o->offmax = value; + + if (o->newpoints >= 10) + offset_adjust_settings(p, callback); + } +} |