00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "language.h"
00006 #include "picon_png.h"
00007 #include "spectrogram.h"
00008 #include "units.h"
00009 #include "vframe.h"
00010
00011
00012 #include <string.h>
00013
00014
00015
00016 REGISTER_PLUGIN(Spectrogram)
00017
00018 #define WINDOW_SIZE 4096
00019 #define HALF_WINDOW 2048
00020
00021
00022 SpectrogramConfig::SpectrogramConfig()
00023 {
00024 level = 0.0;
00025 }
00026
00027
00028
00029
00030
00031
00032
00033 SpectrogramLevel::SpectrogramLevel(Spectrogram *plugin, int x, int y)
00034 : BC_FPot(x, y, plugin->config.level, INFINITYGAIN, 0)
00035 {
00036 this->plugin = plugin;
00037 }
00038
00039 int SpectrogramLevel::handle_event()
00040 {
00041 plugin->config.level = get_value();
00042 plugin->send_configure_change();
00043 return 1;
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 SpectrogramWindow::SpectrogramWindow(Spectrogram *plugin, int x, int y)
00057 : BC_Window(plugin->gui_string,
00058 x,
00059 y,
00060 640,
00061 480,
00062 640,
00063 480,
00064 0,
00065 0,
00066 1)
00067 {
00068 this->plugin = plugin;
00069 }
00070
00071 SpectrogramWindow::~SpectrogramWindow()
00072 {
00073 }
00074
00075 void SpectrogramWindow::create_objects()
00076 {
00077 int x = 60, y = 10;
00078 int divisions = 5;
00079 char string[BCTEXTLEN];
00080
00081 add_subwindow(canvas = new BC_SubWindow(x,
00082 y,
00083 get_w() - x - 10,
00084 get_h() - 50 - y,
00085 BLACK));
00086 x = 10;
00087
00088 for(int i = 0; i <= divisions; i++)
00089 {
00090 y = (int)((float)(canvas->get_h() - 10) / divisions * i) + 10;
00091 sprintf(string, "%d",
00092 Freq::tofreq((int)((float)TOTALFREQS / divisions * (divisions - i))));
00093 add_subwindow(new BC_Title(x, y, string));
00094 }
00095
00096 x = canvas->get_x();
00097 y = canvas->get_y() + canvas->get_h() + 5;
00098
00099 add_subwindow(new BC_Title(x, y + 10, _("Level:")));
00100 add_subwindow(level = new SpectrogramLevel(plugin, x + 50, y));
00101
00102 show_window();
00103 flush();
00104 }
00105
00106 WINDOW_CLOSE_EVENT(SpectrogramWindow)
00107
00108
00109 void SpectrogramWindow::update_gui()
00110 {
00111 level->update(plugin->config.level);
00112 }
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 PLUGIN_THREAD_OBJECT(Spectrogram, SpectrogramThread, SpectrogramWindow)
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 SpectrogramFFT::SpectrogramFFT(Spectrogram *plugin)
00134 : CrossfadeFFT()
00135 {
00136 this->plugin = plugin;
00137 }
00138
00139 SpectrogramFFT::~SpectrogramFFT()
00140 {
00141 }
00142
00143
00144 int SpectrogramFFT::signal_process()
00145 {
00146 double level = DB::fromdb(plugin->config.level);
00147 for(int i = 0; i < HALF_WINDOW; i++)
00148 {
00149 plugin->data[i] += level *
00150 sqrt(freq_real[i] * freq_real[i] +
00151 freq_imag[i] * freq_imag[i]);
00152 }
00153
00154 plugin->total_windows++;
00155 return 0;
00156 }
00157
00158 int SpectrogramFFT::read_samples(int64_t output_sample,
00159 int samples,
00160 double *buffer)
00161 {
00162 return plugin->read_samples(buffer,
00163 0,
00164 plugin->get_samplerate(),
00165 output_sample,
00166 samples);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 Spectrogram::Spectrogram(PluginServer *server)
00178 : PluginAClient(server)
00179 {
00180 reset();
00181 PLUGIN_CONSTRUCTOR_MACRO
00182 }
00183
00184 Spectrogram::~Spectrogram()
00185 {
00186 PLUGIN_DESTRUCTOR_MACRO
00187
00188 if(fft) delete fft;
00189 if(data) delete [] data;
00190 }
00191
00192
00193 void Spectrogram::reset()
00194 {
00195 thread = 0;
00196 fft = 0;
00197 done = 0;
00198 data = 0;
00199 }
00200
00201
00202 char* Spectrogram::plugin_title() { return N_("Spectrogram"); }
00203 int Spectrogram::is_realtime() { return 1; }
00204
00205 int Spectrogram::process_buffer(int64_t size,
00206 double *buffer,
00207 int64_t start_position,
00208 int sample_rate)
00209 {
00210 load_configuration();
00211 if(!fft)
00212 {
00213 fft = new SpectrogramFFT(this);
00214 fft->initialize(WINDOW_SIZE);
00215 }
00216 if(!data)
00217 {
00218 data = new float[HALF_WINDOW];
00219 }
00220
00221 bzero(data, sizeof(float) * HALF_WINDOW);
00222 total_windows = 0;
00223 fft->process_buffer(start_position,
00224 size,
00225 buffer,
00226 get_direction());
00227 for(int i = 0; i < HALF_WINDOW; i++)
00228 data[i] /= total_windows;
00229 send_render_gui(data, HALF_WINDOW);
00230
00231 return 0;
00232 }
00233
00234 SET_STRING_MACRO(Spectrogram)
00235
00236 NEW_PICON_MACRO(Spectrogram)
00237
00238 SHOW_GUI_MACRO(Spectrogram, SpectrogramThread)
00239
00240 RAISE_WINDOW_MACRO(Spectrogram)
00241
00242 void Spectrogram::update_gui()
00243 {
00244 if(thread)
00245 {
00246 load_configuration();
00247 thread->window->lock_window("Spectrogram::update_gui");
00248 thread->window->update_gui();
00249 thread->window->unlock_window();
00250 }
00251 }
00252
00253 void Spectrogram::render_gui(void *data, int size)
00254 {
00255 if(thread)
00256 {
00257 thread->window->lock_window("Spectrogram::render_gui");
00258 float *frame = (float*)data;
00259 int niquist = get_project_samplerate();
00260 BC_SubWindow *canvas = thread->window->canvas;
00261 int h = canvas->get_h();
00262 int input1 = HALF_WINDOW - 1;
00263 double *temp = new double[h];
00264
00265
00266 for(int i = 0; i < h; i++)
00267 {
00268 int input2 = (int)((h - 1 - i) * TOTALFREQS / h);
00269 input2 = Freq::tofreq(input2) *
00270 HALF_WINDOW /
00271 niquist;
00272 input2 = MIN(HALF_WINDOW - 1, input2);
00273 double sum = 0;
00274 if(input1 > input2)
00275 {
00276 for(int j = input1 - 1; j >= input2; j--)
00277 sum += frame[j];
00278
00279 sum /= input1 - input2;
00280 }
00281 else
00282 {
00283 sum = frame[input2];
00284 }
00285
00286 temp[i] = sum;
00287 input1 = input2;
00288 }
00289
00290
00291 canvas->copy_area(1,
00292 0,
00293 0,
00294 0,
00295 canvas->get_w() - 1,
00296 canvas->get_h());
00297 int x = canvas->get_w() - 1;
00298 double scale = (double)0xffffff;
00299 for(int i = 0; i < h; i++)
00300 {
00301 int64_t color;
00302 color = (int)(scale * temp[i]);
00303
00304 if(color < 0) color = 0;
00305 if(color > 0xffffff) color = 0xffffff;
00306 canvas->set_color(color);
00307 canvas->draw_pixel(x, i);
00308 }
00309
00310 canvas->flash();
00311 canvas->flush();
00312 delete [] temp;
00313
00314 thread->window->unlock_window();
00315 }
00316 }
00317
00318 void Spectrogram::load_configuration()
00319 {
00320 KeyFrame *prev_keyframe;
00321 prev_keyframe = get_prev_keyframe(get_source_position());
00322
00323 read_data(prev_keyframe);
00324 }
00325
00326 void Spectrogram::read_data(KeyFrame *keyframe)
00327 {
00328 FileXML input;
00329 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00330
00331 int result = 0;
00332 while(!result)
00333 {
00334 result = input.read_tag();
00335
00336 if(!result)
00337 {
00338 if(input.tag.title_is("SPECTROGRAM"))
00339 {
00340 config.level = input.tag.get_property("LEVEL", config.level);
00341 }
00342 }
00343 }
00344 }
00345
00346 void Spectrogram::save_data(KeyFrame *keyframe)
00347 {
00348 FileXML output;
00349 output.set_shared_string(keyframe->data, MESSAGESIZE);
00350
00351 output.tag.set_title("SPECTROGRAM");
00352 output.tag.set_property("LEVEL", (double)config.level);
00353 output.append_tag();
00354 output.tag.set_title("/SPECTROGRAM");
00355 output.append_tag();
00356 output.append_newline();
00357 output.terminate_string();
00358 }
00359
00360 int Spectrogram::load_defaults()
00361 {
00362 char directory[BCTEXTLEN];
00363
00364 sprintf(directory, "%sspectrogram.rc", BCASTDIR);
00365 defaults = new BC_Hash(directory);
00366 defaults->load();
00367 config.level = defaults->get("LEVEL", config.level);
00368 return 0;
00369 }
00370
00371 int Spectrogram::save_defaults()
00372 {
00373 defaults->update("LEVEL", config.level);
00374 defaults->save();
00375 return 0;
00376 }
00377
00378
00379
00380