• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files

hvirtual/plugins/synthesizer/synthesizer.C

Go to the documentation of this file.
00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "picon_png.h"
00006 #include "synthesizer.h"
00007 #include "vframe.h"
00008 
00009 #include <string.h>
00010 
00011 
00012 #include <libintl.h>
00013 #define _(String) gettext(String)
00014 #define gettext_noop(String) String
00015 #define N_(String) gettext_noop (String)
00016 
00017 
00018 
00019 PluginClient* new_plugin(PluginServer *server)
00020 {
00021         return new Synth(server);
00022 }
00023 
00024 
00025 
00026 
00027 
00028 Synth::Synth(PluginServer *server)
00029  : PluginAClient(server)
00030 {
00031         reset();
00032         load_defaults();
00033 }
00034 
00035 
00036 
00037 Synth::~Synth()
00038 {
00039         if(thread)
00040         {
00041                 thread->window->set_done(0);
00042                 thread->completion.lock();
00043                 delete thread;
00044         }
00045 
00046         save_defaults();
00047         delete defaults;
00048         
00049         if(dsp_buffer) delete [] dsp_buffer;
00050 }
00051 
00052 VFrame* Synth::new_picon()
00053 {
00054         return new VFrame(picon_png);
00055 }
00056 
00057 
00058 char* Synth::plugin_title() { return N_("Synthesizer"); }
00059 int Synth::is_realtime() { return 1; }
00060 int Synth::is_synthesis() { return 1; }
00061 
00062 
00063 void Synth::reset()
00064 {
00065         thread = 0;
00066         need_reconfigure = 1;
00067         dsp_buffer = 0;
00068 }
00069 
00070 
00071 
00072 
00073 LOAD_CONFIGURATION_MACRO(Synth, SynthConfig)
00074 
00075 
00076 
00077 
00078 int Synth::load_defaults()
00079 {
00080         char directory[BCTEXTLEN], string[BCTEXTLEN];
00081 
00082         sprintf(directory, "%ssynthesizer.rc", BCASTDIR);
00083         defaults = new BC_Hash(directory);
00084         defaults->load();
00085         w = defaults->get("WIDTH", 380);
00086         h = defaults->get("HEIGHT", 400);
00087 
00088         config.wetness = defaults->get("WETNESS", 0);
00089         config.base_freq = defaults->get("BASEFREQ", 440);
00090         config.wavefunction = defaults->get("WAVEFUNCTION", 0);
00091 
00092         int total_oscillators = defaults->get("OSCILLATORS", TOTALOSCILLATORS);
00093         config.oscillator_config.remove_all_objects();
00094         for(int i = 0; i < total_oscillators; i++)
00095         {
00096                 config.oscillator_config.append(new SynthOscillatorConfig(i));
00097                 config.oscillator_config.values[i]->load_defaults(defaults);
00098         }
00099 
00100         return 0;
00101 }
00102 
00103 
00104 void Synth::read_data(KeyFrame *keyframe)
00105 {
00106         FileXML input;
00107 // cause htal file to read directly from text
00108         input.set_shared_string(keyframe->data, strlen(keyframe->data));
00109 
00110 //printf("Synth::read_data %s\n", keyframe->data);
00111         int result = 0, current_osc = 0, total_oscillators = 0;
00112         while(!result)
00113         {
00114                 result = input.read_tag();
00115 
00116                 if(!result)
00117                 {
00118                         if(input.tag.title_is("SYNTH"))
00119                         {
00120                                 config.wetness = input.tag.get_property("WETNESS", config.wetness);
00121                                 config.base_freq = input.tag.get_property("BASEFREQ", config.base_freq);
00122                                 config.wavefunction = input.tag.get_property("WAVEFUNCTION", config.wavefunction);
00123                                 total_oscillators = input.tag.get_property("OSCILLATORS", 0);
00124                         }
00125                         else
00126                         if(input.tag.title_is("OSCILLATOR"))
00127                         {
00128                                 if(current_osc >= config.oscillator_config.total)
00129                                         config.oscillator_config.append(new SynthOscillatorConfig(current_osc));
00130 
00131                                 config.oscillator_config.values[current_osc]->read_data(&input);
00132                                 current_osc++;
00133                         }
00134                 }
00135         }
00136 
00137         while(config.oscillator_config.total > current_osc)
00138                 config.oscillator_config.remove_object();
00139 }
00140 
00141 void Synth::save_data(KeyFrame *keyframe)
00142 {
00143         FileXML output;
00144 // cause htal file to store data directly in text
00145         output.set_shared_string(keyframe->data, MESSAGESIZE);
00146 
00147         output.tag.set_title("SYNTH");
00148         output.tag.set_property("WETNESS", config.wetness);
00149         output.tag.set_property("BASEFREQ", config.base_freq);
00150         output.tag.set_property("WAVEFUNCTION", config.wavefunction);
00151         output.tag.set_property("OSCILLATORS", config.oscillator_config.total);
00152         output.append_tag();
00153         output.append_newline();
00154 
00155         for(int i = 0; i < config.oscillator_config.total; i++)
00156         {
00157                 config.oscillator_config.values[i]->save_data(&output);
00158         }
00159 
00160         output.tag.set_title("/SYNTH");
00161         output.append_tag();
00162         output.terminate_string();
00163 // data is now in *text
00164 }
00165 
00166 int Synth::save_defaults()
00167 {
00168         char string[BCTEXTLEN];
00169 
00170         defaults->update("WIDTH", w);
00171         defaults->update("HEIGHT", h);
00172         defaults->update("WETNESS", config.wetness);
00173         defaults->update("BASEFREQ", config.base_freq);
00174         defaults->update("WAVEFUNCTION", config.wavefunction);
00175         defaults->update("OSCILLATORS", config.oscillator_config.total);
00176 
00177         for(int i = 0; i < config.oscillator_config.total; i++)
00178         {
00179                 config.oscillator_config.values[i]->save_defaults(defaults);
00180         }
00181         defaults->save();
00182 
00183         return 0;
00184 }
00185 
00186 int Synth::show_gui()
00187 {
00188         load_configuration();
00189         
00190         thread = new SynthThread(this);
00191         thread->start();
00192         return 0;
00193 }
00194 
00195 int Synth::set_string()
00196 {
00197         if(thread) thread->window->set_title(gui_string);
00198         return 0;
00199 }
00200 
00201 void Synth::raise_window()
00202 {
00203         if(thread)
00204         {
00205                 thread->window->raise_window();
00206                 thread->window->flush();
00207         }
00208 }
00209 
00210 void Synth::update_gui()
00211 {
00212         if(thread)
00213         {
00214                 load_configuration();
00215                 thread->window->lock_window();
00216                 thread->window->update_gui();
00217                 thread->window->unlock_window();
00218         }
00219 }
00220 
00221 
00222 void Synth::add_oscillator()
00223 {
00224         if(config.oscillator_config.total > 20) return;
00225 
00226         config.oscillator_config.append(new SynthOscillatorConfig(config.oscillator_config.total - 1));
00227 }
00228 
00229 void Synth::delete_oscillator()
00230 {
00231         if(config.oscillator_config.total)
00232         {
00233                 config.oscillator_config.remove_object();
00234         }
00235 }
00236 
00237 
00238 double Synth::get_total_power()
00239 {
00240         double result = 0;
00241 
00242         if(config.wavefunction == DC) return 1.0;
00243 
00244         for(int i = 0; i < config.oscillator_config.total; i++)
00245         {
00246                 result += db.fromdb(config.oscillator_config.values[i]->level);
00247         }
00248 
00249         if(result == 0) result = 1;  // prevent division by 0
00250         return result;
00251 }
00252 
00253 
00254 double Synth::solve_eqn(double *output, 
00255         double x1, 
00256         double x2, 
00257         double normalize_constant,
00258         int oscillator)
00259 {
00260         SynthOscillatorConfig *config = this->config.oscillator_config.values[oscillator];
00261         if(config->level <= INFINITYGAIN) return 0;
00262 
00263         double result;
00264         register double x;
00265         double power = this->db.fromdb(config->level) * normalize_constant;
00266         double phase_offset = config->phase * this->period;
00267         double x3 = x1 + phase_offset;
00268         double x4 = x2 + phase_offset;
00269         double period = this->period / config->freq_factor;
00270         int sample;
00271 
00272         switch(this->config.wavefunction)
00273         {
00274                 case DC:
00275                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00276                         {
00277                                 output[sample] += power;
00278                         }
00279                         break;
00280                 case SINE:
00281                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00282                         {
00283                                 output[sample] += sin(x / period * 2 * M_PI) * power;
00284                         }
00285                         break;
00286                 case SAWTOOTH:
00287                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00288                         {
00289                                 output[sample] += function_sawtooth(x / period) * power;
00290                         }
00291                         break;
00292                 case SQUARE:
00293                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00294                         {
00295                                 output[sample] += function_square(x / period) * power;
00296                         }
00297                         break;
00298                 case TRIANGLE:
00299                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00300                         {
00301                                 output[sample] += function_triangle(x / period) * power;
00302                         }
00303                         break;
00304                 case PULSE:
00305                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00306                         {
00307                                 output[sample] += function_pulse(x / period) * power;
00308                         }
00309                         break;
00310                 case NOISE:
00311                         for(sample = (int)x1, x = x3; x < x4; x++, sample++)
00312                         {
00313                                 output[sample] += function_noise() * power;
00314                         }
00315                         break;
00316         }
00317 }
00318 
00319 double Synth::get_point(float x, double normalize_constant)
00320 {
00321         double result = 0;
00322         for(int i = 0; i < config.oscillator_config.total; i++)
00323                 result += get_oscillator_point(x, normalize_constant, i);
00324 
00325         return result;
00326 }
00327 
00328 double Synth::get_oscillator_point(float x, 
00329                 double normalize_constant, 
00330                 int oscillator)
00331 {
00332         SynthOscillatorConfig *config = this->config.oscillator_config.values[oscillator];
00333         double power = db.fromdb(config->level) * normalize_constant;
00334         switch(this->config.wavefunction)
00335         {
00336                 case DC:
00337                         return power;
00338                         break;
00339                 case SINE:
00340                         return sin((x + config->phase) * config->freq_factor * 2 * M_PI) * power;
00341                         break;
00342                 case SAWTOOTH:
00343                         return function_sawtooth((x + config->phase) * config->freq_factor) * power;
00344                         break;
00345                 case SQUARE:
00346                         return function_square((x + config->phase) * config->freq_factor) * power;
00347                         break;
00348                 case TRIANGLE:
00349                         return function_triangle((x + config->phase) * config->freq_factor) * power;
00350                         break;
00351                 case PULSE:
00352                         return function_pulse((x + config->phase) * config->freq_factor) * power;
00353                         break;
00354                 case NOISE:
00355                         return function_noise() * power;
00356                         break;
00357         }
00358 }
00359 
00360 double Synth::function_square(double x)
00361 {
00362         x -= (int)x; // only fraction counts
00363         return (x < .5) ? -1 : 1;
00364 }
00365 
00366 double Synth::function_pulse(double x)
00367 {
00368         x -= (int)x; // only fraction counts
00369         return (x < .5) ? 0 : 1;
00370 }
00371 
00372 double Synth::function_noise()
00373 {
00374         return (double)(rand() % 65536 - 32768) / 32768;
00375 }
00376 
00377 double Synth::function_sawtooth(double x)
00378 {
00379         x -= (int)x;
00380         return 1 - x * 2;
00381 }
00382 
00383 double Synth::function_triangle(double x)
00384 {
00385         x -= (int)x;
00386         return (x < .5) ? 1 - x * 4 : -3 + x * 4;
00387 }
00388 
00389 int Synth::process_realtime(int64_t size, double *input_ptr, double *output_ptr)
00390 {
00391 
00392 
00393         need_reconfigure |= load_configuration();
00394         if(need_reconfigure) reconfigure();
00395 
00396         double wetness = DB::fromdb(config.wetness);
00397         if(EQUIV(config.wetness, INFINITYGAIN)) wetness = 0;
00398 
00399         for(int j = 0; j < size; j++)
00400                 output_ptr[j] = input_ptr[j] * wetness;
00401 
00402         int64_t fragment_len;
00403         for(int64_t i = 0; i < size; i += fragment_len)
00404         {
00405                 fragment_len = size;
00406                 if(i + fragment_len > size) fragment_len = size - i;
00407 
00408 //printf("Synth::process_realtime 1 %d %d %d\n", i, fragment_len, size);
00409                 fragment_len = overlay_synth(i, fragment_len, input_ptr, output_ptr);
00410 //printf("Synth::process_realtime 2\n");
00411         }
00412         
00413         
00414         return 0;
00415 }
00416 
00417 int Synth::overlay_synth(int64_t start, int64_t length, double *input, double *output)
00418 {
00419         if(waveform_sample + length > waveform_length) 
00420                 length = waveform_length - waveform_sample;
00421 
00422 //printf("Synth::overlay_synth 1 %d %d\n", length, waveform_length);
00423 
00424 // calculate some more data
00425 // only calculate what's needed to speed it up
00426         if(waveform_sample + length > samples_rendered)
00427         {
00428                 int64_t start = waveform_sample, end = waveform_sample + length;
00429                 for(int i = start; i < end; i++) dsp_buffer[i] = 0;
00430                 
00431                 double normalize_constant = 1 / get_total_power();
00432                 for(int i = 0; i < config.oscillator_config.total; i++)
00433                         solve_eqn(dsp_buffer, 
00434                                 start, 
00435                                 end, 
00436                                 normalize_constant,
00437                                 i);
00438 
00439                 
00440                 samples_rendered = end;
00441         }
00442 //printf("Synth::overlay_synth 2\n");
00443 
00444 
00445         double *buffer_in = &input[start];
00446         double *buffer_out = &output[start];
00447 
00448         for(int i = 0; i < length; i++)
00449         {
00450                 buffer_out[i] += dsp_buffer[waveform_sample++];
00451         }
00452 //printf("Synth::overlay_synth 3\n");
00453 
00454         if(waveform_sample >= waveform_length) waveform_sample = 0;
00455 
00456         return length;
00457 }
00458 
00459 void Synth::reconfigure()
00460 {
00461         need_reconfigure = 0;
00462 
00463         if(dsp_buffer)
00464         {
00465                 delete [] dsp_buffer;
00466         }
00467 
00468 //printf("Synth::reconfigure 1 %d\n", PluginAClient::project_sample_rate);
00469         waveform_length = PluginAClient::project_sample_rate;
00470         period = (float)PluginAClient::project_sample_rate / config.base_freq;
00471         dsp_buffer = new double[waveform_length + 1];
00472 
00473         samples_rendered = 0;     // do some calculations on the next process_realtime
00474         waveform_sample = 0;
00475 }
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497 SynthThread::SynthThread(Synth *synth)
00498  : Thread()
00499 {
00500         this->synth = synth;
00501         set_synchronous(0);
00502         completion.lock();
00503 }
00504 
00505 SynthThread::~SynthThread()
00506 {
00507         delete window;
00508 }
00509 
00510 void SynthThread::run()
00511 {
00512         BC_DisplayInfo info;
00513         window = new SynthWindow(synth, 
00514                 info.get_abs_cursor_x() - 125, 
00515                 info.get_abs_cursor_y() - 115);
00516         window->create_objects();
00517         int result = window->run_window();
00518         completion.unlock();
00519 // Last command executed in thread
00520         if(result) synth->client_side_close();
00521 }
00522 
00523 
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 SynthWindow::SynthWindow(Synth *synth, int x, int y)
00534  : BC_Window(synth->gui_string, 
00535         x, 
00536         y, 
00537         380, 
00538         synth->h, 
00539         380, 
00540         10, 
00541         1, 
00542         0,
00543         1)
00544 {
00545         this->synth = synth; 
00546 }
00547 
00548 SynthWindow::~SynthWindow()
00549 {
00550 }
00551 
00552 int SynthWindow::create_objects()
00553 {
00554         BC_MenuBar *menu;
00555         add_subwindow(menu = new BC_MenuBar(0, 0, get_w()));
00556 
00557         BC_Menu *levelmenu, *phasemenu, *harmonicmenu;
00558         menu->add_menu(levelmenu = new BC_Menu(_("Level")));
00559         menu->add_menu(phasemenu = new BC_Menu(_("Phase")));
00560         menu->add_menu(harmonicmenu = new BC_Menu(_("Harmonic")));
00561 
00562         levelmenu->add_item(new SynthLevelInvert(synth));
00563         levelmenu->add_item(new SynthLevelMax(synth));
00564         levelmenu->add_item(new SynthLevelRandom(synth));
00565         levelmenu->add_item(new SynthLevelSine(synth));
00566         levelmenu->add_item(new SynthLevelSlope(synth));
00567         levelmenu->add_item(new SynthLevelZero(synth));
00568 
00569         phasemenu->add_item(new SynthPhaseInvert(synth));
00570         phasemenu->add_item(new SynthPhaseRandom(synth));
00571         phasemenu->add_item(new SynthPhaseSine(synth));
00572         phasemenu->add_item(new SynthPhaseZero(synth));
00573 
00574         harmonicmenu->add_item(new SynthFreqEnum(synth));
00575         harmonicmenu->add_item(new SynthFreqEven(synth));
00576         harmonicmenu->add_item(new SynthFreqFibonacci(synth));
00577         harmonicmenu->add_item(new SynthFreqOdd(synth));
00578         harmonicmenu->add_item(new SynthFreqPrime(synth));
00579 
00580         int x = 10, y = 30, i;
00581         add_subwindow(new BC_Title(x, y, _("Waveform")));
00582         x += 240;
00583         add_subwindow(new BC_Title(x, y, _("Wave Function")));
00584         y += 20;
00585         x = 10;
00586         add_subwindow(canvas = new SynthCanvas(synth, this, x, y, 230, 160));
00587         canvas->update();
00588 
00589         x += 240;
00590         char string[BCTEXTLEN];
00591         waveform_to_text(string, synth->config.wavefunction);
00592 
00593         add_subwindow(waveform = new SynthWaveForm(synth, x, y, string));
00594         waveform->create_objects();
00595         y += 30;
00596 
00597 
00598         add_subwindow(new BC_Title(x, y, _("Base Frequency:")));
00599         y += 30;
00600         add_subwindow(base_freq = new SynthBaseFreq(synth, x, y));
00601         x += 80;
00602         add_subwindow(freqpot = new SynthFreqPot(synth, this, x, y - 10));
00603         base_freq->freq_pot = freqpot;
00604         freqpot->freq_text = base_freq;
00605         x -= 80;
00606         y += 40;
00607         add_subwindow(new BC_Title(x, y, _("Wetness:")));
00608         add_subwindow(wetness = new SynthWetness(synth, x + 70, y - 10));
00609 
00610         y += 40;
00611         add_subwindow(new SynthClear(synth, x, y));
00612 
00613 
00614         x = 50;  
00615         y = 220;
00616         add_subwindow(new BC_Title(x, y, _("Level"))); 
00617         x += 75;
00618         add_subwindow(new BC_Title(x, y, _("Phase"))); 
00619         x += 75;
00620         add_subwindow(new BC_Title(x, y, _("Harmonic")));
00621 
00622 
00623 
00624         y += 20; x = 10;
00625         add_subwindow(subwindow = new SynthSubWindow(synth, x, y, 265, get_h() - y));
00626         x += 265;
00627         add_subwindow(scroll = new SynthScroll(synth, this, x, y, get_h() - y));
00628 
00629 
00630         x += 20;
00631         add_subwindow(new SynthAddOsc(synth, this, x, y));
00632         y += 30;
00633         add_subwindow(new SynthDelOsc(synth, this, x, y));
00634 
00635         update_scrollbar();
00636         update_oscillators();
00637 
00638         show_window();
00639         flush();
00640         return 0;
00641 }
00642 
00643 int SynthWindow::close_event()
00644 {
00645 // Set result to 1 to indicate a client side close
00646         set_done(1);
00647         return 1;
00648 }
00649 
00650 int SynthWindow::resize_event(int w, int h)
00651 {
00652         clear_box(0, 0, w, h);
00653         subwindow->reposition_window(subwindow->get_x(), 
00654                 subwindow->get_y(), 
00655                 subwindow->get_w(), 
00656                 h - subwindow->get_y());
00657         subwindow->clear_box(0, 0, subwindow->get_w(), subwindow->get_h());
00658         scroll->reposition_window(scroll->get_x(), 
00659                 scroll->get_y(), 
00660                 h - scroll->get_y());
00661         update_scrollbar();
00662         update_oscillators();
00663         synth->w = w;
00664         synth->h = h;
00665         return 1;
00666 }
00667 
00668 void SynthWindow::update_gui()
00669 {
00670         char string[BCTEXTLEN];
00671         freqpot->update(synth->config.base_freq);
00672         base_freq->update((int64_t)synth->config.base_freq);
00673         wetness->update(synth->config.wetness);
00674         waveform_to_text(string, synth->config.wavefunction);
00675         waveform->set_text(string);
00676         
00677         update_scrollbar();
00678         update_oscillators();
00679         canvas->update();
00680 }
00681 
00682 void SynthWindow::update_scrollbar()
00683 {
00684         scroll->update_length(synth->config.oscillator_config.total * OSCILLATORHEIGHT, 
00685                 scroll->get_position(), 
00686                 subwindow->get_h());
00687 }
00688 
00689 void SynthWindow::update_oscillators()
00690 {
00691         int i, y = -scroll->get_position();
00692 
00693 
00694 
00695 // Add new oscillators
00696         for(i = 0; 
00697                 i < synth->config.oscillator_config.total; 
00698                 i++)
00699         {
00700                 SynthOscGUI *gui;
00701                 SynthOscillatorConfig *config = synth->config.oscillator_config.values[i];
00702 
00703                 if(oscillators.total <= i)
00704                 {
00705                         oscillators.append(gui = new SynthOscGUI(this, i));
00706                         gui->create_objects(y);
00707                 }
00708                 else
00709                 {
00710                         gui = oscillators.values[i];
00711 
00712                         gui->title->reposition_window(gui->title->get_x(), y + 15);
00713 
00714                         gui->level->reposition_window(gui->level->get_x(), y);
00715                         gui->level->update(config->level);
00716 
00717                         gui->phase->reposition_window(gui->phase->get_x(), y);
00718                         gui->phase->update((int64_t)(config->phase * 360));
00719 
00720                         gui->freq->reposition_window(gui->freq->get_x(), y);
00721                         gui->freq->update((int64_t)(config->freq_factor));
00722                 }
00723                 y += OSCILLATORHEIGHT;
00724         }
00725 
00726 // Delete old oscillators
00727         for( ; 
00728                 i < oscillators.total;
00729                 i++)
00730                 oscillators.remove_object();
00731 }
00732 
00733 
00734 int SynthWindow::waveform_to_text(char *text, int waveform)
00735 {
00736         switch(waveform)
00737         {
00738                 case DC:              sprintf(text, _("DC"));           break;
00739                 case SINE:            sprintf(text, _("Sine"));           break;
00740                 case SAWTOOTH:        sprintf(text, _("Sawtooth"));       break;
00741                 case SQUARE:          sprintf(text, _("Square"));         break;
00742                 case TRIANGLE:        sprintf(text, _("Triangle"));       break;
00743                 case PULSE:           sprintf(text, _("Pulse"));       break;
00744                 case NOISE:           sprintf(text, _("Noise"));       break;
00745         }
00746         return 0;
00747 }
00748 
00749 
00750 
00751 
00752 
00753 
00754 
00755 SynthOscGUI::SynthOscGUI(SynthWindow *window, int number)
00756 {
00757         this->window = window;
00758         this->number = number;
00759 }
00760 
00761 SynthOscGUI::~SynthOscGUI()
00762 {
00763         delete title;
00764         delete level;
00765         delete phase;
00766         delete freq;
00767 }
00768 
00769 int SynthOscGUI::create_objects(int y)
00770 {
00771         char text[BCTEXTLEN];
00772         sprintf(text, "%d:", number + 1);
00773         window->subwindow->add_subwindow(title = new BC_Title(10, y + 15, text));
00774 
00775         window->subwindow->add_subwindow(level = new SynthOscGUILevel(window->synth, this, y));
00776         window->subwindow->add_subwindow(phase = new SynthOscGUIPhase(window->synth, this, y));
00777         window->subwindow->add_subwindow(freq = new SynthOscGUIFreq(window->synth, this, y));
00778         return 1;
00779 }
00780 
00781 
00782 
00783 
00784 SynthOscGUILevel::SynthOscGUILevel(Synth *synth, SynthOscGUI *gui, int y)
00785  : BC_FPot(50, 
00786         y, 
00787         synth->config.oscillator_config.values[gui->number]->level, 
00788         INFINITYGAIN, 
00789         0)
00790 {
00791         this->synth = synth;
00792         this->gui = gui;
00793 }
00794 
00795 SynthOscGUILevel::~SynthOscGUILevel()
00796 {
00797 }
00798 
00799 int SynthOscGUILevel::handle_event()
00800 {
00801         SynthOscillatorConfig *config = synth->config.oscillator_config.values[gui->number];
00802         config->level = get_value();
00803         gui->window->canvas->update();
00804         synth->send_configure_change();
00805         return 1;
00806 }
00807 
00808 
00809 
00810 SynthOscGUIPhase::SynthOscGUIPhase(Synth *synth, SynthOscGUI *gui, int y)
00811  : BC_IPot(125, 
00812         y, 
00813         (int64_t)(synth->config.oscillator_config.values[gui->number]->phase * 360), 
00814         0, 
00815         360)
00816 {
00817         this->synth = synth;
00818         this->gui = gui;
00819 }
00820 
00821 SynthOscGUIPhase::~SynthOscGUIPhase()
00822 {
00823 }
00824 
00825 int SynthOscGUIPhase::handle_event()
00826 {
00827         SynthOscillatorConfig *config = synth->config.oscillator_config.values[gui->number];
00828         config->phase = (float)get_value() / 360;
00829         gui->window->canvas->update();
00830         synth->send_configure_change();
00831         return 1;
00832 }
00833 
00834 
00835 
00836 SynthOscGUIFreq::SynthOscGUIFreq(Synth *synth, SynthOscGUI *gui, int y)
00837  : BC_IPot(200, 
00838         y, 
00839         (int64_t)(synth->config.oscillator_config.values[gui->number]->freq_factor), 
00840         1, 
00841         100)
00842 {
00843         this->synth = synth;
00844         this->gui = gui;
00845 }
00846 
00847 SynthOscGUIFreq::~SynthOscGUIFreq()
00848 {
00849 }
00850 
00851 int SynthOscGUIFreq::handle_event()
00852 {
00853         SynthOscillatorConfig *config = synth->config.oscillator_config.values[gui->number];
00854         config->freq_factor = get_value();
00855         gui->window->canvas->update();
00856         synth->send_configure_change();
00857         return 1;
00858 }
00859 
00860 
00861 
00862 
00863 
00864 
00865