%Measuring directional characteristics of sound sources
%Made by Benjamin Nimmerrichter 2022/23 for BUT

%% SETTINGS
clear
%---initialize variables---
buffer=1024; %buffer samples of ASIO device
samplerate=48000; %samplerate of ASIO device
mics=8; %amount of microphones/audio channels for recording

time=1; %time in seconds
A=1; %amplitude of signal
f=8000; %frequency of signal

device = "ASIO Hammerfall DSP"; %ASIO audio device for example ASIO Hammerfall DSP or ASIO4ALL v2
headroom = 3; %headroom in dBFS for clip detect to activate
num_clips = 50; %number of clipped samples for clip detect to activate
snr_conf = 20; %minimal SNR for measurement in dB
mute_set = false; %set to false if you want to generate a signal
noise_set = false; %measure with IEC 60268-5 simulated programme

meas_passes = 1; %number of measurement passes

calibration_freq = 1000; %frequency, which the calibrator plays

%% INITIALIZATION
playRec = audioPlayerRecorder(samplerate,'BitDepth','16-bit integer','Device',device,'RecorderChannelMapping',1:(mics),'SupportVariableSize',true,'BufferSize',buffer);
% ^^^^ initialize audio player recorder object


snr = zeros (mics,1); %signal to noise ratio





%----------MAIN-LOOP---------
while (true) %loop to calibrate until SNR and clip specs are met
    %% NOISE DETECTION
    input("Uzavřete místnost pro šumové měření a zmáčkněte enter");
    noise = generator(playRec,samplerate,f,A,1,buffer,true);
    noise_rms = calc_rms(noise(1024:end,:),mics);
    
    %% MICROPHONE CALIBRATION
    clear hold
    clear avg
    clear calib
    hold = zeros(mics,1); %value of how many similar measurements were made
    avg = zeros(mics,1); %average RMS value over multiple passes
    calib = zeros(mics,1); %final calibration for 94 dB SPL
    num = 0;
    input("Nyní si nachystejte kalibrátor a zmáčkněte enter, kalibrace proběhne automaticky při nasazení kalibrátoru na mikrofon");
   
    
    while (true)%calibration loop (wait until a long loud sound comes)
        signal = generator(playRec,samplerate,f,A,0.2,buffer,true);
        signal_rms = calc_rms(signal,mics);
        for i=(1:mics)%for each microphone
            if (calib(i) == 0)
                if (clip_detect(signal(:,i),headroom,num_clips) == 1)
                    %disp(['Vstupní signál mikrofonu č. ',num2str(i),' je limitován']);
                    %jen po dlouhém limitu
                    %break
                else
                    if (signal_rms(i) > (noise_rms(i)*20)) %look for a 26dB louder signal than noise floor
                        hold(i)=hold(i)+1;
                        %disp(['calibrating mic ', num2str(i)]);
                        if avg(i)>0 %averaging of multiple long signals
                            avg(i) = ((avg(i)+signal_rms(i))/2);
                        else
                            avg(i) = signal_rms(i);
                        end
            
                        if (hold(i) > 6)
                            autoc_freq = autoc(signal(:,i),samplerate);
                            %disp(['autoc freq is ', num2str(autoc_freq)]);
                            if (calibration_freq + 15 > autoc_freq) && (autoc_freq > calibration_freq - 15)
                                calib(i)=avg(i);
                                disp(['Mikrofon ', num2str(i), 'byl úspěšně nakalibrován.']);
                                num = num+1;
                            end
                        end
                    else
                        hold(i) = 0;
                        avg(i) = 0;
                    end
                end
            end
        end  
        if(num >= mics)
            break
        end
     end
        
    input("Teď připravte měřený signál pro kontrolu poměru signál šum a po stisknutí enter jej spusťte");
    
    %% CLIP AND SNR CRITERIA CHECK

    clear crit_met
    crit_met = 0;
    test_meas = generator(playRec,samplerate,f,A,time,buffer,mute_set);
    
    test_meas_rms = calc_rms(test_meas(1024:end,:),mics);
    snr = calculate_db(test_meas_rms,noise_rms,false);


    for i = 1:mics
        if(clip_detect(test_meas(1024:end,i),headroom,num_clips) == 0) %clip detect
            if (snr(i) > snr_conf)%minimal needed snr
                crit_met = crit_met + 1; % if SNR and clip criteria is met add one to mics meeting criteria
            else
                disp(['Poměr signálu a šumu je moc malý, zkuste zvýšit gain, nebo zmenšit potřebné SNR (mikrofon ', num2str(i),')']);
            end
        else
            disp(['Signál je omezen, zkuste snížit gain, nebo zmenšit headroom (mikrofon ', num2str(i),')']);
        end
    end
    if (crit_met == mics)
        break
    end
    disp('Výsledné poměry SNR')
    snr
    vstup = input("Přejete si i přesto pokračovat A pro ano N pro opakovanou kalibraci","s");
    if (vstup == 'a' || vstup == 'A')
        break;
    end

    
end

snr_min = min(snr);

%% STORING VALUES
%---save values to 'conf' struct---
conf.amplitude = A;
conf.buffer = buffer;
conf.time = time;
conf.mics = mics;
conf.Fs = samplerate;
conf.noise = noise_rms;
conf.calibration = calib;
conf.SNR = snr_min;
conf.device = device;
conf.headroom = headroom; 
conf.num_clips = num_clips; 
conf.snr_lim = snr_conf; 
conf.mute_set = mute_set;
conf.noise_set = noise_set;
conf.passes = meas_passes;
%---save 'conf' struct to config.mat file in the MEASUREMENT folder---
if (isfolder("MEASUREMENT"))
else
    mkdir("MEASUREMENT")
end

save ('MEASUREMENT/config.mat','conf'); %save file
clear playRec;
input("Kalibrace dokončena, stiskněte enter pro měření");
clear; %clear variables from RAM
measurement; %continue to measurement script