Skip to content

Commit

Permalink
silence analyzer rewrite
Browse files Browse the repository at this point in the history
bound optimization enabled
batch process simplified, last argument removed
  • Loading branch information
superg committed Mar 28, 2023
1 parent 495ec53 commit e57bb15
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 44 deletions.
2 changes: 1 addition & 1 deletion analyzers/analyzer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Analyzer
public:
virtual ~Analyzer() {}

virtual void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset, bool last) = 0;
virtual void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset) = 0;
};

}
108 changes: 80 additions & 28 deletions analyzers/silence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,113 @@ namespace gpsxre
{

SilenceAnalyzer::SilenceAnalyzer(uint16_t silence_threshold, const std::vector<std::pair<int32_t, int32_t>> &index0_ranges)
: _silenceLimit(silence_threshold + 1)
, _silenceSamplesMin(std::numeric_limits<uint32_t>::max())
, _silenceStart(std::make_unique<int32_t[]>(_silenceLimit))
, _silenceRanges(_silenceLimit)
: _limit(silence_threshold + 1)
, _samplesMin(std::numeric_limits<uint32_t>::max())
, _count(0)
, _state(std::make_unique<std::pair<int32_t, bool>[]>(_limit))
, _ranges(_limit)
{
for(auto const &r : index0_ranges)
{
uint32_t length = r.second - r.first;
if(_silenceSamplesMin > length)
_silenceSamplesMin = length;
if(_samplesMin > length)
_samplesMin = length;
}

std::fill_n(_silenceStart.get(), _silenceLimit, std::numeric_limits<int32_t>::min());
std::fill_n(_state.get(), _limit, std::pair(-_samplesMin, true));
}


const std::vector<std::vector<std::pair<int32_t, int32_t>>> &SilenceAnalyzer::ranges() const
std::vector<std::vector<std::pair<int32_t, int32_t>>> SilenceAnalyzer::ranges() const
{
return _silenceRanges;
std::vector<std::vector<std::pair<int32_t, int32_t>>> silence_ranges;

for(int i = 0; i < _limit; ++i)
{
std::vector<std::pair<int32_t, int32_t>> silence_range(_ranges[i]);
silence_range.emplace_back(_state[i].second ? _state[i].first : _count, 0);

int32_t base = LBA_START * CD_DATA_SIZE_SAMPLES;
for(auto &r : silence_range)
{
r.first += base;
r.second += base;
}
silence_range.front().first = std::numeric_limits<int32_t>::min();
silence_range.back().second = std::numeric_limits<int32_t>::max();

silence_ranges.push_back(silence_range);
}

return silence_ranges;
}


void SilenceAnalyzer::process(uint32_t *samples, State *state, uint32_t count, uint32_t offset, bool last)
void SilenceAnalyzer::process(uint32_t *samples, State *state, uint32_t count, uint32_t offset)
{
for(uint32_t j = 0; j < count; ++j)
_count = offset;
for(uint32_t n = offset + count; _count < n; ++_count)
{
int32_t position = LBA_START * CD_DATA_SIZE_SAMPLES + offset + j;

auto sample = (int16_t *)&samples[j];
auto sample = (int16_t *)&samples[_count - offset];
int sample_l = std::abs(sample[0]);
int sample_r = std::abs(sample[1]);

for(uint16_t k = 0; k < _silenceLimit; ++k)
// bound optimization
#if 1
int bound = std::min(std::max(sample_l, sample_r), _limit);

for(int k = 0; k < bound; ++k)
{
int32_t &start = _state[k].first;
bool &silence = _state[k].second;

if(silence)
{
if(_count - start >= (int32_t)_samplesMin)
_ranges[k].emplace_back(start, _count);
silence = false;
}
}

for(int k = bound; k < _limit; ++k)
{
int32_t &start = _state[k].first;
bool &silence = _state[k].second;

if(!silence)
{
start = _count;
silence = true;
}
}
#else
for(int k = 0; k < _limit; ++k)
{
int32_t &start = _state[k].first;
bool &silence = _state[k].second;
// silence
if(sample_l <= (int)k && sample_r <= (int)k)
if(sample_l <= k && sample_r <= k)
{
if(_silenceStart[k] == std::numeric_limits<int32_t>::max())
_silenceStart[k] = position;
if(!silence)
{
start = _count;
silence = true;
}
}
// not silence
else if(_silenceStart[k] != std::numeric_limits<int32_t>::max())
else
{
if(_silenceStart[k] == std::numeric_limits<int32_t>::min() || position - _silenceStart[k] >= (int32_t)_silenceSamplesMin)
_silenceRanges[k].emplace_back(_silenceStart[k], position);

_silenceStart[k] = std::numeric_limits<int32_t>::max();
if(silence)
{
if(_count - start >= (int32_t)_samplesMin)
_ranges[k].emplace_back(start, _count);
silence = false;
}
}
}
#endif
}

// tail
if(last)
for(uint16_t k = 0; k < _silenceLimit; ++k)
_silenceRanges[k].emplace_back(_silenceStart[k] == std::numeric_limits<int32_t>::max() ? LBA_START * CD_DATA_SIZE_SAMPLES + offset + count : _silenceStart[k], std::numeric_limits<int32_t>::max());
}

}
14 changes: 8 additions & 6 deletions analyzers/silence.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ class SilenceAnalyzer : public Analyzer
public:
SilenceAnalyzer(uint16_t silence_threshold, const std::vector<std::pair<int32_t, int32_t>> &index0_ranges);

const std::vector<std::vector<std::pair<int32_t, int32_t>>> &ranges() const;
std::vector<std::vector<std::pair<int32_t, int32_t>>> ranges() const;

void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset, bool last) override;
void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset) override;

private:
uint16_t _silenceLimit;
uint32_t _silenceSamplesMin;
int _limit;
uint32_t _samplesMin;

uint32_t _count;

// don't use std::vector here because it's too slow
std::unique_ptr<int32_t[]> _silenceStart;
std::unique_ptr<std::pair<int32_t, bool>[]> _state;

std::vector<std::vector<std::pair<int32_t, int32_t>>> _silenceRanges;
std::vector<std::vector<std::pair<int32_t, int32_t>>> _ranges;
};

}
2 changes: 1 addition & 1 deletion analyzers/sync.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ std::vector<SyncAnalyzer::Record> SyncAnalyzer::getRecords() const
}


void SyncAnalyzer::process(uint32_t *samples, State *state, uint32_t count, uint32_t offset, bool)
void SyncAnalyzer::process(uint32_t *samples, State *state, uint32_t count, uint32_t offset)
{
for(uint32_t i = 0; i < count; ++i)
{
Expand Down
2 changes: 1 addition & 1 deletion analyzers/sync.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public:

std::vector<Record> getRecords() const;

void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset, bool last) override;
void process(uint32_t *samples, State *state, uint32_t count, uint32_t offset) override;

private:
static constexpr uint32_t SYNC_SIZE_SAMPLES = sizeof(CD_DATA_SYNC) / CD_SAMPLE_SIZE;
Expand Down
4 changes: 2 additions & 2 deletions common.hh
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ T diff_bytes_count(const uint8_t *data1, const uint8_t *data2, T size)
}

template<typename T>
bool batch_process_range(const std::pair<T, T> &range, T batch_size, const std::function<bool(T, T, bool)> &func)
bool batch_process_range(const std::pair<T, T> &range, T batch_size, const std::function<bool(T, T)> &func)
{
bool interrupted = false;

Expand All @@ -267,7 +267,7 @@ bool batch_process_range(const std::pair<T, T> &range, T batch_size, const std::

T offset_next = offset + size;

if(func(offset, size, offset_next == range.second))
if(func(offset, size))
{
interrupted = true;
break;
Expand Down
12 changes: 7 additions & 5 deletions split.cc
Original file line number Diff line number Diff line change
Expand Up @@ -569,13 +569,13 @@ void analyze_scram_samples(std::fstream &scm_fs, std::fstream &state_fs, uint32_
std::vector<uint32_t> samples(batch_size);
std::vector<State> state(batch_size);

batch_process_range<uint32_t>(std::pair(0, samples_count), batch_size, [&scm_fs, &state_fs, &samples, &state, &analyzers](int32_t offset, int32_t size, bool last) -> bool
batch_process_range<uint32_t>(std::pair(0, samples_count), batch_size, [&scm_fs, &state_fs, &samples, &state, &analyzers](int32_t offset, int32_t size) -> bool
{
read_entry(scm_fs, (uint8_t *)samples.data(), CD_SAMPLE_SIZE, offset, size, 0, 0);
read_entry(state_fs, (uint8_t *)state.data(), 1, offset, size, 0, (uint8_t)State::ERROR_SKIP);

for(auto const &a : analyzers)
a->process(samples.data(), state.data(), size, offset, last);
a->process(samples.data(), state.data(), size, offset);

return false;
});
Expand Down Expand Up @@ -777,7 +777,7 @@ std::string calculate_universal_hash(std::fstream &scm_fs, std::pair<int32_t, in
SHA1 bh_sha1;

std::vector<uint32_t> samples(10 * 1024 * 1024); // 10Mb chunk
batch_process_range<int32_t>(nonzero_data_range, samples.size(), [&scm_fs, &samples, &bh_sha1](int32_t offset, int32_t size, bool) -> bool
batch_process_range<int32_t>(nonzero_data_range, samples.size(), [&scm_fs, &samples, &bh_sha1](int32_t offset, int32_t size) -> bool
{
read_entry(scm_fs, (uint8_t *)samples.data(), CD_SAMPLE_SIZE, offset - LBA_START * CD_DATA_SIZE_SAMPLES, size, 0, 0);
bh_sha1.Update((uint8_t *)samples.data(), size * sizeof(uint32_t));
Expand Down Expand Up @@ -1186,9 +1186,11 @@ void redumper_split(const Options &options)
auto sync_analyzer = std::make_shared<SyncAnalyzer>(scrap);
analyzers.emplace_back(sync_analyzer);

LOG_F("analyzing image... ");
LOG("analysis started");
auto analysis_time_start = std::chrono::high_resolution_clock::now();
analyze_scram_samples(scm_fs, state_fs, std::filesystem::file_size(scra_path), CD_DATA_SIZE_SAMPLES, analyzers);
LOG("done");
auto analysis_time_stop = std::chrono::high_resolution_clock::now();
LOG("analysis complete (time: {}s)", std::chrono::duration_cast<std::chrono::seconds>(analysis_time_stop - analysis_time_start).count());
LOG("");

auto silence_ranges = silence_analyzer->ranges();
Expand Down

0 comments on commit e57bb15

Please sign in to comment.