function varargout = spectrogram(x,varargin)
%SPECTROGRAM Spectrogram using a Short-Time Fourier Transform (STFT) on the GPU.
%
%     S = SPECTROGRAM(X)
%     S = SPECTROGRAM(X,WINDOW)
%     S = SPECTROGRAM(X,WINDOW,NOVERLAP)
%     S = SPECTROGRAM(X,WINDOW,NOVERLAP,NFFT)
%     S = SPECTROGRAM(X,WINDOW,NOVERLAP,NFFT,Fs)
%     [S,F,T] = SPECTROGRAM(...)
%     [S,F,T] = SPECTROGRAM(X,WINDOW,NOVERLAP,F)
%     [S,F,T] = SPECTROGRAM(X,WINDOW,NOVERLAP,F,Fs)
%     [S,F,T,P] = SPECTROGRAM(...)
%     [S,F,T,P] = SPECTROGRAM(...,'MinThreshold',THRESH)
%     [S,F,T,P] = SPECTROGRAM(...,'reassigned')
%     [S,F,T,P,Fc,Tc] = SPECTROGRAM(...)
%     [...]  = SPECTROGRAM(...,SPECTRUMTYPE)
%     [...] = SPECTROGRAM(...,FREQRANGE)
%     [...] = SPECTROGRAM(...,'OutputTimeDimension',TIMEDIMENSION)
%     SPECTROGRAM(...)
%     SPECTROGRAM(...,FREQLOCATION)
%
%    See also: SPECTROGRAM

%   Copyright 2019-2023 The MathWorks, Inc.

narginchk(1,13);
nargoutchk(0,6);
% Validate input x
validateattributes(x,{'single','double'},{'vector','nonempty','nonsparse','nonnan','finite'},'spectrogram','X');

if nargin > 1
    [varargin{:}] = convertStringsToChars(varargin{:});
end

% Check if WINDOW and NFFT are on GPU
% WINDOW and NFFT are on GPU when each is a vector and a gpuArray
isNFFTSecondArg = false;
[windowOrNFFTOnGPU,windowIsVector,nfftIsVector,nfftArgInd,extraArgInd] = ...
    signal.internal.gpu.utilities.isWindowNFFTOnGPU(isNFFTSecondArg,varargin{:});

onGPU = false;
% X, WINDOW (if it is a vector), and NFFT (if it is a vector) determine
% whether the calculation is done on the GPU
if isgpuarray(x) || windowOrNFFTOnGPU
    onGPU = true;
    % Ensure that the input signal is on the GPU
    x = gpuArray(x);
    % Check that a window vector has been provided. If so, ensure that
    % it is on the GPU.
    if windowIsVector
        varargin{1} = gpuArray(varargin{1});
    end
    % If a vector NFFT is provided, make sure it is on GPU
    if nfftIsVector
        varargin{nfftArgInd} = gpuArray(varargin{nfftArgInd});
    end
    % Gather all extra arguments if any 
    [varargin{extraArgInd}] = gather(varargin{extraArgInd});
else
    % Gather all extra arguments
    [varargin{:}] = gather(varargin{:});
end

% Call Spectrogram on GPU if input signal (X) or WINDOW is gpuArray
if onGPU
    if nargout > 0
        [varargout{1:nargout}] = pspectrogram({x},'spect',varargin{:});
    else
        pspectrogram({x},'spect',varargin{:});
    end
else
    % Dispatch in-memory Spectrogram if input signal is not gpuArray
    if nargout > 0
        [varargout{1:nargout}] = spectrogram(x,varargin{:});
    else
        spectrogram(x,varargin{:});
    end
end

end