% File "README.m"

% Complete MATLAB/C implementations of the multispeaker detection-localization
% systems described in IDIAP RR 06-26. Unless you are on Pentium (4) architecture
% with Linux on it, you will need to recompile the C files used by MATLAB (MEX).
% Precise instructions for MEX compilations are given at the top of
% "FAST_detect_locate.m".
%
% Along with the implementations, eight real audio recordings are
% provided, with the true 3-D position of each speaker. You can freely
% access the AVI videos associated with the audio examples, using the
% following weblink:
%
% http://mmm.idiap.ch/Lathoud/av16.3_v6
%
% If you are only looking for a fast (near real-time)
% but reasonably precise (SRP-PHAT) multisource detection-localization,
% use the 'FAST' implementation (see ( 1 ) and ( 2 ) for examples).
%
% Brief summary of what you find below:
%
% ( 1 ) Basic example (the 'FAST' implementation on one recording).
%
% ( 2 ) Everything (all implementations, all recordings + performance evaluation).
%       Recordings comprise mostly moving speakers.
%
% ( 3 ) Basic example + the GMM for improved speech/non-speech discrimination.
%       This may be useful to remove some noises (body, papers), e.g. in meetings (M4 corpus).
%
% ( 4 ) Application to unsupervised location-based speaker segmentation (in meetings). 
%       "Unsupervised" means that we don't know in advance the occupied locations 
%       and the number of such locations. We are using here one recording 
%       from the M4 Corpus (mmm.idiap.ch).

%
% By G. Lathoud, 2006
% lathoud@idiap.ch


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ( 1 ) Basic example (the 'FAST' implementation on one recording).
% 
% Run the "FAST" implementation of multispeaker detection-localization, 
% short-term clustering, and extraction of sector-based MFCC 
% and single-channel MFCC.
%
% -> "FAST" speed is comparable to real-time (about 1xRT to 3xRT duration).
%
% This is just one example: one implementation, one recording.
%
% If you want to run everything, go to ( 2 ).

% ( 1.1 ) Multisource detection and localization

FAST_detect_locate_wrapper( 'seq18-2p-0101' );

% ( 1.2 ) Set an automatic threshold on posteriors of wideband activity

par = [];
par.in_filename = 'DATA/FAST_detect_locate_wrapper-seq18-2p-0101-result.mat';
% To select the automatic threshold for the final decision, 
% based on IDIAP RR 05-52. This is a False Alarm Rate target, between 0 and 1.
par.far_t = 0.001;
par.out_dir     = 'DATA';

wa_sns_model( par );

% Show the result, before and after FRAME-LEVEL speech/non-speech classification

example_frame_level_sns( 'DATA/wa_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );

% ( 1.3 ) Now use the threshold to take a cluster-level decision

classify_cluster_sns( 'DATA/wa_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );

% Show the result after CLUSTER-LEVEL speech/non-speech classification

example_cluster_level_sns( 'DATA/classify_cluster_sns-wa_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ( 2 ) Run all three implementation on all available examples.
% - FASTTDE uses GCCPHAT Time Delay Estimation, it is the fastest, but less precise.
% - FAST uses SRPPHAT, it is more precise than FASTTDE, but still runs near real-time.
% - FULL uses SRPPHAT, it is the slowest (not necessarily better than FAST).


% ( 2.1 ) Select which recordings you want

rec_list = { 'seq01-1p-0000', 'seq11-1p-0100', 'seq15-1p-0100', 'seq18-2p-0101', 'seq24-2p-0111', 'seq37-3p-0001', 'seq40-3p-0111', 'seq45-3p-1111' };


% ( 2.2 ) Select which implementations you want

impl_list = { 'FASTTDE', 'FAST', 'FULL' };


% ( 2.3 ) Okay now we can loop: 
% for each implementation and each recording,
% - multisource detection-localization.
% - speech/non-speech discrimination.
% - evaluation of the result.

main_loop( impl_list, rec_list );


% ( 2.4 ) Look at all the raw results

display_raw_loop( impl_list, rec_list );

% If you want to look at just one of them, do this

display_raw_loop( impl_list( 2 ), rec_list( 5 ) );


% ( 2.5 ) Look at the evaluation statistics

display_stats( 'FULL', rec_list );

display_stats( 'FAST', rec_list );

display_stats( 'FASTTDE', rec_list );


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ( 3 ) Example of multisource detection-localization
% with the enhanced GMM speech/non-speech discrimination
% ( we used it on the M4 corpus mainly )
% 
% Watch out: fitting a full covariance GMM takes time...

% ( 3.1 ) Multisource detection and localization

FAST_detect_locate_wrapper( 'seq18-2p-0101' );

% ( 3.2 ) Set an automatic threshold on posteriors of wideband activity

par = [];
par.in_filename = 'DATA/FAST_detect_locate_wrapper-seq18-2p-0101-result.mat';
par.n_comp_list = 2:10;

% To select the automatic threshold for the final decision,
% based on IDIAP RR 05-52. This is a False Alarm Rate target, between 0 and 1.
%
% NOTE: the threshold is less conservative than above, in order to
% counterbalance the fact that we now use BOTH wideband activeness and
% MFCC vectors to discriminate between speech and non-speech.
par.far_t = 0.01;

par.out_dir     = 'DATA';

sbmfcc_sns_model( par );   % This one takes time

% Show the result, before and after FRAME-LEVEL speech/non-speech classification

example_frame_level_sns( 'DATA/sbmfcc_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );

% ( 3.3 ) Now use the threshold to take a cluster-level decision

classify_cluster_sns( 'DATA/sbmfcc_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );

% Show the result after CLUSTER-LEVEL speech/non-speech classification

example_cluster_level_sns( 'DATA/classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-seq18-2p-0101-result.mat' );

% ( 3.4 ) Do them all

rec_list = { 'seq01-1p-0000', 'seq11-1p-0100', 'seq15-1p-0100', 'seq18-2p-0101', 'seq24-2p-0111', 'seq37-3p-0001', 'seq40-3p-0111', 'seq45-3p-1111' };
impl_list = { 'FASTTDE', 'FAST', 'FULL' };

main_loop_gmm( impl_list, rec_list );


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ( 4 ) Application to unsupervised location-based speaker segmentation
% "unsupervised" means that we don't know in advance the occupied locations
% and the number of such locations.
%
% We are using here one recording from the M4 Corpus (mmm.idiap.ch).

% ( 4.1 ) Run multisource detection-localization and short-term clustering

FAST_detect_locate_wrapper( 'Scripted-Meeting-TST-01' );

% ( 4.2 ) Set an automatic threshold on posteriors of wideband activity

par = [];
par.in_filename = 'DATA/FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat';
par.n_comp_list = 2:10;

% To select the automatic threshold for the final decision,
% based on IDIAP RR 05-52. This is a False Alarm Rate target, between 0 and 1.
%
% NOTE: the threshold is less conservative than above, in order to
% counterbalance the fact that we now use BOTH wideband activeness and
% MFCC vectors to discriminate between speech and non-speech.
par.far_t = 0.01;

par.out_dir     = 'DATA';

sbmfcc_sns_model( par );   % This one takes time

% Show the result, before and after FRAME-LEVEL speech/non-speech classification

example_frame_level_sns( 'DATA/sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat' );

% ( 4.3 ) Now use the threshold to take a cluster-level decision

classify_cluster_sns( 'DATA/sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat' );

% Show the result after CLUSTER-LEVEL speech/non-speech classification

example_cluster_level_sns( 'DATA/classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat' );

% ( 4.4 ) Now run STATIC location clustering to determine automatically:
% - the number and positions of most occupied locations in the meeting.
% - the speech segments.
%
% This is done by fitting a single Gaussian on each SPEECH short-term
% cluster, in azimuth space, and running BIC iterative
% merging. Increase (decrease) lambda if you want less (more)
% locations after convergence. In the original BIC lambda = 1.

lambda = 3;

static_bic( 'DATA/classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat', lambda );

% -> not that great, the data for each location is too complex to be modelled with a single Gaussian.
% -> static_bic requires tuning.

% -> let's try another criterion: minimize sum( sigma .^ 2 )

static_sigma( 'DATA/classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat' );

% -> not too bad, found the 6 locations correctly

% ( 4.5 ) Show the resulting meeting segmentation
%
% (these two ways are strictly equivalent)

if 1

  % Show the figure
  % (a matlab file and a text file are also written)
  show_static_seg( 'DATA/static_sigma-classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat', [], 1 );

else

  % Don't show the figure
  % (a matlab file and a text file are also written)
  show_static_seg( 'DATA/static_sigma-classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat' );

  % Load the result
  load( 'DATA/show_static_seg-static_sigma-classify_cluster_sns-sbmfcc_sns_model-FAST_detect_locate_wrapper-Scripted-Meeting-TST-01-result.mat', 'static_obj' );
  
  % Show the figure(s)
  for a = 1:numel( static_obj.list )
    figure;
    plot_loctimeseg( static_obj.list( a ).smooth_loctimeseg );
    title( static_obj.list( a ).name );
  end
  
  % Also show the text file contents
  system( 'cat DATA/show_static_seg-Scripted-Meeting-TST-01-smooth_seg.txt' );

end