mirror of
https://github.com/LMMS/lmms.git
synced 2025-12-23 22:58:33 -05:00
* Renamed lmms_basics.h to LmmsTypes.h and scoped it down for that purpose. * Shifted the LMMS_STRINGIFY macro to it's own header. * Removed the debug.h header file and use cmake to handle the macro logic. * Remove some unused headers and include directives
233 lines
4.4 KiB
C++
233 lines
4.4 KiB
C++
/*
|
|
* SampleFrame.h - Representation of a stereo sample
|
|
*
|
|
* Copyright (c) 2004-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
|
* Copyright (c) 2024- Michael Gregorius
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef LMMS_SAMPLEFRAME_H
|
|
#define LMMS_SAMPLEFRAME_H
|
|
|
|
#include "LmmsTypes.h"
|
|
#include "lmms_constants.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cmath>
|
|
|
|
|
|
namespace lmms
|
|
{
|
|
|
|
class SampleFrame
|
|
{
|
|
public:
|
|
SampleFrame() : SampleFrame(0., 0.)
|
|
{
|
|
}
|
|
|
|
explicit SampleFrame(sample_t value) : SampleFrame(value, value)
|
|
{
|
|
}
|
|
|
|
SampleFrame(sample_t left, sample_t right) :
|
|
m_samples({ left, right })
|
|
{
|
|
}
|
|
|
|
sample_t* data()
|
|
{
|
|
return m_samples.data();
|
|
}
|
|
|
|
const sample_t* data() const
|
|
{
|
|
return m_samples.data();
|
|
}
|
|
|
|
sample_t& left()
|
|
{
|
|
return m_samples[0];
|
|
}
|
|
|
|
const sample_t& left() const
|
|
{
|
|
return m_samples[0];
|
|
}
|
|
|
|
void setLeft(const sample_t& value)
|
|
{
|
|
m_samples[0] = value;
|
|
}
|
|
|
|
sample_t& right()
|
|
{
|
|
return m_samples[1];
|
|
}
|
|
|
|
const sample_t& right() const
|
|
{
|
|
return m_samples[1];
|
|
}
|
|
|
|
void setRight(const sample_t& value)
|
|
{
|
|
m_samples[1] = value;
|
|
}
|
|
|
|
sample_t& operator[](size_t index)
|
|
{
|
|
return m_samples[index];
|
|
}
|
|
|
|
const sample_t& operator[](size_t index) const
|
|
{
|
|
return m_samples[index];
|
|
}
|
|
|
|
SampleFrame operator+(const SampleFrame& other) const
|
|
{
|
|
return SampleFrame(left() + other.left(), right() + other.right());
|
|
}
|
|
|
|
SampleFrame& operator+=(const SampleFrame& other)
|
|
{
|
|
auto & l = left();
|
|
auto & r = right();
|
|
|
|
l += other.left();
|
|
r += other.right();
|
|
|
|
return *this;
|
|
}
|
|
|
|
SampleFrame operator*(float value) const
|
|
{
|
|
return SampleFrame(left() * value, right() * value);
|
|
}
|
|
|
|
SampleFrame& operator*=(float value)
|
|
{
|
|
setLeft(left() * value);
|
|
setRight(right() * value);
|
|
|
|
return *this;
|
|
}
|
|
|
|
SampleFrame operator*(const SampleFrame& other) const
|
|
{
|
|
return SampleFrame(left() * other.left(), right() * other.right());
|
|
}
|
|
|
|
void operator*=(const SampleFrame& other)
|
|
{
|
|
left() *= other.left();
|
|
right() *= other.right();
|
|
}
|
|
|
|
sample_t sumOfSquaredAmplitudes() const
|
|
{
|
|
return left() * left() + right() * right();
|
|
}
|
|
|
|
SampleFrame abs() const
|
|
{
|
|
return SampleFrame{std::abs(this->left()), std::abs(this->right())};
|
|
}
|
|
|
|
SampleFrame absMax(const SampleFrame& other)
|
|
{
|
|
const auto a = abs();
|
|
const auto b = other.abs();
|
|
|
|
return SampleFrame(std::max(a.left(), b.left()), std::max(a.right(), b.right()));
|
|
}
|
|
|
|
sample_t average() const
|
|
{
|
|
return (left() + right()) / 2;
|
|
}
|
|
|
|
void clamp(sample_t low, sample_t high)
|
|
{
|
|
auto & l = left();
|
|
l = std::clamp(l, low, high);
|
|
|
|
auto & r = right();
|
|
r = std::clamp(r, low, high);
|
|
}
|
|
|
|
bool containsInf() const
|
|
{
|
|
return std::isinf(left()) || std::isinf(right());
|
|
}
|
|
|
|
bool containsNaN() const
|
|
{
|
|
return std::isnan(left()) || std::isnan(right());
|
|
}
|
|
|
|
private:
|
|
std::array<sample_t, DEFAULT_CHANNELS> m_samples;
|
|
};
|
|
|
|
inline void zeroSampleFrames(SampleFrame* buffer, size_t frames)
|
|
{
|
|
// The equivalent of the following operation which yields compiler warnings
|
|
// memset(buffer, 0, sizeof(SampleFrame) * frames);
|
|
|
|
std::fill(buffer, buffer + frames, SampleFrame());
|
|
}
|
|
|
|
inline SampleFrame getAbsPeakValues(SampleFrame* buffer, size_t frames)
|
|
{
|
|
SampleFrame peaks;
|
|
|
|
for (f_cnt_t i = 0; i < frames; ++i)
|
|
{
|
|
peaks = peaks.absMax(buffer[i]);
|
|
}
|
|
|
|
return peaks;
|
|
}
|
|
|
|
inline void copyToSampleFrames(SampleFrame* target, const float* source, size_t frames)
|
|
{
|
|
for (size_t i = 0; i < frames; ++i)
|
|
{
|
|
target[i].setLeft(source[2*i]);
|
|
target[i].setRight(source[2*i + 1]);
|
|
}
|
|
}
|
|
|
|
inline void copyFromSampleFrames(float* target, const SampleFrame* source, size_t frames)
|
|
{
|
|
for (size_t i = 0; i < frames; ++i)
|
|
{
|
|
target[2*i] = source[i].left();
|
|
target[2*i + 1] = source[i].right();
|
|
}
|
|
}
|
|
|
|
} // namespace lmms
|
|
|
|
#endif // LMMS_SAMPLEFRAME_H
|