Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / spectrogram / spectrogram.C
blob17f661d2a7cf473d6906c3ce8777fe9ec720bcb2
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "bchash.h"
4 #include "filexml.h"
5 #include "language.h"
6 #include "picon_png.h"
7 #include "spectrogram.h"
8 #include "units.h"
9 #include "vframe.h"
12 #include <string.h>
16 REGISTER_PLUGIN(Spectrogram)
18 #define WINDOW_SIZE 4096
19 #define HALF_WINDOW 2048
22 SpectrogramConfig::SpectrogramConfig()
24         level = 0.0;
33 SpectrogramLevel::SpectrogramLevel(Spectrogram *plugin, int x, int y)
34  : BC_FPot(x, y, plugin->config.level, INFINITYGAIN, 0)
36         this->plugin = plugin;
39 int SpectrogramLevel::handle_event()
41         plugin->config.level = get_value();
42         plugin->send_configure_change();
43         return 1;
56 SpectrogramWindow::SpectrogramWindow(Spectrogram *plugin, int x, int y)
57  : BC_Window(plugin->gui_string, 
58         x, 
59         y, 
60         640, 
61         480, 
62         640, 
63         480,
64         0, 
65         0,
66         1)
68         this->plugin = plugin;
71 SpectrogramWindow::~SpectrogramWindow()
75 void SpectrogramWindow::create_objects()
77         int x = 60, y = 10;
78         int divisions = 5;
79         char string[BCTEXTLEN];
81         add_subwindow(canvas = new BC_SubWindow(x, 
82                 y, 
83                 get_w() - x - 10, 
84                 get_h() - 50 - y,
85                 BLACK));
86         x = 10;
88         for(int i = 0; i <= divisions; i++)
89         {
90                 y = (int)((float)(canvas->get_h() - 10) / divisions * i) + 10;
91                 sprintf(string, "%d", 
92                         Freq::tofreq((int)((float)TOTALFREQS / divisions * (divisions - i))));
93                 add_subwindow(new BC_Title(x, y, string));
94         }
96         x = canvas->get_x();
97         y = canvas->get_y() + canvas->get_h() + 5;
99         add_subwindow(new BC_Title(x, y + 10, _("Level:")));
100         add_subwindow(level = new SpectrogramLevel(plugin, x + 50, y));
102         show_window();
103         flush();
106 WINDOW_CLOSE_EVENT(SpectrogramWindow)
109 void SpectrogramWindow::update_gui()
111         level->update(plugin->config.level);
123 PLUGIN_THREAD_OBJECT(Spectrogram, SpectrogramThread, SpectrogramWindow)
133 SpectrogramFFT::SpectrogramFFT(Spectrogram *plugin)
134  : CrossfadeFFT()
136         this->plugin = plugin;
139 SpectrogramFFT::~SpectrogramFFT()
144 int SpectrogramFFT::signal_process()
146         double level = DB::fromdb(plugin->config.level);
147         for(int i = 0; i < HALF_WINDOW; i++)
148         {
149                 plugin->data[i] += level *
150                         sqrt(freq_real[i] * freq_real[i] + 
151                                 freq_imag[i] * freq_imag[i]);
152         }
154         plugin->total_windows++;
155         return 0;
158 int SpectrogramFFT::read_samples(int64_t output_sample, 
159         int samples, 
160         double *buffer)
162         return plugin->read_samples(buffer,
163                 0,
164                 plugin->get_samplerate(),
165                 output_sample,
166                 samples);
177 Spectrogram::Spectrogram(PluginServer *server)
178  : PluginAClient(server)
180         reset();
181         PLUGIN_CONSTRUCTOR_MACRO
184 Spectrogram::~Spectrogram()
186         PLUGIN_DESTRUCTOR_MACRO
188         if(fft) delete fft;
189         if(data) delete [] data;
193 void Spectrogram::reset()
195         thread = 0;
196         fft = 0;
197         done = 0;
198         data = 0;
202 char* Spectrogram::plugin_title() { return N_("Spectrogram"); }
203 int Spectrogram::is_realtime() { return 1; }
205 int Spectrogram::process_buffer(int64_t size, 
206                 double *buffer,
207                 int64_t start_position,
208                 int sample_rate)
210         load_configuration();
211         if(!fft)
212         {
213                 fft = new SpectrogramFFT(this);
214                 fft->initialize(WINDOW_SIZE);
215         }
216         if(!data)
217         {
218                 data = new float[HALF_WINDOW];
219         }
221         bzero(data, sizeof(float) * HALF_WINDOW);
222         total_windows = 0;
223         fft->process_buffer(start_position,
224                 size, 
225                 buffer,
226                 get_direction());
227         for(int i = 0; i < HALF_WINDOW; i++)
228                 data[i] /= total_windows;
229         send_render_gui(data, HALF_WINDOW);
231         return 0;
234 SET_STRING_MACRO(Spectrogram)
236 NEW_PICON_MACRO(Spectrogram)
238 SHOW_GUI_MACRO(Spectrogram, SpectrogramThread)
240 RAISE_WINDOW_MACRO(Spectrogram)
242 void Spectrogram::update_gui()
244         if(thread)
245         {
246                 load_configuration();
247                 thread->window->lock_window("Spectrogram::update_gui");
248                 thread->window->update_gui();
249                 thread->window->unlock_window();
250         }
253 void Spectrogram::render_gui(void *data, int size)
255         if(thread)
256         {
257                 thread->window->lock_window("Spectrogram::render_gui");
258                 float *frame = (float*)data;
259                 int niquist = get_project_samplerate();
260                 BC_SubWindow *canvas = thread->window->canvas;
261                 int h = canvas->get_h();
262                 int input1 = HALF_WINDOW - 1;
263                 double *temp = new double[h];
265 // Scale frame to canvas height
266                 for(int i = 0; i < h; i++)
267                 {
268                         int input2 = (int)((h - 1 - i) * TOTALFREQS / h);
269                         input2 = Freq::tofreq(input2) * 
270                                 HALF_WINDOW / 
271                                 niquist;
272                         input2 = MIN(HALF_WINDOW - 1, input2);
273                         double sum = 0;
274                         if(input1 > input2)
275                         {
276                                 for(int j = input1 - 1; j >= input2; j--)
277                                         sum += frame[j];
279                                 sum /= input1 - input2;
280                         }
281                         else
282                         {
283                                 sum = frame[input2];
284                         }
286                         temp[i] = sum;
287                         input1 = input2;
288                 }
290 // Shift left
291                 canvas->copy_area(1, 
292                         0, 
293                         0, 
294                         0, 
295                         canvas->get_w() - 1,
296                         canvas->get_h());
297                 int x = canvas->get_w() - 1;
298                 double scale = (double)0xffffff;
299                 for(int i = 0; i < h; i++)
300                 {
301                         int64_t color;
302                         color = (int)(scale * temp[i]);
304                         if(color < 0) color = 0;
305                         if(color > 0xffffff) color = 0xffffff;
306                         canvas->set_color(color);
307                         canvas->draw_pixel(x, i);
308                 }
310                 canvas->flash();
311                 canvas->flush();
312                 delete [] temp;
314                 thread->window->unlock_window();
315         }
318 void Spectrogram::load_configuration()
320         KeyFrame *prev_keyframe;
321         prev_keyframe = get_prev_keyframe(get_source_position());
323         read_data(prev_keyframe);
326 void Spectrogram::read_data(KeyFrame *keyframe)
328         FileXML input;
329         input.set_shared_string(keyframe->data, strlen(keyframe->data));
331         int result = 0;
332         while(!result)
333         {
334                 result = input.read_tag();
336                 if(!result)
337                 {
338                         if(input.tag.title_is("SPECTROGRAM"))
339                         {
340                                 config.level = input.tag.get_property("LEVEL", config.level);
341                         }
342                 }
343         }
346 void Spectrogram::save_data(KeyFrame *keyframe)
348         FileXML output;
349         output.set_shared_string(keyframe->data, MESSAGESIZE);
351         output.tag.set_title("SPECTROGRAM");
352         output.tag.set_property("LEVEL", (double)config.level);
353         output.append_tag();
354         output.append_newline();
355         output.terminate_string();
358 int Spectrogram::load_defaults()
360         char directory[BCTEXTLEN];
362         sprintf(directory, "%sspectrogram.rc", BCASTDIR);
363         defaults = new BC_Hash(directory);
364         defaults->load();
365         config.level = defaults->get("LEVEL", config.level);
366         return 0;
369 int Spectrogram::save_defaults()
371         defaults->update("LEVEL", config.level);
372         defaults->save();
373         return 0;