%% Design User Interface for Audio Plugin
% Audio plugins enable you to tune parameters of a processing algorithm while streaming audio in real time. To enhance usability, you can define a custom user interface (UI) that maps parameters to intuitively designed and positioned controls. You can use audioPluginInterface, audioPluginParameter, and audioPluginGridLayout to define the custom UI. You can interact with the custom UI in MATLAB®  using parameterTuner, or deploy the plugin with a custom UI to a digital audio workstation (DAW). This tutorial walks through key design capabilities of audio plugins by sequentially enhancing a basic audio plugin UI.
% To learn more about audio plugins in general, see Design an Audio Plugin.
%% Default User Interface
% The equalizerV1 audio plugin enables you to tune the gains and center frequencies of a three-band equalizer, tune the overall volume, and toggle between enabled and disabled states.
% classdef equalizerV1 < audioPlugin
%     properties
%         GainLow = 0
%         FreqLow = sqrt(20*500)
%         GainMid = 0
%         FreqMid = sqrt(500*3e3)
%         GainHigh = 0
%         FreqHigh = sqrt(3e3*20e3)
%         Volume = 1
%         Enable = true
%     end
%     properties (Constant)
%         PluginInterface = audioPluginInterface( ...
%             audioPluginParameter('GainLow', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}), ...
%             audioPluginParameter('FreqLow', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',20,500}), ...
%             audioPluginParameter('GainMid', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}), ...
%             audioPluginParameter('FreqMid', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',500,3e3}), ...
%             audioPluginParameter('GainHigh', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}), ...
%             audioPluginParameter('FreqHigh', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',3e3,20e3}), ...
%             audioPluginParameter('Volume', ...
%                 'Mapping',{'lin',0,2}), ...
%             audioPluginParameter('Enable'))
%     end
%     properties (Access = private)
%         mPEQ
%     end
%     methods
%         function obj = equalizerV1
%             obj.mPEQ = multibandParametricEQ('HasHighpassFilter',false, ...
%                 'HasLowShelfFilter',false,'HasHighShelfFilter',false, ...
%                 'HasLowpassFilter',false,'Oversample',false,'NumEQBands',3, ...
%                 'EQOrder',2);
%         end
%         function y = process(obj, x)
%             if obj.Enable
%                 y = step(obj.mPEQ,x);
%                 y = y*obj.Volume;
%             else
%                 y = x;
%             end
%         end
%         function reset(obj)
%             obj.mPEQ.SampleRate = getSampleRate(obj);
%             reset(obj.mPEQ);
%         end
%         function set.FreqLow(obj,val)
%             obj.FreqLow = val;
%             obj.mPEQ.Frequencies(1) = val; %#ok<*MCSUP>
%         end
%         function set.GainLow(obj,val)
%             obj.GainLow = val;
%             obj.mPEQ.PeakGains(1) = val;
%         end
%         function set.FreqMid(obj,val)
%             obj.FreqMid = val;
%             obj.mPEQ.Frequencies(2) = val;
%         end
%         function set.GainMid(obj,val)
%             obj.GainMid = val;
%             obj.mPEQ.PeakGains(2) = val;
%         end
%         function set.FreqHigh(obj,val)
%             obj.FreqHigh = val;
%             obj.mPEQ.Frequencies(3) = val;
%         end
%         function set.GainHigh(obj,val)
%             obj.GainHigh = val;
%             obj.mPEQ.PeakGains(3) = val;
%         end
%     end
% end
% Call parameterTuner to visualize the default UI of the audio plugin.

parameterTuner(equalizerV1)

%
%
%% Control Style and Layout
% To define the UI grid, add audioPluginGridLayout to the audioPluginInterface. You can specify the number, size, spacing, and border of cells in the UI grid. In this example, specify RowHeight as [20,20,160,20,100] and ColumnWidth as [100,100,100,50,150]. This creates the following UI grid:
%
% To define the UI control style, update the audioPluginParameter definition of each parameter to include the Style and Layout name-value pairs. Style defines the type of control (rotary knob, slider, or switch, for example). Layout defines which cells the controls occupy on the UI grid. You can specify Layout as the [row, column] of the grid to occupy, or as the [upper, left; lower, right] of the group of cells to occupy. By default, control display names are also displayed and occupy their own cells on the UI grid. The cells they occupy depend on the DisplayNameLocation name-value pair.
% The commented arrows indicate the difference between equalizerV1 and equalzierV2.
% classdef equalizerV2 < audioPlugin
%     ... % omited for example purposes
%     properties (Constant)
%         PluginInterface = audioPluginInterface( ...
%             audioPluginParameter('GainLow', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...                                     %<--
%                 'Layout',[2,1;4,1], ...                                    %<--
%                 'DisplayName','Low','DisplayNameLocation','Above'), ...    %<--
%             audioPluginParameter('FreqLow', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',20,500}, ...
%                 'Style','rotaryknob', ...                                  %<--
%                 'Layout',[5,1], ...                                        %<--
%                 'DisplayNameLocation','None'), ...                         %<--
%             audioPluginParameter('GainMid', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...                                     %<--
%                 'Layout',[2,2;4,2], ...                                    %<--
%                 'DisplayNameLocation','None'), ...                         %<--
%             audioPluginParameter('FreqMid', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',500,3e3}, ...
%                 'Style','rotaryknob', ...                                  %<--
%                 'Layout',[5,2], ...                                        %<--
%                 'DisplayNameLocation','None'), ...                         %<--
%             audioPluginParameter('GainHigh', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...                                     %<--
%                 'Layout',[2,3;4,3], ...                                    %<--
%                 'DisplayName','High','DisplayNameLocation','Above'), ...   %<--
%             audioPluginParameter('FreqHigh', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',3e3,20e3}, ...
%                 'Style','rotaryknob', ...                                  %<--
%                 'Layout',[5,3], ...                                        %<--
%                 'DisplayNameLocation','None'), ...                         %<--
%             audioPluginParameter('Volume', ...
%                 'Mapping',{'lin',0,2}, ...
%                 'Style','rotaryknob', ...                                  %<--
%                 'Layout',[3,5], ...                                        %<--
%                 'DisplayNameLocation','Above'), ...                        %<--
%             audioPluginParameter('Enable', ...
%                 'Style','vtoggle', ...                                     %<--
%                 'Layout',[5,5], ...                                        %<--
%                 'DisplayNameLocation','None'), ...                         %<--
%                 ...
%             audioPluginGridLayout( ...                                     %<--
%                 'RowHeight',[20,20,160,20,100], ...                        %<--
%                 'ColumnWidth',[100,100,100,50,150])                        %<--
%     end
%     ... % omitted for example purposes
% end
% The Layout and DisplayNameLocation defined in the audioPluginParameters maps the respective parameters to the control grid as follows:
%
% Call parameterTuner to visualize the UI of equalizerV2.

parameterTuner(equalizerV2)

%
%
%% Background Image and Color
% To customize the background of your UI, specify BackgroundImage and BackgroundColor in audioPluginInterface.
% The BackgroundColor can be specified as a short or long color name string or as an RBG triplet. See ColorSpec (Color Specification) for details. When you specify BackgroundColor, the color is applied to all space on the UI except space occupied by controls or a BackgroundImage. If the control or background image includes a transparency, then the background color shows through the transparency.
% The BackgroundImage can be specified as a PNG, GIF, or JPG file. The image is applied to the UI grid by aligning the top left corners of the UI grid and image. If the image is larger than the UI grid size defined in audioPluginGridLayout, then the image is clipped to the UI grid size. The background image is not resized. If the image is smaller than the UI grid, then unoccupied regions of the UI grid are treated as transparent.
% In this example, you increase the padding around the perimeter of the grid to create space for the MathWorks® logo. You can calculate the total width of the UI grid as the sum of all column widths plus the left and right padding plus the column spacing (the default column spacing of 10 pixels is used in this example): \left(100+100+100+50+150\right)+\left(20+20\right)+\left(4\times 10\right)=580. The total height of the UI grid is the sum of all row heights plus the top and bottom padding plus the row spacing (the default row spacing of 10 pixels is used in this example):\left(20+20+160+20+100\right)+\left(20+120\right)+\left(4\times 10\right)=500\ldotp To locate the logo at the bottom of the UI grid, use a 580-by-500 image:
%
% classdef equalizerV3 < audioPlugin
%     ... % omitted for example purposes
%     properties (Constant)
%         PluginInterface = audioPluginInterface( ...
%             audioPluginParameter('GainLow', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,1;4,1], ...
%                 'DisplayName','Low','DisplayNameLocation','Above'), ...
%             audioPluginParameter('FreqLow', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',20,500}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,1], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('GainMid', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,2;4,2], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('FreqMid', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',500,3e3}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,2], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('GainHigh', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,3;4,3], ...
%                 'DisplayName','High','DisplayNameLocation','Above'), ...
%             audioPluginParameter('FreqHigh', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',3e3,20e3}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,3], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('Volume', ...
%                 'DisplayName','Volume', ...
%                 'Mapping',{'lin',0,2}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[3,5], ...
%                 'DisplayNameLocation','Above'), ...
%             audioPluginParameter('Enable', ...
%                 'Style','vtoggle', ...
%                 'Layout',[5,5], ...
%                 'DisplayNameLocation','None'), ...
%                 ...
%             audioPluginGridLayout( ...
%                 'RowHeight',[20,20,160,20,100], ...
%                 'ColumnWidth',[100,100,100,50,150], ...
%                 'Padding',[20,120,20,20]), ...                             %<--
%                 ...
%             'BackgroundImage','background.png', ...                        %<--
%             'BackgroundColor',[210/255,210/255,210/255])                   %<--
%     end
%     ... % omited for example purposes
% end
% Call parameterTuner to visualize the UI of equalizerV3.

parameterTuner(equalizerV3)

%
%
%% Custom Control Filmstrips
% To use custom filmstrips, specify the Filmstrip and FilmstripFrameSize name-value pairs in audioPluginParameter. The filmstrip can be a PNG, GIF, or JPG file, and should consist of frames placed end-to-end either vertically or horizontally. The filmstrip is mapped to the control's range so that the corresponding filmstrip frame is displayed on the plugin UI as you tune parameters. In this example, specify a two-frame filmstrip for the Enable parameter. As a best practice, the size of each frame of the film strip should equal the size of the region occupied by the parameter. The Enable parameter occupies one cell that is 150-by-100 pixels. To create a vertical filmstrip where each frame is 150-by-100, make the total filmstrip size 150-by-200 and set FilmstripFrameSize to [150,100]. The filmstrip used in this example contains the frame corresponding to the off position first, then the on position:
%
% classdef equalizerV4 < audioPlugin
%     ... % omitted for example purposes
%     properties (Constant)
%         PluginInterface = audioPluginInterface( ...
%             audioPluginParameter('GainLow', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,1;4,1], ...
%                 'DisplayName','Low','DisplayNameLocation','Above'), ...
%             audioPluginParameter('FreqLow', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',20,500}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,1], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('GainMid', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,2;4,2], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('FreqMid', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',500,3e3}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,2], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('GainHigh', ...
%                 'Label','dB', ...
%                 'Mapping',{'lin',-20,20}, ...
%                 'Style','vslider', ...
%                 'Layout',[2,3;4,3], ...
%                 'DisplayName','High','DisplayNameLocation','Above'), ...
%             audioPluginParameter('FreqHigh', ...
%                 'Label','Hz', ...
%                 'Mapping',{'log',3e3,20e3}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[5,3], ...
%                 'DisplayNameLocation','None'), ...
%             audioPluginParameter('Volume', ...
%                 'Mapping',{'lin',0,2}, ...
%                 'Style','rotaryknob', ...
%                 'Layout',[3,5], ...
%                 'DisplayNameLocation','Above'), ...
%             audioPluginParameter('Enable', ...
%                 'Style','vtoggle', ...
%                 'Layout',[5,5], ...
%                 'DisplayNameLocation','None', ...
%                 'Filmstrip','vtoggle.png', ...                             %<--
%                 'FilmstripFrameSize',[150,100]), ...                       %<--
%                 ...
%             audioPluginGridLayout( ...
%                 'RowHeight',[20,20,160,20,100], ...
%                 'ColumnWidth',[100,100,100,50,150], ...
%                 'Padding',[20,120,20,20]), ...
%                 ...
%             'BackgroundImage','background.png', ...
%             'BackgroundColor',[210/255,210/255,210/255])
%     end
%     ... % omitted for example purposes
% end
% Filmstrips are not supported by parameterTuner. To see the custom plugin UI, you must deploy the plugin to a DAW. Use generateAudioPlugin to create a VST plugin.

generateAudioPlugin equalizerV4

% In this example, the plugin was opened in REAPER. A screenshot of the UI in REAPER is displayed below.
%
% Copyright 2019 The MathWorks, Inc.