summaryrefslogtreecommitdiff
path: root/libparanoia/overlap.c
diff options
context:
space:
mode:
Diffstat (limited to 'libparanoia/overlap.c')
-rw-r--r--libparanoia/overlap.c228
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);
+ }
+}