%***************************************%
% リアルタイム音声処理(Audio Toolbox)   %
% 遅延器                                %
%         by Arata Kawamura (2021.01.10)%
%***************************************%
% 入力デバイス(マイク)の設定
clear;
deviceReader = audioDeviceReader;    % 読み込み(マイク)オーディオデバイス情報を取得
setup(deviceReader);                 % デバイスを使えるようにする
% 出力デバイス(スピーカ)の設定
deviceWriter = audioDeviceWriter(...
    'SampleRate', deviceReader.SampleRate);  % 書き出し(スピーカ)オーディオデバイス情報を取得
setup(deviceWriter,zeros(deviceReader.SamplesPerFrame,deviceReader.NumChannels)); %% デバイスを使えるようにする
%************************************%
%            基本項目設定            %
% Fs :サンプリング周波数(44100)      %
% out:出力バッファ (長さ1024)        %
%************************************%
Fs  = deviceReader.SampleRate;       % サンプリング周波数
Buf = deviceReader.SamplesPerFrame;  % デバイスから1回に読み込む信号長
out = zeros(Buf, 1);                 % 出力デバイスに送る信号
%************************************%
%            録音用設定              %
%************************************%
RecTime = 10;                        % 実行時間の設定 [秒]
l   = 1;                             % 録音用の時刻インデクス
in_wav  = zeros(RecTime*Fs,1);       % 録音用入力信号
out_wav = zeros(RecTime*Fs,1);       % 録音用出力信号
%************************************%
%       信号処理用変数設定           %
%************************************%
D   = 1;                             % 遅延時間(秒で設定)
M   = D*Fs;                          % 入出力信号の配列の長さ（バッファ長とは無関係に設定）
x = zeros(M, 1);                     % 入力信号
y = zeros(M, 1);                     % 出力信号
n   = 1;                             % 時刻インデクスの初期値
%************************************%

%*********************************************************%
% メインループ                                            %
% マイク入力がリアルタイムでスピーカ出力される            %
% RecTime[秒]経過後，入力と出力がwavファイルに記録される  %
%*********************************************************%
tic;
while toc <= RecTime
    audioData = deviceReader();        % バッファの長さ(1024個)のマイク入力信号
    %plot(1:length(audioData),audioData);ylim([-0.2,0.2]);drawnow % 波形の表示
    xin = audioData;                   % 入力信号を格納
    for i=1:Buf                        % バッファの長さだけ出力を作る
        x(n)   = xin(i);               % 現在の入力信号
        %***************************%
        %    信号処理部             %
        %    x(n): 時刻nの入力信号  %
        %    y(n): 時刻nの出力信号  %
        %***************************%
        m = n+1;                       % 最も過去の時刻インデクス
        if m>M; m=m-M; end             % mはD秒(=Mサンプル)だけ過去の時刻
        y(n)   = x(m);                 % 遅延出力 y(n)=x(n-M+1)

        %************************%
        %   信号処理部ここまで   %
        %************************%
        out(i) = y(n);                 % y(n)を出力バッファout(n)に記録
        %******************************************************************%
        in_wav (l) = x(n);             % 入力信号の記録(録音用)
        out_wav(l) = y(n);             % 出力信号の記録(録音用)
        l = l+1;                       % 録音用時刻の更新
        %******************************************************************%
        n = mod(n,M);                  % 信号処理用時刻の更新
        n = n + 1;                     % n=1, 2, ..., M
    end
    deviceWriter(out);                 % スピーカデバイスから out を出力
end

%% デバイスの解放
release(deviceReader);
release(deviceWriter);

%% 入力と出力をwavファイルに保存
audiowrite('input.wav', in_wav, Fs);
audiowrite('output.wav', out_wav, Fs);
