Implement buffering of visualizer samples read from the fifo
This commit is contained in:
@@ -25,6 +25,7 @@ ncmpcpp_SOURCES = \
|
|||||||
utility/comparators.cpp \
|
utility/comparators.cpp \
|
||||||
utility/html.cpp \
|
utility/html.cpp \
|
||||||
utility/option_parser.cpp \
|
utility/option_parser.cpp \
|
||||||
|
utility/sample_buffer.cpp \
|
||||||
utility/string.cpp \
|
utility/string.cpp \
|
||||||
utility/type_conversions.cpp \
|
utility/type_conversions.cpp \
|
||||||
utility/wide_string.cpp \
|
utility/wide_string.cpp \
|
||||||
@@ -90,6 +91,7 @@ noinst_HEADERS = \
|
|||||||
utility/html.h \
|
utility/html.h \
|
||||||
utility/option_parser.h \
|
utility/option_parser.h \
|
||||||
utility/readline.h \
|
utility/readline.h \
|
||||||
|
utility/sample_buffer.h \
|
||||||
utility/scoped_value.h \
|
utility/scoped_value.h \
|
||||||
utility/storage_kind.h \
|
utility/storage_kind.h \
|
||||||
utility/shared_resource.h \
|
utility/shared_resource.h \
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ struct ArtistInfo : public Service
|
|||||||
ArtistInfo(std::string artist, std::string lang)
|
ArtistInfo(std::string artist, std::string lang)
|
||||||
: Service({{"artist", artist}, {"lang", lang}}) { }
|
: Service({{"artist", artist}, {"lang", lang}}) { }
|
||||||
|
|
||||||
|
virtual ~ArtistInfo() { }
|
||||||
|
|
||||||
virtual const char *name() { return "Artist info"; }
|
virtual const char *name() { return "Artist info"; }
|
||||||
|
|
||||||
virtual void beautifyOutput(NC::Scrollpad &w);
|
virtual void beautifyOutput(NC::Scrollpad &w);
|
||||||
|
|||||||
@@ -33,6 +33,9 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
@@ -68,6 +71,9 @@ const NC::FormattedColor &toColor(size_t number, size_t max, bool wrap = true)
|
|||||||
|
|
||||||
Visualizer::Visualizer()
|
Visualizer::Visualizer()
|
||||||
: Screen(NC::Window(0, MainStartY, COLS, MainHeight, "", NC::Color::Default, NC::Border()))
|
: Screen(NC::Window(0, MainStartY, COLS, MainHeight, "", NC::Color::Default, NC::Border()))
|
||||||
|
, m_sample_consumption_rate(5)
|
||||||
|
, m_sample_consumption_rate_up_ctr(0)
|
||||||
|
, m_sample_consumption_rate_dn_ctr(0)
|
||||||
# ifdef HAVE_FFTW3_H
|
# ifdef HAVE_FFTW3_H
|
||||||
,
|
,
|
||||||
DFT_NONZERO_SIZE(1 << Config.visualizer_spectrum_dft_size),
|
DFT_NONZERO_SIZE(1 << Config.visualizer_spectrum_dft_size),
|
||||||
@@ -131,13 +137,6 @@ void Visualizer::update()
|
|||||||
if (m_fifo < 0)
|
if (m_fifo < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// PCM in format 44100:16:1 (for mono visualization) and
|
|
||||||
// 44100:16:2 (for stereo visualization) is supported.
|
|
||||||
const int buf_size = sizeof(int16_t)*m_read_samples;
|
|
||||||
ssize_t bytes_read = read(m_fifo, m_temp_sample_buffer.data(), buf_size);
|
|
||||||
if (bytes_read <= 0) // no data available in fifo
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_output_id != -1 && Global::Timer - m_timer > Config.visualizer_sync_interval)
|
if (m_output_id != -1 && Global::Timer - m_timer > Config.visualizer_sync_interval)
|
||||||
{
|
{
|
||||||
Mpd.DisableOutput(m_output_id);
|
Mpd.DisableOutput(m_output_id);
|
||||||
@@ -146,51 +145,81 @@ void Visualizer::update()
|
|||||||
m_timer = Global::Timer;
|
m_timer = Global::Timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.visualizer_autoscale)
|
// PCM in format 44100:16:1 (for mono visualization) and
|
||||||
|
// 44100:16:2 (for stereo visualization) is supported.
|
||||||
|
ssize_t bytes_read = read(m_fifo, m_incoming_samples.data(),
|
||||||
|
sizeof(int16_t) * m_incoming_samples.size());
|
||||||
|
if (bytes_read > 0)
|
||||||
{
|
{
|
||||||
m_auto_scale_multiplier += 1.0/Config.visualizer_fps;
|
const auto begin = m_incoming_samples.begin();
|
||||||
const auto begin = m_temp_sample_buffer.begin();
|
const auto end = m_incoming_samples.begin() + bytes_read/sizeof(int16_t);
|
||||||
const auto end = m_temp_sample_buffer.begin() + bytes_read/sizeof(int16_t);
|
|
||||||
for (auto sample = begin; sample != end; ++sample)
|
if (Config.visualizer_autoscale)
|
||||||
{
|
{
|
||||||
double scale = std::numeric_limits<int16_t>::min();
|
m_auto_scale_multiplier += 1.0/Config.visualizer_fps;
|
||||||
scale /= *sample;
|
for (auto sample = begin; sample != end; ++sample)
|
||||||
scale = fabs(scale);
|
{
|
||||||
if (scale < m_auto_scale_multiplier)
|
double scale = std::numeric_limits<int16_t>::min();
|
||||||
m_auto_scale_multiplier = scale;
|
scale /= *sample;
|
||||||
}
|
scale = fabs(scale);
|
||||||
for (auto sample = begin; sample != end; ++sample)
|
if (scale < m_auto_scale_multiplier)
|
||||||
{
|
m_auto_scale_multiplier = scale;
|
||||||
int32_t tmp = *sample;
|
}
|
||||||
if (m_auto_scale_multiplier <= 50.0) // limit the auto scale
|
for (auto sample = begin; sample != end; ++sample)
|
||||||
tmp *= m_auto_scale_multiplier;
|
{
|
||||||
if (tmp < std::numeric_limits<int16_t>::min())
|
int32_t tmp = *sample;
|
||||||
*sample = std::numeric_limits<int16_t>::min();
|
if (m_auto_scale_multiplier <= 50.0) // limit the auto scale
|
||||||
else if (tmp > std::numeric_limits<int16_t>::max())
|
tmp *= m_auto_scale_multiplier;
|
||||||
*sample = std::numeric_limits<int16_t>::max();
|
if (tmp < std::numeric_limits<int16_t>::min())
|
||||||
else
|
*sample = std::numeric_limits<int16_t>::min();
|
||||||
*sample = tmp;
|
else if (tmp > std::numeric_limits<int16_t>::max())
|
||||||
|
*sample = std::numeric_limits<int16_t>::max();
|
||||||
|
else
|
||||||
|
*sample = tmp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
m_buffered_samples.put(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t requested_samples =
|
||||||
|
44100.0 / Config.visualizer_fps * pow(1.1, m_sample_consumption_rate);
|
||||||
|
if (Config.visualizer_in_stereo)
|
||||||
|
requested_samples *= 2;
|
||||||
|
|
||||||
|
Statusbar::printf("Samples: %1%, %2%, %3%", m_buffered_samples.size(),
|
||||||
|
requested_samples, m_sample_consumption_rate);
|
||||||
|
|
||||||
|
size_t new_samples = m_buffered_samples.move(requested_samples, m_rendered_samples);
|
||||||
|
if (new_samples == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_buffered_samples.size() > 0)
|
||||||
{
|
{
|
||||||
// create int8_t pointers for arithmetic
|
if (++m_sample_consumption_rate_up_ctr > 8)
|
||||||
int8_t *const sdata = (int8_t *)m_sample_buffer.data();
|
{
|
||||||
int8_t *const temp_sdata = (int8_t *)m_temp_sample_buffer.data();
|
m_sample_consumption_rate_up_ctr = 0;
|
||||||
int8_t *const sdata_end = sdata + buf_size;
|
++m_sample_consumption_rate;
|
||||||
memmove(sdata, sdata + bytes_read, buf_size - bytes_read);
|
}
|
||||||
memcpy(sdata_end - bytes_read, temp_sdata, bytes_read);
|
}
|
||||||
|
else if (m_sample_consumption_rate > 0)
|
||||||
|
{
|
||||||
|
if (++m_sample_consumption_rate_dn_ctr > 2)
|
||||||
|
{
|
||||||
|
m_sample_consumption_rate_dn_ctr = 0;
|
||||||
|
--m_sample_consumption_rate;
|
||||||
|
}
|
||||||
|
m_sample_consumption_rate_up_ctr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
w.clear();
|
w.clear();
|
||||||
if (Config.visualizer_in_stereo)
|
if (Config.visualizer_in_stereo)
|
||||||
{
|
{
|
||||||
auto chan_samples = m_read_samples/2;
|
auto chan_samples = m_rendered_samples.size()/2;
|
||||||
int16_t buf_left[chan_samples], buf_right[chan_samples];
|
int16_t buf_left[chan_samples], buf_right[chan_samples];
|
||||||
for (size_t i = 0, j = 0; i < m_read_samples; i += 2, ++j)
|
for (size_t i = 0, j = 0; i < m_rendered_samples.size(); i += 2, ++j)
|
||||||
{
|
{
|
||||||
buf_left[j] = m_sample_buffer[i];
|
buf_left[j] = m_rendered_samples[i];
|
||||||
buf_right[j] = m_sample_buffer[i+1];
|
buf_right[j] = m_rendered_samples[i+1];
|
||||||
}
|
}
|
||||||
size_t half_height = w.getHeight()/2;
|
size_t half_height = w.getHeight()/2;
|
||||||
|
|
||||||
@@ -198,14 +227,14 @@ void Visualizer::update()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(this->*draw)(m_sample_buffer.data(), m_read_samples, 0, w.getHeight());
|
(this->*draw)(m_rendered_samples.data(), m_rendered_samples.size(), 0, w.getHeight());
|
||||||
}
|
}
|
||||||
w.refresh();
|
w.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Visualizer::windowTimeout()
|
int Visualizer::windowTimeout()
|
||||||
{
|
{
|
||||||
if (m_fifo >= 0 && Status::State::player() == MPD::psPlay)
|
if (m_fifo >= 0)// && Status::State::player() == MPD::psPlay)
|
||||||
return 1000/Config.visualizer_fps;
|
return 1000/Config.visualizer_fps;
|
||||||
else
|
else
|
||||||
return Screen<WindowType>::windowTimeout();
|
return Screen<WindowType>::windowTimeout();
|
||||||
@@ -596,42 +625,51 @@ void Visualizer::GenLogspace()
|
|||||||
|
|
||||||
void Visualizer::InitVisualization()
|
void Visualizer::InitVisualization()
|
||||||
{
|
{
|
||||||
|
size_t rendered_samples = 0;
|
||||||
switch (Config.visualizer_type)
|
switch (Config.visualizer_type)
|
||||||
{
|
{
|
||||||
case VisualizerType::Wave:
|
case VisualizerType::Wave:
|
||||||
// Guarantee integral amount of samples per column.
|
// Guarantee integral amount of samples per column.
|
||||||
m_read_samples = ceil(44100.0 / Config.visualizer_fps / w.getWidth());
|
rendered_samples = ceil(44100.0 / Config.visualizer_fps / w.getWidth());
|
||||||
m_read_samples *= w.getWidth();
|
rendered_samples *= w.getWidth();
|
||||||
|
// Slow the scolling 10 times to make it watchable.
|
||||||
|
rendered_samples *= 10;
|
||||||
draw = &Visualizer::DrawSoundWave;
|
draw = &Visualizer::DrawSoundWave;
|
||||||
drawStereo = &Visualizer::DrawSoundWaveStereo;
|
drawStereo = &Visualizer::DrawSoundWaveStereo;
|
||||||
break;
|
break;
|
||||||
case VisualizerType::WaveFilled:
|
case VisualizerType::WaveFilled:
|
||||||
// Guarantee integral amount of samples per column.
|
// Guarantee integral amount of samples per column.
|
||||||
m_read_samples = ceil(44100.0 / Config.visualizer_fps / w.getWidth());
|
rendered_samples = ceil(44100.0 / Config.visualizer_fps / w.getWidth());
|
||||||
m_read_samples *= w.getWidth();
|
rendered_samples *= w.getWidth();
|
||||||
|
// Slow the scolling 10 times to make it watchable.
|
||||||
|
rendered_samples *= 10;
|
||||||
draw = &Visualizer::DrawSoundWaveFill;
|
draw = &Visualizer::DrawSoundWaveFill;
|
||||||
drawStereo = &Visualizer::DrawSoundWaveFillStereo;
|
drawStereo = &Visualizer::DrawSoundWaveFillStereo;
|
||||||
break;
|
break;
|
||||||
# ifdef HAVE_FFTW3_H
|
# ifdef HAVE_FFTW3_H
|
||||||
case VisualizerType::Spectrum:
|
case VisualizerType::Spectrum:
|
||||||
m_read_samples = DFT_NONZERO_SIZE;
|
rendered_samples = DFT_NONZERO_SIZE;
|
||||||
draw = &Visualizer::DrawFrequencySpectrum;
|
draw = &Visualizer::DrawFrequencySpectrum;
|
||||||
drawStereo = &Visualizer::DrawFrequencySpectrumStereo;
|
drawStereo = &Visualizer::DrawFrequencySpectrumStereo;
|
||||||
break;
|
break;
|
||||||
# endif // HAVE_FFTW3_H
|
# endif // HAVE_FFTW3_H
|
||||||
case VisualizerType::Ellipse:
|
case VisualizerType::Ellipse:
|
||||||
// Keep constant amount of samples on the screen regardless of fps.
|
// Keep constant amount of samples on the screen regardless of fps.
|
||||||
m_read_samples = 44100 / 25;
|
rendered_samples = 44100 / 30;
|
||||||
draw = &Visualizer::DrawSoundEllipse;
|
draw = &Visualizer::DrawSoundEllipse;
|
||||||
drawStereo = &Visualizer::DrawSoundEllipseStereo;
|
drawStereo = &Visualizer::DrawSoundEllipseStereo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (Config.visualizer_in_stereo)
|
if (Config.visualizer_in_stereo)
|
||||||
m_read_samples *= 2;
|
rendered_samples *= 2;
|
||||||
m_sample_buffer.resize(m_read_samples);
|
m_rendered_samples.resize(rendered_samples);
|
||||||
m_temp_sample_buffer.resize(m_read_samples);
|
|
||||||
std::fill(m_sample_buffer.begin(), m_sample_buffer.end(), 0);
|
// Keep 500ms worth of samples in the incoming buffer.
|
||||||
std::fill(m_temp_sample_buffer.begin(), m_temp_sample_buffer.end(), 0);
|
size_t buffered_samples = 44100.0 / 2;
|
||||||
|
if (Config.visualizer_in_stereo)
|
||||||
|
buffered_samples *= 2;
|
||||||
|
m_incoming_samples.resize(buffered_samples);
|
||||||
|
m_buffered_samples.resize(buffered_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
@@ -639,7 +677,7 @@ void Visualizer::InitVisualization()
|
|||||||
void Visualizer::Clear()
|
void Visualizer::Clear()
|
||||||
{
|
{
|
||||||
w.clear();
|
w.clear();
|
||||||
std::fill(m_sample_buffer.begin(), m_sample_buffer.end(), 0);
|
std::fill(m_rendered_samples.begin(), m_rendered_samples.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Visualizer::ToggleVisualizationType()
|
void Visualizer::ToggleVisualizationType()
|
||||||
@@ -671,6 +709,38 @@ void Visualizer::ToggleVisualizationType()
|
|||||||
|
|
||||||
void Visualizer::SetFD()
|
void Visualizer::SetFD()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
if (m_fifo >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sockaddr_in si_me;
|
||||||
|
|
||||||
|
if ((m_fifo = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
|
||||||
|
{
|
||||||
|
Statusbar::printf("socket failed: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = fcntl(m_fifo, F_GETFL, 0);
|
||||||
|
fcntl(m_fifo, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
memset(&si_me, 0, sizeof(si_me));
|
||||||
|
|
||||||
|
si_me.sin_family = AF_INET;
|
||||||
|
si_me.sin_port = htons(5555);
|
||||||
|
si_me.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
// bind socket to port
|
||||||
|
if (bind(m_fifo, (sockaddr *)&si_me, sizeof(si_me)) < 0)
|
||||||
|
{
|
||||||
|
Statusbar::printf("bind failed: %s", strerror(errno));
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
*/
|
||||||
|
|
||||||
if (m_fifo < 0 && (m_fifo = open(Config.visualizer_fifo_path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
if (m_fifo < 0 && (m_fifo = open(Config.visualizer_fifo_path.c_str(), O_RDONLY | O_NONBLOCK)) < 0)
|
||||||
Statusbar::printf("Couldn't open \"%1%\" for reading PCM data: %2%",
|
Statusbar::printf("Couldn't open \"%1%\" for reading PCM data: %2%",
|
||||||
Config.visualizer_fifo_path, strerror(errno)
|
Config.visualizer_fifo_path, strerror(errno)
|
||||||
@@ -679,6 +749,8 @@ void Visualizer::SetFD()
|
|||||||
|
|
||||||
void Visualizer::ResetFD()
|
void Visualizer::ResetFD()
|
||||||
{
|
{
|
||||||
|
if (m_fifo > 0)
|
||||||
|
close(m_fifo);
|
||||||
m_fifo = -1;
|
m_fifo = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,13 @@
|
|||||||
#include "curses/window.h"
|
#include "curses/window.h"
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
#include "screens/screen.h"
|
#include "screens/screen.h"
|
||||||
|
#include "utility/sample_buffer.h"
|
||||||
|
|
||||||
#ifdef HAVE_FFTW3_H
|
#ifdef HAVE_FFTW3_H
|
||||||
# include <fftw3.h>
|
# include <fftw3.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct Visualizer: Screen<NC::Window>, Tabbable
|
struct Visualizer: Screen<NC::Window>, Tabbable
|
||||||
{
|
{
|
||||||
Visualizer();
|
Visualizer();
|
||||||
@@ -86,9 +88,14 @@ private:
|
|||||||
boost::posix_time::ptime m_timer;
|
boost::posix_time::ptime m_timer;
|
||||||
|
|
||||||
int m_fifo;
|
int m_fifo;
|
||||||
size_t m_read_samples;
|
|
||||||
std::vector<int16_t> m_sample_buffer;
|
std::vector<int16_t> m_rendered_samples;
|
||||||
std::vector<int16_t> m_temp_sample_buffer;
|
std::vector<int16_t> m_incoming_samples;
|
||||||
|
SampleBuffer m_buffered_samples;
|
||||||
|
size_t m_sample_consumption_rate;
|
||||||
|
size_t m_sample_consumption_rate_up_ctr;
|
||||||
|
size_t m_sample_consumption_rate_dn_ctr;
|
||||||
|
|
||||||
double m_auto_scale_multiplier;
|
double m_auto_scale_multiplier;
|
||||||
# ifdef HAVE_FFTW3_H
|
# ifdef HAVE_FFTW3_H
|
||||||
size_t m_fftw_results;
|
size_t m_fftw_results;
|
||||||
|
|||||||
93
src/utility/sample_buffer.cpp
Normal file
93
src/utility/sample_buffer.cpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008-2017 by Andrzej Rybczak *
|
||||||
|
* electricityispower@gmail.com *
|
||||||
|
* *
|
||||||
|
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "utility/sample_buffer.h"
|
||||||
|
|
||||||
|
void SampleBuffer::put(SampleBuffer::Iterator begin, SampleBuffer::Iterator end)
|
||||||
|
{
|
||||||
|
size_t elems = end - begin;
|
||||||
|
if (elems > m_buffer.size())
|
||||||
|
throw std::out_of_range("Size of the buffer is smaller than the amount of elements");
|
||||||
|
|
||||||
|
size_t free_elems = m_buffer.size() - m_offset;
|
||||||
|
if (elems > free_elems)
|
||||||
|
{
|
||||||
|
size_t to_remove = elems - free_elems;
|
||||||
|
std::copy(m_buffer.begin() + to_remove, m_buffer.end() - free_elems,
|
||||||
|
m_buffer.begin());
|
||||||
|
m_offset -= to_remove;
|
||||||
|
}
|
||||||
|
std::copy(begin, end, m_buffer.begin() + m_offset);
|
||||||
|
m_offset += elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SampleBuffer::move(size_t elems, std::vector<int16_t> &dest)
|
||||||
|
{
|
||||||
|
if (m_offset == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// If the amount of requested samples is bigger than available, return only
|
||||||
|
// available.
|
||||||
|
if (elems > m_offset)
|
||||||
|
elems = m_offset;
|
||||||
|
|
||||||
|
if (elems >= dest.size())
|
||||||
|
{
|
||||||
|
// If dest is smaller than the available amount of samples, discard the
|
||||||
|
// ones that come first.
|
||||||
|
size_t elems_lost = elems - dest.size();
|
||||||
|
std::copy(m_buffer.begin() + elems_lost, m_buffer.begin() + elems, dest.begin());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Copy samples to the destination buffer.
|
||||||
|
std::copy(dest.begin() + elems, dest.end(), dest.begin());
|
||||||
|
std::copy(m_buffer.begin(), m_buffer.begin() + elems, dest.end() - elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove them from the internal buffer.
|
||||||
|
std::copy(m_buffer.begin() + elems, m_buffer.begin() + m_offset, m_buffer.begin());
|
||||||
|
m_offset -= elems;
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleBuffer::resize(size_t n)
|
||||||
|
{
|
||||||
|
m_buffer.resize(n);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleBuffer::clear()
|
||||||
|
{
|
||||||
|
m_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SampleBuffer::size() const
|
||||||
|
{
|
||||||
|
return m_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<int16_t> &SampleBuffer::buffer() const
|
||||||
|
{
|
||||||
|
return m_buffer;
|
||||||
|
}
|
||||||
47
src/utility/sample_buffer.h
Normal file
47
src/utility/sample_buffer.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008-2017 by Andrzej Rybczak *
|
||||||
|
* electricityispower@gmail.com *
|
||||||
|
* *
|
||||||
|
* 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 St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef NCMPCPP_SAMPLE_BUFFER_H
|
||||||
|
#define NCMPCPP_SAMPLE_BUFFER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct SampleBuffer
|
||||||
|
{
|
||||||
|
typedef std::vector<int16_t>::iterator Iterator;
|
||||||
|
|
||||||
|
SampleBuffer() : m_offset(0) { }
|
||||||
|
|
||||||
|
void put(Iterator begin, Iterator end);
|
||||||
|
size_t move(size_t elems, std::vector<int16_t> &dest);
|
||||||
|
|
||||||
|
void resize(size_t n);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
size_t size() const;
|
||||||
|
const std::vector<int16_t> &buffer() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t m_offset;
|
||||||
|
std::vector<int16_t> m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NCMPCPP_SAMPLE_BUFFER_H
|
||||||
Reference in New Issue
Block a user