Credit Andrew for build mods and cineform format
[goodguy/cinelerra.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 "transportque.inc"
31 #include "units.h"
32 #include "vframe.h"
33
34 #include <errno.h>
35 #include <math.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 REGISTER_PLUGIN(SoundLevelEffect)
40
41
42 SoundLevelConfig::SoundLevelConfig()
43 {
44         duration = 1.0;
45 }
46
47 void SoundLevelConfig::copy_from(SoundLevelConfig &that)
48 {
49         duration = that.duration;
50 }
51
52 int SoundLevelConfig::equivalent(SoundLevelConfig &that)
53 {
54         return EQUIV(duration, that.duration);
55 }
56
57 void SoundLevelConfig::interpolate(SoundLevelConfig &prev, SoundLevelConfig &next,
58         int64_t prev_frame, int64_t next_frame, int64_t current_frame)
59 {
60         duration = prev.duration;
61 }
62
63
64 SoundLevelDuration::SoundLevelDuration(SoundLevelEffect *plugin, int x, int y)
65  : BC_FSlider(x, y, 0, xS(180), yS(180), 0.0, 10.0, plugin->config.duration)
66 {
67         this->plugin = plugin;
68         set_precision(0.1);
69 }
70
71 int SoundLevelDuration::handle_event()
72 {
73         plugin->config.duration = get_value();
74         plugin->send_configure_change();
75         return 1;
76 }
77
78
79 SoundLevelWindow::SoundLevelWindow(SoundLevelEffect *plugin)
80  : PluginClientWindow(plugin, xS(350), yS(120), xS(350), yS(120), 0)
81 {
82         this->plugin = plugin;
83 }
84
85 void SoundLevelWindow::create_objects()
86 {
87         int xs10 = xS(10), xs150 = xS(150);
88         int ys10 = yS(10), ys35 = yS(35);
89 //printf("SoundLevelWindow::create_objects 1\n");
90         int x = xs10, y = ys10;
91
92
93         add_subwindow(new BC_Title(x, y, _("Duration (seconds):")));
94         add_subwindow(duration = new SoundLevelDuration(plugin, x + xs150, y));
95         y += ys35;
96         add_subwindow(new BC_Title(x, y, _("Max soundlevel (dB):")));
97         add_subwindow(soundlevel_max = new BC_Title(x + xs150, y, "0.0"));
98         y += ys35;
99         add_subwindow(new BC_Title(x, y, _("RMS soundlevel (dB):")));
100         add_subwindow(soundlevel_rms = new BC_Title(x + xs150, y, "0.0"));
101
102         show_window();
103         flush();
104 //printf("SoundLevelWindow::create_objects 2\n");
105 }
106
107
108 SoundLevelEffect::SoundLevelEffect(PluginServer *server)
109  : PluginAClient(server)
110 {
111
112         reset();
113 }
114
115 SoundLevelEffect::~SoundLevelEffect()
116 {
117
118 }
119
120
121 LOAD_CONFIGURATION_MACRO(SoundLevelEffect, SoundLevelConfig)
122
123 NEW_WINDOW_MACRO(SoundLevelEffect, SoundLevelWindow)
124
125
126
127 void SoundLevelEffect::reset()
128 {
129         rms_accum = 0;
130         max_accum = 0;
131         accum_size = 0;
132 }
133
134 const char* SoundLevelEffect::plugin_title() { return N_("SoundLevel"); }
135 int SoundLevelEffect::is_realtime() { return 1; }
136
137
138 void SoundLevelEffect::read_data(KeyFrame *keyframe)
139 {
140         FileXML input;
141         input.set_shared_input(keyframe->xbuf);
142
143         int result = 0;
144         while( !(result = input.read_tag()) ) {
145                 if( input.tag.title_is("SOUNDLEVEL") ) {
146                         config.duration = input.tag.get_property("DURATION", config.duration);
147                 }
148         }
149 }
150
151 void SoundLevelEffect::save_data(KeyFrame *keyframe)
152 {
153         FileXML output;
154         output.set_shared_output(keyframe->xbuf);
155
156         output.tag.set_title("SOUNDLEVEL");
157         output.tag.set_property("DURATION", config.duration);
158         output.append_tag();
159         output.tag.set_title("/SOUNDLEVEL");
160         output.append_tag();
161         output.append_newline();
162         output.terminate_string();
163 }
164
165
166 void SoundLevelEffect::update_gui()
167 {
168         if( !thread ) return;
169         SoundLevelWindow *window = (SoundLevelWindow*)thread->window;
170         if( !window ) return;
171         int reconfigure = load_configuration();
172         int pending = pending_gui_frame();
173         if( !reconfigure && !pending ) return;
174         window->lock_window();
175         if( reconfigure ) {
176                 window->duration->update(config.duration);
177         }
178         if( pending ) {
179                 double pos = get_tracking_position();
180                 double dir = get_tracking_direction() == PLAY_REVERSE ? -1 : 1;
181                 SoundLevelClientFrame *frame =
182                         (SoundLevelClientFrame *)get_gui_frame(pos, dir);
183                 char string[BCSTRLEN];
184                 sprintf(string, "%.2f", DB::todb(frame->max));
185                 window->soundlevel_max->update(string);
186                 sprintf(string, "%.2f", DB::todb(frame->rms));
187                 window->soundlevel_rms->update(string);
188         }
189         window->unlock_window();
190 }
191
192 int SoundLevelEffect::process_realtime(int64_t size, Samples *input_ptr, Samples *output_ptr)
193 {
194         load_configuration();
195
196         int sample_rate = get_project_samplerate();
197         int fragment = config.duration * sample_rate;
198         int64_t position = get_source_position();
199         accum_size += size;
200         double *input_samples = input_ptr->get_data();
201         for( int i=0; i<size; ++i ) {
202                 double value = fabs(input_samples[i]);
203                 if(value > max_accum) max_accum = value;
204                 rms_accum += value * value;
205                 if( ++accum_size >= fragment ) {
206                         rms_accum = sqrt(rms_accum / accum_size);
207                         SoundLevelClientFrame *level_frame = new SoundLevelClientFrame();
208                         level_frame->max = max_accum;
209                         level_frame->rms = rms_accum;
210                         level_frame->position = (double)(position+i)/get_project_samplerate();
211                         add_gui_frame(level_frame);
212                         rms_accum = 0;
213                         max_accum = 0;
214                         accum_size = 0;
215                 }
216         }
217         return 0;
218 }
219
220 void SoundLevelEffect::render_gui(void *data, int size)
221 {
222         if( !thread ) return;
223         SoundLevelWindow *window = (SoundLevelWindow*)thread->window;
224         if( !window ) return;
225         window->lock_window();
226         char string[BCTEXTLEN];
227         double *arg = (double*)data;
228         sprintf(string, "%.2f", DB::todb(arg[0]));
229         window->soundlevel_max->update(string);
230         sprintf(string, "%.2f", DB::todb(arg[1]));
231         window->soundlevel_rms->update(string);
232         window->flush();
233         window->unlock_window();
234 }
235
236 void SoundLevelEffect::render_stop()
237 {
238         rms_accum = 0;
239         max_accum = 0;
240         accum_size = 0;
241 }
242