OpenShot Library | libopenshot  0.3.2
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 
17 using namespace openshot;
18 
19 Compressor::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
33 void 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
48 std::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
116 std::string Compressor::Json() const {
117 
118  // Return formatted string
119  return JsonValue().toStyledString();
120 }
121 
122 // Generate Json::Value for this object
123 Json::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
140 void 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
157 void 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
183 std::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
Compressor()
Default constructor.
Definition: Compressor.cpp:19
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
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:53
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:372
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:339
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