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