AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

WowFlutterMenu.cpp (4381B)


      1 #include "WowFlutterMenu.h"
      2 
      3 class WowFlutterMenuLNF : public ComboBoxLNF
      4 {
      5 public:
      6     WowFlutterMenuLNF() = default;
      7 
      8     void drawComboBox (Graphics& g, int width, int height, bool, int, int, int, int, ComboBox& box) override
      9     {
     10         auto cornerSize = 5.0f;
     11         Rectangle<int> boxBounds (0, 0, width, height);
     12 
     13         g.setColour (box.findColour (ComboBox::backgroundColourId));
     14         g.fillRoundedRectangle (boxBounds.toFloat(), cornerSize);
     15 
     16         g.setColour (box.findColour (ComboBox::outlineColourId));
     17         g.drawRoundedRectangle (boxBounds.toFloat().reduced (1.0f), cornerSize, 1.0f);
     18 
     19         if (box.getName().isNotEmpty())
     20         {
     21             g.setColour (Colours::white);
     22             g.setFont (getComboBoxFont (box).boldened());
     23             g.drawFittedText (box.getName(), boxBounds, Justification::centred, 1);
     24         }
     25     }
     26 
     27     void positionComboBoxText (ComboBox& box, Label& label) override
     28     {
     29         auto b = box.getBounds();
     30         label.setBounds (b);
     31         label.setFont (getComboBoxFont (box).boldened());
     32     }
     33 
     34 private:
     35     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WowFlutterMenuLNF)
     36 };
     37 
     38 //============================================================================
     39 namespace
     40 {
     41 float flutterFreqToParam (float freq)
     42 {
     43     return 0.144765f * std::log (10.0f * freq);
     44 }
     45 
     46 float wowFreqToParam (float freq)
     47 {
     48     return 0.664859f * std::log (freq + 1.0f);
     49 }
     50 } // namespace
     51 
     52 WowFlutterMenu::WowFlutterMenu (const ChowtapeModelAudioProcessor& proc, const String& type) : proc (proc)
     53 {
     54     setDescription (type + " Sync Menu");
     55     setupUI();
     56 
     57     const bool isFlutter = type == "Flutter";
     58     setupRateParam (isFlutter);
     59 
     60     auto snycToTapeSpeed = [=, &proc]
     61     {
     62         const auto& vts = proc.getVTS();
     63         if (auto speedParam = dynamic_cast<AudioParameterFloat*> (vts.getParameter ("speed")))
     64         {
     65             auto speedIps = speedParam->get();
     66 
     67             auto motorFreq = speedIps / (6.0f * MathConstants<float>::pi);
     68             auto newRate = isFlutter ? flutterFreqToParam (motorFreq)
     69                                      : wowFreqToParam (std::sqrt (motorFreq));
     70             setRateValue (newRate);
     71         }
     72         else
     73         {
     74             // speedParam was nullptr!
     75             jassertfalse;
     76         }
     77     };
     78 
     79     auto syncToRhythm = [=, &proc] (float multipleOfQuarterNote)
     80     {
     81         const auto& posInfo = proc.getPositionInfo();
     82         auto quarterNoteTime = 60.0f / (float) posInfo.bpm;
     83 
     84         auto newFreq = 1.0f / (quarterNoteTime * multipleOfQuarterNote);
     85         auto newRate = isFlutter ? flutterFreqToParam (newFreq) : wowFreqToParam (newFreq);
     86         setRateValue (newRate);
     87     };
     88 
     89     auto menu = getRootMenu();
     90     menu->addItem ("Sync to tape speed", snycToTapeSpeed);
     91 
     92     if (isFlutter)
     93     {
     94         menu->addItem ("Sync to eighth note", std::bind (syncToRhythm, 0.125f));
     95         menu->addItem ("Sync to quarter note", std::bind (syncToRhythm, 0.25f));
     96         menu->addItem ("Sync to half note", std::bind (syncToRhythm, 0.5f));
     97         menu->addItem ("Sync to whole note", std::bind (syncToRhythm, 1.0f));
     98     }
     99     else
    100     {
    101         menu->addItem ("Sync to one bar", std::bind (syncToRhythm, 1.0f));
    102         menu->addItem ("Sync to two bars", std::bind (syncToRhythm, 2.0f));
    103         menu->addItem ("Sync to four bars", std::bind (syncToRhythm, 4.0f));
    104         menu->addItem ("Sync to eight bars", std::bind (syncToRhythm, 8.0f));
    105     }
    106 }
    107 
    108 WowFlutterMenu::~WowFlutterMenu()
    109 {
    110     setLookAndFeel (nullptr);
    111 }
    112 
    113 void WowFlutterMenu::setupUI()
    114 {
    115     setColour (ComboBox::backgroundColourId, Colours::transparentBlack);
    116     setColour (ComboBox::outlineColourId, Colour (0xff595c6b));
    117 
    118     lnf = std::make_unique<WowFlutterMenuLNF>();
    119     setLookAndFeel (lnf.get());
    120 
    121     onChange = [=]
    122     { setSelectedItemIndex (-1); };
    123 }
    124 
    125 void WowFlutterMenu::setupRateParam (bool isFlutter)
    126 {
    127     auto& vts = proc.getVTS();
    128     if (isFlutter)
    129         rateParam = dynamic_cast<AudioParameterFloat*> (vts.getParameter ("rate"));
    130     else // "Wow"
    131         rateParam = dynamic_cast<AudioParameterFloat*> (vts.getParameter ("wow_rate"));
    132 
    133     jassert (rateParam); // this should never be nullptr!
    134 }
    135 
    136 void WowFlutterMenu::setRateValue (float value)
    137 {
    138     rateParam->beginChangeGesture();
    139     rateParam->setValueNotifyingHost (jlimit (0.0f, 1.0f, value));
    140     rateParam->endChangeGesture();
    141 }