...
 
Commits (2)
......@@ -35,6 +35,8 @@ template <typename PluginSettings>
class PluginBaseTemplate : public Plugin
{
protected:
/// \brief Constructor.
/// \param[in] num_parameters Number of parameters of the plugin.
PluginBaseTemplate(std::uint32_t num_parameters);
/// \brief Returns plugin author.
......
/// \file
/// \brief Header file that describes the PulsePluginTemplate class template.
/// \author Lyberta
/// \copyright GNU GPLv3 or any later version.
#pragma once
#include <ftz/Audio/PolyphonicSynth.h>
#include "PluginBaseTemplate.h"
namespace DISTRHO
{
enum class PulseParameterIndex
{
MasterVolume,
Pan,
PitchBendRange,
DutyCycle,
AttackTime,
DecayTime,
SustainLevel,
ReleaseTime
};
/// \brief A plugin template for a pulse synth.
/// \details Pulse wave has duty cycle so it needs special handling.
/// \tparam Generator Generator of the synth.
/// \tparam PluginSettings Settings of the plugin. See Config.h.
template <typename Generator, typename PluginSettings>
class PulsePluginTemplate : public PluginBaseTemplate<PluginSettings>
{
public:
/// \brief Constructor.
/// \param[in] settings Settings of the generator.
PulsePluginTemplate(typename Generator::Settings generator_settings);
protected:
/// \brief Initializes plugin parameter.
/// \param[in] index Index of the parameter.
/// \param[out] parameter Parameter info.
void initParameter(std::uint32_t index, Parameter& parameter) override;
/// \brief Returns the value of the plugin parameter.
/// \param[in] index Index of the parameter.
/// \return Parameter value.
float getParameterValue(std::uint32_t index) const override;
/// \brief Sets the value of the plugin parameter.
/// \param[in] index Index of the parameter.
/// \param[in] value Value to set.
void setParameterValue(std::uint32_t index, float value) override;
/// \brief Called when sample rate has changed.
/// \param[in] new_sample_rate Sample rate to set.
void sampleRateChanged(double new_sample_rate) override;
protected:
/// \brief Type of the synth.
using Synth = ftz::Audio::PolyphonicSynth<Generator,
typename PluginSettings::SampleFormat>;
Synth synth; ///< Holds the synth.
};
}
#include "PulsePluginTemplate.hpp"
/// \file
/// \brief Internal header file that contains implementation of the
/// PulsePluginTemplate class template.
/// \author Lyberta
/// \copyright GNU GPLv3 or any later version.
#pragma once
namespace DISTRHO
{
const std::uint32_t NumParameters = 8;
inline BaseParameterIndex ToBaseParameterIndex(std::uint32_t index)
{
switch (static_cast<PulseParameterIndex>(index))
{
case PulseParameterIndex::MasterVolume:
{
return BaseParameterIndex::MasterVolume;
}
case PulseParameterIndex::Pan:
{
return BaseParameterIndex::Pan;
}
case PulseParameterIndex::PitchBendRange:
{
return BaseParameterIndex::PitchBendRange;
}
case PulseParameterIndex::DutyCycle:
{
throw std::out_of_range{"ToBaseParameterIndex: Invalid index."};
}
case PulseParameterIndex::AttackTime:
{
return BaseParameterIndex::AttackTime;
}
case PulseParameterIndex::DecayTime:
{
return BaseParameterIndex::DecayTime;
}
case PulseParameterIndex::SustainLevel:
{
return BaseParameterIndex::SustainLevel;
}
case PulseParameterIndex::ReleaseTime:
{
return BaseParameterIndex::ReleaseTime;
}
}
}
template <typename Generator, typename PluginSettings>
PulsePluginTemplate<Generator, PluginSettings>::PulsePluginTemplate(
typename Generator::Settings generator_settings)
: PluginBaseTemplate<PluginSettings>{NumParameters},
synth{this->settings, this->channel, generator_settings, {}}
{
this->effects.insert(std::begin(this->effects), synth);
}
template <typename Generator, typename PluginSettings>
void PulsePluginTemplate<Generator, PluginSettings>::initParameter(
std::uint32_t index, Parameter& parameter)
{
auto new_index = static_cast<PulseParameterIndex>(index);
if (new_index != PulseParameterIndex::DutyCycle)
{
this->template InitParameter<Synth>(ToBaseParameterIndex(index),
parameter);
return;
}
parameter.hints = kParameterIsAutomable;
parameter.name = "Duty cycle";
parameter.symbol = "duty_cycle";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f;
parameter.ranges.def = ftz::Audio::DutyCycle<
typename PluginSettings::CalcType>{};
}
template <typename Generator, typename PluginSettings>
float PulsePluginTemplate<Generator, PluginSettings>::getParameterValue(
std::uint32_t index) const
{
return this->GetParameterValue(synth, ToBaseParameterIndex(index));
}
template <typename Generator, typename PluginSettings>
void PulsePluginTemplate<Generator, PluginSettings>::setParameterValue(
std::uint32_t index, float value)
{
this->SetParameterValue(synth, ToBaseParameterIndex(index), value);
}
template <typename Generator, typename PluginSettings>
void PulsePluginTemplate<Generator, PluginSettings>::sampleRateChanged(
double new_sample_rate)
{
this->settings.SetSampleRate(new_sample_rate);
auto generator_settings = synth.GetGeneratorSettings();
generator_settings.SetSampleRate(new_sample_rate);
synth.SetGeneratorSettings(std::move(generator_settings));
auto envelope = synth.GetEnvelopeSettings();
envelope.SetSampleRate(new_sample_rate);
synth.SetEnvelopeSettings(std::move(envelope));
}
}
......@@ -6,35 +6,14 @@
#include "Plugin.h"
#include "../DPF/Utils.h"
namespace DISTRHO
{
const std::uint32_t NumParameters = 8;
enum class ParameterIndex
{
MasterVolume,
Pan,
PitchBendRange,
DutyCycle,
AttackTime,
DecayTime,
SustainLevel,
ReleaseTime
};
AliasedPulsePlugin::AliasedPulsePlugin()
: Plugin{NumParameters, 0, 0},
synth{settings, channel, {{}, this->getSampleRate()},
{this->getSampleRate()}},
amp{AliasedSettings::DefaultGain}
: PulsePluginTemplate<ftz::Audio::OscillatorGenerator<
ftz::Audio::PulseWave<AliasedSettings::CalcType>>, AliasedSettings>{
{{}, {}}}
{
effects.PushBack(synth);
effects.PushBack(pan);
effects.PushBack(amp);
effects.PushBack(clamp);
}
const char* AliasedPulsePlugin::getName() const
......@@ -52,257 +31,36 @@ const char* AliasedPulsePlugin::getDescription() const
return "Pulse wave synth.";
}
const char* AliasedPulsePlugin::getMaker() const
{
return "Lyberta";
}
const char* AliasedPulsePlugin::getHomePage() const
{
return "https://ftz.lyberta.net/projects/chiptune";
}
const char* AliasedPulsePlugin::getLicense() const
{
return "GNU GPLv3+";
}
std::uint32_t AliasedPulsePlugin::getVersion() const
{
return PluginVersion;
}
std::int64_t AliasedPulsePlugin::getUniqueId() const
{
return d_cconst('F', 'C', 'T', '2');
}
void AliasedPulsePlugin::initParameter(std::uint32_t index,
Parameter& parameter)
{
switch (static_cast<ParameterIndex>(index))
{
case ParameterIndex::MasterVolume:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Master volume";
parameter.symbol = "master_volume";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f;
parameter.ranges.def = AliasedSettings::DefaultGain.GetValue();
return;
}
case ParameterIndex::Pan:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Pan";
parameter.symbol = "pan";
parameter.ranges.min = -1.0f;
parameter.ranges.max = 1.0f;
parameter.ranges.def = 0.0f;
return;
}
case ParameterIndex::PitchBendRange:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Pitch bend range";
parameter.symbol = "pitch_bend_range";
parameter.ranges.min = 0.0f;
parameter.ranges.max = AliasedSettings::MaxPitchBend;
parameter.ranges.def = Synth::DefaultPitchBendRange;
return;
}
case ParameterIndex::DutyCycle:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Duty cycle";
parameter.symbol = "duty_cycle";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f;
parameter.ranges.def = ftz::Audio::DutyCycle<
AliasedSettings::CalcType>{};
return;
}
case ParameterIndex::AttackTime:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Attack time";
parameter.symbol = "decay_time";
parameter.unit = "seconds";
parameter.ranges.min = 0.0f;
parameter.ranges.max = AliasedSettings::MaxAttackTime.count();
parameter.ranges.def = 0.0f;
return;
}
case ParameterIndex::DecayTime:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Decay time";
parameter.symbol = "decay_time";
parameter.unit = "seconds";
parameter.ranges.min = 0.0f;
parameter.ranges.max = AliasedSettings::MaxDecayTime.count();
parameter.ranges.def = 0.0f;
return;
}
case ParameterIndex::SustainLevel:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Sustain level";
parameter.symbol = "sustain_level";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 1.0f;
parameter.ranges.def = 1.0f;
return;
}
case ParameterIndex::ReleaseTime:
{
parameter.hints = kParameterIsAutomable;
parameter.name = "Release time";
parameter.symbol = "release_time";
parameter.unit = "seconds";
parameter.ranges.min = 0.0f;
parameter.ranges.max = AliasedSettings::MaxReleaseTime.count();
parameter.ranges.def = 0.0f;
return;
}
}
}
float AliasedPulsePlugin::getParameterValue(std::uint32_t index) const
{
switch (static_cast<ParameterIndex>(index))
auto new_index = static_cast<PulseParameterIndex>(index);
if (new_index != PulseParameterIndex::DutyCycle)
{
case ParameterIndex::MasterVolume:
{
return amp.GetGain().GetValue();
}
case ParameterIndex::Pan:
{
return pan.GetPosition();
}
case ParameterIndex::PitchBendRange:
{
return synth.GetPitchBendRange();
}
case ParameterIndex::DutyCycle:
{
return synth.GetGeneratorSettings().GetOscillator().GetDutyCycle();
}
case ParameterIndex::AttackTime:
{
return synth.GetEnvelopeSettings().GetAttackTime().count();
}
case ParameterIndex::DecayTime:
{
return synth.GetEnvelopeSettings().GetDecayTime().count();
}
case ParameterIndex::SustainLevel:
{
return synth.GetEnvelopeSettings().GetSustainLevel();
}
case ParameterIndex::ReleaseTime:
{
return synth.GetEnvelopeSettings().GetDecayTime().count();
}
return PulsePluginTemplate<ftz::Audio::OscillatorGenerator<
ftz::Audio::PulseWave<AliasedSettings::CalcType>>,
AliasedSettings>::getParameterValue(index);
}
return 0.0f;
return synth.GetGeneratorSettings().GetOscillator().GetDutyCycle();
}
void AliasedPulsePlugin::setParameterValue(std::uint32_t index, float value)
{
switch (static_cast<ParameterIndex>(index))
{
case ParameterIndex::MasterVolume:
{
amp.SetGain(ftz::Audio::Gain<AliasedSettings::CalcType>{value});
return;
}
case ParameterIndex::Pan:
{
pan.SetPosition(value);
return;
}
case ParameterIndex::PitchBendRange:
{
synth.SetPitchBendRange(value);
return;
}
case ParameterIndex::DutyCycle:
{
auto generatorsettings = synth.GetGeneratorSettings();
generatorsettings.GetOscillator().SetDutyCycle(value);
synth.SetGeneratorSettings(std::move(generatorsettings));
return;
}
case ParameterIndex::AttackTime:
{
auto envelope = synth.GetEnvelopeSettings();
envelope.SetAttackTime(
ftz::Audio::TimeDuration<AliasedSettings::CalcType>{value});
synth.SetEnvelopeSettings(std::move(envelope));
return;
}
case ParameterIndex::DecayTime:
{
auto envelope = synth.GetEnvelopeSettings();
envelope.SetDecayTime(
ftz::Audio::TimeDuration<AliasedSettings::CalcType>{value});
synth.SetEnvelopeSettings(std::move(envelope));
return;
}
case ParameterIndex::SustainLevel:
{
auto envelope = synth.GetEnvelopeSettings();
envelope.SetSustainLevel(value);
synth.SetEnvelopeSettings(std::move(envelope));
return;
}
case ParameterIndex::ReleaseTime:
{
auto envelope = synth.GetEnvelopeSettings();
envelope.SetReleaseTime(
ftz::Audio::TimeDuration<AliasedSettings::CalcType>{value});
synth.SetEnvelopeSettings(std::move(envelope));
return;
}
}
}
void AliasedPulsePlugin::activate()
{
auto sample_rate = this->getSampleRate();
this->sampleRateChanged(sample_rate);
}
void AliasedPulsePlugin::run(const float**, float** outputs,
std::uint32_t frames, const MidiEvent* midi_events,
std::uint32_t midi_event_count)
{
ftz::Audio::MultichannelAudioBufferReference<
AliasedSettings::SampleFormat> buffer{outputs, 2, frames};
auto first = std::begin(buffer);
decltype(first) last;
for (std::uint32_t i = 0; i < midi_event_count; ++i)
auto new_index = static_cast<PulseParameterIndex>(index);
if (new_index != PulseParameterIndex::DutyCycle)
{
last = std::begin(buffer) + midi_events[i].frame;
effects.Render(first, last);
auto event = Utils::ConvertEvent(midi_events[i]);
channel.HandleEvent(*event);
first = last;
PulsePluginTemplate<ftz::Audio::OscillatorGenerator<
ftz::Audio::PulseWave<AliasedSettings::CalcType>>,
AliasedSettings>::setParameterValue(index, value);
return;
}
effects.Render(first, std::end(buffer));
}
void AliasedPulsePlugin::sampleRateChanged(double new_sample_rate)
{
settings.SetSampleRate(new_sample_rate);
auto generator_settings = synth.GetGeneratorSettings();
generator_settings.SetSampleRate(new_sample_rate);
generator_settings.GetOscillator().SetDutyCycle(value);
synth.SetGeneratorSettings(std::move(generator_settings));
auto envelope = synth.GetEnvelopeSettings();
envelope.SetSampleRate(new_sample_rate);
synth.SetEnvelopeSettings(std::move(envelope));
}
Plugin* createPlugin()
......
......@@ -5,17 +5,10 @@
#pragma once
#include <ftz/Audio/SynthSettings.h>
#include <ftz/Audio/PulseWave.h>
#include <ftz/Audio/OscillatorGenerator.h>
#include <ftz/Audio/EnvelopeSettings.h>
#include <ftz/Audio/PolyphonicSynth.h>
#include <ftz/Audio/Pan.h>
#include <ftz/Audio/Amplifier.h>
#include <ftz/Audio/Clamper.h>
#include <ftz/Audio/EffectChain.h>
#include "../DPF/Config.h"
#include "../DPF/PulsePluginTemplate.h"
namespace DISTRHO
{
......@@ -23,7 +16,9 @@ namespace DISTRHO
/// \brief An aliased pulse synth plugin.
/// \details This is a DPF wrapper of the aliased pulse synth.
class AliasedPulsePlugin final : public Plugin
class AliasedPulsePlugin final : public PulsePluginTemplate<
ftz::Audio::OscillatorGenerator<ftz::Audio::PulseWave<
AliasedSettings::CalcType>>, AliasedSettings>
{
public:
/// \brief Constructor.
......@@ -41,31 +36,10 @@ protected:
/// \return Plugin description.
const char* getDescription() const override;
/// \brief Returns plugin author.
/// \return Plugin author.
const char* getMaker() const override;
/// \brief Returns plugin home page.
/// \return Plugin home page.
const char* getHomePage() const override;
/// \brief Returns plugin license.
/// \return Plugin license.
const char* getLicense() const override;
/// \brief Returns plugin version.
/// \return Plugin version.
std::uint32_t getVersion() const override;
/// \brief Returns plugin unique id.
/// \return Plugin unique id.
std::int64_t getUniqueId() const override;
/// \brief Initializes plugin parameter.
/// \param[in] index Index of the parameter.
/// \param[out] parameter Parameter info.
void initParameter(std::uint32_t index, Parameter& parameter) override;
/// \brief Returns the value of the plugin parameter.
/// \param[in] index Index of the parameter.
/// \return Parameter value.
......@@ -75,38 +49,6 @@ protected:
/// \param[in] index Index of the parameter.
/// \param[in] value Value to set.
void setParameterValue(std::uint32_t index, float value) override;
/// \brief Activates the plugin.
void activate() override;
/// \brief Processes MIDI input and renders audio.
/// \param[out] outputs Array of output channels.
/// \param[in] frames Number of frames to process.
/// \param[in] midi_events MIDI events to process.
/// \param[in] midi_event_count Number of MIDI events to process.
void run(const float**, float** outputs, std::uint32_t frames,
const MidiEvent* midi_events, std::uint32_t midi_event_count)
override;
/// \brief Called when sample rate has changed.
/// \param[in] new_sample_rate Sample rate to set.
void sampleRateChanged(double new_sample_rate) override;
private:
/// \brief Type of the synth.
using Synth = ftz::Audio::PolyphonicSynth<ftz::Audio::OscillatorGenerator<
ftz::Audio::PulseWave<AliasedSettings::CalcType>>,
AliasedSettings::SampleFormat>;
ftz::MIDI::InputChannel channel; ///< Holds the MIDI channel.
/// \brief Holds synth settings.
ftz::Audio::SynthSettings<AliasedSettings::CalcType> settings;
Synth synth; ///< Holds the synth.
ftz::Audio::Pan<AliasedSettings::SampleFormat> pan; ///< Holds the pan.
/// \brief Holds the amplifier.
ftz::Audio::Amplifier<AliasedSettings::SampleFormat> amp;
/// \brief Holds the clamper.
ftz::Audio::Clamper<AliasedSettings::SampleFormat> clamp;
/// \brief Holds the effect chain.
ftz::Audio::EffectChain<AliasedSettings::SampleFormat> effects;
};
}
#pragma once
#define DISTRHO_PLUGIN_NAME "ftz Pulse bandlimited"
#define DISTRHO_PLUGIN_NUM_INPUTS 0
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
#define DISTRHO_PLUGIN_URI "https://ftz.lyberta.net/projects/chiptune/pulse_bandlimited.html"
#define DISTRHO_PLUGIN_IS_SYNTH 1
#!/usr/bin/make -f
# Makefile for DISTRHO Plugins #
# ---------------------------- #
# Created by falkTX
#
# --------------------------------------------------------------
# Project name, used for binaries
NAME = ftz_chiptune_pulse_bandlimited
# --------------------------------------------------------------
# Files to build
OBJS_DSP = \
Plugin.cpp.o \
../DPF/Utils.cpp.o
OBJS_UI =
# --------------------------------------------------------------
# Do some magic
include ../Makefile.mk
# --------------------------------------------------------------
# Enable all possible plugin types
ifeq ($(HAVE_JACK),true)
TARGETS += jack
endif
ifeq ($(LINUX),true)
TARGETS += dssi_dsp
ifeq ($(HAVE_DGL),true)
ifeq ($(HAVE_LIBLO),true)
TARGETS += dssi_ui
endif
endif
endif
ifeq ($(HAVE_DGL),true)
TARGETS += lv2_sep
else
TARGETS += lv2_dsp
endif
TARGETS += vst
all: $(TARGETS)
# --------------------------------------------------------------
/// \file
/// \brief Source file that contains implementation of the
/// BandlimitedPulsePlugin class.
/// \author Lyberta
/// \copyright GNU GPLv3 or any later version.
#include "Plugin.h"
namespace DISTRHO
{
BandlimitedPulsePlugin::BandlimitedPulsePlugin()
: PulsePluginTemplate<
ftz::Audio::BandlimitedPulseWave<BandlimitedSettings::CalcType>,
BandlimitedSettings>{{{}, {}}}
{
}
const char* BandlimitedPulsePlugin::getName() const
{
return "ftz Chiptune Pulse bandlimited";
}
const char* BandlimitedPulsePlugin::getLabel() const
{
return "ftz Chiptune Pulse bandlimited";
}
const char* BandlimitedPulsePlugin::getDescription() const
{
return "Pulse wave synth.";
}
std::int64_t BandlimitedPulsePlugin::getUniqueId() const
{
return d_cconst('F', 'C', 'T', '6');
}
float BandlimitedPulsePlugin::getParameterValue(std::uint32_t index) const
{
auto new_index = static_cast<PulseParameterIndex>(index);
if (new_index != PulseParameterIndex::DutyCycle)
{
return PulsePluginTemplate<ftz::Audio::BandlimitedPulseWave<
BandlimitedSettings::CalcType>, BandlimitedSettings>::
getParameterValue(index);
}
return synth.GetGeneratorSettings().GetDutyCycle();
}
void BandlimitedPulsePlugin::setParameterValue(std::uint32_t index, float value)
{
auto new_index = static_cast<PulseParameterIndex>(index);
if (new_index != PulseParameterIndex::DutyCycle)
{
PulsePluginTemplate<ftz::Audio::BandlimitedPulseWave<
BandlimitedSettings::CalcType>, BandlimitedSettings>::
setParameterValue(index, value);
return;
}
auto generator_settings = synth.GetGeneratorSettings();
generator_settings.SetDutyCycle(value);
synth.SetGeneratorSettings(std::move(generator_settings));
}
Plugin* createPlugin()
{
return new BandlimitedPulsePlugin{};
}
}
/// \file
/// \brief Header file that describes the BandlimitedPulsePlugin class.
/// \author Lyberta
/// \copyright GNU GPLv3 or any later version.
#pragma once
#include <ftz/Audio/PulseWave.h>
#include <ftz/Audio/OscillatorGenerator.h>
#include "../DPF/PulsePluginTemplate.h"
namespace DISTRHO
{
/// \brief An aliased pulse synth plugin.
/// \details This is a DPF wrapper of the aliased pulse synth.
class BandlimitedPulsePlugin final : public PulsePluginTemplate<
ftz::Audio::BandlimitedPulseWave<BandlimitedSettings::CalcType>,
BandlimitedSettings>
{
public:
/// \brief Constructor.
BandlimitedPulsePlugin();
protected:
/// \brief Returns plugin name.
/// \return Plugin name.
const char* getName() const override;
/// \brief Returns plugin label.
/// \return Plugin label.
const char* getLabel() const override;
/// \brief Returns plugin description.
/// \return Plugin description.
const char* getDescription() const override;
/// \brief Returns plugin unique id.
/// \return Plugin unique id.
std::int64_t getUniqueId() const override;
/// \brief Returns the value of the plugin parameter.
/// \param[in] index Index of the parameter.
/// \return Parameter value.
float getParameterValue(std::uint32_t index) const override;
/// \brief Sets the value of the plugin parameter.
/// \param[in] index Index of the parameter.
/// \param[in] value Value to set.
void setParameterValue(std::uint32_t index, float value) override;
};
}