Возможна ли обработка звука в реальном времени с помощью App Designer в Matlab?
Я хочу написать простое приложение с аудио-фильтром, используя App Designer в Matlab. Во время воспроизведения файла необходимо уметь загружать аудиофайл, нажимать кнопку воспроизведения и изменять такие параметры, как усиление входного сигнала, частоту среза и т. Д.
Я просто не могу понять, как можно изменить параметры в реальном времени и обновить соответствующие переменные, чтобы можно было услышать, как меняется фильтр.
Это код, который я написал сейчас:
classdef EulerFilter < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
CutoffKnobLabel matlab.ui.control.Label
CutoffKnob matlab.ui.control.Knob
PlayButton matlab.ui.control.StateButton
end
properties (Access = public)
inputGain % input Gain
CutoffHz % cutoff frequency in Hz
end
methods (Access = public)
function play(app)
% setup file stream
frameLength = 256;
fileReader = dsp.AudioFileReader(...
'Sun Behind CloudsDry.wav',...
'SamplesPerFrame',frameLength);
deviceWriter = audioDeviceWriter(...
'SampleRate',fileReader.SampleRate);
% code snippet
% porcessing of frames
while ~isDone(fileReader)
% code snippet
end
release(fileReader);
release(deviceWriter);
end
end
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
app.inputGain = 1;
app.CutoffHz = 22000;
end
% Value changed function: PlayButton
function PlayButtonValueChanged(app, event)
value = app.PlayButton.Value;
play(app);
end
% Value changing function: CutoffKnob
function CutoffKnobValueChanging(app, event)
%display(event)
changingValue = event.Value;
app.CutoffHz = changingValue;
end
end
% App initialization and construction
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure
app.UIFigure = uifigure;
app.UIFigure.Position = [100 100 640 480];
app.UIFigure.Name = 'UI Figure';
% Create CutoffKnobLabel
app.CutoffKnobLabel = uilabel(app.UIFigure);
app.CutoffKnobLabel.HorizontalAlignment = 'center';
app.CutoffKnobLabel.Position = [159 322 37 22];
app.CutoffKnobLabel.Text = 'Cutoff';
% Create CutoffKnob
app.CutoffKnob = uiknob(app.UIFigure, 'continuous');
app.CutoffKnob.Limits = [10 22000];
app.CutoffKnob.MajorTicks = [10 1000 5000 22000];
app.CutoffKnob.ValueChangingFcn = createCallbackFcn(app, @CutoffKnobValueChanging, true);
app.CutoffKnob.Position = [155 367 45 45];
app.CutoffKnob.Value = 22000;
% Create PlayButton
app.PlayButton = uibutton(app.UIFigure, 'state');
app.PlayButton.ValueChangedFcn = createCallbackFcn(app, @PlayButtonValueChanged, true);
app.PlayButton.Text = 'Play';
app.PlayButton.Position = [60 40 100 22];
end
end
methods (Access = public)
% Construct app
function app = EulerFilter
% Create and configure components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, @startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end
В основном это функции, сгенерированные Matlab для GUI. Я добавил некоторые свойства, которые содержат значения для входного усиления, среза и т. Д., А также функцию play(), которая выполняет обработку сигнала. Я могу запустить приложение, нажать кнопку воспроизведения и услышать аудиофайл, который воспроизводится, но когда я, например, изменяю частоту среза, ничего не меняется. Я предполагаю, что это потому, что я выполняю функцию play() внутри функции обратного вызова, когда кнопка воспроизведения нажата, и, таким образом, функции обратного вызова, когда ручка отсечки повернута, не могут быть выполнены до того, как завершится другая.
Когда я сначала изменяю параметры, а затем нажимаю кнопку воспроизведения, все верно, за исключением того, что я не могу изменить параметры во время воспроизведения файла.
Я попробовал следующее без успеха:
- вызов функции обратного вызова внутри цикла while в функции play(), но я не знаю, какой аргумент мне нужно передать для события (Matlab всегда говорит мне, что он не знает, что команда или аргументы отсутствуют) или если это даже полезно
- выполнить функцию play() внутри runStartupFcn(), но эта функция выполняется до отображения графического интерфейса, что, конечно, бесполезно
- Я не могу добавить функции в другом месте, насколько я могу сказать
Итак, теперь вопрос: могу ли я заставить приложение работать в реальном времени?
Я с нетерпением жду ваших ответов!
3 ответа
Кажется, есть много решений / примеров для руководства Matlab, но еще не для дизайнера приложений.
Похоже, что вам лучше всего вызывать функцию pause в цикле while, чтобы дать вашей программе время для получения обновленных значений. Эксперимент с разными pause
раз, чтобы убедиться, что ваша программа имеет достаточно времени для обновления. Matlab может приостановить текущий исполняемый поток, используя:
pause(0.001) % 0.001 sec
Или сделайте прямой вызов на Java для большей точности
java.lang.Thread.sleep(duration) % duration in msec
Я уверен, что это даст вашей программе время для доступа к переменным и обновления. Таким образом, вы можете проверять каждые 10/20/50/1000 циклов цикла и обновлять параметры так часто, как вы хотели бы свести к минимуму любые слышимые артефакты.
% Init counter to see how many loops have passed
counter = 0;
% processing of frames
while ~isDone(fileReader)
% Do your playback process stuff
if(counter > 10) % Updates every 10 loops or so
pause(0.001);
counter = 0;
end
counter = counter + 1;
end
Примечание: код не проверен, пожалуйста, дайте мне знать
В противном случае, может быть, взглянуть на решение подхода обратного вызова.
Вот почему графические интерфейсы в Matlab не всегда являются хорошей идеей:-) Я понимаю, почему вы могли бы делать это для целей обучения, но в противном случае я бы, возможно, исследовал бы большую интеграцию с Java в ваш графический интерфейс Matlab для обработки всех потоков (или даже дизайн GUI с самой Java). Для начала...
Может быть слишком поздно для потока, чтобы быть полезным, но проблема, с которой вы сталкиваетесь, заключается в том, что когда вызывается CALLBACK1, он вызывает вашу функцию PLAY(), которая не запускается до завершения, пока не завершится цикл чтения файла WHILE. Другими словами, CALLBACK1 никогда не завершает работу, пока не завершится чтение файла.
Если вы измените частоту среза, когда CALLBACK1 все еще читает файл, он (я полагаю) вызывает свой собственный обратный вызов, я буду называть CALLBACK2. Поскольку MATLAB является однопоточным, CALLBACK2 не может работать, пока CALLBACK1 не завершит работу. Следовательно, почему вы сталкиваетесь с проблемой, которая у вас есть.
Способ справиться с этим - для CALLBACK1 запустить объект MATLAB TIMER и настроить объект таймера (который выполняется в отдельном потоке) для чтения файла с определенной частотой. Таким образом, CALLBACK1 завершает работу довольно быстро, в то время как объект таймера выполняет вашу игру. Это позволяет CALLBACK2 выполнять и делать свое дело.
Сложность, с которой вы все еще можете столкнуться, заключается в том, можете ли вы изменить частоту среза "на лету", чтобы "игра" отражала ее. Это еще вопрос, позволяет ли объект AudioFileReader это делать.
Надеюсь это поможет.
Я думаю, что решением вашей проблемы является создание второго потока. В вашем основном потоке у вас есть доступ к вашим дескрипторам и переменным, а ваш второй поток запускает звук. Моя идея состояла бы в том, чтобы включить изменения, которые вы делаете в потоке A в потоке B. К сожалению, вы можете просто использовать многопоточность с MatLab Parallel Processing Toolbox. Я надеюсь, что есть и другой способ.
Ура, Пабло