Add a CircularSampleBuffer for input port scopes
This commit is contained in:
parent
303d7bb2e8
commit
9a7379dfff
77
libs/ardour/ardour/circular_buffer.h
Normal file
77
libs/ardour/ardour/circular_buffer.h
Normal file
|
@ -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
|
151
libs/ardour/circular_buffer.cc
Normal file
151
libs/ardour/circular_buffer.cc
Normal file
|
@ -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',
|
'capturing_processor.cc',
|
||||||
'chan_count.cc',
|
'chan_count.cc',
|
||||||
'chan_mapping.cc',
|
'chan_mapping.cc',
|
||||||
|
'circular_buffer.cc',
|
||||||
'config_text.cc',
|
'config_text.cc',
|
||||||
'control_group.cc',
|
'control_group.cc',
|
||||||
'control_protocol_manager.cc',
|
'control_protocol_manager.cc',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user