classdef MultiChAudioTlbx
    % Author F Olivieri
    % Version 1.1
    
    % It requires the PA_wavplay Tlbx
    
    properties (Constant)
        Dev = 0;
        Drv = 'asio';
        MaxGainDefault = 0.05;
        fsDefault = 48000; % Default sampling frequency
    end
    
    methods (Static)
        
        function ListenToFiltersTOBEIMPLEMENTED
            
            MaxGain_INIT = 0.1;
            
            TotalNumOutputChan = 16;
            aa = qWN; %a = qWN{1};
            %aa = FilterTlbx.ApplyModellingDelayToFilterMatrix(aa);
            pause(10)
            %bb = circshift(1:32, [0 -16])
            MultiChAudioTlbx.Play(aa, 1, TotalNumOutputChan, fs, MaxGain_INIT, 12);
            
        end
        function Play(InputFile, out_ch_idx, TotalNumbOutputChannels, fs, MaxGain, NumberOfRepeats)
            % PLAY is an abstraction to pa_wavplay.
            % INPUTS:
            % - INPUTFILE is a vector with the input signal
            % - OUT_CH_IDX is a scalar indicating the output channel where
            % we want to play INPUTFILE
            % - TOTALNUMBEROUTPUTCHANNELS is a scalar indicating the total
            % number of output channels
            % - FS is the sampling frequency (scalar)
            % - MAXGAIN is a scalar indicating the maximum value for the
            % normalization of the input signal INPUTFILE (i.e., the
            % maximum value of INPUTFILE will be equal to MAXGAIN). If
            % MaxGain == NaN or MaxGain == 0 there will be no
            % normalization. Careful as, in practice, resonable values of
            % MaxGain are something like 0.05 or so.
            % - NUMBEROFREPEATS is a scalar indicating the total number of
            % times the playback of INPUTFILE will be repeated.
            
            if nargin < 6, NumberOfRepeats = 1; end;
            if nargin < 5, MaxGain = MultiChAudioTlbx.MaxGainDefault; end;
            if nargin < 4, fs = MultiChAudioTlbx.fsDefault; end;
            
            % Adapting the input file to the format required by PA_WAVPLAYRECORD (it needs a matrix)
            InputWAVSignalMatrix =  MultiChAudioTlbx.OutputMatrixFormat(InputFile, TotalNumbOutputChannels, out_ch_idx);
            InputWAVSignalMatrix = Normalize(InputWAVSignalMatrix, MaxGain);
            
            repeat_idx = 0;
            while repeat_idx ~= NumberOfRepeats
                pa_wavplay(InputWAVSignalMatrix, fs, MultiChAudioTlbx.Dev, MultiChAudioTlbx.Drv); % Reproducing the signal
                repeat_idx = repeat_idx + 1;
            end
            
        end% Play
        
        %%
        function OutputFile = PlayRecord(InputFile, out_ch_idx, total_number_of_output_channels, fs, NumberOfMicrophones, MaxGain)
            %PLAYRECORD is an abstraction to pa_wavplayrecord
            
            % NumberOfMicrophones is a vector with the channel to be used. Example: use
            % channel 1 to 16, NumberOfMicrophones = [1,16];
            % If you want to use a specific mic single channel, use NumberOfMicrophones
            % = scalar (e.g., NumberOfMicrophones = 1)
            
            if nargin < 5, NumberOfMicrophones = [1, 1]; end; %It will be a single-channel recording
            
            if size(NumberOfMicrophones) == 1, NumberOfMicrophones = [NumberOfMicrophones, NumberOfMicrophones]; end; % it is not a vector
            
            RecordChanStart = NumberOfMicrophones(1); RecordChanStop = NumberOfMicrophones(2);
            
            % Adapting the input file to the format required by PA_WAVPLAYRECORD (it needs a matrix)
            InputWAVSignalMatrix = MultiChAudioTlbx.OutputMatrixFormat(InputFile, total_number_of_output_channels, out_ch_idx);
            %InputWAVSignalMatrix = Normalize(InputWAVSignalMatrix, MaxGain);
           % InputWAVSignalMatrix = Normalize(InputWAVSignalMatrix, MaxGain);
            
             InputWAVSignalMatrix = AudioTlbx.NormalizeLevel(InputWAVSignalMatrix, MaxGain); % Normalization before playback
            % Recording the signal
            OutputFile = ...
                pa_wavplayrecord(InputWAVSignalMatrix, MultiChAudioTlbx.Dev, ...
                fs, length(InputFile), RecordChanStart, RecordChanStop, ...
                MultiChAudioTlbx.Dev, MultiChAudioTlbx.Drv);
            
      
            
        end% PlayRecord
        
        %%
        
        function OutputWAVSignalMatrix = ...
                OutputMatrixFormat(InputWavSignal, TotalNumberOfOutputChannels, ChannelsIdxs)
            % OUTPUTMATRIXFORMAT adapts the input file to the format required by the multichannel audio function
            % InputWavSignal is the input signal (vector SAMPLES*1, or matrix SAMPLES*NCHAN)
            % ChannelsIdxs is a vector with the indeces of the output
            % channels where the input file is to be reproduced
            
            [n_samples, n_channels] = size(InputWavSignal);
            
            if n_samples == TotalNumberOfOutputChannels % it means that we have a matrix of the form NUMBCH*LENGTH
                InputWavSignal = transpose(InputWavSignal);
            end
            [n_samples, n_channels] = size(InputWavSignal);
            
            if isvector(InputWavSignal) % The signal is a vector (single channels)
                OutputWAVSignalMatrix = zeros(length(InputWavSignal), TotalNumberOfOutputChannels);
                
                for ch_idx = ChannelsIdxs
                    OutputWAVSignalMatrix(:, ch_idx) = InputWavSignal;
                end
                
            elseif isscalar(InputWavSignal)
                OutputWAVSignalMatrix = 0;
                ErrorDisplay('The Input signal is a scalar. Please choose a different type of input signal');
                
            elseif ismatrix(InputWavSignal) % It is a matrix (multichannel audio)
                
                if n_channels == length(ChannelsIdxs)
                    OutputWAVSignalMatrix = zeros(length(InputWavSignal), TotalNumberOfOutputChannels);
                    for ch_idx = 1:length(ChannelsIdxs)
                        OutputWAVSignalMatrix(:, ch_idx) = InputWavSignal(ch_idx, :);
                    end
                elseif n_channels == TotalNumberOfOutputChannels
                    OutputWAVSignalMatrix = InputWavSignal;
                end
            end
            
            
        end%
        
        
        %%
        function TestOutputChannels(WavSignal, ChosenSpeakerIdx, TotalNumbOfOutChannels, fs, MaxGain, TestOptStr, NumbTimesRepeatTest)
            
            if nargin < 7, NumbTimesRepeatTest = 1; end;
            if nargin < 5, MaxGain = MultiChAudioTlbx.MaxGainDefault; end;
            if nargin < 6, TestOptStr = 'SingleChannels'; end;
            
            PauseBtwEachSpeakerTest = 0.5;
            display('Test of the output channels...');
            test_idx = 0;
            while test_idx ~= NumbTimesRepeatTest
                
                switch TestOptStr
                    
                    case 'SingleChannels'
                        for loudsp_idx = ChosenSpeakerIdx
                            MultiChAudioTlbx.Play(WavSignal, loudsp_idx, TotalNumbOfOutChannels, fs, MaxGain);
                        end
                        
                    case 'AllOutputs-OneAtATime'
                        
                        for loudsp_idx = 1:TotalNumbOfOutChannels
                            MultiChAudioTlbx.Play(WavSignal, loudsp_idx, TotalNumbOfOutChannels, fs, MaxGain);
                        end
                        
                    case 'AllOutputs-AtSameTime'
                        
                        OutputWAVSignalMatrix = ...
                            MultiChAudioTlbx.OutputMatrixFormat(WavSignal, TotalNumbOfOutChannels, [1:TotalNumbOfOutChannels]);
                        MultiChAudioTlbx.Play(OutputWAVSignalMatrix, 1, TotalNumbOfOutChannels, fs, MaxGain);
                    otherwise, ErrorDisplay('Not a valid Playback choice');
                end
                pause(PauseBtwEachSpeakerTest) % If you want to check speaker by speaker...
                test_idx = test_idx + 1;
                
            end% while
            
        end%
        
        function ConvolvedAudioMatrix = ConvolutionOfIRWithFilterMatrix(FilterMatrixIRs, IR)
            
            [a, b] = size(FilterMatrixIRs);
            N_fft = max(a,b); % Assuming N_fft is always larger than the number of filters in the matrix
            NumberOfFilters = min(a,b);
            
            for filter_idx = 1:NumberOfFilters
                current_speaker_filter = squeeze(FilterMatrixIRs(filter_idx, :));
                FiltTemp = conv(current_speaker_filter, IR);
                
                ConvolvedAudioMatrix(filter_idx, :) = FiltTemp;%ifft(FiltTemp, N_fft, 'symmetric');
                
            end
            
        end
        
    end
    
end


%%
function InputWAVSignalMatrix = Normalize(InputWAVSignalMatrix, MaxGain)
if MaxGain ~= 0
    InputWAVSignalMatrix = AudioTlbx.NormalizeLevel(InputWAVSignalMatrix, MaxGain); % Normalization before playback
else
    InputWAVSignalMatrix = 1*InputWAVSignalMatrix;
end

end