Loading...
Searching...
No Matches
ParametricEQ.cpp
Go to the documentation of this file.
// Copyright (c) 2008-2019 OpenShot Studios, LLC
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "ParametricEQ.h"
#include "Exceptions.h"
using namespace openshot;
using namespace juce;
ParametricEQ::ParametricEQ(): ParametricEQ::ParametricEQ(LOW_PASS, 500, 0, 0) {}
ParametricEQ::ParametricEQ(openshot::FilterType filter_type,
Keyframe frequency, Keyframe gain, Keyframe q_factor) :
filter_type(filter_type),
frequency(frequency), gain(gain), q_factor(q_factor)
{
// Init effect properties
init_effect_details();
}
// Init effect settings
void ParametricEQ::init_effect_details()
{
InitEffectInfo();
info.class_name = "ParametricEQ";
info.name = "Parametric EQ";
info.description = "Filter that allows you to adjust the volume level of a frequency in the audio track.";
info.has_audio = true;
info.has_video = false;
initialized = false;
}
// This method is required for all derived classes of EffectBase, and returns a
// modified openshot::Frame object
std::shared_ptr<openshot::Frame> ParametricEQ::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
{
if (!initialized)
{
filters.clear();
for (int i = 0; i < frame->audio->getNumChannels(); ++i) {
Filter *filter;
filters.add(filter = new Filter());
}
initialized = true;
}
const int num_input_channels = frame->audio->getNumChannels();
const int num_output_channels = frame->audio->getNumChannels();
const int num_samples = frame->audio->getNumSamples();
updateFilters(frame_number, num_samples);
for (int channel = 0; channel < frame->audio->getNumChannels(); channel++)
{
auto *channel_data = frame->audio->getWritePointer(channel);
filters[channel]->processSamples(channel_data, num_samples);
}
for (int channel = num_input_channels; channel < num_output_channels; ++channel)
{
frame->audio->clear(channel, 0, num_samples);
}
// return the modified frame
return frame;
}
void ParametricEQ::Filter::updateCoefficients (
const double discrete_frequency,
const double q_factor,
const double gain,
const int filter_type)
{
double bandwidth = jmin (discrete_frequency / q_factor, M_PI * 0.99);
double two_cos_wc = -2.0 * cos (discrete_frequency);
double tan_half_bw = tan (bandwidth / 2.0);
double tan_half_wc = tan (discrete_frequency / 2.0);
double sqrt_gain = sqrt (gain);
switch (filter_type) {
case 0 /* LOW_PASS */: {
coefficients = IIRCoefficients (/* b0 */ tan_half_wc,
/* b1 */ tan_half_wc,
/* b2 */ 0.0,
/* a0 */ tan_half_wc + 1.0,
/* a1 */ tan_half_wc - 1.0,
/* a2 */ 0.0);
break;
}
case 1 /* HIGH_PASS */: {
coefficients = IIRCoefficients (/* b0 */ 1.0,
/* b1 */ -1.0,
/* b2 */ 0.0,
/* a0 */ tan_half_wc + 1.0,
/* a1 */ tan_half_wc - 1.0,
/* a2 */ 0.0);
break;
}
case 2 /* LOW_SHELF */: {
coefficients = IIRCoefficients (/* b0 */ gain * tan_half_wc + sqrt_gain,
/* b1 */ gain * tan_half_wc - sqrt_gain,
/* b2 */ 0.0,
/* a0 */ tan_half_wc + sqrt_gain,
/* a1 */ tan_half_wc - sqrt_gain,
/* a2 */ 0.0);
break;
}
case 3 /* HIGH_SHELF */: {
coefficients = IIRCoefficients (/* b0 */ sqrt_gain * tan_half_wc + gain,
/* b1 */ sqrt_gain * tan_half_wc - gain,
/* b2 */ 0.0,
/* a0 */ sqrt_gain * tan_half_wc + 1.0,
/* a1 */ sqrt_gain * tan_half_wc - 1.0,
/* a2 */ 0.0);
break;
}
case 4 /* BAND_PASS */: {
coefficients = IIRCoefficients (/* b0 */ tan_half_bw,
/* b1 */ 0.0,
/* b2 */ -tan_half_bw,
/* a0 */ 1.0 + tan_half_bw,
/* a1 */ two_cos_wc,
/* a2 */ 1.0 - tan_half_bw);
break;
}
case 5 /* BAND_STOP */: {
coefficients = IIRCoefficients (/* b0 */ 1.0,
/* b1 */ two_cos_wc,
/* b2 */ 1.0,
/* a0 */ 1.0 + tan_half_bw,
/* a1 */ two_cos_wc,
/* a2 */ 1.0 - tan_half_bw);
break;
}
case 6 /* PEAKING_NOTCH */: {
coefficients = IIRCoefficients (/* b0 */ sqrt_gain + gain * tan_half_bw,
/* b1 */ sqrt_gain * two_cos_wc,
/* b2 */ sqrt_gain - gain * tan_half_bw,
/* a0 */ sqrt_gain + tan_half_bw,
/* a1 */ sqrt_gain * two_cos_wc,
/* a2 */ sqrt_gain - tan_half_bw);
break;
}
}
setCoefficients(coefficients);
}
void ParametricEQ::updateFilters(int64_t frame_number, double sample_rate)
{
double discrete_frequency = 2.0 * M_PI * (double)frequency.GetValue(frame_number) / sample_rate;
double q_value = (double)q_factor.GetValue(frame_number);
double gain_value = pow(10.0, (double)gain.GetValue(frame_number) * 0.05);
int filter_type_value = (int)filter_type;
for (int i = 0; i < filters.size(); ++i)
filters[i]->updateCoefficients(discrete_frequency, q_value, gain_value, filter_type_value);
}
// Generate JSON string of this object
std::string ParametricEQ::Json() const {
// Return formatted string
return JsonValue().toStyledString();
}
// Generate Json::Value for this object
Json::Value ParametricEQ::JsonValue() const {
// Create root json object
Json::Value root = EffectBase::JsonValue(); // get parent properties
root["type"] = info.class_name;
root["filter_type"] = filter_type;
root["frequency"] = frequency.JsonValue();;
root["q_factor"] = q_factor.JsonValue();
root["gain"] = gain.JsonValue();
// return JsonValue
return root;
}
// Load JSON string into this object
void ParametricEQ::SetJson(const std::string value) {
// Parse JSON string into JSON objects
try
{
const Json::Value root = openshot::stringToJson(value);
// Set all values that match
SetJsonValue(root);
}
catch (const std::exception& e)
{
// Error parsing JSON (or missing keys)
throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
}
}
// Load Json::Value into this object
void ParametricEQ::SetJsonValue(const Json::Value root) {
// Set parent data
EffectBase::SetJsonValue(root);
// Set data from Json (if key is found)
if (!root["filter_type"].isNull())
filter_type = (FilterType)root["filter_type"].asInt();
if (!root["frequency"].isNull())
frequency.SetJsonValue(root["frequency"]);
if (!root["gain"].isNull())
gain.SetJsonValue(root["gain"]);
if (!root["q_factor"].isNull())
q_factor.SetJsonValue(root["q_factor"]);
}
// Get all properties for a specific frame
std::string ParametricEQ::PropertiesJSON(int64_t requested_frame) const {
// Generate JSON properties list
Json::Value root = BasePropertiesJSON(requested_frame);
// Keyframes
root["filter_type"] = add_property_json("Filter Type", filter_type, "int", "", NULL, 0, 3, false, requested_frame);
root["frequency"] = add_property_json("Frequency (Hz)", frequency.GetValue(requested_frame), "int", "", &frequency, 20, 20000, false, requested_frame);
root["gain"] = add_property_json("Gain (dB)", gain.GetValue(requested_frame), "int", "", &gain, -24, 24, false, requested_frame);
root["q_factor"] = add_property_json("Q Factor", q_factor.GetValue(requested_frame), "float", "", &q_factor, 0, 20, false, requested_frame);
// Add filter_type choices (dropdown style)
root["filter_type"]["choices"].append(add_property_choice_json("Low Pass", LOW_PASS, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("High Pass", HIGH_PASS, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("Low Shelf", LOW_SHELF, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("High Shelf", HIGH_SHELF, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("Band Pass", BAND_PASS, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("Band Stop", BAND_STOP, filter_type));
root["filter_type"]["choices"].append(add_property_choice_json("Peaking Notch", PEAKING_NOTCH, filter_type));
// Return formatted string
return root.toStyledString();
}
Exceptions.h
Header file for all Exception classes.
ParametricEQ.h
Header file for Parametric EQ audio effect class.
openshot::ClipBase::add_property_choice_json
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
Definition ClipBase.cpp:132
openshot::ClipBase::add_property_json
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const
Generate JSON for a property.
Definition ClipBase.cpp:96
openshot::EffectBase::JsonValue
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Definition EffectBase.cpp:79
openshot::EffectBase::InitEffectInfo
void InitEffectInfo()
Definition EffectBase.cpp:24
openshot::EffectBase::BasePropertiesJSON
Json::Value BasePropertiesJSON(int64_t requested_frame) const
Generate JSON object of base properties (recommended to be used by all effects)
Definition EffectBase.cpp:179
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition EffectBase.cpp:115
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition EffectBase.h:69
openshot::InvalidJSON
Exception for invalid JSON.
Definition Exceptions.h:218
openshot::Keyframe
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition KeyFrame.h:53
openshot::Keyframe::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition KeyFrame.cpp:372
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition KeyFrame.cpp:258
openshot::Keyframe::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition KeyFrame.cpp:339
openshot::ParametricEQ::Filter
Definition ParametricEQ.h:73
openshot::ParametricEQ::Filter::updateCoefficients
void updateCoefficients(const double discrete_frequency, const double q_factor, const double gain, const int filter_type)
Definition ParametricEQ.cpp:81
openshot::ParametricEQ
This class adds a equalization into the audio.
Definition ParametricEQ.h:38
openshot::ParametricEQ::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition ParametricEQ.cpp:233
openshot::ParametricEQ::q_factor
Keyframe q_factor
Definition ParametricEQ.h:46
openshot::ParametricEQ::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition ParametricEQ.cpp:196
openshot::ParametricEQ::ParametricEQ
ParametricEQ()
Blank constructor, useful when using Json to load the effect properties.
Definition ParametricEQ.cpp:19
openshot::ParametricEQ::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
This method is required for all derived classes of ClipBase, and returns a new openshot::Frame object...
Definition ParametricEQ.h:57
openshot::ParametricEQ::Json
std::string Json() const override
Generate JSON string of this object.
Definition ParametricEQ.cpp:174
openshot::ParametricEQ::initialized
bool initialized
Definition ParametricEQ.h:48
openshot::ParametricEQ::updateFilters
void updateFilters(int64_t frame_number, double sample_rate)
Definition ParametricEQ.cpp:162
openshot::ParametricEQ::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition ParametricEQ.cpp:213
openshot::ParametricEQ::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition ParametricEQ.cpp:181
openshot::ParametricEQ::frequency
Keyframe frequency
Definition ParametricEQ.h:45
openshot::ParametricEQ::gain
Keyframe gain
Definition ParametricEQ.h:47
openshot::ParametricEQ::filter_type
openshot::FilterType filter_type
Definition ParametricEQ.h:44
openshot::ParametricEQ::filters
juce::OwnedArray< Filter > filters
Definition ParametricEQ.h:81
juce
Definition Robotization.h:29
openshot
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29
openshot::FilterType
FilterType
This enumeration determines the filter type of ParametricEQ Effect.
Definition Enums.h:80
openshot::LOW_SHELF
@ LOW_SHELF
Definition Enums.h:83
openshot::HIGH_SHELF
@ HIGH_SHELF
Definition Enums.h:84
openshot::BAND_PASS
@ BAND_PASS
Definition Enums.h:85
openshot::BAND_STOP
@ BAND_STOP
Definition Enums.h:86
openshot::LOW_PASS
@ LOW_PASS
Definition Enums.h:81
openshot::HIGH_PASS
@ HIGH_PASS
Definition Enums.h:82
openshot::PEAKING_NOTCH
@ PEAKING_NOTCH
Definition Enums.h:87
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition Json.cpp:16
openshot::EffectInfoStruct::has_video
bool has_video
Determines if this effect manipulates the image of a frame.
Definition EffectBase.h:40
openshot::EffectInfoStruct::has_audio
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition EffectBase.h:41
openshot::EffectInfoStruct::class_name
std::string class_name
The class name of the effect.
Definition EffectBase.h:36
openshot::EffectInfoStruct::name
std::string name
The name of the effect.
Definition EffectBase.h:37
openshot::EffectInfoStruct::description
std::string description
The description of this effect and what it does.
Definition EffectBase.h:38