function helperKeywordSpotting() 
% The helperKeywordSpotting function captures live speech input 
% from a microphone and spots the keyword “YES”. C++ code generation 
% is supported using MATLAB Coder Interface for Deep Learning Libraries
% The generated executable (.exe) file runs on the same computer as the 
% MATLAB script, and communication between the two occurs over asynchronous
% User Datagram Protocol (UDP).
% #codegen

% Copyright 2020-2021 The MathWorks, Inc.

% Set audio parameters
fs = 16e3;
windowLength = 512;
overlapLength = 384;
hopLength = windowLength - overlapLength;
frameLength = hopLength;
numHopsPerUpdate = 16;
numFeatures = 39;

% Load the pre-trained network (Bi-LSTM Network)
KWSNet = coder.loadDeepLearningNetwork('./KeywordSpotting/KWSNet.mat');

% Load variables used for Feature Standardization
structM = coder.load('./KeywordSpotting/KWSNet.mat',"M","S");
tempM = structM.M;
tempS = structM.S;
M = repmat(tempM,numHopsPerUpdate,1);
S = repmat(tempS,numHopsPerUpdate,1);

% Initialize buffers for audio input, features, and plotting
dataBuff = dsp.AsyncBuffer(windowLength);
featureBuff = dsp.AsyncBuffer(numHopsPerUpdate);
plotBuff = dsp.AsyncBuffer(numHopsPerUpdate*windowLength);

% Create an audioDeviceReader object to accept audio input
adr = audioDeviceReader('SampleRate',fs, ...
    'SamplesPerFrame',frameLength,'OutputDataType',"single");

% Initialize UDPSender object
UDPSend = dsp.UDPSender('RemoteIPPort', 20000);

% Perform keyword spotting on speech signal
while true
    x = adr();
    x = x(1:numel(x));
    write(dataBuff,x);
    write(plotBuff,x);
    frame = read(dataBuff,windowLength,overlapLength);
    features = generateKeywordFeatures(frame,fs);
    featuresT = features.';
    featuresT = featuresT(1:numFeatures);
    write(featureBuff,featuresT);
    if featureBuff.NumUnreadSamples == numHopsPerUpdate
        featureMatrix = read(featureBuff);
        featureMatrix(~isfinite(featureMatrix)) = 0;
        featureMatrix = (featureMatrix - M)./S;
        
        predictedScores = predict(KWSNet, featureMatrix.');
        [~, predictedMaskFrameIndex] = max(predictedScores);
        
        predictedMaskFrameIndex = single(predictedMaskFrameIndex) - 1;
        replicatedMaskFrames = single(repmat(predictedMaskFrameIndex, hopLength, 1));
        replicatedMaskSamples = replicatedMaskFrames(:);
        predictedLabel = mode(replicatedMaskSamples);
        
        plotMask = repmat(predictedLabel, numHopsPerUpdate * hopLength,1);        
        plotAudio = single(read(plotBuff));        
        UDPSend([plotMask; plotAudio]);
    end
end

end
