-
-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
850 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
// This code is part of the sfizz library and is licensed under a BSD 2-clause | ||
// license. You should have receive a LICENSE.md file along with the code. | ||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz | ||
|
||
#include "Effects.h" | ||
#include "AudioSpan.h" | ||
#include "Opcode.h" | ||
#include "SIMDHelpers.h" | ||
#include "Config.h" | ||
#include "effects/Nothing.h" | ||
#include "effects/Lofi.h" | ||
#include <algorithm> | ||
|
||
namespace sfz { | ||
|
||
void EffectFactory::registerStandardEffectTypes() | ||
{ | ||
// TODO | ||
registerEffectType("lofi", fx::Lofi::makeInstance); | ||
} | ||
|
||
void EffectFactory::registerEffectType(absl::string_view name, Effect::MakeInstance& make) | ||
{ | ||
FactoryEntry ent; | ||
ent.name = std::string(name); | ||
ent.make = &make; | ||
_entries.push_back(std::move(ent)); | ||
} | ||
|
||
Effect* EffectFactory::makeEffect(absl::Span<const Opcode> members) | ||
{ | ||
const Opcode* opcode = nullptr; | ||
|
||
for (auto it = members.rbegin(); it != members.rend() && !opcode; ++it) { | ||
if (it->lettersOnlyHash == hash("type")) | ||
opcode = &*it; | ||
} | ||
|
||
if (!opcode) { | ||
DBG("The effect does not specify a type"); | ||
return new sfz::fx::Nothing; | ||
} | ||
|
||
absl::string_view type = opcode->value; | ||
|
||
auto it = _entries.begin(); | ||
auto end = _entries.end(); | ||
for (; it != end && it->name != type; ++it) | ||
; | ||
|
||
if (it == end) { | ||
DBG("Unsupported effect type: " << type); | ||
return new sfz::fx::Nothing; | ||
} | ||
|
||
Effect* fx = it->make(members); | ||
if (!fx) { | ||
DBG("Could not instantiate effect of type: " << type); | ||
return new sfz::fx::Nothing; | ||
} | ||
|
||
return fx; | ||
} | ||
|
||
/// | ||
EffectBus::EffectBus() | ||
{ | ||
} | ||
|
||
EffectBus::~EffectBus() | ||
{ | ||
} | ||
|
||
void EffectBus::addEffect(std::unique_ptr<Effect> fx) | ||
{ | ||
_effects.emplace_back(std::move(fx)); | ||
} | ||
|
||
void EffectBus::clearInputs(unsigned nframes) | ||
{ | ||
AudioSpan<float>(_inputs).first(nframes).fill(0.0f); | ||
AudioSpan<float>(_outputs).first(nframes).fill(0.0f); | ||
} | ||
|
||
void EffectBus::addToInputs(const float* const addInput[], float addGain, unsigned nframes) | ||
{ | ||
if (addGain == 0) | ||
return; | ||
|
||
for (unsigned c = 0; c < EffectChannels; ++c) { | ||
absl::Span<const float> addIn(addInput[c], nframes); | ||
sfz::multiplyAdd(addGain, addIn, _inputs.getSpan(c)); | ||
} | ||
} | ||
|
||
void EffectBus::init(double sampleRate) | ||
{ | ||
for (const auto& effectPtr : _effects) | ||
effectPtr->init(sampleRate); | ||
} | ||
|
||
void EffectBus::clear() | ||
{ | ||
for (const auto& effectPtr : _effects) | ||
effectPtr->clear(); | ||
} | ||
|
||
void EffectBus::process(unsigned nframes) | ||
{ | ||
size_t numEffects = _effects.size(); | ||
|
||
if (numEffects > 0 && hasNonZeroOutput()) { | ||
_effects[0]->process( | ||
AudioSpan<float>(_inputs), AudioSpan<float>(_outputs), nframes); | ||
for (size_t i = 1; i < numEffects; ++i) | ||
_effects[i]->process( | ||
AudioSpan<float>(_outputs), AudioSpan<float>(_outputs), nframes); | ||
} else | ||
fx::Nothing().process( | ||
AudioSpan<float>(_inputs), AudioSpan<float>(_outputs), nframes); | ||
} | ||
|
||
void EffectBus::mixOutputsTo(float* const mainOutput[], float* const mixOutput[], unsigned nframes) | ||
{ | ||
const float gainToMain = _gainToMain; | ||
const float gainToMix = _gainToMix; | ||
|
||
for (unsigned c = 0; c < EffectChannels; ++c) { | ||
absl::Span<const float> fxOut = _outputs.getConstSpan(c); | ||
sfz::multiplyAdd(gainToMain, fxOut, absl::Span<float>(mainOutput[c], nframes)); | ||
sfz::multiplyAdd(gainToMix, fxOut, absl::Span<float>(mixOutput[c], nframes)); | ||
} | ||
} | ||
|
||
} // namespace sfz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// SPDX-License-Identifier: BSD-2-Clause | ||
|
||
// This code is part of the sfizz library and is licensed under a BSD 2-clause | ||
// license. You should have receive a LICENSE.md file along with the code. | ||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz | ||
|
||
#pragma once | ||
#include "AudioBuffer.h" | ||
#include "absl/strings/string_view.h" | ||
#include "absl/types/span.h" | ||
#include <array> | ||
#include <vector> | ||
#include <memory> | ||
|
||
namespace sfz { | ||
struct Opcode; | ||
|
||
enum { | ||
// Number of channels processed by effects | ||
EffectChannels = 2, | ||
}; | ||
|
||
/** | ||
@brief Abstract base of SFZ effects | ||
*/ | ||
class Effect { | ||
public: | ||
virtual ~Effect() {} | ||
|
||
/** | ||
@brief Initializes with the given sample rate. | ||
*/ | ||
virtual void init(double sampleRate) = 0; | ||
|
||
/** | ||
@brief Reset the state to initial. | ||
*/ | ||
virtual void clear() = 0; | ||
|
||
/** | ||
@brief Computes a cycle of the effect in stereo. | ||
*/ | ||
virtual void process(const float* const inputs[], float* const outputs[], unsigned nframes) = 0; | ||
|
||
/** | ||
@brief Type of the factory function used to instantiate an effect given | ||
the contents of the <effect> block | ||
*/ | ||
typedef Effect* (MakeInstance)(absl::Span<const Opcode> members); | ||
}; | ||
|
||
/** | ||
@brief SFZ effects factory | ||
*/ | ||
class EffectFactory { | ||
public: | ||
/** | ||
@brief Registers all available standard effects into the factory. | ||
*/ | ||
void registerStandardEffectTypes(); | ||
|
||
/** | ||
@brief Registers a user-defined effect into the factory. | ||
*/ | ||
void registerEffectType(absl::string_view name, Effect::MakeInstance& make); | ||
|
||
/** | ||
@brief Instantiates an effect given the contents of the <effect> block. | ||
*/ | ||
Effect* makeEffect(absl::Span<const Opcode> members); | ||
|
||
private: | ||
struct FactoryEntry { | ||
std::string name; | ||
Effect::MakeInstance* make; | ||
}; | ||
|
||
std::vector<FactoryEntry> _entries; | ||
}; | ||
|
||
/** | ||
@brief Sequence of effects processed in series | ||
*/ | ||
class EffectBus { | ||
public: | ||
EffectBus(); | ||
~EffectBus(); | ||
|
||
/** | ||
@brief Adds an effect at the end of the bus. | ||
*/ | ||
void addEffect(std::unique_ptr<Effect> fx); | ||
|
||
/** | ||
@brief Checks whether this bus can produce output. | ||
*/ | ||
bool hasNonZeroOutput() const { return _gainToMain != 0 || _gainToMix != 0; } | ||
|
||
/** | ||
@brief Sets the amount of effect output going to the main. | ||
*/ | ||
void setGainToMain(float gain) { _gainToMain = gain; } | ||
|
||
/** | ||
@brief Sets the amount of effect output going to the mix. | ||
*/ | ||
void setGainToMix(float gain) { _gainToMix = gain; } | ||
|
||
/** | ||
@brief Resets the input buffers to zero. | ||
*/ | ||
void clearInputs(unsigned nframes); | ||
|
||
/** | ||
@brief Adds some audio into the input buffer. | ||
*/ | ||
void addToInputs(const float* const addInput[], float addGain, unsigned nframes); | ||
|
||
/** | ||
@brief Initializes all effects in the bus with the given sample rate. | ||
*/ | ||
void init(double sampleRate); | ||
|
||
/** | ||
@brief Resets the state of all effects in the bus. | ||
*/ | ||
void clear(); | ||
|
||
/** | ||
@brief Computes a cycle of the effect bus. | ||
*/ | ||
void process(unsigned nframes); | ||
|
||
/** | ||
@brief Mixes the outputs into a pair of stereo signals: Main and Mix. | ||
*/ | ||
void mixOutputsTo(float* const mainOutput[], float* const mixOutput[], unsigned nframes); | ||
|
||
private: | ||
std::vector<std::unique_ptr<Effect>> _effects; | ||
AudioBuffer<float> _inputs { EffectChannels, config::defaultSamplesPerBlock }; | ||
AudioBuffer<float> _outputs { EffectChannels, config::defaultSamplesPerBlock }; | ||
float _gainToMain = 0.0; | ||
float _gainToMix = 0.0; | ||
}; | ||
|
||
} // namespace sfz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.