r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / pitch / pitch.C
blobceaf052e73be521665f4d1aae42c30d29dfbdec3
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "pitch.h"
6 #include "picon_png.h"
7 #include "units.h"
8 #include "vframe.h"
10 #include <math.h>
11 #include <string.h>
14 #include <libintl.h>
15 #define _(String) gettext(String)
16 #define gettext_noop(String) String
17 #define N_(String) gettext_noop (String)
25 PluginClient* new_plugin(PluginServer *server)
27         return new PitchEffect(server);
34 PitchEffect::PitchEffect(PluginServer *server)
35  : PluginAClient(server)
37         reset();
38         load_defaults();
41 PitchEffect::~PitchEffect()
43         if(thread)
44         {
45                 thread->window->set_done(0);
46                 thread->completion.lock();
47                 delete thread;
48         }
49         
50         save_defaults();
51         delete defaults;
53         if(fft) delete fft;
56 VFrame* PitchEffect::new_picon()
58         return new VFrame(picon_png);
61 char* PitchEffect::plugin_title()
63         return _("Pitch shift");
67 int PitchEffect::is_realtime()
69         return 1;
74 void PitchEffect::read_data(KeyFrame *keyframe)
76         FileXML input;
77         input.set_shared_string(keyframe->data, strlen(keyframe->data));
79         int result = 0;
80         while(!result)
81         {
82                 result = input.read_tag();
84                 if(!result)
85                 {
86                         if(input.tag.title_is("PITCH"))
87                         {
88                                 config.scale = input.tag.get_property("SCALE", config.scale);
89                         }
90                 }
91         }
94 void PitchEffect::save_data(KeyFrame *keyframe)
96         FileXML output;
97         output.set_shared_string(keyframe->data, MESSAGESIZE);
99         output.tag.set_title("PITCH");
100         output.tag.set_property("SCALE", config.scale);
101         output.append_tag();
102         output.append_newline();
104         output.terminate_string();
107 int PitchEffect::load_defaults()
109         char directory[BCTEXTLEN], string[BCTEXTLEN];
110         sprintf(directory, "%spitch.rc", BCASTDIR);
111         defaults = new Defaults(directory);
112         defaults->load();
113         
114         config.scale = defaults->get("SCALE", config.scale);
115         return 0;
118 int PitchEffect::save_defaults()
120         char string[BCTEXTLEN];
122         defaults->update("SCALE", config.scale);
123         defaults->save();
125         return 0;
129 LOAD_CONFIGURATION_MACRO(PitchEffect, PitchConfig)
132 void PitchEffect::reset()
134         thread = 0;
135         fft = 0;
138 void PitchEffect::update_gui()
140         if(thread)
141         {
142                 load_configuration();
143                 thread->window->lock_window();
144                 thread->window->update();
145                 thread->window->unlock_window();
146         }
149 int PitchEffect::show_gui()
151         load_configuration();
152         
153         thread = new PitchThread(this);
154         thread->start();
155         return 0;
158 void PitchEffect::raise_window()
160         if(thread)
161         {
162                 thread->window->lock_window();
163                 thread->window->raise_window();
164                 thread->window->flush();
165                 thread->window->unlock_window();
166         }
169 int PitchEffect::set_string()
171         if(thread) 
172         {
173                 thread->window->lock_window();
174                 thread->window->set_title(gui_string);
175                 thread->window->unlock_window();
176         }
177         return 0;
180 int PitchEffect::process_realtime(int64_t size, double *input_ptr, double *output_ptr)
182         load_configuration();
183         if(!fft) fft = new PitchFFT(this);
184         fft->process_fifo(size, input_ptr, output_ptr);
185         return 0;
196 PitchFFT::PitchFFT(PitchEffect *plugin)
197  : CrossfadeFFT()
199         this->plugin = plugin;
203 int PitchFFT::signal_process()
205         int min_freq = 
206                 1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / window_size * 2) + 0.5);
207 //printf("PitchFFT::signal_process %d\n", min_freq);
208         if(plugin->config.scale < 1)
209         {
210                 for(int i = min_freq; i < window_size / 2; i++)
211                 {
212                         double destination = i * plugin->config.scale;
213                         int dest_i = (int)(destination + 0.5);
214                         if(dest_i != i)
215                         {
216                                 if(dest_i <= window_size / 2)
217                                 {
218                                         freq_real[dest_i] = freq_real[i];
219                                         freq_imag[dest_i] = freq_imag[i];
220                                 }
221                                 freq_real[i] = 0;
222                                 freq_imag[i] = 0;
223                         }
224                 }
225         }
226         else
227         if(plugin->config.scale > 1)
228         {
229                 for(int i = window_size / 2 - 1; i >= min_freq; i--)
230                 {
231                         double destination = i * plugin->config.scale;
232                         int dest_i = (int)(destination + 0.5);
233                         if(dest_i != i)
234                         {
235                                 if(dest_i <= window_size / 2)
236                                 {
237                                         freq_real[dest_i] = freq_real[i];
238                                         freq_imag[dest_i] = freq_imag[i];
239                                 }
240                                 freq_real[i] = 0;
241                                 freq_imag[i] = 0;
242                         }
243                 }
244         }
246         symmetry(window_size, freq_real, freq_imag);
248         return 0;
257 PitchConfig::PitchConfig()
259         scale = 1.0;
262 int PitchConfig::equivalent(PitchConfig &that)
264         return EQUIV(scale, that.scale);
267 void PitchConfig::copy_from(PitchConfig &that)
269         scale = that.scale;
272 void PitchConfig::interpolate(PitchConfig &prev, 
273         PitchConfig &next, 
274         int64_t prev_frame, 
275         int64_t next_frame, 
276         int64_t current_frame)
278         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
279         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
280         scale = prev.scale * prev_scale + next.scale * next_scale;
291 PitchThread::PitchThread(PitchEffect *plugin)
292  : Thread()
294         this->plugin = plugin;
295         set_synchronous(0);
296         completion.lock();
299 PitchThread::~PitchThread()
301         delete window;
305 void PitchThread::run()
307         BC_DisplayInfo info;
309         window = new PitchWindow(plugin,
310                 info.get_abs_cursor_x() - 125, 
311                 info.get_abs_cursor_y() - 115);
313         window->create_objects();
314         int result = window->run_window();
315         completion.unlock();
316 // Last command in thread
317         if(result) plugin->client_side_close();
327 PitchWindow::PitchWindow(PitchEffect *plugin, int x, int y)
328  : BC_Window(plugin->gui_string, 
329         x, 
330         y, 
331         150, 
332         50, 
333         150, 
334         50,
335         0, 
336         0,
337         1)
339         this->plugin = plugin;
342 void PitchWindow::create_objects()
344         int x = 10, y = 10;
345         
346         add_subwindow(new BC_Title(x, y, _("Scale:")));
347         x += 70;
348         add_subwindow(scale = new PitchScale(plugin, x, y));
349         show_window();
350         flush();
353 int PitchWindow::close_event()
355 // Set result to 1 to indicate a client side close
356         set_done(1);
357         return 1;
360 void PitchWindow::update()
362         scale->update(plugin->config.scale);
376 PitchScale::PitchScale(PitchEffect *plugin, int x, int y)
377  : BC_FPot(x, y, (float)plugin->config.scale, .5, 1.5)
379         this->plugin = plugin;
380         set_precision(0.01);
383 int PitchScale::handle_event()
385         plugin->config.scale = get_value();
386         plugin->send_configure_change();
387         return 1;