Skip to content

Commit

Permalink
Add interface for interpolator selection
Browse files Browse the repository at this point in the history
  • Loading branch information
sakertooth committed May 20, 2024
1 parent 7daf3b1 commit 5ac908e
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 0 deletions.
68 changes: 68 additions & 0 deletions include/AudioInterpolator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* AudioInterpolator.h
*
* Copyright (c) 2024 saker
*
* 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_AUDIO_INTERPOLATOR_H
#define LMMS_AUDIO_INTERPOLATOR_H

#include <functional>
#include <variant>

namespace lmms {
class AudioInterpolator
{
public:
using FourPointInterpolator = std::function<float(float, float, float, float, float)>;
using TwoPointInterpolator = std::function<float(float, float, float)>;

constexpr static auto DefaultInterpolator = "hermite";

struct Interpolator
{
const char* name;
const char* displayName;
std::variant<FourPointInterpolator, TwoPointInterpolator> fn;
};

static auto interpolate(const float* buffer, size_t size, size_t index, float fracPosition) -> float;
static auto interpolators() -> const std::vector<Interpolator>&;

static void setPlaybackInterpolator(const char* name);
static void setExportInterpolator(const char* name);
static void setExporting(bool exporting);

private:
static auto interpolate(FourPointInterpolator interpolator, const float* buffer, size_t size, size_t index,
float fracPosition) -> float;
static auto interpolate(
TwoPointInterpolator interpolator, const float* buffer, size_t size, size_t index, float fracPosition) -> float;
static auto findInterpolator(const char* name) -> Interpolator*;

static Interpolator* s_playbackInterpolator;
static Interpolator* s_exportInterpolator;
static bool s_exporting;
static std::vector<Interpolator> s_interpolators;
};
} // namespace lmms

#endif // LMMS_AUDIO_INTERPOLATOR_H
130 changes: 130 additions & 0 deletions src/core/audio/AudioInterpolator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* AudioInterpolator.cpp
*
* Copyright (c) 2024 saker
*
* 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 "AudioInterpolator.h"

#include <cstring>

#include "interpolation.h"
#include "lmms_basics.h"

namespace lmms {

std::vector<AudioInterpolator::Interpolator> AudioInterpolator::s_interpolators
= {{"hermite", "4-point Hermite", hermiteInterpolate}, {"linear", "Linear", linearInterpolate}};

AudioInterpolator::Interpolator* AudioInterpolator::s_playbackInterpolator
= AudioInterpolator::findInterpolator(DefaultInterpolator);
AudioInterpolator::Interpolator* AudioInterpolator::s_exportInterpolator
= AudioInterpolator::findInterpolator(DefaultInterpolator);

bool AudioInterpolator::s_exporting = false;

float AudioInterpolator::interpolate(const float* buffer, size_t size, size_t index, float fracPosition)
{
assert(s_playbackInterpolator && s_exportInterpolator
&& "Either the playback interpolator or export interpolator were not found");

const auto playbackFourPointInterpolator = std::get_if<FourPointInterpolator>(&s_playbackInterpolator->fn);
const auto playbackTwoPointInterpolator = std::get_if<TwoPointInterpolator>(&s_playbackInterpolator->fn);
const auto exportFourPointInterpolator = std::get_if<FourPointInterpolator>(&s_exportInterpolator->fn);
const auto exportTwoPointInterpolator = std::get_if<TwoPointInterpolator>(&s_exportInterpolator->fn);

if (s_exporting)
{
assert(s_exportInterpolator);
if (exportFourPointInterpolator)
{
return interpolate(*exportFourPointInterpolator, buffer, size, index, fracPosition);
}
else if (exportTwoPointInterpolator)
{
return interpolate(*exportTwoPointInterpolator, buffer, size, index, fracPosition);
}
}
else
{
assert(s_playbackInterpolator);
if (playbackFourPointInterpolator)
{
return interpolate(*playbackFourPointInterpolator, buffer, size, index, fracPosition);
}
else if (playbackTwoPointInterpolator)
{
return interpolate(*playbackTwoPointInterpolator, buffer, size, index, fracPosition);
}
}

return 0;
}

float AudioInterpolator::interpolate(
FourPointInterpolator interpolator, const float* buffer, size_t size, size_t index, float fracPosition)
{
const auto x0 = index == 0 ? 0.0f : buffer[index - 1];
const auto x1 = buffer[index];
const auto x2 = (index + 1 * DEFAULT_CHANNELS) >= size ? 0.0f : buffer[index + 1 * DEFAULT_CHANNELS];
const auto x3 = (index + 2 * DEFAULT_CHANNELS) >= size ? 0.0f : buffer[index + 2 * DEFAULT_CHANNELS];
return interpolator(x0, x1, x2, x3, fracPosition);
}

float AudioInterpolator::interpolate(
TwoPointInterpolator interpolator, const float* buffer, size_t size, size_t index, float fracPosition)
{
const auto x0 = buffer[index];
const auto x1 = (index + DEFAULT_CHANNELS) >= size ? 0.0f : buffer[index + DEFAULT_CHANNELS];
return interpolator(x0, x1, fracPosition);
}

void AudioInterpolator::setPlaybackInterpolator(const char* name)
{
s_playbackInterpolator = findInterpolator(name);
}

void AudioInterpolator::setExportInterpolator(const char* name)
{
s_exportInterpolator = findInterpolator(name);
}

void AudioInterpolator::setExporting(bool exporting)
{
s_exporting = exporting;
}

auto AudioInterpolator::findInterpolator(const char* name) -> Interpolator*
{
for (auto& interpolator : s_interpolators)
{
if (std::strcmp(interpolator.name, name)) { return &interpolator; }
}

return nullptr;
}

auto AudioInterpolator::interpolators() -> const std::vector<Interpolator>&
{
return s_interpolators;
}

} // namespace lmms

0 comments on commit 5ac908e

Please sign in to comment.