Возможна ли обработка звука в реальном времени с помощью 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. Я надеюсь, что есть и другой способ.

Ура, Пабло

Другие вопросы по тегам