function classify_cluster_sns( sns_filename )
  
  if nargin < 1
    error( [ mfilename ' needs 1 input argument.' ] );
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  % ( 0 ) Inputs and output
  
  disp( ' ' );
  
  % Define the output filename.
  % We will write out a file very similar to "FULL_detect_locate_wrapper....",
  % except for a few additional fields ("cluster_sns_par" etc.).
  
  [ p, n ] = fileparts( sns_filename );

  out_filename = fullfile( 'DATA', [ mfilename '-' n '.mat' ] );

  % Make sure it does not exist yet

  if exist( out_filename, 'file' )
    disp( [ mfilename ': output file already exists. Skipped.' ] );
    disp( [ '("' out_filename ')"' ] );
    return;
  end

  % Lock it by creating it

  fid = fopen( out_filename, 'wt' );
  fclose( fid );

  % Load the speech/non-speech GMM models
  
  load( sns_filename, 'model_list', 'par' );
  disp( [ mfilename ' loaded ' sns_filename ] );

  % Load the multisource detection-localization result

  result_filename = par.in_filename;
  load( result_filename, 'result' );
  disp( [ mfilename ' loaded ' result_filename ] );
  
  % (in case there is a GMM)
  % Among the GMMs with at least one full covariance matrix component,
  % select the one with maximum BIC score.

  BIC_list = [ model_list.BIC ];
  BIC_list( find( [ model_list.n_full ] < 1 ) ) = -Inf;
  
  [ tmp, gmm_max_ind ] = max( BIC_list );

  if tmp == -Inf
    
    disp( [ mfilename ' did not find a suitable GMM for MFCCs -> only wideband activeness will be used, along with C0.' ] );
    gmm_max_ind = [];
    
    % In such a case we'll only use wideband activeness
    % to take the speech/non-speech decision (see below).

  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  % ( 2 ) Process the recording(s)

  if numel( result.list ) ~= 1
    error( [ mfilename ' can process only one recording at a time.' ] );
  end
  
  % In "loc_to_keep", we are going to mark which location estimates we want to keep.

  tag = result.list.sphloc_mat( 7,: );
  
  loc_to_keep = ones( 1, numel( tag ) );
  
  % Extract the posterior probability of "speech"
  % for each location estimate.

  if isempty( gmm_max_ind )

    % Obtained using only wideband activeness
    % (very rare case).
    loc_log_post           = result.list.sphloc_mat( 6,: );
    loc_log_post_threshold = log( model_list( 1 ).wa_threshold );
    
  else

    % Obtained using both wideband activeness and sector-based MFCCs
    % (usual case).
    loc_log_post           = result.list.sphloc_mat( 6,: ) + model_list( gmm_max_ind ).log_post_speech;
    loc_log_post_threshold = log( model_list( gmm_max_ind ).wa_speech_threshold );
    
  end
  
  % A cluster is a set of location estimates sharing the same tag.
  %
  % For each cluster, we are going to decide between speech and non-speech.
  % A speech cluster should have:
  % - at least two "speech" location estimates.
  % - enough C0 standard deviation (speech is non-stationary).
  %
  % Note that the fixed threshold: C0 standard deviation > 0.6
  % is justified by the normalization inherent to sector-based MFCCs
  % (see IDIAP RR 06-26).
  
  cluster_sns_par = [];
  cluster_sns_par.n_speech_sample_min = 2;
  cluster_sns_par.sb_c0_std_threshold = 0.6;

  % Store the parameters

  result.list.cluster_sns_par     = cluster_sns_par;
  result.list.raw_result_filename = result_filename;
  result.list.sns_filename        = sns_filename;
  
  % List the clusters
  
  tag_list  = unique( tag );

  n_cluster = numel( tag_list );

  is_speech_cluster = zeros( 1, n_cluster );

  for i_cluster = 1:n_cluster

    % For each cluster:

    % ( 2.1 ) List the location estimates
    
    loc_ind = find( tag == tag_list( i_cluster ) );

    % ( 2.2 ) Count the number of "speech" location estimates.

    n_speech = sum( loc_log_post( loc_ind ) > loc_log_post_threshold );

    % ( 2.3 ) Compute the standard deviation of the sector-based C0 coefficient.
    
    sb_c0_std = std( result.list.sbmfcc_mat( 3,loc_ind ) );
    
    % ( 2.4 ) Take the speech/non-speech decision at the cluster level
    
    is_speech_cluster( i_cluster ) = ( n_speech >= cluster_sns_par.n_speech_sample_min ) & ( sb_c0_std > cluster_sns_par.sb_c0_std_threshold );
    
  end

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  % ( 3 ) Remove all location estimates belonging to non-speech clusters,
  % keep all others.

  loc_to_keep = find( ismember( tag, tag_list( find( is_speech_cluster ) ) ) );

  result.list.sphloc_mat = result.list.sphloc_mat( :, loc_to_keep );

  if ~isempty( gmm_max_ind )
    result.list.sbmfcc_mat = result.list.sbmfcc_mat( :, loc_to_keep );
  else
    result.list.sbmfcc_mat  = [];
  end
  
  % Write out

  save( out_filename, 'result' );

  disp( [ mfilename ' wrote out "' out_filename '".' ] );
  