matlab - 实时音频调制

标签 matlab audio synthesizer

我不知道如何继续我的项目。简而言之,我正在尝试使用来自加速度计的数据创建一个 FM 合成器来实时更改 FM 和音调参数。

这是我所基于的一些代码:

% X axis data will be used for fc parameter
% Y axis data will be used for fm parameter

function y = fmSynth(fc, dur, fm)

fs = 48000;
T = 1/fs;      % seconds
t = 0:T:dur;    % time vector

% FM parameters
Imin = 0;
Imax = 20;
I = t.*(Imax - Imin)/dur + Imin;

y = sin(2*pi*fc*t + I.*sin(2*pi*fm*t));
plot(t(1:10000), y(1:10000));
sound(y, fs);

我确实有一个生成波的函数,但仅限于设定的持续时间(由于内置 matlab 函数的限制)。我希望它是连续的(直到这样的用户输入来停止它),并且能够“实时”调制它(有点滞后就可以了)。

为了解决这个问题,我找到了一个实时音频处理器代码 here .

但是,这是用面向对象的编程语言编写的,我不熟悉。

是否有一种简单的方法可以在此代码中实现上述功能(输出 rtap),或者我是否必须在子类中编写?如果是这样,怎么办?

对于那些不愿意下载代码的人,这里是主类:

% RealTimeAudioProcessor
%
% The RealTimeAudioProcessor object allows the user to process consecutive
% frames of audio in real-time (it lags real-time by the frame size plus 
% hardware overhead). The object can easily be extended for any type of
% audio processing by overloading the stepImpl method in a derived class.
%
% Use:
%
% % Create the processor with a number of input channels, number of output
% % channels, sample rate, frame size, and device name.
% rtap = RealTimeAudioProcessor(1, 2, 48000, 256, 'Default');
% 
% % Play. This will start *immediately* and block until all audio output is
% % complete.
% rtap.Play();
% 
% % Release the audio resource for others (be nice).
% rtap.release();
% 
% % The RTAP records some timing values while playing. Show the results.
% rtap.Analyze();
% 
% It is recommended that an ASIO audio driver with appropriate hardware be
% used for the audio interface. (ASIO is an open standard from Steinberg
% Media Technologies GmbH).
%
% Tucker McClure @ The MathWorks
% Copyright 2012 The MathWorks, Inc.

classdef RealTimeAudioProcessor < matlab.system.System

     properties (Nontunable, Access = protected)

        % Settings
        frame_size   = 256;   % Number of samples in the buffer
        sample_rate  = 48000; % Number of samples per second [samples/s]
        end_time     = inf;   % Number of seconds until playback stops [s]
        in_channels  = 2;     % Number of input channels
        out_channels = 2;     % Number of output channels
        device_name  = 'Default';
        draw_rate    = 0.02;  % Rate to update graphics [s]

        % Derived quantities
        time_step;   % Length of frame [s]
        time_window; % Array of time values from [0 time_step) [s]

        % Device interfaces
        ap; % AudioPlayer object to manage output
        ar; % AudioRecorder object to manage input

    end

    properties

        % UI handles
        figure_handle; % Handle of UI figure
        text_handle;   % Handle of text in figure

        samples_until_draw = 0; % Samples left before updating GUI

        % Analysis stuff
        max_in_step_time      = 0;
        max_process_step_time = 0;
        max_out_step_time     = 0;

    end

    methods

        % Constructor; creates the RTAP and its internal dsp.AudioPlayer.
        % After creation, the RTAP is ready to play.
        function rtap = RealTimeAudioProcessor(ins, outs, Fs, w, device)

            fprintf('Initializing a RealTimeAudioProcessor on %s... ', ...
                    device);

            % Set some internals.
            rtap.frame_size   = w;
            rtap.sample_rate  = Fs;
            rtap.in_channels  = ins;
            rtap.out_channels = outs;
            rtap.device_name  = device;

            % Calculate the period.
            rtap.time_step = w/Fs;

            % Create all the time values for a window.
            rtap.time_window = (0:w-1)'/Fs;

            % Ok, we set everything up.
            fprintf('done.\n');

            % Display latency to user.
            fprintf('Minimum latency due to buffering: %5.1fms\n', ...
                    1000 * rtap.time_step);

        end

        % Enter a quasi-real-time loop in which audio is acquired/generated
        % and plugged into the output buffer (if a buffer exists).
        function Play(rtap)

            % If not set up, setup.
            if ~rtap.isLocked

                setup(rtap, ...
                      zeros(rtap.frame_size, 1), ...
                      zeros(rtap.frame_size, rtap.in_channels));

            % Otherwise, if we need a new figure, open one.
            elseif ~ishandle(rtap.figure_handle)

                rtap.GenerateFigure();

            end

            % Keep track of time since 'tic'.
            t_clock = 0;

            % Keep track of how much material we've played since 'tic'.
            % At t_clock, this should reach to t_clock + time_step.
            t_played = 0;

            % Initialize the input.
            in = zeros(rtap.frame_size, rtap.in_channels); %#ok<NASGU>

            % Start a timer.
            tic();

            % Loop until the end time has been reached or the figure has
            % been closed.
            while t_clock < rtap.end_time && ishandle(rtap.figure_handle)

                % Play steps until we're |buffer| into the future.
                if t_played < t_clock + rtap.time_step

                    % Create the times for this frame.
                    time = t_played + rtap.time_window;

                    % Get the input for one frame.
                    if rtap.in_channels > 0
                        step_timer = tic();
                        in = step(rtap.ar);
                        rtap.max_in_step_time = ...
                            max(rtap.max_in_step_time, toc(step_timer));
                    else
                        in = zeros(rtap.frame_size, rtap.in_channels);
                    end

                    % Process one frame.
                    step_timer = tic();
                    out = step(rtap, time, in);
                    rtap.max_process_step_time = ...
                        max(rtap.max_process_step_time, toc(step_timer));

                    % Step the AudioPlayer. Time the step for analysis
                    % purposes.
                    if rtap.out_channels > 0
                        step_timer = tic();
                        step(rtap.ap, out);
                        rtap.max_out_step_time = ...
                            max(rtap.max_out_step_time, toc(step_timer));
                    end

                    % Update the time.
                    t_played = t_played + rtap.time_step;

                end

                % Release focus so that figure callbacks can occur.
                if rtap.samples_until_draw <= 0
                    drawnow();
                    rtap.UpdateGraphics();
                    rtap.samples_until_draw = ...
                        rtap.sample_rate * rtap.draw_rate;
                else
                    rtap.samples_until_draw = ...
                        rtap.samples_until_draw - rtap.frame_size;
                end

                % Update the clock.
                t_clock = toc();

            end

            % Wait for audio to end before exiting. We may have just
            % written out a frame, and there may have already been a frame
            % in the buffer, so chill for 2 frames.
            pause(2*rtap.time_step);

        end

        % Display timing results from last play.
        function Analyze(rtap)
            fprintf(['Results for last play:\n', ...
                     'Maximum input step time:   %5.1fms\n', ...
                     'Maximum process step time: %5.1fms\n', ...
                     'Maximum output step time:  %5.1fms\n'], ...
                    1000*rtap.max_in_step_time, ...  
                    1000*rtap.max_process_step_time, ...  
                    1000*rtap.max_out_step_time);
        end

    end

    methods (Access = protected)

        % Set up the internal System Objects and the figure.
        function setupImpl(rtap, ~, ~)

            % Create the AudioPlayer.
            if rtap.out_channels > 0

                rtap.ap = dsp.AudioPlayer(...
                    'DeviceName',       rtap.device_name, ...
                    'BufferSizeSource', 'Property', ...
                    'BufferSize',       rtap.frame_size, ...
                    'QueueDuration',    0, ...
                    'SampleRate',       rtap.sample_rate);


                % Start with silence. This initializes the AudioPlayer to
                % the window size and number of channels and takes longer
                % than any subsequent call will take.
                step(rtap.ap, zeros(rtap.frame_size, rtap.out_channels));

            end

            % Create the AudioRecorder (if requested).
            if rtap.in_channels > 0

                rtap.ar = dsp.AudioRecorder(...
                    'DeviceName',       'Default', ...
                    'SampleRate',       rtap.sample_rate, ...
                    'BufferSizeSource', 'Property', ...
                    'BufferSize',       rtap.frame_size, ...
                    'SamplesPerFrame',  rtap.frame_size, ...
                    'QueueDuration',    0, ...
                    'OutputDataType',   'double', ...
                    'NumChannels',      rtap.in_channels);

                % Initialize the input.
                step(rtap.ar);

            end

            if ishandle(rtap.figure_handle)
                close(rtap.figure_handle);
            end
            rtap.GenerateFigure();

            % Draw it.
            drawnow();

            % Chill out for a second before rushing forward with sound.
            pause(rtap.time_step);

        end

        % Process one frame of audio, given the inputs corresponding to the
        % frame and the times.
        function out = stepImpl(rtap, time, in) %#ok<INUSD>
            out = zeros(rtap.frame_size, rtap.out_channels);
        end

        % Specify that the step requires 2 inputs.
        function n = getNumInputsImpl(~)
            n = 2;
        end

        % Specify that the step requires 1 output.
        function n = getNumOutputsImpl(~)
            n = 1;
        end

        % Clean up the AudioPlayer.
        function releaseImpl(rtap)

            % Release the dsp.AudioPlayer resource.
            if rtap.out_channels > 0
                release(rtap.ap);
            end

            % Release the dsp.AudioRecorder too.
            if rtap.in_channels > 0
                release(rtap.ar);
            end

            % Close the figure if it's still open.
            if ishandle(rtap.figure_handle)
                set(rtap.text_handle, 'String', 'Closing.');
                close(rtap.figure_handle);
                rtap.figure_handle = [];
            end

        end

        % Generate a figure that stays open with updates for the user.
        % Closing this figure ends playback.
        function GenerateFigure(rtap)

            % Get the screen dimensions for centering the figure.
            screen_dims = get(0, 'ScreenSize');
            figure_width_height = [640 160];
            figure_dims = [floor(0.5*(  screen_dims(3:4) ...
                                      - figure_width_height)) ...
                           figure_width_height];

            % Generate a figure.
            rtap.figure_handle = figure(...
                'Name',          'Real-Time Audio Processor Controller',...
                'NumberTitle',   'off', ...
                'Position',      figure_dims);
            axes('Position', [0 0 1 1], ...
                 'Visible', 'off');
            rtap.text_handle = text(0.5, 0.5, ...
                'Real Time Audio Processor is active.', ...
                'HorizontalAlignment', 'center', ...
                'VerticalAlignment',   'middle', ...
                'Interpreter',         'none');

        end

        function UpdateGraphics(rtap) %#ok<*MANU>
        end

    end

end

包中还有其他文件用作示例,但我一直无法成功修改它们。另外,我很抱歉没有发布我的读取和过滤加速度计数据的代码(有点长)。

最佳答案

一个不采用 OOP 的粗略解决方案是将声音生成代码放置在循环中,例如在伪代码中:

Fs = ...;
while 1
    % generate your signal here ...
    signal = ....
    % ...
    wavplay(signal,Fs,'sync')   
end

但是,您希望包含一个转义子句,以便以一种很好的方式脱离循环。您最终会想要一些类似 OOP 的解决方案,基本上是一个监听器,以便您可以逃脱循环并可选择交互地修改信号。监听器可以是非常基本的,例如实现为带有按钮的图形。

关于matlab - 实时音频调制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18434967/

相关文章:

matlab - 在matlab中创建特定的大矩阵

c++ - 多线程 mex 代码比单线程慢

iPhone AVAudioPlayer 停止背景音乐

java - 我怎样才能在java中处理声音?

audio - 正弦波音乐发生器

audio - 免费波表合成器?

matlab - 将平面弯曲成封闭的曲面/圆柱体

matlab - 二阶摆模型的 NMPC 优化

javascript - 在生成 PCM 时播放它

audio - 如何使用 SoX 库制作机器人或 Dalek 语音?