Skip to content

Commit

Permalink
Make sampleFrame a class
Browse files Browse the repository at this point in the history
Make `sampleFrame` a class with several convenience methods. As a first step and demonstration adjust the follow methods to make use of the new functionality:
* `AudioEngine::getPeakValues`: Much more concise now.
* `lmms::MixHelpers::sanitize`: Better structure, better readable, less dereferencing and juggling with indices.
* `AddOp`, `AddMultipliedOp`, `multiply`: Make use of operators. Might become superfluous in the future.
  • Loading branch information
michaelgregorius committed Mar 22, 2024
1 parent ad5d88b commit 1c86e7e
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 35 deletions.
108 changes: 107 additions & 1 deletion include/lmms_basics.h
Expand Up @@ -33,6 +33,9 @@
#include <cstdint>
#include <array>

#include <cmath>
#include <algorithm>


namespace lmms
{
Expand Down Expand Up @@ -117,8 +120,111 @@ constexpr char LADSPA_PATH_SEPERATOR =
#endif


class sampleFrame : public std::array<sample_t, DEFAULT_CHANNELS>
{
public:
sampleFrame() : sampleFrame(0., 0.)
{
}

sampleFrame(sample_t left, sample_t right) :
std::array<sample_t, DEFAULT_CHANNELS>(std::array<sample_t, DEFAULT_CHANNELS> { left, right })
{
}

sample_t & left()
{
sampleFrame & thisFrame = *this;
return thisFrame[0];
}

sample_t const & left() const
{
sampleFrame const & thisFrame = *this;
return thisFrame[0];
}

void setLeft(sample_t const & value)
{
sampleFrame & thisFrame = *this;
thisFrame[0] = value;
}

sample_t & right()
{
sampleFrame & thisFrame = *this;
return thisFrame[1];
}

sample_t const & right() const
{
sampleFrame const & thisFrame = *this;
return thisFrame[1];
}

void setRight(sample_t const & value)
{
sampleFrame & thisFrame = *this;
thisFrame[1] = value;
}

void operator+=(sampleFrame const & other)
{
auto & l = left();
auto & r = right();

l += other.left();
r += other.right();
}

sampleFrame operator*(float value) const
{
return sampleFrame(left() * value, right() * value);
}

void operator*=(float value)
{
setLeft(left() * value);
setRight(right() * value);
}

sampleFrame abs() const
{
return sampleFrame{std::abs(this->left()), std::abs(this->right())};
}

using sampleFrame = std::array<sample_t, DEFAULT_CHANNELS>;
void max(sampleFrame const & other)
{
if (other.left() > left())
{
setLeft(other.left());
}

if (other.right() > right())
{
setRight(other.right());
}
}

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());
}
};

constexpr std::size_t LMMS_ALIGN_SIZE = 16;

Expand Down
10 changes: 3 additions & 7 deletions src/core/AudioEngine.cpp
Expand Up @@ -567,18 +567,14 @@ void AudioEngine::clearInternal()

sampleFrame AudioEngine::getPeakValues(sampleFrame * ab, const f_cnt_t frames) const
{
sample_t peakLeft = 0.0f;
sample_t peakRight = 0.0f;
sampleFrame peaks;

for (f_cnt_t f = 0; f < frames; ++f)
{
auto const & currentSample = ab[f];

peakLeft = std::max(std::abs(currentSample[0]), peakLeft);
peakRight = std::max(std::abs(currentSample[1]), peakRight);
peaks.max(ab[f].abs());
}

return sampleFrame{peakLeft, peakRight};
return peaks;
}


Expand Down
55 changes: 28 additions & 27 deletions src/core/MixHelpers.cpp
Expand Up @@ -98,33 +98,37 @@ bool sanitize( sampleFrame * src, int frames )
}

bool found = false;
for( int f = 0; f < frames; ++f )
for (int f = 0; f < frames; ++f)
{
for( int c = 0; c < 2; ++c )
auto & currentFrame = src[f];

if (currentFrame.containsInf() || currentFrame.containsNaN())
{
if( std::isinf( src[f][c] ) || std::isnan( src[f][c] ) )
{
#ifdef LMMS_DEBUG
#ifdef LMMS_DEBUG
// TODO don't use printf here
printf("Bad data, clearing buffer. frame: ");
printf("%d: value %f\n", f, src[f][c]);
#endif
for( int f = 0; f < frames; ++f )
{
for( int c = 0; c < 2; ++c )
{
src[f][c] = 0.0f;
}
}
found = true;
return found;
}
else
{
src[f][c] = std::clamp(src[f][c], -1000.0f, 1000.0f);
}
printf("%d: value %f, %f\n", f, currentFrame.left(), currentFrame.right());
#endif
found = true;
break;
}
else
{
// TODO What is this supposed to do? This corresponds to saying: "Pushing a signal with 60 dbFS is no problem".
currentFrame.clamp(sample_t(-1000.0), sample_t(1000.0));
}
};

if (found)
{
// Clear the whole buffer if a problem is found
for (int f = 0; f < frames; ++f)
{
auto & currentFrame = src[f];
currentFrame = sampleFrame();
}
}

return found;
}

Expand All @@ -133,8 +137,7 @@ struct AddOp
{
void operator()( sampleFrame& dst, const sampleFrame& src ) const
{
dst[0] += src[0];
dst[1] += src[1];
dst += src;
}
} ;

Expand All @@ -151,8 +154,7 @@ struct AddMultipliedOp

void operator()( sampleFrame& dst, const sampleFrame& src ) const
{
dst[0] += src[0] * m_coeff;
dst[1] += src[1] * m_coeff;
dst += src * m_coeff;
}

const float m_coeff;
Expand Down Expand Up @@ -182,8 +184,7 @@ void multiply(sampleFrame* dst, float coeff, int frames)
{
for (int i = 0; i < frames; ++i)
{
dst[i][0] *= coeff;
dst[i][1] *= coeff;
dst[i] *= coeff;
}
}

Expand Down

0 comments on commit 1c86e7e

Please sign in to comment.