OpenShot Library | libopenshot 0.3.2
Loading...
Searching...
No Matches
Compressor.cpp
Go to the documentation of this file.
1
9// Copyright (c) 2008-2019 OpenShot Studios, LLC
10//
11// SPDX-License-Identifier: LGPL-3.0-or-later
12
13#include "Compressor.h"
14#include "Exceptions.h"
15#include "Frame.h"
16
17using namespace openshot;
18
19Compressor::Compressor() : Compressor::Compressor(-10, 1, 1, 1, 1, false) {}
20
22 Keyframe release, Keyframe makeup_gain,
23 Keyframe bypass):
24 threshold(threshold), ratio(ratio), attack(attack),
25 release(release), makeup_gain(makeup_gain), bypass(bypass),
26 input_level(0.0), yl_prev(0.0)
27{
28 // Init effect properties
29 init_effect_details();
30}
31
32// Init effect settings
33void Compressor::init_effect_details()
34{
37
39 info.class_name = "Compressor";
40 info.name = "Compressor";
41 info.description = "Reduce the volume of loud sounds or amplify quiet sounds.";
42 info.has_audio = true;
43 info.has_video = false;
44}
45
46// This method is required for all derived classes of EffectBase, and returns a
47// modified openshot::Frame object
48std::shared_ptr<openshot::Frame> Compressor::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
49{
50 // Adding Compressor
51 const int num_input_channels = frame->audio->getNumChannels();
52 const int num_output_channels = frame->audio->getNumChannels();
53 const int num_samples = frame->audio->getNumSamples();
54
55 mixed_down_input.setSize(1, num_samples);
56 inverse_sample_rate = 1.0f / frame->SampleRate();
57 inverseE = 1.0f / M_E;
58
59 if ((bool)bypass.GetValue(frame_number))
60 return frame;
61
62 mixed_down_input.clear();
63
64 for (int channel = 0; channel < num_input_channels; ++channel)
65 mixed_down_input.addFrom(0, 0, *frame->audio, channel, 0, num_samples, 1.0f / num_input_channels);
66
67 for (int sample = 0; sample < num_samples; ++sample) {
68 float T = threshold.GetValue(frame_number);
69 float R = ratio.GetValue(frame_number);
70 float alphaA = calculateAttackOrRelease(attack.GetValue(frame_number));
71 float alphaR = calculateAttackOrRelease(release.GetValue(frame_number));
72 float gain = makeup_gain.GetValue(frame_number);
73 float input_squared = powf(mixed_down_input.getSample(0, sample), 2.0f);
74
75 input_level = input_squared;
76
77 xg = (input_level <= 1e-6f) ? -60.0f : 10.0f * log10f(input_level);
78
79 if (xg < T)
80 yg = xg;
81 else
82 yg = T + (xg - T) / R;
83
84 xl = xg - yg;
85
86 if (xl > yl_prev)
87 yl = alphaA * yl_prev + (1.0f - alphaA) * xl;
88 else
89 yl = alphaR * yl_prev + (1.0f - alphaR) * xl;
90
91 control = powf (10.0f, (gain - yl) * 0.05f);
92 yl_prev = yl;
93
94 for (int channel = 0; channel < num_input_channels; ++channel) {
95 float new_value = frame->audio->getSample(channel, sample)*control;
96 frame->audio->setSample(channel, sample, new_value);
97 }
98 }
99
100 for (int channel = num_input_channels; channel < num_output_channels; ++channel)
101 frame->audio->clear(channel, 0, num_samples);
102
103 // return the modified frame
104 return frame;
105}
106
108{
109 if (value == 0.0f)
110 return 0.0f;
111 else
112 return pow (inverseE, inverse_sample_rate / value);
113}
114
115// Generate JSON string of this object
116std::string Compressor::Json() const {
117
118 // Return formatted string
119 return JsonValue().toStyledString();
120}
121
122// Generate Json::Value for this object
123Json::Value Compressor::JsonValue() const {
124
125 // Create root json object
126 Json::Value root = EffectBase::JsonValue(); // get parent properties
127 root["type"] = info.class_name;
128 root["threshold"] = threshold.JsonValue();
129 root["ratio"] = ratio.JsonValue();
130 root["attack"] = attack.JsonValue();
131 root["release"] = release.JsonValue();
132 root["makeup_gain"] = makeup_gain.JsonValue();
133 root["bypass"] = bypass.JsonValue();
134
135 // return JsonValue
136 return root;
137}
138
139// Load JSON string into this object
140void Compressor::SetJson(const std::string value) {
141
142 // Parse JSON string into JSON objects
143 try
144 {
145 const Json::Value root = openshot::stringToJson(value);
146 // Set all values that match
147 SetJsonValue(root);
148 }
149 catch (const std::exception& e)
150 {
151 // Error parsing JSON (or missing keys)
152 throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
153 }
154}
155
156// Load Json::Value into this object
157void Compressor::SetJsonValue(const Json::Value root) {
158
159 // Set parent data
161
162 // Set data from Json (if key is found)
163 if (!root["threshold"].isNull())
164 threshold.SetJsonValue(root["threshold"]);
165
166 if (!root["ratio"].isNull())
167 ratio.SetJsonValue(root["ratio"]);
168
169 if (!root["attack"].isNull())
170 attack.SetJsonValue(root["attack"]);
171
172 if (!root["release"].isNull())
173 release.SetJsonValue(root["release"]);
174
175 if (!root["makeup_gain"].isNull())
176 makeup_gain.SetJsonValue(root["makeup_gain"]);
177
178 if (!root["bypass"].isNull())
179 bypass.SetJsonValue(root["bypass"]);
180}
181
182// Get all properties for a specific frame
183std::string Compressor::PropertiesJSON(int64_t requested_frame) const {
184
185 // Generate JSON properties list
186 Json::Value root;
187 root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame);
188 root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame);
189 root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
190 root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
191 root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame);
192
193 // Keyframes
194 root["threshold"] = add_property_json("Threshold (dB)", threshold.GetValue(requested_frame), "float", "", &threshold, -60, 0, false, requested_frame);
195 root["ratio"] = add_property_json("Ratio", ratio.GetValue(requested_frame), "float", "", &ratio, 1, 100, false, requested_frame);
196 root["attack"] = add_property_json("Attack (ms)", attack.GetValue(requested_frame), "float", "", &attack, 0.1, 100, false, requested_frame);
197 root["release"] = add_property_json("Release (ms)", release.GetValue(requested_frame), "float", "", &release, 10, 1000, false, requested_frame);
198 root["makeup_gain"] = add_property_json("Makeup gain (dB)", makeup_gain.GetValue(requested_frame), "float", "", &makeup_gain, -12, 12, false, requested_frame);
199 root["bypass"] = add_property_json("Bypass", bypass.GetValue(requested_frame), "bool", "", &bypass, 0, 1, false, requested_frame);
200
201 // Return formatted string
202 return root.toStyledString();
203}
Header file for Compressor audio effect class.
Header file for all Exception classes.
Header file for Frame class.
float Start() const
Get start position (in seconds) of clip (trim start of video)
Definition: ClipBase.h:88
float Duration() const
Get the length of this clip (in seconds)
Definition: ClipBase.h:90
virtual float End() const
Get end position (in seconds) of clip (trim end of video)
Definition: ClipBase.h:89
std::string Id() const
Get the Id of this clip object.
Definition: ClipBase.h:85
int Layer() const
Get layer of clip on timeline (lower number is covered by higher numbers)
Definition: ClipBase.h:87
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
This class adds a compressor into the audio.
Definition: Compressor.h:36
std::string PropertiesJSON(int64_t requested_frame) const override
Definition: Compressor.cpp:183
Keyframe makeup_gain
Definition: Compressor.h:47
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: Compressor.h:72
Compressor()
Default constructor.
Definition: Compressor.cpp:19
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: Compressor.cpp:123
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition: Compressor.cpp:157
juce::AudioBuffer< float > mixed_down_input
Definition: Compressor.h:50
void SetJson(const std::string value) override
Load JSON string into this object.
Definition: Compressor.cpp:140
std::string Json() const override
Generate JSON string of this object.
Definition: Compressor.cpp:116
float calculateAttackOrRelease(float value)
Definition: Compressor.cpp:107
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: EffectBase.cpp:77
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: EffectBase.cpp:112
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:69
Exception for invalid JSON.
Definition: Exceptions.h:218
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition: KeyFrame.h:54
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:358
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:325
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:29
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:40
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:41
std::string class_name
The class name of the effect.
Definition: EffectBase.h:36
std::string name
The name of the effect.
Definition: EffectBase.h:37
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:38