function [speechCommandIdx, spec] = HelperSpeechCommandRecognition(x) %#codegen
% Copyright 2020 The MathWorks, Inc.

% Declaring Persistent 
persistent probBuffer YBuffer z audioBuffer;

% Load the pre-trained network.
persistent trainedNet;
if isempty(trainedNet)
    trainedNet = coder.loadDeepLearningNetwork('commandNet.mat');
end

% Setting Real-Time Parameters
fs = 16000;
NumLabels = 12;
BackGroundIdx = single(12);
classificationRate = single(20);
audioCaptureDuration = 1/classificationRate;
audioCaptureSamples = audioCaptureDuration*fs;

countThreshold = ceil(classificationRate*0.2);
probThreshold = single(0.7);

% Defining and Initializing History Buffers
if isempty(probBuffer)
    probBuffer = single(zeros([NumLabels,classificationRate/2]));
    YBuffer = single(NumLabels * ones(1, classificationRate/2)); %"background" --> 12
    audioBuffer = dsp.AsyncBuffer(fs);
    z = zeros(fs, 1, 'single');
end

% Buffering: Pushing captures audio frame into 1 sec FIFO buffer z
x = x(1:audioCaptureSamples, 1);
write(audioBuffer,x);
z = read(audioBuffer,fs,fs-audioCaptureSamples);

%  Compute Auditory Features
features = extractSpeechFeatures(z);

% Take the log. 
epsil = 1e-6;
features = log10(features + epsil);
spec = features';

% Predicting
% features must have known size to generate code for predict()
features = features(1:98, 1:50); 
probs = predict(trainedNet, features);

[~, YPredicted] = max(probs);

% Statistical post processing
% Keeping history 
YBuffer = [YBuffer(2:end), YPredicted];
probBuffer = [probBuffer(1:NumLabels, 2:end),probs(:)];

[YMode_idx, count] = mode(YBuffer);
count = single(count);
maxProb = max(probBuffer(YMode_idx,:));

if (YMode_idx == BackGroundIdx || count < countThreshold || maxProb < probThreshold)
    speechCommandIdx = BackGroundIdx;
else
    speechCommandIdx = YMode_idx;
end

end 
