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
00108 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00109
00110
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
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
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;
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;
00363 return (x < .5) ? -1 : 1;
00364 }
00365
00366 double Synth::function_pulse(double x)
00367 {
00368 x -= (int)x;
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
00409 fragment_len = overlay_synth(i, fragment_len, input_ptr, output_ptr);
00410
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
00423
00424
00425
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
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
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
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;
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
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
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
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
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