Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / synthesizer / synthesizer.C
index 194da4c70ec13be23009c71db725a4a135aece7e..3b0e9f2b027f1f85da546ea4f8c58c01f43eb46a 100644 (file)
@@ -1,7 +1,7 @@
 
 /*
  * CINELERRA
- * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * Copyright (C) 1997-2017 Adam Williams <broadcast at earthling dot net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -44,8 +44,8 @@ Synth::Synth(PluginServer *server)
  : PluginAClient(server)
 {
        reset();
-       window_w = 640;
-       window_h = 480;
+       window_w = xS(640);
+       window_h = yS(480);
 }
 
 
@@ -86,7 +86,6 @@ void Synth::read_data(KeyFrame *keyframe)
 
 //printf("Synth::read_data %s\n", keyframe->get_data());
        int result = 0, current_osc = 0;
-       //int total_oscillators = 0;
        while(!result)
        {
                result = input.read_tag();
@@ -112,7 +111,7 @@ void Synth::read_data(KeyFrame *keyframe)
                                }
 
                                config.wavefunction = input.tag.get_property("WAVEFUNCTION", config.wavefunction);
-                               //total_oscillators = input.tag.get_property("OSCILLATORS", 0);
+                               // int total_oscillators = input.tag.get_property("OSCILLATORS", 0);
                        }
                        else
                        if(input.tag.title_is("OSCILLATOR"))
@@ -164,9 +163,6 @@ void Synth::save_data(KeyFrame *keyframe)
                config.oscillator_config.values[i]->save_data(&output);
        }
 
-       output.tag.set_title("/SYNTH");
-       output.append_tag();
-       output.append_newline();
        output.terminate_string();
 //printf("Synth::save_data %d %s\n", __LINE__, output.string);
 // data is now in *text
@@ -176,19 +172,21 @@ void Synth::save_data(KeyFrame *keyframe)
 
 void Synth::update_gui()
 {
-       if( !thread ) return;
-       SynthWindow *window = (SynthWindow*)thread->window;
-// load_configuration,read_data deletes oscillator_config
-       window->lock_window("Synth::update_gui");
-       if( load_configuration() )
-               window->update_gui();
-       window->unlock_window();
+       if(thread)
+       {
+               if(load_configuration())
+               {
+                       thread->window->lock_window();
+                       ((SynthWindow*)thread->window)->update_gui();
+                       thread->window->unlock_window();
+               }
+       }
 }
 
 
 void Synth::add_oscillator()
 {
-       if(config.oscillator_config.total > 20) return;
+       if(config.oscillator_config.total > MAX_OSCILLATORS) return;
 
        config.oscillator_config.append(new SynthOscillatorConfig(config.oscillator_config.total - 1));
 }
@@ -234,8 +232,8 @@ double Synth::solve_eqn(double *output,
                freq;
 // Starting sample in waveform
        double x = waveform_sample;
-       double phase_offset = config->phase * orig_period;
 //printf("Synth::solve_eqn %d %f\n", __LINE__, config->phase);
+       double phase_offset = config->phase * orig_period;
 // Period of current oscillator
        double period = orig_period / config->freq_factor;
        int sample;
@@ -255,9 +253,7 @@ double Synth::solve_eqn(double *output,
                        for(sample = 0; sample < length; sample++)
                        {
                                output[sample] += sin((x + phase_offset) /
-                                       period *
-                                       2 *
-                                       M_PI) * power;
+                                       period * 2 * M_PI) * power;
                                x += step;
                        }
                        break;
@@ -425,11 +421,7 @@ int Synth::overlay_synth(double freq,
 {
        double normalize_constant = 1.0 / get_total_power();
        for(int i = 0; i < config.oscillator_config.total; i++)
-               solve_eqn(output,
-                       length,
-                       freq,
-                       normalize_constant,
-                       i);
+               solve_eqn(output, length, freq, normalize_constant, i);
        return length;
 }
 
@@ -501,39 +493,9 @@ void Synth::delete_freqs()
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 SynthWindow::SynthWindow(Synth *synth)
- : PluginClientWindow(synth,
-       synth->window_w,
-       synth->window_h,
-       400,
-       350,
-       1)
+ : PluginClientWindow(synth, synth->window_w, synth->window_h,
+               xS(400), yS(350), 1)
 {
        this->synth = synth;
        white_key[0] = 0;
@@ -564,6 +526,8 @@ static const char *keyboard_map[] =
 
 void SynthWindow::create_objects()
 {
+       int margin = client->get_theme()->widget_border;
+
        BC_MenuBar *menu;
        add_subwindow(menu = new BC_MenuBar(0, 0, get_w()));
 
@@ -584,72 +548,75 @@ void SynthWindow::create_objects()
        phasemenu->add_item(new SynthPhaseSine(synth));
        phasemenu->add_item(new SynthPhaseZero(synth));
 
+       harmonicmenu->add_item(new SynthFreqMin(synth));
        harmonicmenu->add_item(new SynthFreqEnum(synth));
        harmonicmenu->add_item(new SynthFreqEven(synth));
        harmonicmenu->add_item(new SynthFreqFibonacci(synth));
        harmonicmenu->add_item(new SynthFreqOdd(synth));
        harmonicmenu->add_item(new SynthFreqPrime(synth));
 
-       int x = 10, y = 30;
+       int xs10 = xS(10), xs20 = xS(20), xs50 = xS(50), xs70 = xS(70), xs75 = xS(75), xs240 = xS(240), xs265 = xS(265);
+       int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys220 = yS(220);
+       int x = xs10, y = ys30;
 
        add_subwindow(new BC_Title(x, y, _("Waveform")));
-       x += 240;
+       x += xs240;
        add_subwindow(new BC_Title(x, y, _("Wave Function")));
-       y += 20;
-       x = 10;
-       add_subwindow(canvas = new SynthCanvas(synth, this, x, y, 230, 160));
+       y += ys20;
+       x = xs10;
+       add_subwindow(canvas = new SynthCanvas(synth, this, x, y, xS(230), yS(160)));
        canvas->update();
 
-       x += 240;
+       x += xs240;
        char string[BCTEXTLEN];
        waveform_to_text(string, synth->config.wavefunction);
 
        add_subwindow(waveform = new SynthWaveForm(synth, x, y, string));
        waveform->create_objects();
-       y += 30;
-       int x1 = x + waveform->get_w() + 10;
+       y += ys30;
+       int x1 = x + waveform->get_w() + xs50;
 
 
        add_subwindow(new BC_Title(x, y, _("Base Frequency:")));
-       y += 30;
+       y += ys30;
        add_subwindow(base_freq = new SynthBaseFreq(synth, this, x, y));
        base_freq->update((float)synth->config.base_freq[0]);
        x += base_freq->get_w() + synth->get_theme()->widget_border;
-       add_subwindow(freqpot = new SynthFreqPot(synth, this, x, y - 10));
+       add_subwindow(freqpot = new SynthFreqPot(synth, this, x, y - ys10));
        base_freq->freq_pot = freqpot;
        freqpot->freq_text = base_freq;
        x -= base_freq->get_w() + synth->get_theme()->widget_border;
-       y += 40;
+       y += ys40;
        add_subwindow(new BC_Title(x, y, _("Wetness:")));
-       add_subwindow(wetness = new SynthWetness(synth, x + 70, y - 10));
+       add_subwindow(wetness = new SynthWetness(synth, x + xs70, y - ys10));
 
-       y += 40;
+       y += ys40;
        add_subwindow(new SynthClear(synth, x, y));
 
 
-       x = 50;
-       y = 220;
+       x = xs50;
+       y = ys220;
        add_subwindow(new BC_Title(x, y, _("Level")));
-       x += 75;
+       x += xs75;
        add_subwindow(new BC_Title(x, y, _("Phase")));
-       x += 75;
+       x += xs75;
        add_subwindow(new BC_Title(x, y, _("Harmonic")));
 
 
 
-       y += 20; x = 10;
-       add_subwindow(osc_subwindow = new BC_SubWindow(x, y, 265, get_h() - y));
-       x += 265;
+       y += ys20; x = xs10;
+       add_subwindow(osc_subwindow = new BC_SubWindow(x, y, xs265, get_h() - y));
+       x += xs265;
        add_subwindow(osc_scroll = new OscScroll(synth, this, x, y, get_h() - y));
 
 
-       x += 20;
+       x += xs20;
        add_subwindow(new SynthAddOsc(synth, this, x, y));
-       y += 30;
+       y += ys30;
        add_subwindow(new SynthDelOsc(synth, this, x, y));
 
 // Create keyboard
-       y = 30;
+       y = ys30;
 
 #include "white_up_png.h"
 #include "white_hi_png.h"
@@ -673,27 +640,22 @@ void SynthWindow::create_objects()
        black_key[4] = new VFramePng(black_checkedhi_png);
 
 
-       add_subwindow(note_subwindow = new BC_SubWindow(x1,
-               y,
-               get_w() - x1,
-               white_key[0]->get_h() + MARGIN +
-               get_text_height(MEDIUMFONT) + MARGIN +
-               get_text_height(MEDIUMFONT) + MARGIN));
-       add_subwindow(note_scroll = new NoteScroll(synth,
-               this,
-               x1,
+       add_subwindow(note_subwindow = new BC_SubWindow(x1+xS(20),
+               y, get_w() - (x1+xS(20)),
+               white_key[0]->get_h() + margin +
+               get_text_height(MEDIUMFONT) + margin +
+               get_text_height(MEDIUMFONT) + margin));
+       add_subwindow(note_scroll = new NoteScroll(synth, this, x1,
                note_subwindow->get_y() + note_subwindow->get_h(),
                note_subwindow->get_w()));
 
-       add_subwindow(momentary = new SynthMomentary(this,
-               x1,
-               note_scroll->get_y() + note_scroll->get_h() + MARGIN,
+       add_subwindow(momentary = new SynthMomentary(this, x1,
+               note_scroll->get_y() + note_scroll->get_h() + margin,
                _("Momentary notes")));
 
 
-       add_subwindow(note_instructions = new BC_Title(
-               x1,
-               momentary->get_y() + momentary->get_h() + MARGIN,
+       add_subwindow(note_instructions = new BC_Title( x1,
+               momentary->get_y() + momentary->get_h() + margin,
                _("Ctrl or Shift to select multiple notes.")));
 
        update_scrollbar();
@@ -710,7 +672,7 @@ int SynthWindow::keypress_event()
                set_done(1);
                return 1;
        }
-       return 0;
+       return context_help_check_and_show();
 }
 
 int SynthWindow::resize_event(int w, int h)
@@ -783,8 +745,7 @@ void SynthWindow::update_whitekey(int number,
                if(number >= FIRST_TITLE && number < LAST_TITLE)
                        note_subwindow->add_subwindow(
                                note_titles[(*current_title)++] = new BC_Title(
-                                       x + text_white_margin,
-                                       y2,
+                                       x + text_white_margin, y2,
                                        keyboard_map[number - FIRST_TITLE]));
 //printf("SynthWindow::update_whitekey %d\n", __LINE__);
        }
@@ -810,15 +771,13 @@ void SynthWindow::update_blackkey(int number,
                if(number >= FIRST_TITLE && number < LAST_TITLE)
                        note_subwindow->add_subwindow(
                                note_titles[(*current_title)++] = new BC_Title(x + text_black_margin,
-                                       y1,
-                                       keyboard_map[number - FIRST_TITLE]));
+                                       y1, keyboard_map[number - FIRST_TITLE]));
        }
        else
        {
                notes[number]->reposition_window(x, y);
                if(number >= FIRST_TITLE && number < LAST_TITLE)
-                       note_titles[(*current_title)++]->reposition_window(x + text_black_margin,
-                                       y1);
+                       note_titles[(*current_title)++]->reposition_window(x + text_black_margin, y1);
        }
 }
 
@@ -830,11 +789,10 @@ void SynthWindow::update_notes()
        int white_w1 = white_w - black_w / 2 - 2;
        int white_w2 = white_w / 2;
        int white_w3 = white_w * 2 / 3;
-       int y = 0;
-       int x = 0;
-       y1 = y + white_key[0]->get_h() + 10;
-       y2 = y1 + get_text_height(MEDIUMFONT) + 10;
-       y3 = y2 + get_text_height(MEDIUMFONT) + 10;
+       int x = 0, y = 0, ys5 = yS(5);
+       y1 = y + white_key[0]->get_h() + ys5;
+       y2 = y1 + get_text_height(MEDIUMFONT) + ys5;
+       y3 = y2 + get_text_height(MEDIUMFONT) + ys5;
        text_black_margin = black_w / 2 - get_text_width(MEDIUMFONT, "O") / 2;
        text_white_margin = white_w / 2 - get_text_width(MEDIUMFONT, "O") / 2;
 
@@ -985,7 +943,7 @@ void SynthWindow::update_oscillators()
                {
                        gui = oscillators.values[i];
 
-                       gui->title->reposition_window(gui->title->get_x(), y + 15);
+                       gui->title->reposition_window(gui->title->get_x(), y + yS(15));
 
                        gui->level->reposition_window(gui->level->get_x(), y);
                        gui->level->update(config->level);
@@ -994,7 +952,7 @@ void SynthWindow::update_oscillators()
                        gui->phase->update((int64_t)(config->phase * 360));
 
                        gui->freq->reposition_window(gui->freq->get_x(), y);
-                       gui->freq->update((int64_t)(config->freq_factor));
+                       gui->freq->update(config->freq_factor);
                }
                y += OSCILLATORHEIGHT;
        }
@@ -1024,10 +982,7 @@ int SynthWindow::waveform_to_text(char *text, int waveform)
 
 
 SynthMomentary::SynthMomentary(SynthWindow *window, int x, int y, char *text)
- : BC_CheckBox(x,
-       y,
-       window->synth->config.momentary_notes,
-       text)
+ : BC_CheckBox(x, y, window->synth->config.momentary_notes, text)
 {
        this->window = window;
 }
@@ -1042,15 +997,8 @@ int SynthMomentary::handle_event()
 
 
 
-SynthNote::SynthNote(SynthWindow *window,
-       VFrame **images,
-       int number,
-       int x,
-       int y)
- : BC_Toggle(x,
-       y,
-       images,
-       window->synth->freq_exists(keyboard_freqs[number]))
+SynthNote::SynthNote(SynthWindow *window, VFrame **images, int number, int x, int y)
+ : BC_Toggle(x, y, images, window->synth->freq_exists(keyboard_freqs[number]))
 {
        this->window = window;
        this->number = number;
@@ -1090,6 +1038,13 @@ void SynthNote::stop_note()
 
 int SynthNote::keypress_event()
 {
+// Evtl catch Alt/H
+       if (get_keypress() == 'h' && alt_down())
+       {
+               context_help_show();
+               return 1;
+       }
+
        if(number >= FIRST_TITLE && number < LAST_TITLE)
        {
                if(get_keypress() == keyboard_map[number - FIRST_TITLE][0])
@@ -1258,7 +1213,7 @@ void SynthOscGUI::create_objects(int y)
 {
        char text[BCTEXTLEN];
        sprintf(text, "%d:", number + 1);
-       window->osc_subwindow->add_subwindow(title = new BC_Title(10, y + 15, text));
+       window->osc_subwindow->add_subwindow(title = new BC_Title(xS(10), y+yS(15), text));
 
        window->osc_subwindow->add_subwindow(level = new SynthOscGUILevel(window->synth, this, y));
        window->osc_subwindow->add_subwindow(phase = new SynthOscGUIPhase(window->synth, this, y));
@@ -1269,11 +1224,9 @@ void SynthOscGUI::create_objects(int y)
 
 
 SynthOscGUILevel::SynthOscGUILevel(Synth *synth, SynthOscGUI *gui, int y)
- : BC_FPot(50,
-       y,
+ : BC_FPot(xS(50), y,
        synth->config.oscillator_config.values[gui->number]->level,
-       INFINITYGAIN,
-       0)
+       INFINITYGAIN, 0)
 {
        this->synth = synth;
        this->gui = gui;
@@ -1295,11 +1248,9 @@ int SynthOscGUILevel::handle_event()
 
 
 SynthOscGUIPhase::SynthOscGUIPhase(Synth *synth, SynthOscGUI *gui, int y)
- : BC_IPot(125,
-       y,
+ : BC_IPot(xS(125), y,
        (int64_t)(synth->config.oscillator_config.values[gui->number]->phase * 360),
-       0,
-       360)
+       0, 360)
 {
        this->synth = synth;
        this->gui = gui;
@@ -1321,11 +1272,9 @@ int SynthOscGUIPhase::handle_event()
 
 
 SynthOscGUIFreq::SynthOscGUIFreq(Synth *synth, SynthOscGUI *gui, int y)
- : BC_IPot(200,
-       y,
+ : BC_FPot(xS(200), y,
        (int64_t)(synth->config.oscillator_config.values[gui->number]->freq_factor),
-       1,
-       100)
+       1, 100)
 {
        this->synth = synth;
        this->gui = gui;
@@ -1345,11 +1294,6 @@ int SynthOscGUIFreq::handle_event()
 }
 
 
-
-
-
-
-
 SynthAddOsc::SynthAddOsc(Synth *synth, SynthWindow *window, int x, int y)
  : BC_GenericButton(x, y, _("Add"))
 {
@@ -1370,7 +1314,6 @@ int SynthAddOsc::handle_event()
 }
 
 
-
 SynthDelOsc::SynthDelOsc(Synth *synth, SynthWindow *window, int x, int y)
  : BC_GenericButton(x, y, _("Delete"))
 {
@@ -1391,18 +1334,11 @@ int SynthDelOsc::handle_event()
 }
 
 
-OscScroll::OscScroll(Synth *synth,
-       SynthWindow *window,
-       int x,
-       int y,
-       int h)
- : BC_ScrollBar(x,
-       y,
-       SCROLL_VERT,
-       h,
+OscScroll::OscScroll(Synth *synth, SynthWindow *window,
+               int x, int y, int h)
+ : BC_ScrollBar(x, y, SCROLL_VERT, h,
        synth->config.oscillator_config.total * OSCILLATORHEIGHT,
-       0,
-       window->osc_subwindow->get_h())
+       0, window->osc_subwindow->get_h())
 {
        this->synth = synth;
        this->window = window;
@@ -1420,18 +1356,11 @@ int OscScroll::handle_event()
 
 
 
-NoteScroll::NoteScroll(Synth *synth,
-       SynthWindow *window,
-       int x,
-       int y,
-       int w)
- : BC_ScrollBar(x,
-       y,
-       SCROLL_HORIZ,
-       w,
+NoteScroll::NoteScroll(Synth *synth, SynthWindow *window,
+               int x, int y, int w)
+ : BC_ScrollBar(x, y, SCROLL_HORIZ, w,
        window->white_key[0]->get_w() * TOTALNOTES * 7 / 12 + window->white_key[0]->get_w(),
-       0,
-       window->note_subwindow->get_w())
+       0, window->note_subwindow->get_w())
 {
        this->synth = synth;
        this->window = window;
@@ -1448,18 +1377,6 @@ int NoteScroll::handle_event()
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
 SynthClear::SynthClear(Synth *synth, int x, int y)
  : BC_GenericButton(x, y, _("Clear"))
 {
@@ -1482,7 +1399,7 @@ int SynthClear::handle_event()
 
 
 SynthWaveForm::SynthWaveForm(Synth *synth, int x, int y, char *text)
- : BC_PopupMenu(x, y, 120, text)
+ : BC_PopupMenu(x, y, xS(120), text)
 {
        this->synth = synth;
 }
@@ -1524,11 +1441,7 @@ int SynthWaveFormItem::handle_event()
 
 
 SynthWetness::SynthWetness(Synth *synth, int x, int y)
- : BC_FPot(x,
-               y,
-               synth->config.wetness,
-               INFINITYGAIN,
-               0)
+ : BC_FPot(x, y, synth->config.wetness, INFINITYGAIN, 0)
 {
        this->synth = synth;
 }
@@ -1566,7 +1479,7 @@ int SynthFreqPot::handle_event()
 
 
 SynthBaseFreq::SynthBaseFreq(Synth *synth, SynthWindow *window, int x, int y)
- : BC_TextBox(x, y, 100, 1, (float)0)
+ : BC_TextBox(x, y, xS(100), 1, (float)0)
 {
        this->synth = synth;
        this->window = window;
@@ -1593,17 +1506,9 @@ int SynthBaseFreq::handle_event()
 
 
 
-SynthCanvas::SynthCanvas(Synth *synth,
-       SynthWindow *window,
-       int x,
-       int y,
-       int w,
-       int h)
- : BC_SubWindow(x,
-       y,
-       w,
-       h,
-       BLACK)
+SynthCanvas::SynthCanvas(Synth *synth, SynthWindow *window,
+               int x, int y, int w, int h)
+ : BC_SubWindow(x, y, w, h, BLACK)
 {
        this->synth = synth;
        this->window = window;
@@ -1638,12 +1543,6 @@ int SynthCanvas::update()
 }
 
 
-
-
-
-
-
-
 // ======================= level calculations
 SynthLevelZero::SynthLevelZero(Synth *synth)
  : BC_MenuItem(_("Zero"))
@@ -1935,6 +1834,74 @@ int SynthFreqRandom::handle_event()
        return 1;
 }
 
+SynthFreqPow1::SynthFreqPow1(Synth *synth)
+ : BC_MenuItem(_("Powers of 1.4"))
+{
+       this->synth = synth;
+}
+SynthFreqPow1::~SynthFreqPow1()
+{
+}
+
+int SynthFreqPow1::handle_event()
+{
+       for(int i = 0; i < synth->config.oscillator_config.total; i++)
+       {
+               synth->config.oscillator_config.values[i]->freq_factor = pow(sqrt(2), i);
+       }
+
+       ((SynthWindow*)synth->thread->window)->update_gui();
+       synth->send_configure_change();
+       return 1;
+}
+
+
+SynthFreqPow2::SynthFreqPow2(Synth *synth)
+ : BC_MenuItem(_("Powers of 2"))
+{
+       this->synth = synth;
+}
+SynthFreqPow2::~SynthFreqPow2()
+{
+}
+
+int SynthFreqPow2::handle_event()
+{
+       for(int i = 0; i < synth->config.oscillator_config.total; i++)
+       {
+               synth->config.oscillator_config.values[i]->freq_factor = pow(2, i);
+       }
+
+       ((SynthWindow*)synth->thread->window)->update_gui();
+       synth->send_configure_change();
+       return 1;
+}
+
+
+
+
+SynthFreqMin::SynthFreqMin(Synth *synth)
+ : BC_MenuItem(_("Minimum"))
+{
+       this->synth = synth;
+}
+SynthFreqMin::~SynthFreqMin()
+{
+}
+
+int SynthFreqMin::handle_event()
+{
+       for(int i = 0; i < synth->config.oscillator_config.total; i++)
+       {
+               synth->config.oscillator_config.values[i]->freq_factor = 1;
+       }
+
+       ((SynthWindow*)synth->thread->window)->update_gui();
+       synth->send_configure_change();
+       return 1;
+}
+
+
 SynthFreqEnum::SynthFreqEnum(Synth *synth)
  : BC_MenuItem(_("Enumerate"))
 {
@@ -2014,7 +1981,8 @@ int SynthFreqFibonacci::handle_event()
        for(int i = 0; i < synth->config.oscillator_config.total; i++)
        {
                synth->config.oscillator_config.values[i]->freq_factor = last_value1 + last_value2;
-               if(synth->config.oscillator_config.values[i]->freq_factor > 100) synth->config.oscillator_config.values[i]->freq_factor = 100;
+               if(synth->config.oscillator_config.values[i]->freq_factor > 100)
+                       synth->config.oscillator_config.values[i]->freq_factor = 100;
                last_value1 = last_value2;
                last_value2 = synth->config.oscillator_config.values[i]->freq_factor;
        }