mirror of
https://github.com/LMMS/lmms.git
synced 2026-05-17 11:18:30 -04:00
This revisits two main aspects of playback from `Sample`: copying frames into a temporary playback buffer before resampling, and advancing the state's frame index. Both operations were improperly done, causing distorted audio to be heard when resampling from within the `Sample::play` function. To fix this, playback into the temporary playback buffer is now done using the `playRaw` function, which copies the frame one by one in a loop, moving through the buffer correctly as determined by the loop mode. In addition, advancement of the playback index is done using the `advance` function, which advances the index by the given amount and handles an out of bounds index for the loop modes as necessary using the modulo operator.
97 lines
2.9 KiB
C++
97 lines
2.9 KiB
C++
/*
|
|
* SampleBuffer.cpp - container-class SampleBuffer
|
|
*
|
|
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
|
*
|
|
* This file is part of LMMS - https://lmms.io
|
|
*
|
|
* 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 (see COPYING); if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include "SampleBuffer.h"
|
|
#include <cstring>
|
|
|
|
#include "PathUtil.h"
|
|
#include "SampleDecoder.h"
|
|
#include "lmms_basics.h"
|
|
|
|
namespace lmms {
|
|
|
|
SampleBuffer::SampleBuffer(const sampleFrame* data, size_t numFrames, int sampleRate)
|
|
: m_data(data, data + numFrames)
|
|
, m_sampleRate(sampleRate)
|
|
{
|
|
}
|
|
|
|
SampleBuffer::SampleBuffer(const QString& audioFile)
|
|
{
|
|
if (audioFile.isEmpty()) { throw std::runtime_error{"Failure loading audio file: Audio file path is empty."}; }
|
|
const auto absolutePath = PathUtil::toAbsolute(audioFile);
|
|
|
|
if (auto decodedResult = SampleDecoder::decode(absolutePath))
|
|
{
|
|
auto& [data, sampleRate] = *decodedResult;
|
|
m_data = std::move(data);
|
|
m_sampleRate = sampleRate;
|
|
m_audioFile = PathUtil::toShortestRelative(audioFile);
|
|
return;
|
|
}
|
|
|
|
throw std::runtime_error{
|
|
"Failed to decode audio file: Either the audio codec is unsupported, or the file is corrupted."};
|
|
}
|
|
|
|
SampleBuffer::SampleBuffer(const QString& base64, int sampleRate)
|
|
: m_sampleRate(sampleRate)
|
|
{
|
|
// TODO: Replace with non-Qt equivalent
|
|
const auto bytes = QByteArray::fromBase64(base64.toUtf8());
|
|
m_data.resize(bytes.size() / sizeof(sampleFrame));
|
|
std::memcpy(reinterpret_cast<char*>(m_data.data()), bytes, m_data.size() * sizeof(sampleFrame));
|
|
}
|
|
|
|
SampleBuffer::SampleBuffer(std::vector<sampleFrame> data, int sampleRate)
|
|
: m_data(std::move(data))
|
|
, m_sampleRate(sampleRate)
|
|
{
|
|
}
|
|
|
|
void swap(SampleBuffer& first, SampleBuffer& second) noexcept
|
|
{
|
|
using std::swap;
|
|
swap(first.m_data, second.m_data);
|
|
swap(first.m_audioFile, second.m_audioFile);
|
|
swap(first.m_sampleRate, second.m_sampleRate);
|
|
}
|
|
|
|
QString SampleBuffer::toBase64() const
|
|
{
|
|
// TODO: Replace with non-Qt equivalent
|
|
const auto data = reinterpret_cast<const char*>(m_data.data());
|
|
const auto size = static_cast<int>(m_data.size() * sizeof(sampleFrame));
|
|
const auto byteArray = QByteArray{data, size};
|
|
return byteArray.toBase64();
|
|
}
|
|
|
|
auto SampleBuffer::emptyBuffer() -> std::shared_ptr<const SampleBuffer>
|
|
{
|
|
static auto s_buffer = std::make_shared<const SampleBuffer>();
|
|
return s_buffer;
|
|
}
|
|
|
|
} // namespace lmms
|