X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=pv%2Fdata%2Fanalogsnapshot.cpp;h=4907d7954a186af7c6d7b5f0c2c8447714edc32a;hb=8d3e0764def48fdf19dc9100c87bbb42da5a9d6d;hp=1658a04c3bfe365138b5ba21f064702e3719e0f7;hpb=d37583678256450d7eb646213d0b9e170a427933;p=pulseview.git diff --git a/pv/data/analogsnapshot.cpp b/pv/data/analogsnapshot.cpp index 1658a04c..4907d795 100644 --- a/pv/data/analogsnapshot.cpp +++ b/pv/data/analogsnapshot.cpp @@ -25,28 +25,63 @@ #include #include +#include + #include #include "analogsnapshot.h" -using namespace boost; -using namespace std; +using boost::lock_guard; +using boost::recursive_mutex; +using std::max; +using std::max_element; +using std::min; +using std::min_element; namespace pv { namespace data { -AnalogSnapshot::AnalogSnapshot(const sr_datafeed_analog &analog) : +const int AnalogSnapshot::EnvelopeScalePower = 4; +const int AnalogSnapshot::EnvelopeScaleFactor = 1 << EnvelopeScalePower; +const float AnalogSnapshot::LogEnvelopeScaleFactor = + logf(EnvelopeScaleFactor); +const uint64_t AnalogSnapshot::EnvelopeDataUnit = 64*1024; // bytes + +AnalogSnapshot::AnalogSnapshot() : Snapshot(sizeof(float)) { lock_guard lock(_mutex); - append_payload(analog); + memset(_envelope_levels, 0, sizeof(_envelope_levels)); } -void AnalogSnapshot::append_payload( - const sr_datafeed_analog &analog) +AnalogSnapshot::~AnalogSnapshot() { lock_guard lock(_mutex); - append_data(analog.data, analog.num_samples); + BOOST_FOREACH(Envelope &e, _envelope_levels) + free(e.samples); +} + +void AnalogSnapshot::append_interleaved_samples(const float *data, + size_t sample_count, size_t stride) +{ + assert(_unit_size == sizeof(float)); + + lock_guard lock(_mutex); + + _data = realloc(_data, (_sample_count + sample_count) * sizeof(float)); + + float *dst = (float*)_data + _sample_count; + const float *dst_end = dst + sample_count; + while (dst != dst_end) + { + *dst++ = *data; + data += stride; + } + + _sample_count += sample_count; + + // Generate the first mip-map from the data + append_payload_to_envelope_levels(); } const float* AnalogSnapshot::get_samples( @@ -66,5 +101,113 @@ const float* AnalogSnapshot::get_samples( return data; } +void AnalogSnapshot::get_envelope_section(EnvelopeSection &s, + uint64_t start, uint64_t end, float min_length) const +{ + assert(end <= get_sample_count()); + assert(start <= end); + assert(min_length > 0); + + lock_guard lock(_mutex); + + const unsigned int min_level = max((int)floorf(logf(min_length) / + LogEnvelopeScaleFactor) - 1, 0); + const unsigned int scale_power = (min_level + 1) * + EnvelopeScalePower; + start >>= scale_power; + end >>= scale_power; + + s.start = start << scale_power; + s.scale = 1 << scale_power; + s.length = end - start; + s.samples = new EnvelopeSample[s.length]; + memcpy(s.samples, _envelope_levels[min_level].samples + start, + s.length * sizeof(EnvelopeSample)); +} + +void AnalogSnapshot::reallocate_envelope(Envelope &e) +{ + const uint64_t new_data_length = ((e.length + EnvelopeDataUnit - 1) / + EnvelopeDataUnit) * EnvelopeDataUnit; + if (new_data_length > e.data_length) + { + e.data_length = new_data_length; + e.samples = (EnvelopeSample*)realloc(e.samples, + new_data_length * sizeof(EnvelopeSample)); + } +} + +void AnalogSnapshot::append_payload_to_envelope_levels() +{ + Envelope &e0 = _envelope_levels[0]; + uint64_t prev_length; + EnvelopeSample *dest_ptr; + + // Expand the data buffer to fit the new samples + prev_length = e0.length; + e0.length = _sample_count / EnvelopeScaleFactor; + + // Break off if there are no new samples to compute + if (e0.length == prev_length) + return; + + reallocate_envelope(e0); + + dest_ptr = e0.samples + prev_length; + + // Iterate through the samples to populate the first level mipmap + const float *const end_src_ptr = (float*)_data + + e0.length * EnvelopeScaleFactor; + for (const float *src_ptr = (float*)_data + + prev_length * EnvelopeScaleFactor; + src_ptr < end_src_ptr; src_ptr += EnvelopeScaleFactor) + { + const EnvelopeSample sub_sample = { + *min_element(src_ptr, src_ptr + EnvelopeScaleFactor), + *max_element(src_ptr, src_ptr + EnvelopeScaleFactor), + }; + + *dest_ptr++ = sub_sample; + } + + // Compute higher level mipmaps + for (unsigned int level = 1; level < ScaleStepCount; level++) + { + Envelope &e = _envelope_levels[level]; + const Envelope &el = _envelope_levels[level-1]; + + // Expand the data buffer to fit the new samples + prev_length = e.length; + e.length = el.length / EnvelopeScaleFactor; + + // Break off if there are no more samples to computed + if (e.length == prev_length) + break; + + reallocate_envelope(e); + + // Subsample the level lower level + const EnvelopeSample *src_ptr = + el.samples + prev_length * EnvelopeScaleFactor; + const EnvelopeSample *const end_dest_ptr = e.samples + e.length; + for (dest_ptr = e.samples + prev_length; + dest_ptr < end_dest_ptr; dest_ptr++) + { + const EnvelopeSample *const end_src_ptr = + src_ptr + EnvelopeScaleFactor; + + EnvelopeSample sub_sample = *src_ptr++; + while (src_ptr < end_src_ptr) + { + sub_sample.min = min(sub_sample.min, src_ptr->min); + sub_sample.max = max(sub_sample.max, src_ptr->max); + src_ptr++; + } + + *dest_ptr = sub_sample; + } + } +} + } // namespace data } // namespace pv