function [speechCommandIdx, spec] = ProfileSpeechCommandRecognitionRaspi(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;
classificationRate = single(20);
NumLabels = 12;
audioCaptureDuration = 1/classificationRate;
audioCaptureSamples = audioCaptureDuration*fs;

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

% Defining and Initializing History Buffers
if isempty(probBuffer)
    probBuffer = single(zeros([NumLabels,classificationRate/2]));
    YBuffer = single(backgroundIdx * ones(1, classificationRate/2)); 
    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);

% Extract 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(:,2:end),probs(:)];

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

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