8f70e467b68ced465f7f88b430f0f3546532df9d
[goodguy/history.git] / cinelerra-5.1 / plugins / level / leveleffect.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filesystem.h"
26 #include "filexml.h"
27 #include "language.h"
28 #include "leveleffect.h"
29 #include "samples.h"
30 #include "units.h"
31 #include "vframe.h"
32
33 #include <errno.h>
34 #include <math.h>
35 #include <string.h>
36 #include <unistd.h>
37
38
39
40
41
42
43
44
45
46
47 REGISTER_PLUGIN(SoundLevelEffect)
48
49
50
51
52
53
54
55
56
57 SoundLevelConfig::SoundLevelConfig()
58 {
59         duration = 1.0;
60 }
61
62 void SoundLevelConfig::copy_from(SoundLevelConfig &that)
63 {
64         duration = that.duration;
65 }
66
67 int SoundLevelConfig::equivalent(SoundLevelConfig &that)
68 {
69         return EQUIV(duration, that.duration);
70 }
71
72 void SoundLevelConfig::interpolate(SoundLevelConfig &prev,
73         SoundLevelConfig &next,
74         int64_t prev_frame,
75         int64_t next_frame,
76         int64_t current_frame)
77 {
78         duration = prev.duration;
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 SoundLevelDuration::SoundLevelDuration(SoundLevelEffect *plugin, int x, int y)
96  : BC_FSlider(x, y, 0, 180, 180, 0.0, 10.0, plugin->config.duration)
97 {
98         this->plugin = plugin;
99         set_precision(0.1);
100 }
101
102 int SoundLevelDuration::handle_event()
103 {
104         plugin->config.duration = get_value();
105         plugin->send_configure_change();
106         return 1;
107 }
108
109
110
111 SoundLevelWindow::SoundLevelWindow(SoundLevelEffect *plugin)
112  : PluginClientWindow(plugin,
113         350,
114         120,
115         350,
116         120,
117         0)
118 {
119         this->plugin = plugin;
120 }
121
122 void SoundLevelWindow::create_objects()
123 {
124 //printf("SoundLevelWindow::create_objects 1\n");
125         int x = 10, y = 10;
126
127
128         add_subwindow(new BC_Title(x, y, _("Duration (seconds):")));
129         add_subwindow(duration = new SoundLevelDuration(plugin, x + 150, y));
130         y += 35;
131         add_subwindow(new BC_Title(x, y, _("Max soundlevel (dB):")));
132         add_subwindow(soundlevel_max = new BC_Title(x + 150, y, "0.0"));
133         y += 35;
134         add_subwindow(new BC_Title(x, y, _("RMS soundlevel (dB):")));
135         add_subwindow(soundlevel_rms = new BC_Title(x + 150, y, "0.0"));
136
137         show_window();
138         flush();
139 //printf("SoundLevelWindow::create_objects 2\n");
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 SoundLevelEffect::SoundLevelEffect(PluginServer *server)
171  : PluginAClient(server)
172 {
173
174         reset();
175 }
176
177 SoundLevelEffect::~SoundLevelEffect()
178 {
179
180 }
181
182
183 LOAD_CONFIGURATION_MACRO(SoundLevelEffect, SoundLevelConfig)
184
185 NEW_WINDOW_MACRO(SoundLevelEffect, SoundLevelWindow)
186
187
188
189 void SoundLevelEffect::reset()
190 {
191         rms_accum = 0;
192         max_accum = 0;
193         accum_size = 0;
194 }
195
196 const char* SoundLevelEffect::plugin_title() { return N_("SoundLevel"); }
197 int SoundLevelEffect::is_realtime() { return 1; }
198
199
200 void SoundLevelEffect::read_data(KeyFrame *keyframe)
201 {
202         FileXML input;
203         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
204
205         int result = 0;
206         while(!result)
207         {
208                 result = input.read_tag();
209
210                 if(!result)
211                 {
212                         if(input.tag.title_is("SOUNDLEVEL"))
213                         {
214                                 config.duration = input.tag.get_property("DURATION", config.duration);
215                         }
216                 }
217         }
218 }
219
220 void SoundLevelEffect::save_data(KeyFrame *keyframe)
221 {
222         FileXML output;
223         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
224
225         output.tag.set_title("SOUNDLEVEL");
226         output.tag.set_property("DURATION", config.duration);
227         output.append_tag();
228         output.tag.set_title("/SOUNDLEVEL");
229         output.append_tag();
230         output.append_newline();
231         output.terminate_string();
232 }
233
234
235 void SoundLevelEffect::update_gui()
236 {
237 //printf("SoundLevelEffect::update_gui 1\n");
238         if(thread)
239         {
240                 load_configuration();
241                 thread->window->lock_window();
242                 ((SoundLevelWindow*)thread->window)->duration->update(config.duration);
243                 thread->window->unlock_window();
244         }
245 //printf("SoundLevelEffect::update_gui 2\n");
246 }
247
248 int SoundLevelEffect::process_realtime(int64_t size, Samples *input_ptr, Samples *output_ptr)
249 {
250         load_configuration();
251
252         accum_size += size;
253         double *input_samples = input_ptr->get_data();
254         for(int i = 0; i < size; i++)
255         {
256                 double value = fabs(input_samples[i]);
257                 if(value > max_accum) max_accum = value;
258                 rms_accum += value * value;
259         }
260
261         if(accum_size > config.duration * PluginAClient::project_sample_rate)
262         {
263 //printf("SoundLevelEffect::process_realtime 1 %f %d\n", rms_accum, accum_size);
264                 rms_accum = sqrt(rms_accum / accum_size);
265                 double arg[2];
266                 arg[0] = max_accum;
267                 arg[1] = rms_accum;
268                 send_render_gui(arg, 2);
269                 rms_accum = 0;
270                 max_accum = 0;
271                 accum_size = 0;
272         }
273         return 0;
274 }
275
276 void SoundLevelEffect::render_gui(void *data, int size)
277 {
278         if(thread)
279         {
280                 thread->window->lock_window();
281                 char string[BCTEXTLEN];
282                 double *arg = (double*)data;
283                 sprintf(string, "%.2f", DB::todb(arg[0]));
284                 ((SoundLevelWindow*)thread->window)->soundlevel_max->update(string);
285                 sprintf(string, "%.2f", DB::todb(arg[1]));
286                 ((SoundLevelWindow*)thread->window)->soundlevel_rms->update(string);
287                 thread->window->flush();
288                 thread->window->unlock_window();
289         }
290 }