This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
IntrinsicImaging/WidgetAudioStimuli.m
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
777 lines (587 sloc)
25.5 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
classdef WidgetAudioStimuli < handle | |
%WIDGETAUDIOSTIMULI generates user defined audio stimuli | |
% | |
% GUI Widget for | |
% user defined audio stimuli | |
% choose between monotones, linear or exponential sweeps | |
% load external audio file | |
% combine audio stimuli in trains | |
% plot frequency/time spectrogram | |
% | |
% requires: | |
% uiGridLayout.m | |
% | |
% Georgi Tushev | |
% sciclist@brain.mpg.de | |
% Max-Planck Institute For Brain Research | |
% | |
properties | |
audio | |
end | |
properties (Access = private) | |
duration | |
freqBase | |
freqThresh | |
pulses | |
offset | |
tdata | |
ydata | |
extern | |
tune | |
end | |
properties (Access = protected) | |
ui_parent | |
ui_grid | |
ui_panel | |
ui_edit_duration | |
ui_edit_freqBase | |
ui_edit_freqThresh | |
ui_edit_pulses | |
ui_edit_offset | |
ui_popup_chirp | |
ui_checkbox_train | |
ui_checkbox_extern | |
ui_pushbutton_load | |
ui_pushbutton_spectrum | |
ui_pushbutton_play | |
ui_text_extern | |
ui_spectrogram | |
end | |
properties (Constant = true, Access = private, Hidden = true) | |
UIWINDOW_SIZE = [1, 1, 256, 211]; | |
GRID_VGAP = [12, 2, 5]; | |
GRID_HGAP = [5, 2, 5]; | |
BACKGROUND_COLOR = [1, 1, 1]; | |
FOREGROUND_COLOR = [0.5, 0.5, 0.5]; | |
PUSHBUTTON_SIZE = [1, 1, 90, 26]; | |
EDITBOX_SIZE = [1, 1, 60, 20]; | |
POPUP_SIZE = [1, 1, 90, 20]; | |
CHECKBOX_SIZE = [1, 1, 90, 20]; | |
CHIRP_TYPE = {'pure', 'linear', 'exp'}; | |
SAMPLING_FREQ = 44100; | |
FADE_TIME = 0.05; | |
MIN_FREQUENCY = 1000; | |
MAX_FREQUENCY = 25000; | |
MAX_PULSES = 50; | |
end | |
%% --- constructor / destructor --- %% | |
methods | |
function obj = WidgetAudioStimuli(varargin) | |
%WIDGETAUDIOSTIMULI class constructor | |
parserObj = inputParser; | |
addParameter(parserObj, 'Parent', [], @isgraphics); | |
parse(parserObj, varargin{:}); | |
if isempty(parserObj.Results.Parent) | |
obj.ui_parent = figure(... | |
'Visible', 'on',... | |
'Tag', 'hAudioStimuli',... | |
'Name', 'Audio Stimuli',... | |
'MenuBar', 'none',... | |
'ToolBar', 'none',... | |
'NumberTitle', 'off',... | |
'Color', obj.BACKGROUND_COLOR,... | |
'Resize', 'off',... | |
'Units', 'pixels',... | |
'Position', obj.UIWINDOW_SIZE,... | |
'CloseRequestFcn', @obj.fcnCallback_close); | |
movegui(obj.ui_parent, 'northwest'); | |
else | |
obj.ui_parent = parserObj.Results.Parent; | |
end | |
% set default properties | |
obj.defaults(); | |
% render user interface | |
obj.render(); | |
% compose audio | |
obj.compose(); | |
end | |
function obj = dispose(obj) | |
%DISPOSE class destructor | |
% remove spectrogram figures | |
if isgraphics(obj.ui_spectrogram, 'figure') | |
delete(obj.ui_spectrogram); | |
end | |
% remove audio player object | |
if isa(obj.audio, 'audioplayer') | |
delete(obj.audio); | |
end | |
% remove user interface grid | |
if isa(obj.ui_grid, 'uiGridLayout') | |
delete(obj.ui_grid); | |
end | |
% check if parent is figure or was inherit | |
if isgraphics(obj.ui_parent, 'figure') | |
delete(obj.ui_parent); | |
end | |
% dispose class object | |
delete(obj); | |
end | |
function obj = defaults(obj) | |
%DEFAULTS set default values for class properties | |
% default properties | |
obj.duration = 0.1; | |
obj.freqBase = 5000; | |
obj.freqThresh = 15000; | |
obj.pulses = 5; | |
obj.offset = 0.1; | |
obj.tune = []; | |
obj.extern = []; | |
end | |
function obj = render(obj) | |
%RENDER create user interface | |
%%% --- create widget panel --- %%% | |
obj.ui_panel = uipanel(... | |
'Parent', obj.ui_parent,... | |
'Title', 'Audio Stimuli',... | |
'TitlePosition', 'lefttop',... | |
'BorderType', 'line',... | |
'HighlightColor', obj.FOREGROUND_COLOR,... | |
'ForegroundColor', obj.FOREGROUND_COLOR,... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'normalized',... | |
'Position', [0, 0, 1, 1],... | |
'Units', 'pixels'); | |
%%% --- create grid object --- %%% | |
obj.ui_grid = uiGridLayout(... | |
'Parent', obj.ui_panel,... | |
'VGrid', 7,... | |
'HGrid', 4,... | |
'VGap', obj.GRID_VGAP,... | |
'HGap', obj.GRID_HGAP); | |
%%% --- add UI elements --- %%% | |
ui_text = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'duration [sec]',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 1, 'HIndex', 1:2)); | |
obj.ui_grid.align(ui_text,... | |
'VIndex', 1,... | |
'HIndex', 1:2,... | |
'Anchor', 'east'); | |
obj.ui_edit_duration = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'edit',... | |
'String', sprintf('%.2f', obj.duration),... | |
'Callback', @obj.fcnCallback_parse,... | |
'Units', 'pixels',... | |
'Position', obj.EDITBOX_SIZE); | |
obj.ui_grid.align(obj.ui_edit_duration,... | |
'VIndex', 1,... | |
'HIndex', 3:4,... | |
'Anchor', 'west'); | |
ui_text = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'freq.range [Hz]',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 2, 'HIndex', 1:2)); | |
obj.ui_grid.align(ui_text,... | |
'VIndex', 2,... | |
'HIndex', 1:2,... | |
'Anchor', 'east'); | |
obj.ui_edit_freqBase = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'edit',... | |
'String', sprintf('%d', obj.freqBase),... | |
'Callback', @obj.fcnCallback_parse,... | |
'Units', 'pixels',... | |
'Position', obj.EDITBOX_SIZE); | |
obj.ui_grid.align(obj.ui_edit_freqBase,... | |
'VIndex', 2,... | |
'HIndex', 3,... | |
'Anchor', 'west'); | |
obj.ui_edit_freqThresh = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'edit',... | |
'String', sprintf('%d', obj.freqThresh),... | |
'Enable', 'off',... | |
'Callback', @obj.fcnCallback_parse,... | |
'Units', 'pixels',... | |
'Position', obj.EDITBOX_SIZE); | |
obj.ui_grid.align(obj.ui_edit_freqThresh,... | |
'VIndex', 2,... | |
'HIndex', 4,... | |
'Anchor', 'west'); | |
ui_text = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'chirp function',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 3, 'HIndex', 1:2)); | |
obj.ui_grid.align(ui_text,... | |
'VIndex', 3,... | |
'HIndex', 1:2,... | |
'Anchor', 'east'); | |
obj.ui_popup_chirp = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'popup',... | |
'String', obj.CHIRP_TYPE,... | |
'Value', 1,... | |
'Callback', @obj.fcnCallback_chirp,... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.POPUP_SIZE); | |
obj.ui_grid.align(obj.ui_popup_chirp,... | |
'VIndex', 3,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
obj.ui_checkbox_train = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'checkbox',... | |
'String', 'use train',... | |
'Value', 1,... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Callback', @obj.fcnCallback_checkTrain,... | |
'Units', 'pixels',... | |
'Position', obj.CHECKBOX_SIZE); | |
obj.ui_grid.align(obj.ui_checkbox_train,... | |
'VIndex', 4,... | |
'HIndex', 1:2,... | |
'Anchor', 'center'); | |
obj.ui_checkbox_extern = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'checkbox',... | |
'String', 'use extern',... | |
'Value', 0,... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Callback', @obj.fcnCallback_checkExtern,... | |
'Units', 'pixels',... | |
'Position', obj.CHECKBOX_SIZE); | |
obj.ui_grid.align(obj.ui_checkbox_extern,... | |
'VIndex', 4,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
ui_text = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'pulses',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 5, 'HIndex', 1)); | |
obj.ui_grid.align(ui_text,... | |
'VIndex', 5,... | |
'HIndex', 1,... | |
'Anchor', 'east'); | |
obj.ui_edit_pulses = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'edit',... | |
'String', sprintf('%d', obj.pulses),... | |
'Enable', 'on',... | |
'Callback', @obj.fcnCallback_parse,... | |
'Units', 'pixels',... | |
'Position', obj.EDITBOX_SIZE); | |
obj.ui_grid.align(obj.ui_edit_pulses,... | |
'VIndex', 5,... | |
'HIndex', 2,... | |
'Anchor', 'west'); | |
ui_text = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'offset [sec]',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 6, 'HIndex', 1)); | |
obj.ui_grid.align(ui_text,... | |
'VIndex', 6,... | |
'HIndex', 1,... | |
'Anchor', 'east'); | |
obj.ui_edit_offset = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'edit',... | |
'String', sprintf('%.2f', obj.offset),... | |
'Enable', 'on',... | |
'Callback', @obj.fcnCallback_parse,... | |
'Units', 'pixels',... | |
'Position', obj.EDITBOX_SIZE); | |
obj.ui_grid.align(obj.ui_edit_offset,... | |
'VIndex', 6,... | |
'HIndex', 2,... | |
'Anchor', 'west'); | |
obj.ui_pushbutton_load = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'pushbutton',... | |
'String', 'Load',... | |
'Enable', 'off',... | |
'Callback', @obj.fcnCallback_load,... | |
'Units', 'pixels',... | |
'Position', obj.PUSHBUTTON_SIZE); | |
obj.ui_grid.align(obj.ui_pushbutton_load,... | |
'VIndex', 5,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
obj.ui_text_extern = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'text',... | |
'String', 'load sound file',... | |
'Enable', 'off',... | |
'BackgroundColor', obj.BACKGROUND_COLOR,... | |
'Units', 'pixels',... | |
'Position', obj.ui_grid.getGrid('VIndex', 6, 'HIndex', 3:4)); | |
obj.ui_grid.align(obj.ui_text_extern,... | |
'VIndex', 6,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
obj.ui_pushbutton_spectrum = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'pushbutton',... | |
'String', 'Spectrum',... | |
'Callback', @obj.fcnCallback_spectrum,... | |
'Units', 'pixels',... | |
'Position', obj.PUSHBUTTON_SIZE); | |
obj.ui_grid.align(obj.ui_pushbutton_spectrum,... | |
'VIndex', 7,... | |
'HIndex', 1:2,... | |
'Anchor', 'center'); | |
obj.ui_pushbutton_play = uicontrol(... | |
'Parent', obj.ui_panel,... | |
'Style', 'pushbutton',... | |
'String', 'Play',... | |
'Callback', @obj.fcnCallback_play,... | |
'Units', 'pixels',... | |
'Position', obj.PUSHBUTTON_SIZE); | |
obj.ui_grid.align(obj.ui_pushbutton_play,... | |
'VIndex', 7,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
end | |
function obj = enable(obj, varstate) | |
%ENABLE toggle on/off enable state | |
if strcmp('on', varstate) || strcmp('off', varstate) | |
handles = [obj.ui_edit_duration,... | |
obj.ui_edit_freqBase,... | |
obj.ui_edit_freqThresh,... | |
obj.ui_edit_pulses,... | |
obj.ui_edit_offset,... | |
obj.ui_popup_chirp,... | |
obj.ui_checkbox_train,... | |
obj.ui_checkbox_extern,... | |
obj.ui_pushbutton_load,... | |
obj.ui_pushbutton_spectrum,... | |
obj.ui_pushbutton_play]; | |
set(handles, 'Enable', varstate); | |
% check a chirp function condition | |
if get(obj.ui_popup_chirp, 'Value') == 1 | |
set(obj.ui_edit_freqThresh, 'Enable', 'off'); | |
end | |
end | |
end | |
end | |
%% --- callback methods --- %% | |
methods | |
function obj = fcnCallback_close(obj, ~, ~) | |
%FCNCALLBACK_CLOSE user request on destructor | |
obj.dispose(); | |
end | |
function obj = fcnCallback_parse(obj, hSrc, ~) | |
%FCNCALLBACK_PARSE parse edit box | |
% parse edin box | |
varchar = get(hSrc, 'String'); | |
varnum = str2double(regexp(varchar, '[0-9]+\.?[0-9]*', 'match')); | |
varnum(isempty(varnum)) = 0; | |
% assign to property | |
switch hSrc | |
case obj.ui_edit_duration | |
set(obj.ui_edit_duration, 'String', sprintf('%.2f', varnum)); | |
obj.duration = varnum; | |
obj.compose(); | |
case obj.ui_edit_freqBase | |
varnum = setRange(varnum, obj.MIN_FREQUENCY, obj.MAX_FREQUENCY); | |
set(obj.ui_edit_freqBase, 'String', sprintf('%d', varnum)); | |
obj.freqBase = varnum; | |
obj.compose(); | |
case obj.ui_edit_freqThresh | |
varnum = setRange(varnum, obj.MIN_FREQUENCY, obj.MAX_FREQUENCY); | |
set(obj.ui_edit_freqThresh, 'String', sprintf('%d', varnum)); | |
obj.freqThresh = varnum; | |
obj.compose(); | |
case obj.ui_edit_pulses | |
varnum = setRange(varnum, 1, obj.MAX_PULSES); | |
set(obj.ui_edit_pulses, 'String', sprintf('%d', varnum)); | |
obj.pulses = varnum; | |
obj.compile(); | |
case obj.ui_edit_offset | |
set(obj.ui_edit_offset, 'String', sprintf('%.2f', varnum)); | |
obj.offset = varnum; | |
obj.compile(); | |
end | |
end | |
function obj = fcnCallback_chirp(obj, ~, ~) | |
%FCNCALLBACK_CHIRP | |
if get(obj.ui_popup_chirp, 'Value') == 1 | |
set(obj.ui_edit_freqThresh, 'Enable', 'off'); | |
else | |
set(obj.ui_edit_freqThresh, 'Enable', 'on'); | |
end | |
obj.compose(); | |
end | |
function obj = fcnCallback_checkTrain(obj, ~, ~) | |
%FCNCALLBACK_CHECKTRAIN callback on check box click | |
if get(obj.ui_checkbox_train, 'Value') == 1 | |
varstate = 'on'; | |
else | |
varstate = 'off'; | |
obj.pulses = 1; | |
obj.offset = 0; | |
set(obj.ui_edit_pulses, 'String', sprintf('%d', obj.pulses)); | |
set(obj.ui_edit_offset, 'String', sprintf('%.2f', obj.offset)); | |
end | |
set(obj.ui_edit_pulses, 'Enable', varstate); | |
set(obj.ui_edit_offset, 'Enable', varstate); | |
end | |
function obj = fcnCallback_checkExtern(obj, ~, ~) | |
%FCNCALLBACK_CHECKEXTERN toggle enable state of load button | |
% set Enable state | |
if get(obj.ui_checkbox_extern, 'Value') == 1 | |
varstate = 'off'; | |
varinvstate = 'on'; | |
obj.load(); | |
else | |
varstate = 'on'; | |
varinvstate = 'off'; | |
set(obj.ui_text_extern, 'String', 'load sound file'); | |
obj.ui_grid.align(obj.ui_text_extern,... | |
'VIndex', 6,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
obj.compose(); | |
end | |
% toggle Enable property | |
set(obj.ui_pushbutton_load, 'Enable', varinvstate); | |
set(obj.ui_text_extern, 'Enable', varinvstate); | |
set(obj.ui_edit_duration, 'Enable', varstate); | |
set(obj.ui_edit_freqBase, 'Enable', varstate); | |
set(obj.ui_edit_freqThresh, 'Enable', varstate); | |
set(obj.ui_popup_chirp, 'Enable', varstate); | |
% check if threshold frequency required | |
if strcmp(varstate, 'on') && get(obj.ui_popup_chirp, 'Value') == 1 | |
set(obj.ui_edit_freqThresh, 'Enable', 'off'); | |
end | |
end | |
function obj = fcnCallback_load(obj, ~, ~) | |
%FCNCALLBACK_LOAD on press load button | |
obj.load(); | |
end | |
function obj = fcnCallback_spectrum(obj, ~, ~) | |
%FCNCALLBACK_SPECTRUM on press spectrum button | |
obj.spectrum(); | |
end | |
function obj = fcnCallback_play(obj, ~, ~) | |
%FCNCALLBACK_PLAY on press play button | |
obj.play(); | |
end | |
end | |
%% --- applied methods --- %% | |
methods | |
function obj = load(obj) | |
%LOAD add external file | |
[filename, pathname] = uigetfile({'*.wav'; '*.mp3'; '*.mp4'}, 'Pick an audio file'); | |
if ~(isequal(filename, 0) || isequal(pathname, 0)) | |
[~,filetag] = fileparts(filename); | |
obj.extern = filetag; | |
if length(filetag) > 16 | |
filetag = filetag(1:16); | |
end | |
set(obj.ui_text_extern, 'String', filetag); | |
obj.ui_grid.align(obj.ui_text_extern,... | |
'VIndex', 6,... | |
'HIndex', 3:4,... | |
'Anchor', 'center'); | |
[obj.ydata, samplingFreq] = audioread([pathname, filesep, filename]); | |
obj.ydata = obj.ydata(:, 1)'; | |
obj.tdata = 0 : (1/samplingFreq) : length(obj.ydata)*(1/samplingFreq); | |
obj.tdata = obj.tdata(1:length(obj.ydata)); | |
obj.compile(); | |
end | |
end | |
function obj = spectrum(obj) | |
%SPECTRUM plots current tune spectrogram | |
% create current figure label | |
if get(obj.ui_checkbox_extern, 'Value') == 0 | |
label = sprintf('Spectrogram: t=%.2f sec, freq=(%d, %d)[Hz], type=%s',... | |
obj.duration,... | |
obj.freqBase,... | |
obj.freqThresh,... | |
obj.CHIRP_TYPE{get(obj.ui_popup_chirp, 'Value')}); | |
else | |
label = sprintf('Spectrogram: %s', obj.extern); | |
end | |
% add figure to handle array | |
obj.ui_spectrogram = cat(1, obj.ui_spectrogram,... | |
figure(... | |
'NumberTitle', 'off',... | |
'Name', label)); | |
spectrogram(obj.tune,... | |
hamming(128),... | |
120,... | |
[],... | |
obj.SAMPLING_FREQ,... | |
'yaxis'); | |
end | |
function obj = play(obj) | |
%PLAY plays current tune | |
play(obj.audio); | |
end | |
function obj = compose(obj) | |
%COMPOSE creates audio tune for stimuli | |
% time span | |
obj.tdata = 0 : 1/obj.SAMPLING_FREQ : obj.duration; | |
% generate audio signal | |
switch get(obj.ui_popup_chirp, 'Value') | |
case 1 % 'pure' | |
obj.ydata = chirp(obj.tdata, obj.freqBase, obj.duration, obj.freqBase, 'linear'); | |
case 2 % 'linear' | |
obj.ydata = chirp(obj.tdata, obj.freqBase, obj.duration, obj.freqThresh, 'linear'); | |
case 3 % 'exp' | |
obj.ydata = chirp(obj.tdata, obj.freqBase, obj.duration, obj.freqThresh, 'logarithmic'); | |
end | |
% compile tune | |
obj.compile(); | |
end | |
function obj = compile(obj) | |
%COMPILE compile tune in train and filter for fade in/out | |
% time offset | |
tOffset = 0: 1/obj.SAMPLING_FREQ : obj.offset; | |
yOffset = zeros(1, length(tOffset)); | |
% fade in filter | |
idxFade = obj.tdata < obj.FADE_TIME; | |
fadeInFilter = cat(2,... | |
linspace(0,1,sum(idxFade)),... | |
ones(1,sum(~idxFade))); | |
% fade out filter | |
idxFade = obj.tdata > (obj.duration - obj.FADE_TIME); | |
fadeOutFilter = cat(2,... | |
ones(1,sum(~idxFade)),... | |
linspace(1,0,sum(idxFade))); | |
% fade fileter | |
fadeFilter = fadeInFilter .* fadeOutFilter; | |
obj.ydata = obj.ydata .* fadeFilter; | |
% generate audio train | |
if obj.pulses > 1 | |
lastPoint = length(obj.ydata) * obj.pulses + length(yOffset) * (obj.pulses - 1); | |
obj.tune = repmat([obj.ydata,yOffset], 1, obj.pulses); | |
obj.tune = obj.tune(1:lastPoint); | |
else | |
obj.tune = obj.ydata; | |
end | |
% update audio object | |
obj.audio = audioplayer(obj.tune, obj.SAMPLING_FREQ); | |
end | |
end | |
end | |
%% --- Assistance --- %% | |
function varnum = setRange(varnum, freqMin, freqMax) | |
% round number | |
varnum = round(varnum); | |
% fix lower range | |
if varnum < freqMin | |
varnum = freqMin; | |
end | |
% fix upper range | |
if varnum > freqMax | |
varnum = freqMax; | |
end | |
end |