r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / plugins / pitch / pitch.C
blob65f77687c236e17f8b63d86741ca96370a21105d
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "language.h"
6 #include "pitch.h"
7 #include "picon_png.h"
8 #include "units.h"
9 #include "vframe.h"
11 #include <math.h>
12 #include <string.h>
16 #define WINDOW_SIZE 4096
20 REGISTER_PLUGIN(PitchEffect);
26 PitchEffect::PitchEffect(PluginServer *server)
27  : PluginAClient(server)
29         PLUGIN_CONSTRUCTOR_MACRO
30         reset();
33 PitchEffect::~PitchEffect()
35         PLUGIN_DESTRUCTOR_MACRO
37         if(fft) delete fft;
40 char* PitchEffect::plugin_title() { return N_("Pitch shift"); }
41 int PitchEffect::is_realtime() { return 1; }
45 void PitchEffect::read_data(KeyFrame *keyframe)
47         FileXML input;
48         input.set_shared_string(keyframe->data, strlen(keyframe->data));
50         int result = 0;
51         while(!result)
52         {
53                 result = input.read_tag();
55                 if(!result)
56                 {
57                         if(input.tag.title_is("PITCH"))
58                         {
59                                 config.scale = input.tag.get_property("SCALE", config.scale);
60                         }
61                 }
62         }
65 void PitchEffect::save_data(KeyFrame *keyframe)
67         FileXML output;
68         output.set_shared_string(keyframe->data, MESSAGESIZE);
70         output.tag.set_title("PITCH");
71         output.tag.set_property("SCALE", config.scale);
72         output.append_tag();
73         output.append_newline();
75         output.terminate_string();
78 int PitchEffect::load_defaults()
80         char directory[BCTEXTLEN], string[BCTEXTLEN];
81         sprintf(directory, "%spitch.rc", BCASTDIR);
82         defaults = new Defaults(directory);
83         defaults->load();
84         
85         config.scale = defaults->get("SCALE", config.scale);
86         return 0;
89 int PitchEffect::save_defaults()
91         char string[BCTEXTLEN];
93         defaults->update("SCALE", config.scale);
94         defaults->save();
96         return 0;
100 LOAD_CONFIGURATION_MACRO(PitchEffect, PitchConfig)
102 SHOW_GUI_MACRO(PitchEffect, PitchThread)
104 RAISE_WINDOW_MACRO(PitchEffect)
106 SET_STRING_MACRO(PitchEffect)
108 NEW_PICON_MACRO(PitchEffect)
111 void PitchEffect::reset()
113         fft = 0;
116 void PitchEffect::update_gui()
118         if(thread)
119         {
120                 load_configuration();
121                 thread->window->lock_window("PitchEffect::update_gui");
122                 thread->window->update();
123                 thread->window->unlock_window();
124         }
127 int PitchEffect::process_buffer(int64_t size, 
128                 double *buffer,
129                 int64_t start_position,
130                 int sample_rate)
132         load_configuration();
133         if(!fft)
134         {
135                 fft = new PitchFFT(this);
136                 fft->initialize(WINDOW_SIZE);
137         }
138         fft->process_buffer(start_position,
139                 size, 
140                 buffer,
141                 get_direction());
142         return 0;
153 PitchFFT::PitchFFT(PitchEffect *plugin)
154  : CrossfadeFFT()
156         this->plugin = plugin;
160 int PitchFFT::signal_process()
162         int min_freq = 
163                 1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / 
164                         window_size * 2) + 0.5);
165         if(plugin->config.scale < 1)
166         {
167                 for(int i = min_freq; i < window_size / 2; i++)
168                 {
169                         double destination = i * plugin->config.scale;
170                         int dest_i = (int)(destination + 0.5);
171                         if(dest_i != i)
172                         {
173                                 if(dest_i <= window_size / 2)
174                                 {
175                                         freq_real[dest_i] = freq_real[i];
176                                         freq_imag[dest_i] = freq_imag[i];
177                                 }
178                                 freq_real[i] = 0;
179                                 freq_imag[i] = 0;
180                         }
181                 }
182         }
183         else
184         if(plugin->config.scale > 1)
185         {
186                 for(int i = window_size / 2 - 1; i >= min_freq; i--)
187                 {
188                         double destination = i * plugin->config.scale;
189                         int dest_i = (int)(destination + 0.5);
190                         if(dest_i != i)
191                         {
192                                 if(dest_i <= window_size / 2)
193                                 {
194                                         freq_real[dest_i] = freq_real[i];
195                                         freq_imag[dest_i] = freq_imag[i];
196                                 }
197                                 freq_real[i] = 0;
198                                 freq_imag[i] = 0;
199                         }
200                 }
201         }
203         symmetry(window_size, freq_real, freq_imag);
205         return 0;
208 int PitchFFT::read_samples(int64_t output_sample, 
209         int samples, 
210         double *buffer)
212         return plugin->read_samples(buffer,
213                 0,
214                 plugin->get_samplerate(),
215                 output_sample,
216                 samples);
225 PitchConfig::PitchConfig()
227         scale = 1.0;
230 int PitchConfig::equivalent(PitchConfig &that)
232         return EQUIV(scale, that.scale);
235 void PitchConfig::copy_from(PitchConfig &that)
237         scale = that.scale;
240 void PitchConfig::interpolate(PitchConfig &prev, 
241         PitchConfig &next, 
242         int64_t prev_frame, 
243         int64_t next_frame, 
244         int64_t current_frame)
246         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
247         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
248         scale = prev.scale * prev_scale + next.scale * next_scale;
258 PLUGIN_THREAD_OBJECT(PitchEffect, PitchThread, PitchWindow) 
268 PitchWindow::PitchWindow(PitchEffect *plugin, int x, int y)
269  : BC_Window(plugin->gui_string, 
270         x, 
271         y, 
272         150, 
273         50, 
274         150, 
275         50,
276         0, 
277         0,
278         1)
280         this->plugin = plugin;
283 void PitchWindow::create_objects()
285         int x = 10, y = 10;
286         
287         add_subwindow(new BC_Title(x, y, _("Scale:")));
288         x += 70;
289         add_subwindow(scale = new PitchScale(plugin, x, y));
290         show_window();
291         flush();
294 WINDOW_CLOSE_EVENT(PitchWindow)
296 void PitchWindow::update()
298         scale->update(plugin->config.scale);
312 PitchScale::PitchScale(PitchEffect *plugin, int x, int y)
313  : BC_FPot(x, y, (float)plugin->config.scale, .5, 1.5)
315         this->plugin = plugin;
316         set_precision(0.01);
319 int PitchScale::handle_event()
321         plugin->config.scale = get_value();
322         plugin->send_configure_change();
323         return 1;