136 lines
3.9 KiB
C++
136 lines
3.9 KiB
C++
#ifndef _CIRCULAR_BUFFER_H_
|
|
#define _CIRCULAR_BUFFER_H_
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
long const silence_threshold = 8;
|
|
|
|
template <typename T>
|
|
class circular_buffer {
|
|
std::vector<T> buffer;
|
|
unsigned long readptr, writeptr, used, size;
|
|
unsigned long silence_count;
|
|
T last_written[2];
|
|
T last_read[2];
|
|
|
|
public:
|
|
circular_buffer()
|
|
: readptr(0), writeptr(0), size(0), used(0), silence_count(0) {
|
|
memset(last_written, 0, sizeof(last_written));
|
|
memset(last_read, 0, sizeof(last_read));
|
|
}
|
|
unsigned long data_available() {
|
|
return used;
|
|
}
|
|
unsigned long free_space() {
|
|
return size - used;
|
|
}
|
|
T* get_write_ptr(unsigned long& count_out) {
|
|
count_out = size - writeptr;
|
|
if(count_out > size - used) count_out = size - used;
|
|
return &buffer[writeptr];
|
|
}
|
|
bool samples_written(unsigned long count) {
|
|
unsigned long max_count = size - writeptr;
|
|
if(max_count > size - used) max_count = size - used;
|
|
if(count > max_count) return false;
|
|
silence_count += count_silent(&buffer[0] + writeptr, &buffer[0] + writeptr + count, last_written);
|
|
used += count;
|
|
writeptr = (writeptr + count) % size;
|
|
return true;
|
|
}
|
|
unsigned long read(T* dst, unsigned long count) {
|
|
unsigned long done = 0;
|
|
for(;;) {
|
|
unsigned long delta = size - readptr;
|
|
if(delta > used) delta = used;
|
|
if(delta > count) delta = count;
|
|
if(!delta) break;
|
|
|
|
if(dst) std::copy(buffer.begin() + readptr, buffer.begin() + readptr + delta, dst);
|
|
silence_count -= count_silent(&buffer[0] + readptr, &buffer[0] + readptr + delta, last_read);
|
|
if(dst) dst += delta;
|
|
done += delta;
|
|
readptr = (readptr + delta) % size;
|
|
count -= delta;
|
|
used -= delta;
|
|
}
|
|
return done;
|
|
}
|
|
void reset() {
|
|
readptr = writeptr = used = 0;
|
|
memset(last_written, 0, sizeof(last_written));
|
|
memset(last_read, 0, sizeof(last_read));
|
|
}
|
|
void resize(unsigned long p_size) {
|
|
size = p_size;
|
|
buffer.resize(p_size);
|
|
reset();
|
|
}
|
|
bool test_silence() const {
|
|
return silence_count == used;
|
|
}
|
|
void remove_leading_silence() {
|
|
T const* p;
|
|
T const* begin;
|
|
T const* end;
|
|
if(used) {
|
|
long delta[2];
|
|
p = begin = &buffer[0] + readptr;
|
|
end = &buffer[0] + (writeptr > readptr ? writeptr : size);
|
|
while(p < end) {
|
|
delta[0] = p[0] - last_read[0];
|
|
delta[1] = p[1] - last_read[1];
|
|
if(((unsigned long)(delta[0] + silence_threshold) > (unsigned long)silence_threshold * 2) ||
|
|
((unsigned long)(delta[1] + silence_threshold) > (unsigned long)silence_threshold * 2))
|
|
break;
|
|
last_read[0] += (T)delta[0];
|
|
last_read[1] += (T)delta[1];
|
|
p += 2;
|
|
}
|
|
unsigned long skipped = p - begin;
|
|
silence_count -= skipped;
|
|
used -= skipped;
|
|
readptr = (readptr + skipped) % size;
|
|
if(readptr == 0 && readptr != writeptr) {
|
|
p = begin = &buffer[0];
|
|
end = &buffer[0] + writeptr;
|
|
while(p < end) {
|
|
delta[0] = p[0] - last_read[0];
|
|
delta[1] = p[1] - last_read[1];
|
|
if(((unsigned long)(delta[0] + silence_threshold) > (unsigned long)silence_threshold * 2) ||
|
|
((unsigned long)(delta[1] + silence_threshold) > (unsigned long)silence_threshold * 2))
|
|
break;
|
|
last_read[0] += (T)delta[0];
|
|
last_read[1] += (T)delta[1];
|
|
p += 2;
|
|
}
|
|
skipped = p - begin;
|
|
silence_count -= skipped;
|
|
used -= skipped;
|
|
readptr += skipped;
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
static unsigned long count_silent(T const* begin, T const* end, T* last) {
|
|
unsigned long count = 0;
|
|
T const* p = begin;
|
|
long delta[2];
|
|
while(p < end) {
|
|
delta[0] = p[0] - last[0];
|
|
delta[1] = p[1] - last[1];
|
|
if(((unsigned long)(delta[0] + silence_threshold) <= (unsigned long)silence_threshold * 2) ||
|
|
((unsigned long)(delta[1] + silence_threshold) <= (unsigned long)silence_threshold * 2))
|
|
count += 2;
|
|
last[0] += (T)delta[0];
|
|
last[1] += (T)delta[1];
|
|
p += 2;
|
|
}
|
|
return count;
|
|
}
|
|
};
|
|
|
|
#endif
|