function helperKeywordSpottingRaspi(hostIPAddress)  
% The helperKeywordSpottingRaspi function receives live speech input 
% using UDP and spots the keyword “YES”. C++ code generation on Raspberry 
% Pi is supported using MATLAB Coder Interface for Deep Learning
% Libraries for MATLAB Coder. The generated executable (.elf) file runs on 
% Raspberry Pi and MATLAB script runs on the Computer, and communication 
% between the two occurs over asynchronous User Datagram Protocol (UDP).
%#codegen

%   Copyright 2020-2021 The MathWorks, Inc.

% Set audio Parameters
fs = single(16000);
windowLength = 512;
overlapLength = 384;
hopLength = windowLength - overlapLength;
numHopsPerUpdate = 16;
numMaskSamples = numHopsPerUpdate * hopLength;
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 to plot speech
dataBuff = dsp.AsyncBuffer(windowLength);
featureBuff = dsp.AsyncBuffer(numHopsPerUpdate);
plotBuff = dsp.AsyncBuffer(numHopsPerUpdate*windowLength);


% Initialize UDPSender object
UDPSend = dsp.UDPSender('RemoteIPPort',21000,'RemoteIPAddress',hostIPAddress);

% Initialize UDPReceiver object
UDPReceiveRaspi = dsp.UDPReceiver('LocalIPPort', 26000, ...
    'MaximumMessageLength', (128), ...
    'ReceiveBufferSize', (128*32)*4 ,...
    'MessageDataType','single');

% Perform keyword spotting on speech signal
while true
    x = UDPReceiveRaspi();
    if(~isempty(x))
        x = x(1:hopLength, 1);
        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, numMaskSamples,1);
            
            plotAudio = single(read(plotBuff));
                       
            UDPSend([plotMask(1:numMaskSamples, 1); plotAudio(1:numMaskSamples, 1)]);
        end
    end
end
end
