function [] = simScene(inputPath,outputPath,score,varargin)
% [] = simScene(inputPath,outputPath,score,[opts ... ])
%
% Generate a simulated auditory scene by mixing randomly chosen samples.
% The samples and their mixing properties are chosen partially randomly
% following user-provided guidelines.
%
% Required input variables are:
%
% - inputPath: a dataset of isolated sound events and backgrounds
%             respectively located in inputPat/event/ and
%             inputPat/background
%
% - outputPath: the repository where simscene will write the simulated scene
%              as well as the annotations
%
% - score: a structure describing the scene to simulate
%
%   score.sceneDuration: length of the simulated scene in second
%
%   score.backgrounds: Backgrounds are continuous sounds that keep going
%         over the whole duration of the scene. Several background samples
%         may be mixed together. If 'sceneDuration' is  more than the
%         natural length  of one of the selected bg sounds, they will be
%         looped as necessary -- that may not sound great, depending on the
%         sound... The format of the 'background' field controlling their
%         selection   and use is:
%
%         {{'<bg 1 label>','<bg 1 sampleId>', 1},
%          {'<bg 2 label>','<bg 2 sampleId>', <bg 2 snr>}...}
%
%         The value of 'snr' is ignored for the first bg sound. For the
%         following ones, it will be evaluated against the sum of the
%         previous ones. The value of 'Label' is the label of the
%         background track. Simscene will use the value 'sampleId' to load
%         the background sample(s) located in inputpath/background.
%         Simscene will only use background sample(s) having a name
%         containing the value 'sampleId'.
%
%  score.events: The 'events' is an array of cell arrays containg data use
%        to  simulated the scenes. Event contains the following data:
%
%        {{'<event 1 label>',
%          '<event 1 sampleId>',
%           <event 1 ebr>,
%           <event 1 ebr_stddev>,
%           <event 1 mean_time_between_instances>,
%           <event 1 time_between_instances_stddev>,
%           <event 1 start_time>, 
%           <event 1 end_time>,
%           <event 1 fade_in_time>, 
%           <event 1 fade_out_time>},
%         {'<event 2 ...> ...},
%         {'<event 3 ...> ...}
%        ...}
%
%        If <mean_time_between_instances> is 0, then it will be set to the
%        sample  length (so if <time_between_instances_stddev> is also 0,
%        the sample will be looped).
%        If <mean_time_between_instances> is -1, then the sound will be
%        played just once. The considered EBR value is the maximum EBR
%        of the fg sample relative to the bg on windows of 1000 samples.
%        The considered bg for this is the  mix of all specified bgs.
%
%  This version of simscene allows a lot of options to be controlled, as
%  optional  'name', value pairs from the 4th argument. Here is a brief 
%  description of the optional parameters:
% 
%  - timeMode: control a time spacing between events. 
%  		'generate' (default): values must be set for each track using the 
%                             score control structure
%  		'abstract': values are computed from an abstract representation of 
%                   an existing acoustic scene given as parameter
%  		'replicate': values are replicated from an existing acoustic scene 
%                    given as parameter
%  		
%  - ebrMode: control the Event to Background power level Ratio (EBR) of events. 
%  		Possible options are: 'generate' (default), 'abstract', 'replicate', see above.
%
% If ebrMode is set to 'replicate' or 'abstract', and score.events exist, 
% simScene will use the values <ebr> and <ebr_stddev> as offsets for 
% the class <label>. 
% If timeMode is set to 'abstract' and score.events exist, simScene will use 
% the values <mean_time_between_instances> and <time_between_instances_stddev>.
% as offsets for the class <label>. 
% If one of the mode is not set to 'generate' and score.events exist, SimScene 
% will also use the values <start_time>, <end_time>, <fade_in_time>,  <fade_out_time> 
% and '<sampleId>' of score.events, provided they are not equal to 0 or
% empty.
%  		
%  - instanceAnnotFile: if timeMode and / or ebrMode are set to 'abstract' 
%                       or 'replicate', this parameter is the path to the 
%                       annotation of the reference scene. Annotation must 
%                       be provided as a Comma Separated Value (CSV) file 
%                       with one event per line with class identifier as a 
%                       string, onset and offset times in second as floating 
%                       point value.
%
%  - instanceAudioFile: if timeMode and / or ebrMode are set to 'abstract' 
%                       or 'replicate', this parameter is the path to the wav 
%                       file of the reference scene sampled at 44100 Hz.
%  
%  - displayFigures: Boolean (default 0), save pictures (piano roll, time 
%                    domain stacked visualization, overlaid spectrogram)
% 
%  - outputFileName: name of generated files with no extension
%  
%  - sampleChoice: method for choosing sample to schedule within a track
%  		'random': unconstrained sampling
%  		'close': choose among the sampling dataset the sample that 
%                has the closest duration to the reference one. 
%                This mode is available only for the replicate timeMode.
%  
%  - minSpace: floating point value (default -1: overlapping between events allowed): 
%              minimal spacing in seconds between successive events
%  
%  - endCut: Boolean (default 0): adjust the duration of the last sample of 
%            each track if the latter ends after the track duration. 
%            If 1, cut the last sample to the track duration. If
%            0, the last sample is removed.
%
%  SceneSchedule and SceneObject:
%
%  - sceneObjects: This vector will contain detailed information concerning 
%                  all the samples selected to build this scene.
%                    
%  - sceneSchedule: This vector will contain all scheduling information 
%                   (i.e. what sample goes where, with what scaling factor). 
%                   The sample indices stored in it refer to the position 
%                   in the previous vector.
%
%  SceneSchedule, SceneObject, as well as score are saved in the .mat
%  annotation file.

% This program was written by Mathias Rossignol & Grégoire Lafay
% is Copyright (C) 2015 IRCAM <http://www.ircam.fr>
%
% This program is free software: you can redistribute it and/or modify it
% under the terms of the GNU General Public License as published by the Free
% Software Foundation, either version 3 of the License, or (at your option)
% any later version.
%
% This program is distributed in the hope that it will be useful, but
% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
% or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
% for more details.
%
% You should have received a copy of the GNU General Public License along
% with this program.  If not, see <http://www.gnu.org/licenses/>.
%
% Uses Mark Paskin's process_options.m from KPMtools

addpath(genpath('nonExposed'));

[timeMode,ebrMode,instanceAnnotFile,instanceAudioFile,displayFigures,sampleChoice,outputFileName,minSpace,endCut]=process_options(varargin,'timeMode','generate','ebrMode','generate','instanceAnnotFile','none','instanceAudioFile','none','displayFigures','1','sampleChoice','random','outputFileName','simulatedScene','minSpace',-1,'endCut',0);

check_options(timeMode,ebrMode,score)

%% Get score (only if at least one of the modes is not set to generate).
%  Else use score inpu variable
if (~strcmp(timeMode,'generate') || ~strcmp(ebrMode,'generate'))
    template=getTemplate(instanceAnnotFile,instanceAudioFile);
    if isfield(score,'events')
        score.events=addUserOffsets(template.class,score.events,timeMode,ebrMode);
    else
        warning('score.event is empty: score.event will be created from the scene to replicate');
        score.events=template.class;
    end
    if ~isfield(score,'sceneDuration')
        score.sceneDuration=template.sceneDuration;
    end
end

%% Get sceneSchedule and sceneObjects
[sceneSchedule,sceneObjects]=getBackground(inputPath,score);
[sceneSchedule,sceneObjects]=getEvent(sceneSchedule,sceneObjects,inputPath,score,timeMode,ebrMode,strcmp(sampleChoice,'random'));

%% Manage overlapping
if minSpace>=0
    [sceneSchedule] = manageOverlapping(sceneSchedule,minSpace);
end


%% Generate Scene
if (~exist(outputPath, 'dir'))
    mkdir(outputPath)
end
if (~exist([outputPath,'annotation'], 'dir'))
    mkdir([outputPath,'sound'])
end
if (~exist([outputPath,'annotation'], 'dir'))
    mkdir([outputPath,'annotation'])
end

[simsSceneWav,sceneSchedule] = generateScene(sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,displayFigures,timeMode,endCut);

%% Check simulated scene

checkClassPresence(sceneSchedule,sceneObjects);

if minSpace>=0
    checkOverlapping(sceneSchedule,score.sceneDuration)
end

%% Generate Sound
% wavwrite(simsSceneWav,44100,[outputPath,'sound/',outputFileName,'.wav']);
audiowrite([outputPath,'sound/',outputFileName,'.wav'],simsSceneWav,44100);
end
