From be57e5347947abcc090264d7bef2f49c7ec5a1da Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 31 Aug 2014 03:31:46 +0200 Subject: [PATCH] Umstellung auf eine Score-Heuristik zur Entscheidung. Empirische Schwellen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anstelle eines klaren, logischen Kriteriums müssen wir mit einem Score und Trigger-Schwellen arbeiten, damit die hörbaren Events auch tatsächlich sicher erkannt werden --- sauSynKlick/SynKlick.cc | 77 +++++++++++++++++++++++++++++----------- sauSynKlick/SynKlick.txt | 20 +++++++---- 2 files changed, 69 insertions(+), 28 deletions(-) diff --git a/sauSynKlick/SynKlick.cc b/sauSynKlick/SynKlick.cc index 260ceb4..b2f53f5 100644 --- a/sauSynKlick/SynKlick.cc +++ b/sauSynKlick/SynKlick.cc @@ -30,8 +30,9 @@ const size_t CONTEXT = 100; const size_t BUFF_SIZE = CHUNK_SIZE + 2*CONTEXT; const float EPSILON = 1.0f / (1 << 23); // one normalised sample step for 24bit samples -const float SILENCE_GATE = 1024.0f * EPSILON;// signal below this level (-39dB) is too low to detect jumps -const float TRIGGER_FACTOR = 6.0f; // discontinuity detected by local change compared to average change +const float SILENCE_GATE = 4096.0f * EPSILON;// signal below this level (-33dB) is too low to detect jumps +const float TRIGGER_FACTOR = 5.0f; // discontinuity detected by local change compared to average change +const float CONFIRMATION_DEGREE = 0.66f; // degree of confirmation by multiple tracks for an event to be accepted const uint AVERAGE_SAMPLES = 50; // number of past samples to use for average delta /* ==== Helpers ==== */ @@ -66,15 +67,40 @@ reduceBufferPos (size_t & pos, size_t elementsToRemove) /* ==== Abstraction: single channel to be processed ==== */ -enum Event { - NO=0, - MAYBE, - YES -}; +/** + * Helper to decide if a glitch event should be considered, + * while visiting multiple tracks at the same location. + */ +class EventScore + { + uint contributions_ = 0; + uint positives_ = 0; + + public: + float + confirmationDegree() + { + return contributions_? float(positives_)/contributions_ + : 0.0f; + } + + operator bool() + { + return CONFIRMATION_DEGREE <= this->confirmationDegree(); + } + + void + recordConfirmation(bool confirmed) + { + ++contributions_; + if (confirmed) + ++positives_; + } + }; + class Channel { - string name_; SNDFILE *in_ = nullptr, *out_ = nullptr; SF_INFO info_in_, @@ -87,13 +113,14 @@ class Channel public: + string name_; static bool hitEnd; void open (string name, string target) { - this->name_ = name; - target += name_without_path(name); + this->name_ = name_without_path(name); + target += name_; info_in_.format = 0; in_ = sf_open (name.c_str(), SFM_READ, &info_in_); @@ -117,7 +144,7 @@ class Channel if (in_) sf_close (in_); if (out_) if (0 != sf_close (out_)) - cerr << "WARNING: problems while closing target '" << name_without_path(name_) + cerr << "WARNING: problems while closing target '" << name_ << "' -- " << sf_strerror(out_) << "\n"; in_ = out_ = nullptr; @@ -169,8 +196,8 @@ class Channel * the event state is confirmed; if a glitch can not be confirmed, the state is * cleared. Otherwise, the undecided state is passed on. */ - Event - visit (uint i, Event event) + void + visit (uint i, EventScore& event) { if (i + CONTEXT < numSamples_ && CONTEXT <= i @@ -179,17 +206,19 @@ class Channel workPos_ = i; float averageDelta = updateMovingAverage(); float changeFactor = delta() / (averageDelta + EPSILON); - if (event != NO && SILENCE_GATE < abs(sample())) - event = (changeFactor > TRIGGER_FACTOR? YES : NO); + if (SILENCE_GATE < abs(sample())) + event.recordConfirmation(changeFactor > TRIGGER_FACTOR); } - return event; } private: float sample() { - return buff_[workPos_]; + if (0 < workPos_) + return std::max(buff_[workPos_-1], buff_[workPos_]); + else + return buff_[workPos_]; } float @@ -279,10 +308,16 @@ process() channel.fillBuffer(); for (uint i=0; i < BUFF_SIZE; ++i) { - Event event = MAYBE; - for (Channel& channel : streams) - event = channel.visit(i, event); - if (YES == event) + EventScore event; + bool yesss = false; + for (Channel& channel : streams){ + channel.visit(i, event); + if (event || yesss){ + cerr << "Event ? "<