Cog/Plugins/HighlyComplete/HighlyComplete/circular_buffer.h

145 lines
5.1 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