Add a CircularSampleBuffer for input port scopes
This commit is contained in:
parent
303d7bb2e8
commit
9a7379dfff
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_circular_buffer_h_
|
||||
#define _ardour_circular_buffer_h_
|
||||
|
||||
#include "pbd/ringbuffer.h"
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
/** Endless ringbuffer
|
||||
*
|
||||
* Writing never fails, and may flush out old data.
|
||||
* This is intended for an oscilloscope waveform view.
|
||||
*/
|
||||
class LIBARDOUR_API CircularSampleBuffer
|
||||
{
|
||||
public:
|
||||
CircularSampleBuffer (samplecnt_t size);
|
||||
|
||||
void write (Sample const*, samplecnt_t);
|
||||
bool read (Sample& s_min, Sample& s_max, samplecnt_t n_samples);
|
||||
|
||||
private:
|
||||
PBD::RingBuffer<Sample> _rb;
|
||||
CircularSampleBuffer (CircularSampleBuffer const&);
|
||||
};
|
||||
|
||||
class LIBARDOUR_API CircularEventBuffer
|
||||
{
|
||||
public:
|
||||
struct Event {
|
||||
/* up to 3 byte MIDI events, 32bit aligned */
|
||||
Event (uint8_t const* buf = 0, size_t sz = 0);
|
||||
uint8_t data[3];
|
||||
uint8_t pad;
|
||||
};
|
||||
|
||||
typedef std::vector<Event> EventList;
|
||||
|
||||
CircularEventBuffer (samplecnt_t size);
|
||||
~CircularEventBuffer ();
|
||||
|
||||
void reset ();
|
||||
void write (uint8_t const*, size_t);
|
||||
bool read (EventList&);
|
||||
|
||||
private:
|
||||
CircularEventBuffer (CircularEventBuffer const&);
|
||||
|
||||
Event* _buf;
|
||||
guint _size;
|
||||
guint _size_mask;
|
||||
gint _idx;
|
||||
gint _ack;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "ardour/circular_buffer.h"
|
||||
#include "ardour/runtime_functions.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
CircularSampleBuffer::CircularSampleBuffer (samplecnt_t size)
|
||||
: _rb (size)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CircularSampleBuffer::write (Sample const* buf, samplecnt_t n_samples)
|
||||
{
|
||||
guint ws = _rb.write_space ();
|
||||
if (ws < n_samples) {
|
||||
/* overwrite old data (consider a spinlock wrt ::read) */
|
||||
_rb.increment_read_idx (n_samples - ws);
|
||||
}
|
||||
_rb.write (buf, n_samples);
|
||||
}
|
||||
|
||||
bool
|
||||
CircularSampleBuffer::read (Sample& s_min, Sample& s_max, samplecnt_t spp)
|
||||
{
|
||||
s_min = s_max = 0;
|
||||
|
||||
PBD::RingBuffer<Sample>::rw_vector vec;
|
||||
_rb.get_read_vector (&vec);
|
||||
|
||||
if (vec.len[0] + vec.len[1] < spp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* immediately mark as read, allow writer to overwrite data if needed */
|
||||
_rb.increment_read_idx (spp);
|
||||
|
||||
samplecnt_t to_proc = std::min (spp, (samplecnt_t)vec.len[0]);
|
||||
ARDOUR::find_peaks (vec.buf[0], to_proc, &s_min, &s_max);
|
||||
|
||||
to_proc = std::min (spp - to_proc, (samplecnt_t)vec.len[1]);
|
||||
if (to_proc > 0) { // XXX is this check needed?
|
||||
ARDOUR::find_peaks (vec.buf[1], to_proc, &s_min, &s_max);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CircularEventBuffer::Event::Event (uint8_t const* buf, size_t size)
|
||||
{
|
||||
switch (size) {
|
||||
case 0:
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
break;
|
||||
case 1:
|
||||
data[0] = buf[0];
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
break;
|
||||
case 2:
|
||||
data[0] = buf[0];
|
||||
data[1] = buf[1];
|
||||
data[2] = 0;
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
data[0] = buf[0];
|
||||
data[1] = buf[1];
|
||||
data[2] = buf[2];
|
||||
break;
|
||||
}
|
||||
pad = 0;
|
||||
}
|
||||
|
||||
CircularEventBuffer::CircularEventBuffer (samplecnt_t size)
|
||||
{
|
||||
guint power_of_two;
|
||||
for (power_of_two = 1; 1U << power_of_two < size; ++power_of_two) {}
|
||||
_size = 1 << power_of_two;
|
||||
_size_mask = _size;
|
||||
_size_mask -= 1;
|
||||
_buf = new Event[size];
|
||||
reset ();
|
||||
}
|
||||
|
||||
CircularEventBuffer::~CircularEventBuffer ()
|
||||
{
|
||||
delete [] _buf;
|
||||
}
|
||||
|
||||
void
|
||||
CircularEventBuffer::reset () {
|
||||
g_atomic_int_set (&_idx, 0);
|
||||
g_atomic_int_set (&_ack, 0);
|
||||
memset ((void*)_buf, 0, _size * sizeof (Event));
|
||||
}
|
||||
|
||||
void
|
||||
CircularEventBuffer::write (uint8_t const* buf, size_t size)
|
||||
{
|
||||
Event e (buf, size);
|
||||
|
||||
guint write_idx = g_atomic_int_get (&_idx);
|
||||
memcpy (&_buf[write_idx], &e, sizeof (Event));
|
||||
write_idx = (write_idx + 1) & _size_mask;
|
||||
g_atomic_int_set (&_idx, write_idx);
|
||||
g_atomic_int_set (&_ack, 1);
|
||||
}
|
||||
|
||||
bool
|
||||
CircularEventBuffer::read (EventList& l)
|
||||
{
|
||||
guint to_read = _size_mask;
|
||||
if (!g_atomic_int_compare_and_exchange (&_ack, 1, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
l.clear ();
|
||||
guint priv_idx = g_atomic_int_get (&_idx);
|
||||
while (priv_idx > 0) {
|
||||
--priv_idx;
|
||||
--to_read;
|
||||
l.push_back (_buf[priv_idx]);
|
||||
}
|
||||
priv_idx += _size_mask;
|
||||
while (to_read > 0) {
|
||||
l.push_back (_buf[priv_idx]);
|
||||
--priv_idx;
|
||||
--to_read;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -56,6 +56,7 @@ libardour_sources = [
|
|||
'capturing_processor.cc',
|
||||
'chan_count.cc',
|
||||
'chan_mapping.cc',
|
||||
'circular_buffer.cc',
|
||||
'config_text.cc',
|
||||
'control_group.cc',
|
||||
'control_protocol_manager.cc',
|
||||
|
|
Loading…
Reference in New Issue