Mercurial > hg > simscene-py
changeset 14:b1901e8d8f5f
initial commit
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demo.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,72 @@ +% SimScene is a set of Matlab functions dedicated to the simulation of acoustic scenes. +% This tool is specifically tailored to the evaluation of machine listening systems. +% Thus, extensive and precise annotation of the scene content is provided together with the simulated scene. +% +% This tool is a research tool, provided as-is with the hope that it will be +% useful and easy to adapt to the needs of others. Do not hesitate to provide +% us with feedback at the following mail address: mathieu.lagrange@cnrs.fr +% +% SimScene have been tested on Matlab R2013b. The input audio files must be sampled at 44100 Hz. + +% clear all; +% close all; + +inputPath='./sound/'; +outputPath='./results/'; + +%% timeMode: 'generate' -- ebrMode: 'generate' + +timeMode='generate'; +ebrMode='generate'; +sceneDuration=15; + +score.sceneDuration=sceneDuration; +score.backgrounds={{'forest','forest', 1}}; +score.events={{'alouette','alouette', 12, 0, 2, 0.1, 1, 10, 0, 0},... + {'bulbul' ,'bulbul' , 6 , 0, 2, 0, 3, 13, 0, 0},... + {'geai' ,'geai' , 6 , 0, 1, 0.25, 5, 10, 0, 0}}; + +sceneId = ['demo_forest_timeMode_' timeMode '_ebrMode_' ebrMode]; +disp(sceneId); + +simScene(inputPath,outputPath,score,... + 'timeMode',timeMode,'ebrMode',ebrMode,'outputFileName',sceneId); + +%% timeMode: 'replicate' -- ebrMode: 'replicate' + +instanceAnnotFile='./scene2Replicate/forest.txt'; +instanceAudioFile='./scene2Replicate/forest.wav'; + +timeMode='replicate'; +ebrMode='replicate'; +sceneId = ['demo_forest_timeMode_' timeMode '_ebrMode_' ebrMode]; +disp(sceneId); + +score.backgrounds={{'forest','forest', 1}}; + +score.events={{'alouette','', -3, 0, 0, 0, 0, 0, 0, 0},... % Only change <ebr> + {'bulbul','', 3, 0, 0, 0, 6, 0, 0, 0}}; % Change <ebr> and <start_time> + +% If score.event is of length 1 and <label>='', offsets will be used for all classes. +% score.events={{'','',-6,0,0,0,0,0,0,0}}; % Change <ebr> for the three sound classes of bird. + +simScene(inputPath,outputPath,score,... + 'timeMode',timeMode,'ebrMode',ebrMode,'outputFileName',sceneId,... + 'instanceAnnotFile',instanceAnnotFile,'instanceAudioFile',instanceAudioFile); + +%% timeMode: 'abstract' -- ebrMode: 'abstract' + +instanceAnnotFile='./scene2Replicate/forest.txt'; +instanceAudioFile='./scene2Replicate/forest.wav'; + +timeMode='abstract'; +ebrMode='abstract'; +sceneId = ['demo_forest_timeMode_' timeMode '_ebrMode_' ebrMode]; +disp(sceneId); + +score.backgrounds={{'forest','forest', 1}}; +score.events={{'geai','', -3, 0, 5, 0, 1, 0, 0, 0}}; % Change <ebr>, <mean_time_between_instances> and <start_time> + +simScene(inputPath,outputPath,score,... + 'timeMode',timeMode,'ebrMode',ebrMode,'outputFileName',sceneId,... + 'instanceAnnotFile',instanceAnnotFile,'instanceAudioFile',instanceAudioFile); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/addUserOffsets.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,82 @@ +function [scoreEvent] = addUserOffsets(template,scoreEvent,timeMode,ebrMode) + +% 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/>. + +%% Create userOffsets matrix +userOffset=zeros(length(template),4); + +if length(scoreEvent)==1 && strcmp('',scoreEvent{1}{1}) % add the same offset to all the classes + userOffset=[repmat(scoreEvent{1}{3},length(template),1) repmat(scoreEvent{1}{4},length(template),1) repmat(scoreEvent{1}{5},length(template),1) repmat(scoreEvent{1}{6},length(template),1)]; + warning('score.event if of length 1: classId will set to the class labels of the scene to replicate') +else % add class wise offsets + for jj=1:length(scoreEvent) scoreEventClass{jj}=scoreEvent{jj}{1}; end; + for ii=1:length(template) + indClass=find(strcmp(template{ii}{1},scoreEventClass)); + if ~isempty(indClass) + userOffset(ii,1:4)=[scoreEvent{indClass}{3} scoreEvent{indClass}{4} scoreEvent{indClass}{5} scoreEvent{indClass}{6}]; + if ~strcmp('',scoreEvent{indClass}{2}) + template{ii}{2}=scoreEvent{indClass}{2}; + end + if scoreEvent{indClass}{7} ~= 0 % change class start time + template{ii}{7}= scoreEvent{indClass}{7}; + end + if scoreEvent{indClass}{8} ~= 0 % change class end time + template{ii}{8}= scoreEvent{indClass}{8}; + end + if scoreEvent{indClass}{9} ~= 0 % change fade in time + template{ii}{9}= scoreEvent{indClass}{9}; + end + if scoreEvent{indClass}{10} ~= 0 % change fade out time + template{ii}{10}= scoreEvent{indClass}{10}; + end + else + userOffset(ii,1:4)=zeros(1,4); + end + end +end + +%% add user offsets to time +switch timeMode + case 'abstract' + for ii=1:length(template) + template{ii}{5}=template{ii}{5}+userOffset(ii,3); + template{ii}{6}=template{ii}{6}+userOffset(ii,4); + end +end + +%% add user offsets to ebr +switch ebrMode + case 'generate' + for ii=1:length(template) + template{ii}{3}=userOffset(ii,1); + template{ii}{4}=userOffset(ii,2); + end + case 'abstract' + for ii=1:length(template) + template{ii}{3}=template{ii}{3}+userOffset(ii,1); + template{ii}{4}=template{ii}{4}+userOffset(ii,2); + end + case 'replicate' + for ii=1:length(template) + template{ii}{13}=template{ii}{13}+userOffset(ii,1)+randn(length(template{ii}{13}),1)*userOffset(ii,2); + template{ii}{3}=mean(template{ii}{13}); + template{ii}{4}=std(template{ii}{13}); + end +end + +scoreEvent=template; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/adjustScaleForEBR.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,76 @@ +function scale = adjustScaleForEBR (fg, bg, offset, targetEBR, snrType, eps) +% Computes the value of 'scale' such that fg*scale has a given EBR +% relatively to bg at position 'offset'. +% ebrType is used to select what kind of EBR should be considered: +% 1 - standard temporal ebr over whole length of sample +% 2 - max of standard temporal ebr over 1/4s windows +% 3 - more to come ? +% eps is the epsilon used to check for convergence; optional, defaults to +% 0.01 + +% 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/>. + +if (nargin == 5) eps = 0.01; end +%if (targetSNR <= 0) targetSNR = exp(targetSNR); end +prevScale = 1; +scale = 1; +ebrFunc=@ebr; +if (snrType==2) ebrFunc=@maxWindowEBR; end +count = 0; +while (ebrFunc(fg, bg, offset, scale) > targetEBR && count < 100) + prevScale = scale; + scale = scale/2; + count = count+1; +end +if (count == 100) + msg = ['Max count, stage 1, scale = ', num2str(scale), ' - ', num2str(ebrFunc(fg, bg, offset, scale)), ' - ', num2str(ebrFunc(fg, bg, offset, prevScale)), ' - ', num2str(ebrFunc(fg, bg, offset, 1))]; + error(msg) +end +count=0; +while (ebrFunc(fg, bg, offset, scale) < targetEBR && count < 100) + prevScale = scale; + scale = scale*2; + count = count+1; +end +if (count == 100) + msg = ['Max count, stage 2, scale = ', num2str(scale)]; + error(msg) +end +count=0; +if (scale<prevScale) + a = scale; + b = prevScale; +else + a=prevScale; + b=scale; +end +delta = ebrFunc(fg, bg, offset, (a+b)/2) - targetEBR; +while (abs(delta) > eps && count < 100) + if (delta>0) + b = (a+b)/2; + else + a = (a+b)/2; + end + delta = ebrFunc(fg, bg, offset, (a+b)/2) - targetEBR; + count = count+1; +end +if (count == 100) + msg = ['Max count, stage 3, scale = ', num2str(a)]; + error(msg) +end +scale = (a+b)/2; +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/checkClassPresence.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,12 @@ +function [] = checkClassPresence( sceneSchedule,sceneObjects ) + +classIndex=ones(1,length(sceneObjects)); +classIndex(unique([sceneSchedule.classId]))=0; + +if(find(classIndex==1)) + classLabel= {sceneObjects.classLabel}; + disp({classLabel{logical(classIndex)}}) + error('At least one class has been removed during the simulation process') +end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/checkOverlapping.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,17 @@ +function [] = checkcOverlapping(sceneSchedule,sceneDuration) +%% check overlapping +onset=[sceneSchedule(2:end).position]; +offset=[sceneSchedule(2:end).duration]+onset; +[~,index]=sort(onset); +onset=onset(index); +offset=offset(index); +coveringIndice=onset(2:end)-offset(1:end-1); +if(find(coveringIndice<0)) + error('covering is not respected') +end + +%% check sceneDuration +if(offset(end)>sceneDuration+0.1) + error('Last event length is superior to the scene Duration') +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/check_options.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,65 @@ +function [] = check_options(timeMode,ebrMode,score) + +% 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/>. + + +%% Forbidden modes : +% time abstract - ebr replicate +% time generate - ebr replicate + +%% Check mode validity +if(~strcmp(ebrMode,'abstract') && ~strcmp(ebrMode,'replicate') && ~strcmp(ebrMode,'generate')) + error('wrong ebrMode') +end + +if(~strcmp(timeMode,'abstract') && ~strcmp(timeMode,'replicate') && ~strcmp(timeMode,'generate')) + error('wrong ebrMode') +end + +if(strcmp(timeMode,'abstract') && strcmp(ebrMode,'replicate')) + error(['wrong timeMode, timeMode must be set to replicate if ebrMode is set to replicate (The number of events must be the same); time=' timeMode ', and ebr=' ebrMode]) +elseif(strcmp(timeMode,'generate') && strcmp(ebrMode,'replicate')) + error(['wrong timeMode, timeMode must be set to replicate if ebrMode is set to replicate (The number of events must be the same); time=' timeMode ', and ebr=' ebrMode]) +end + +%% Check options validity +if ~isfield(score,'sceneDuration') + if strcmp(timeMode,'generate') && strcmp(timeMode,'generate') + error('Score does not have a sceneDuration field') + else + warning('score.sceneduration does not exist; sceneDuration will be set to the duration of the scene to replicate') + end +end + +if ~isfield(score,'backgrounds') + error('score does not have a backgrounds field; score.backgrounds is always needed') +end + +if strcmp(timeMode,'generate') || strcmp(timeMode,'generate') + if ~isfield(score,'events') + error('score.event does not exist; score.event is needed if one of the modes is set to generate') + end +end + +if ~strcmp(timeMode,'generate') || ~strcmp(timeMode,'generate') + if isfield(score,'events') + warning('score.event exist; score.events cells values will be used as offsets') + end +end + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/ebr.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,35 @@ +function s = ebr (fg, bg, offset, fgScale) +% Computes the EBR of fg relatively to bg +% If the optional argument offset is provided, will compute the EBR of fg +% at position 'offset' in bg +% If the optional argument fgScale is provided, the SNR of fg*fgScale over +% bg will be returned instead + +% 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/>. + +if (nargin<=2) offset=1; end +if (nargin<=3) fgScale=1; end + +endPosBg = min(offset+length(fg)-1, length(bg)); +endPosFg = endPosBg-offset+1; + +aFg = sqrt(sum((fg(1:endPosFg).*fgScale).^2)/endPosFg); %RMS +aBg = sqrt(sum(bg(offset:endPosBg).^2)/endPosFg); %RMS + +s = 20*log10(aFg/(aBg+.001)); +%fprintf('fg from position %i to %i, %i samples, scale = %f, bg pow = %f, fg pow = %f, snr = %f\n', offset, endPosBg, endPosFg, fgScale, aBg, aFg, s); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/generateColormap.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,43 @@ +function cmap = generateColormap (sceneObjects) +% returns a colormap with randomly chosen colors somewhat evenly spread in +% the color spectrum, to be used for the graphical representations of a +% synthesized scene. + +% Background sounds will have a saturation of .3, foreground sounds of 1 +% Value is always let to .5, since modifying it would erroneously suggest +% a difference of intensity + +% 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/>. + +nbTracks = length(sceneObjects); + +% Colors for figures +% Choosing color hues evenly spread in the color spectrum, then randomizing their order +hues = (0:1/nbTracks:1); +hues = hues(1:nbTracks); +hues = hues(randperm(nbTracks)); +% Generate a colormap: +for c=1:nbTracks + if (sceneObjects(c).isBackground) + cmap(c,:) = hsl2rgb([hues(c), .3, .5]); + else + cmap(c,:) = hsl2rgb([hues(c), 1, .5]); + end +end + + +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/generateScene.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,209 @@ +function [w,sceneSchedule] = generateScene (sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,displayFigures,timeMode,endCut) +% function [w,sceneSchedule] = generateScene (sceneSchedule,sceneObjects,score,inputPath,outputPath,outputFileName,displayFigures,timeMode,endCut) +% This function does the actual job of loading, scaling, positioning and +% mixing the various samples to generate a scene, based on the +% specifications given by its parameters. + +% 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/>. + +sr = 44100; +trackLength = sr*score.sceneDuration; +nbTracks = length(sceneObjects); + +% All instances of one sample will appear on a given track, before +% everything is mixed together, making it possible to apply track-specific +% effects or generate nice colorful representations +tracks = zeros(length(sceneObjects), trackLength); + +% We also generate a "bg" track with all background samples, against which +% the snr of fg sounds will be evaluated +bg = zeros(trackLength, 1); + +%% Preloading all wav samples into memory +waves = {}; +for i=1:nbTracks + if(sceneObjects(i).isBackground) + path = [inputPath,'background/']; + else + path = [inputPath,'event/']; + end + sample = dir([path '*wav']); + sampleId = find(cellfun('isempty',regexpi({sample.name},sceneObjects(i).query,'match'))==0); + for j=1:length(sampleId) + % this test is necessary because mp3 conversion does not + % always maintain exact length, and wavread will crash if asked to + % read too many samples. + waves{i}{j}= wavread([path sample(sampleId(j)).name]); + if(size(waves{i}{j},2)==2) + waves{i}{j}= mean(waves{i}{j},2); + end + waves{i}{j} = waves{i}{j}(:); + end +end + +dominantTrack = zeros(1,trackLength) + 1; +dominantObject = zeros(1,trackLength) + 1; +dominantEnergy = zeros(1,trackLength); +simulatedEBR = zeros(length(sceneSchedule),2); +objNum = 1; + +%% Create sceneSchedule +id2remove=[]; +for i=1:length(sceneSchedule) + id = sceneSchedule(i).classId; + if (sceneSchedule(i).isBackground) + scale = 1; + if (i>1) + scale = adjustScaleForEBR(waves{id}{1}, bg, 1, sceneSchedule(i).ebr, 1, 0.01); + end + if (length(waves{id}{1}) < trackLength) + % need to loop the sample to fill the bg. Linear crossfade + loop = waves{id}{1}; + fadeLen = 20000; + fadeIn = transpose(0:1/fadeLen:1); + fadeOut = transpose(1:-1/fadeLen:0); + loop(1:fadeLen) = loop(1:fadeLen) .* fadeIn(1:fadeLen); + loop(length(loop)-fadeLen+1:length(loop)) = loop(length(loop)+1-fadeLen:length(loop)) .* fadeOut(1:fadeLen); + loop = scale * loop.'; + for l=0:floor(trackLength/(length(loop)-fadeLen)) + t1 = 1+l*(length(loop)-fadeLen); + t2 = min(length(bg), t1+length(loop)-1); + tracks(id,t1:t2) = tracks(id,t1:t2) + loop(1:t2-t1+1); + end + else + dim = min(trackLength, length(waves{id}{1})); + tracks(id,1:dim) = tracks(id,1:dim) + scale*(waves{id}{1}(1:dim).'); + end + if (i==1) + bg = tracks(id,:); + else + bg = bg+tracks(id,:); + end + else + objNum = objNum+1; + inst = sceneSchedule(i).instance; + pos = max(1,floor(sr*sceneSchedule(i).position)); + + switch timeMode + case {'replicate'} + if(length(waves{id}{inst})/sr - sceneSchedule(i).duration > 0.5) + endTime = round(sceneSchedule(i).duration*sr); + else + endTime = length(waves{id}{inst}); + end + case {'abstract'} + endTime = round(sceneSchedule(i).duration*sr); + otherwise + endTime = length(waves{id}{inst}); + end + + if endCut + pos2Test=pos; + else + + pos2Test=pos+endTime-1; + end + + if(pos2Test<round(sceneObjects(sceneSchedule(i).classId).trackLength*sr)) + t2 = min(pos+endTime-1, round(sceneObjects(sceneSchedule(i).classId).trackLength*sr)); + wav2use=waves{id}{inst}(1:t2-pos+1); + sceneSchedule(i).duration=length(wav2use)/sr; + scale = adjustScaleForEBR(wav2use, bg, pos, sceneSchedule(i).ebr, 1, 0.01); + + [~,bgEnergy] = powspec(bg(pos:t2)); + [~,evEnergy] = powspec(scale*wav2use.'); + labelStart = min(find(bgEnergy<evEnergy)); + labelEnd = max(find(bgEnergy<evEnergy)); + for t=labelStart:labelEnd + if evEnergy(t)>dominantEnergy(pos+t) + dominantObject(pos+round(t*(t2-pos)/length(bgEnergy))) = objNum; + dominantEnergy(pos+round(t*(t2-pos)/length(bgEnergy))) = evEnergy(t); + end + end + dominantObject(min(find(dominantObject==objNum)):max(find(dominantObject==objNum))) = objNum; + dominantTrack(dominantObject==objNum) = id; + + tracks(id, pos:t2) = tracks(id, pos:t2) + scale*wav2use.'; + %% Store EBR and event locations + simulatedEBR(i,1) = ebr(tracks(id, pos:t2),tracks(1, pos:t2)); + simulatedEBR(i,2)=pos; + else + id2remove=[id2remove i]; + end + end +end + +sceneSchedule(id2remove)=[]; +% checkClassPresence(sceneSchedule,sceneObjects); + +save ([outputPath 'annotation/' outputFileName '.mat'],'score', 'sceneObjects', 'sceneSchedule','dominantTrack', 'dominantObject','simulatedEBR'); +saveAnnotationTxt(sceneSchedule,outputPath,outputFileName); + +w = sum(tracks); +w = w/(max(abs(w))+0.001); %Normalize to [-1,1] + +if displayFigures + cmap = generateColormap(sceneObjects); + + timeDomainVisualization(tracks, cmap, 1, 10000, 1, [outputPath 'annotation/' outputFileName,'-timeDomain.png']); + + % Producing a colored spectrum visualization + for i=1:nbTracks + spec = log(1+abs(spectrogram(tracks(i,:), hanning(2048), 1024, 2048))); + spec = min(1, spec ./ max(spec(:))); + spec = spec(1:400,:); + spec = flipud(spec); + for colorComp=1:3 + if (i==1) + img(:,:,colorComp) = cmap(i,colorComp)*spec; + else + img(:,:,colorComp) = img(:,:,colorComp)+cmap(i,colorComp)*spec; + end + end + end + img = img/max(img(:)); + f = figure(2); + clf; + set(gca,'YTick', []); + set(f, 'Position', [0, 0, 2*size(img,1), 600]); + imagesc(img); + imwrite(img, [outputPath 'annotation/' outputFileName,'-spectrum.png'], 'png'); + + + %% Producing a "piano roll" visualization + f = figure(3); + clf; + set(gca,'YTick', []); + grid on; + set(f, 'Position', [0, 0, trackLength/512, 300]); + for i=1:length(sceneObjects) + text(0, i+.4, [num2str(sceneObjects(i).classLabel), ' '], 'HorizontalAlignment', 'right'); + end + + for i=1:length(sceneSchedule) + id = sceneSchedule(i).classId; + if (sceneSchedule(i).isBackground) + rectangle('Position', [0, id+.2, score.sceneDuration, .6], 'FaceColor', cmap(id,:)); + else + t1 = sceneSchedule(i).position; + rectangle('Position', [t1, id+.1, sceneSchedule(i).duration, .8], 'FaceColor', cmap(id,:)); + end + end + set(f, 'PaperPositionMode', 'auto'); + print ('-dpng', '-r150', [outputPath 'annotation/' outputFileName,'-piano_roll.png']); +end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getBackground.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,33 @@ +function [sceneSchedule,sceneObjects]=getBackground(inputPath,score) + +% 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/>. + +for i=1:length(score.backgrounds) + sceneObjects(i) = getSampleInfo(score.backgrounds{i}{1},score.backgrounds{i}{2},'background',inputPath,score.sceneDuration); + sceneSchedule(i).classId=i; + sceneSchedule(i).classLabel=score.backgrounds{i}{2}; + sceneSchedule(i).position=0; + sceneSchedule(i).instance=1; + sceneSchedule(i).isBackground = 1; + sceneSchedule(i).duration = score.sceneDuration; + if (i==1) + sceneSchedule(i).ebr=1; + else + sceneSchedule(i).ebr= score.backgrounds{i}{3}; + end +end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getEbrs.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,30 @@ +function [EBRs] = getEbrs(bgLocation,signal,sr,onset,offset) + +% 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/>. + +EBRs=zeros(length(onset),1); + +%% get EBR of all the events of a class +for ii=1:length(onset) + eventLocation=zeros(1,length(signal)); + eventLocation(round(onset(ii)*sr+1):round(offset(ii)*sr))=1; + eventLocation=logical(eventLocation); + EBRs(ii) = ebr(signal(eventLocation),signal(bgLocation),1,1); +end + +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getEvent.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,111 @@ +function [sceneSchedule,sceneObjects]=getEvent(sceneSchedule,sceneObjects,inputPath,score,timeMode,ebrMode,randomFlag) + +% 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/>. + +settings.randomFlag = randomFlag; +settings.schedPos = length(sceneSchedule)+1; + +for ii=1:length(score.events) + settings.classId =ii+length(score.backgrounds); + settings.ebrMode=ebrMode; + settings.timeMode=timeMode; + settings.label=score.events{ii}{1}; + + settings.ebr_mean = score.events{ii}{3}; + settings.ebr_std = score.events{ii}{4}; + + sceneObjects(settings.classId) = getSampleInfo(score.events{ii}{1}, score.events{ii}{2},'event',inputPath,score.events{ii}{8}); + settings.duration_mean = mean(sceneObjects(settings.classId).endTimes-sceneObjects(settings.classId).startTimes); + settings.duration_std = std(sceneObjects(settings.classId).endTimes-sceneObjects(settings.classId).startTimes); + settings.mean_time_between_instances = score.events{ii}{5}; + settings.time_between_instances_std = score.events{ii}{6}; + settings.start_time = score.events{ii}{7}; + settings.end_time = score.events{ii}{8}; + settings.fade_in_time = score.events{ii}{9}; + settings.fade_out_time = score.events{ii}{10}; + + if ~strcmp(settings.timeMode,'generate') || ~strcmp(settings.ebrMode,'generate') + settings.start_times = score.events{ii}{11}; + settings.end_times = score.events{ii}{12}; + settings.ebrs = score.events{ii}{13}; + settings.template_duration_mean=mean(settings.end_times-settings.start_times); + settings.template_duration_std=std(settings.end_times-settings.start_times); + end + + if (settings.start_time > score.sceneDuration) + settings.start_time = score.sceneDuration; + warning(['Sart time of event class ' score.events{ii}{1} ' is superior to the scene Duration; start time has been set to the scene duration.']) + end + + if (settings.end_time > score.sceneDuration) + settings.end_time = score.sceneDuration; + warning(['End time of event class ' score.events{ii}{1} ' is superior to the scene Duration; end time has been set to the scene duration.']) + end + + + + %% generate sceneSchedule + switch timeMode + + case {'generate','abstract'} + + if (settings.mean_time_between_instances == 0) % Looping: only for generate timeMode + if strcmp(timeMode,'abstract') + error('simScene cannot loop event in abstract time Mode') + end + time = settings.start_time; + while time<settings.end_time + if time+sceneSchedule(settings.schedPos).duration > settings.end_time + break; + end + [sceneSchedule] = getSceneSchedule(sceneSchedule,sceneObjects,settings,time); + time = time+sceneSchedule(settings.schedPos).duration; + settings.schedPos = settings.schedPos+1; + end + + elseif (settings.mean_time_between_instances < 0) % Just once: abstract and generate + [sceneSchedule] = getSceneSchedule(sceneSchedule,sceneObjects,settings,settings.start_time); + settings.schedPos = settings.schedPos+1; + + else % General case: abstract and generate + t = settings.start_time; + time = t; + while t<settings.end_time + if (time<0) + time=0; + end + if time > settings.end_time + break; + end + [sceneSchedule] = getSceneSchedule(sceneSchedule,sceneObjects,settings,time); + t = t+settings.mean_time_between_instances; + time=t+settings.time_between_instances_std*randn; + settings.schedPos = settings.schedPos+1; + end + end + + case 'replicate' + + for jj=1:length(settings.start_times) + if settings.start_times(jj) <= settings.end_time && settings.start_times(jj) >= settings.start_time + [sceneSchedule] = getSceneSchedule(sceneSchedule,sceneObjects,settings,settings.start_times(jj),jj); + settings.schedPos = settings.schedPos+1; + end + end + end +end +end \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getEventsLocation.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,33 @@ +function [ eventsLocation ] = getEventsLocation(signalLength,sr,onset,offset) + +% 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/>. + +%% events location: LOGICAL +% 1 : Events +% 0 : BG + +%% Init events Location +eventsLocation=zeros(1,signalLength); + +for ii=1:length(onset) + eventsLocation(round(onset(ii)*sr+1):round(offset(ii)*sr))=1; +end + +%% Logical conversion +eventsLocation=logical(eventsLocation); +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getSampleInfo.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,39 @@ +function [o] = getSampleInfo(label,query,sampleType,inputData,trackLength) + +% 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/>. + +o.isBackground = strcmp(sampleType,'background'); +o.classLabel = label; +o.startTimes = []; +o.endTimes = []; +o.query= query; +o.trackLength=trackLength; +path = [inputData sampleType '/']; + +if ~exist(path, 'dir') + error(['Could not find local dir ',path,'\n']); +end + +samples = dir([path '*wav']); +samplesInd = find(cellfun('isempty',regexpi({samples.name},query,'match'))==0); + +for ii=1:length(samplesInd) + [sampleSize,sr]=wavread([path,'/',samples(samplesInd(ii)).name],'size'); + o.startTimes(end+1) = 0; + o.endTimes(end+1) = sampleSize(1)/sr; +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getSceneSchedule.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,67 @@ +function [sceneSchedule] = getSceneSchedule(sceneSchedule,sceneObjects,settings,time,indReplicate) + +% 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/>. + +if strcmp(settings.ebrMode,'replicate') + sceneSchedule(settings.schedPos).ebr=settings.ebrs(indReplicate); +else + sceneSchedule(settings.schedPos).ebr= settings.ebr_mean+randn*settings.ebr_std; +end + +if settings.randomFlag % Random choice of sample + inst = randi(length(sceneObjects(settings.classId).startTimes)); +else % Choose the sample closest in duration to the annotation. + [~,inst] = min(abs(sceneObjects(settings.classId).endTimes-sceneObjects(settings.classId).startTimes-(settings.end_times(indReplicate)-settings.start_times(indReplicate)))); +end + +switch settings.timeMode + case 'generate' + dur = sceneObjects(settings.classId).endTimes(inst)-sceneObjects(settings.classId).startTimes(inst); + case 'abstract' + dur = sceneObjects(settings.classId).endTimes(inst)-sceneObjects(settings.classId).startTimes(inst); + if(dur-settings.template_duration_mean-settings.template_duration_std>5 ) + dur= settings.template_duration_mean+randn*settings.template_duration_std; + disp('Sample Duration - meanDuration - stdDuration > 5: cut sample') + end + case 'replicate' + dur = settings.end_times(indReplicate)-settings.start_times(indReplicate); +end + + +sceneSchedule(settings.schedPos).classId=settings.classId; +sceneSchedule(settings.schedPos).classLabel=settings.label; +sceneSchedule(settings.schedPos).isBackground = 0; +sceneSchedule(settings.schedPos).instance = inst; +sceneSchedule(settings.schedPos).position = time; +sceneSchedule(settings.schedPos).duration=dur; + +%% Fade I/O + +if (time < settings.start_time+settings.fade_in_time && settings.fade_in_time>0) + sceneSchedule(settings.schedPos).ebr = -20 + ((time-settings.start_time)/settings.fade_in_time) * (sceneSchedule(settings.schedPos).ebr+20); +end +if (time > settings.end_time-settings.fade_out_time && settings.fade_out_time>0) + sceneSchedule(settings.schedPos).ebr = -20 + ((settings.end_time-time)/settings.fade_out_time) * (sceneSchedule(settings.schedPos).ebr+20); +end + +%% check ebr +if (~isfinite(sceneSchedule(settings.schedPos).ebr)) + error('Error while computing ebr; ebr = +/-inf') +end + +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/getTemplate.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,54 @@ +function [template] = getTemplate(instanceAnnotFile,instanceAudioFile) + +% 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/>. + +%% get audioFile +[signal,sr] = wavread(instanceAudioFile); +if(size(signal,2)==2) + signal=mean(signal,2); +end +signal=0.99*signal/(max(abs(signal))); +template.sceneDuration=length(signal)/sr; + +%% get onset/offset times and background Location +[onset,offset,classNames]=loadEventsList(instanceAnnotFile); +bgLocation=(~getEventsLocation(length(signal),sr,onset,offset)); + +%% Get Template +[uniqueClassNames,~,ib]=unique(classNames); +template.class=cell(1,length(uniqueClassNames)); + +for ii=1:length(uniqueClassNames) + template.class{ii}=cell(1,13); + + onsetTmp=onset(ib==ii); + offsetTmp=offset(ib==ii); + + if(length(onsetTmp)>1) + meanSpacingTime = mean(onsetTmp(2:end)-onsetTmp(1:end-1)); + stdSpacingTime = std(onsetTmp(2:end)-onsetTmp(1:end-1)); + else + meanSpacingTime = -1; + stdSpacingTime = 0; + end + + [ebr]=getEbrs(bgLocation,signal,sr,onsetTmp,offsetTmp); + + template.class{ii}={uniqueClassNames{ii},uniqueClassNames{ii},mean(ebr),std(ebr),meanSpacingTime,stdSpacingTime,... + onsetTmp(1),offsetTmp(end),0,0,onsetTmp,offsetTmp,ebr}; +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/loadEventsList.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,43 @@ +function [onset,offset,classNames] = loadEventsList(filename) + +% 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/>. + +% Open raw file +fid = fopen(filename,'r+'); + +% Read 1st line +tline = fgetl(fid); +onset_offset(:,1) = sscanf(tline, '%f\t%f\t%*s'); +classNames{1} = char(sscanf(tline, '%*f\t%*f\t%s')'); + +% Read rest of the lines +i=1; +while ischar(tline) + i = i+1; + tline = fgetl(fid); + if (ischar(tline)) + onset_offset(:,i) = sscanf(tline, '%f\t%f\t%*s'); + classNames{i} = char(sscanf(tline, '%*f\t%*f\t%s')'); + end; +end + +% Split onset_offset +onset = onset_offset(1,:)'; +offset = onset_offset(2,:)'; + +% Close file +fclose(fid); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/manageOverlapping.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,42 @@ +function [ sceneSchedule ] = manageOverlapping( sceneSchedule,minSpace ) + +% 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/>. + +% get sceneSchedule index in order to have position in ascending order + +positions= [sceneSchedule.position]; +isBackground= [sceneSchedule.isBackground]; +[~,index]=sort(positions(logical(~isBackground))); +index=index+length(isBackground(isBackground==1)); +idFlag=zeros(length(unique([sceneSchedule.classId])),1); + +endPos=0; +index2remove=[]; +for jj = index + if(sceneSchedule(jj).position > endPos) + endPos= sceneSchedule(jj).position+sceneSchedule(jj).duration; + idFlag(sceneSchedule(jj).classId)=1; + elseif(2*sceneSchedule(jj).duration>endPos-(sceneSchedule(jj).position+sceneSchedule(jj).duration) || idFlag(sceneSchedule(jj).classId)==0) + sceneSchedule(jj).position=endPos+minSpace; + endPos= sceneSchedule(jj).position+sceneSchedule(jj).duration; + idFlag(sceneSchedule(jj).classId)=1; + else + index2remove=[index2remove jj]; + end +end + +sceneSchedule(index2remove)=[]; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/maxWindowEBR.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,31 @@ +function s = maxWindowEBR(fg, bg, offset, fgScale) +% Computes the maximum EBR on 1/4s windows of a FG relative to a BG when +% that FG is at a given position in time. +% Optional argument fgScale allows to compute what the EBR would be if FG +% was scaled by that much. + +% 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/>. + +if (nargin==3) fgScale=1; end +len=10000; +for k=1:floor(2*length(fg)/len) + t1 = (len/2)*(k-1)+1; + t2 = min(t1+len-1, length(fg)); + if (t2-t1>10) snrs(k) = snr(fg(t1:t2), bg, offset+t1, fgScale); end +end +s = max(snrs); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/saveAnnotationTxt.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,34 @@ +function [] = saveAnnotationTxt(sceneSchedule,outputPath,outputFileName) + +% 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/>. + +sceneSchedule=sceneSchedule([sceneSchedule.isBackground]==0); + +onsets=[sceneSchedule.position]; +offsets=[sceneSchedule.position]+[sceneSchedule.duration]; +classes={sceneSchedule.classLabel}; + +[~,ind]=sort(onsets); + +fid = fopen([outputPath 'annotation/' outputFileName '.txt'],'w+'); +for jj=ind + fprintf(fid,'%.2f\t%.2f\t%s\n',onsets(jj),offsets(jj),classes{jj}); +end +fclose(fid); + +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/timeDomainVisualization.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,60 @@ +function status = timeDomainVisualization (tracks, cmap, figNum, maxWidth, lineThickness, fileName) + +% 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/>. + +nbTracks = size(tracks,1); +trackLength = length(tracks(1,:)); + +% Producing a time domain visualization +wSize = 8192; +wStep = 512; +for t=1:nbTracks + for i=0:ceil((trackLength-wSize)/wStep) + % Not really power, but more nicely additive, better suited for + % this representation I think + powers(i+1,t) = norm(tracks(t,i*wStep+1:min(trackLength, i*wStep+wSize))); + end +end + +powers(powers<max(powers(:))/500) = 0; + + +% Screen res is ~90dpi, print res is 150dpi, hence the " /1.6 " +imgWidth = min(maxWidth, 2*size(powers,1)) / 1.6; + +% Displayed version +f=figure(figNum); +clf; +h=area(powers,'LineWidth', lineThickness/1.6, 'EdgeColor', [.3, .3, .3]); +set(gca,'YTick', []); +set(f, 'Position', [0, 0, imgWidth, 400],'Visible', 'off'); +colormap(cmap); + +% Version saved to graphic file +f = figure(1000); +clf; +h = area(powers,'LineWidth', lineThickness/1.6, 'EdgeColor', [.3, .3, .3]); +set(gca,'YTick', []); +colormap(cmap); +set(f, 'Visible', 'off'); +set(f, 'Position', [0, 0, imgWidth, 400]); +set(f, 'PaperPositionMode', 'auto'); +print ('-dpng', '-r150', fileName); + +status = 1; + +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/utils/hsl2rgb.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,59 @@ +function rgb=hsl2rgb(hsl) + +%Converts Hue-Saturation-Luminance Color value to Red-Green-Blue Color value +% +%Usage +% RGB = hsl2rgb(HSL) +% +% converts HSL, a M X 3 color matrix with values between 0 and 1 +% into RGB, a M X 3 color matrix with values between 0 and 1 +% +%See also rgb2hsl, rgb2hsv, hsv2rgb + +%Suresh E Joel, April 26,2003 + +if nargin<1, + error('Too few arguements for hsl2rgb'); + return; +elseif nargin>1, + error('Too many arguements for hsl2rgb'); + return; +end; + +if max(max(hsl))>1 | min(min(hsl))<0, + error('HSL values have to be between 0 and 1'); + return; +end; + +for i=1:size(hsl,1), + if hsl(i,2)==0,%when sat is 0 + rgb(i,1:3)=hsl(i,3);% all values are same as luminance + end; + if hsl(i,3)<0.5, + temp2=hsl(i,3)*(1+hsl(i,2)); + else + temp2=hsl(i,3)+hsl(i,2)-hsl(i,3)*hsl(i,2); + end; + temp1=2*hsl(i,3)-temp2; + temp3(1)=hsl(i,1)+1/3; + temp3(2)=hsl(i,1); + temp3(3)=hsl(i,1)-1/3; + for j=1:3, + if temp3(j)>1, + temp3(j)=temp3(j)-1; + elseif temp3(j)<0, + temp3(j)=temp3(j)+1; + end; + if 6*temp3(j)<1, + rgb(i,j)=temp1+(temp2-temp1)*6*temp3(j); + elseif 2*temp3(j)<1, + rgb(i,j)=temp2; + elseif 3*temp3(j)<2, + rgb(i,j)=temp1+(temp2-temp1)*(2/3-temp3(j))*6; + else + rgb(i,j)=temp1; + end; + end; +end; + +rgb=round(rgb.*100000)./100000; %Sometimes the result is 1+eps instead of 1 or 0-eps instead of 0 ... so to get rid of this I am rounding to 5 decimal places) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/utils/powspec.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,65 @@ +function [y,e] = powspec(x, sr, wintime, steptime, dither) +%[y,e] = powspec(x, sr, wintime, steptime, sumlin, dither) +% +% compute the powerspectrum and frame energy of the input signal. +% basically outputs a power spectrogram +% +% each column represents a power spectrum for a given frame +% each row represents a frequency +% +% default values: +% sr = 8000Hz +% wintime = 25ms (200 samps) +% steptime = 10ms (80 samps) +% which means use 256 point fft +% hamming window +% +% $Header: /Users/dpwe/matlab/rastamat/RCS/powspec.m,v 1.3 2012/09/03 14:02:01 dpwe Exp dpwe $ + +% for sr = 8000 +%NFFT = 256; +%NOVERLAP = 120; +%SAMPRATE = 8000; +%WINDOW = hamming(200); + +if nargin < 2 + sr = 8000; +end +if nargin < 3 + wintime = 0.025; +end +if nargin < 4 + steptime = 0.010; +end +if nargin < 5 + dither = 1; +end + +winpts = round(wintime*sr); +steppts = round(steptime*sr); + +NFFT = 2^(ceil(log(winpts)/log(2))); +%WINDOW = hamming(winpts); +%WINDOW = [0,hanning(winpts)']; +WINDOW = [hanning(winpts)']; +% hanning gives much less noisy sidelobes +NOVERLAP = winpts - steppts; +SAMPRATE = sr; + +% Values coming out of rasta treat samples as integers, +% not range -1..1, hence scale up here to match (approx) +y = abs(specgram(x*32768,NFFT,SAMPRATE,WINDOW,NOVERLAP)).^2; + +% imagine we had random dither that had a variance of 1 sample +% step and a white spectrum. That's like (in expectation, anyway) +% adding a constant value to every bin (to avoid digital zero) +if (dither) + y = y + winpts; +end +% ignoring the hamming window, total power would be = #pts +% I think this doesn't quite make sense, but it's what rasta/powspec.c does + +% that's all she wrote + +% 2012-09-03 Calculate log energy - after windowing, by parseval +e = log(sum(y));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/utils/process_options.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,146 @@ +% PROCESS_OPTIONS - Processes options passed to a Matlab function. +% This function provides a simple means of +% parsing attribute-value options. Each option is +% named by a unique string and is given a default +% value. +% +% Usage: [var1, var2, ..., varn[, unused]] = ... +% process_options(args, ... +% str1, def1, str2, def2, ..., strn, defn) +% +% Arguments: +% args - a cell array of input arguments, such +% as that provided by VARARGIN. Its contents +% should alternate between strings and +% values. +% str1, ..., strn - Strings that are associated with a +% particular variable +% def1, ..., defn - Default values returned if no option +% is supplied +% NOTE: this version (modified by dpwe) will run str2num on +% string arguments if the default value is numeric +% (to support passing in numbers from the command line). +% +% Returns: +% var1, ..., varn - values to be assigned to variables +% unused - an optional cell array of those +% string-value pairs that were unused; +% if this is not supplied, then a +% warning will be issued for each +% option in args that lacked a match. +% +% Examples: +% +% Suppose we wish to define a Matlab function 'func' that has +% required parameters x and y, and optional arguments 'u' and 'v'. +% With the definition +% +% function y = func(x, y, varargin) +% +% [u, v] = process_options(varargin, 'u', 0, 'v', 1); +% +% calling func(0, 1, 'v', 2) will assign 0 to x, 1 to y, 0 to u, and 2 +% to v. The parameter names are insensitive to case; calling +% func(0, 1, 'V', 2) has the same effect. The function call +% +% func(0, 1, 'u', 5, 'z', 2); +% +% will result in u having the value 5 and v having value 1, but +% will issue a warning that the 'z' option has not been used. On +% the other hand, if func is defined as +% +% function y = func(x, y, varargin) +% +% [u, v, unused_args] = process_options(varargin, 'u', 0, 'v', 1); +% +% then the call func(0, 1, 'u', 5, 'z', 2) will yield no warning, +% and unused_args will have the value {'z', 2}. This behaviour is +% useful for functions with options that invoke other functions +% with options; all options can be passed to the outer function and +% its unprocessed arguments can be passed to the inner function. + +% Copyright (C) 2002 Mark A. Paskin +% +% 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 2 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, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +% USA. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [varargout] = process_options(args, varargin) + +% Check the number of input arguments +n = length(varargin); +if (mod(n, 2)) + error('Each option must be a string/value pair.'); +end + +% Check the number of supplied output arguments +if (nargout < (n / 2)) + error('Insufficient number of output arguments given'); +elseif (nargout == (n / 2)) + warn = 1; + nout = n / 2; +else + warn = 0; + nout = n / 2 + 1; +end + +% Set outputs to be defaults +varargout = cell(1, nout); +for i=2:2:n + varargout{i/2} = varargin{i}; +end + +% Now process all arguments +nunused = 0; +for i=1:2:length(args) + found = 0; + for j=1:2:n + if strcmpi(args{i}, varargin{j}) + % dpwe: promote string args to numeric if default arg is + % numeric + if isnumeric(varargin{j+1}) && ischar(args{i+1}) + varargout{(j + 1)/2} = str2num(args{i + 1}); + % this occurs when specifying arguments from command line + else + % in all other cases, take what you get + varargout{(j + 1)/2} = args{i + 1}; + end + found = 1; + break; + end + end + if (~found) + if (warn) + warning(sprintf('Option ''%s'' not used.', args{i})); + args{i} + else + nunused = nunused + 1; + unused{2 * nunused - 1} = args{i}; + if length(args) > i + % don't demand a value for the last, unused tag (e.g. -help) + unused{2 * nunused} = args{i + 1}; + end + end + end +end + +% Assign the unused arguments +if (~warn) + if (nunused) + varargout{nout} = unused; + else + varargout{nout} = cell(0); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nonExposed/utils/rgb2hsl.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,54 @@ +function hsl=rgb2hsl(rgb) + +%Converts Red-Green-Blue Color value to Hue-Saturation-Luminance Color value +% +%Usage +% HSL = rgb2hsl(RGB) +% +% converts RGB, a M X 3 color matrix with values between 0 and 1 +% into HSL, a M X 3 color matrix with values between 0 and 1 +% +%See also hsl2rgb, rgb2hsv, hsv2rgb + +%Suresh E Joel, April 26,2003 + +if nargin<1, + error('Too few arguements for rgb2hsl'); + return; +elseif nargin>1, + error('Too many arguements for rgb2hsl'); + return; +end; + +if max(max(rgb))>1 | min(min(rgb))<0, + error('RGB values have to be between 0 and 1'); + return; +end; + +for i=1:size(rgb,1), + mx=max(rgb(i,:));%max of the 3 colors + mn=min(rgb(i,:));%min of the 3 colors + imx=find(rgb(i,:)==mx);%which color has the max + hsl(i,3)=(mx+mn)/2;%luminance is half of max value + min value + if(mx-mn)==0,%if all three colors have same value, + hsl(i,2)=0;%then s=0 and + hsl(i,1)=0;%h is undefined but for practical reasons 0 + return; + end; + if hsl(i,3)<0.5, + hsl(i,2)=(mx-mn)/(mx+mn); + else + hsl(i,2)=(mx-mn)/(2-(mx+mn)); + end; + switch(imx(1))%if two colors have same value and be the maximum, use the first color + case 1 %Red is the max color + hsl(i,1)=((rgb(i,2)-rgb(i,3))/(mx-mn))/6; + case 2 %Green is the max color + hsl(i,1)=(2+(rgb(i,3)-rgb(i,1))/(mx-mn))/6; + case 3 %Blue is the max color + hsl(i,1)=(4+(rgb(i,1)-rgb(i,2))/(mx-mn))/6; + end; + if hsl(i,1)<0,hsl(i,1)=hsl(i,1)+1;end;%if hue is negative, add 1 to get it within 0 and 1 +end; + +hsl=round(hsl*100000)/100000; %Sometimes the result is 1+eps instead of 1 or 0-eps instead of 0 ... so to get rid of this I am rounding to 5 decimal places) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scene2Replicate/forest.txt Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,13 @@ +1.00 2.66 alouette +2.95 4.62 alouette +3.00 6.22 bulbul +5.00 8.22 bulbul +5.00 5.56 geai +5.00 6.24 alouette +6.08 7.10 geai +6.74 7.75 geai +7.00 10.22 bulbul +7.06 8.72 alouette +7.84 8.53 geai +9.00 11.75 bulbul +9.11 9.67 geai
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simScene.m Tue Mar 17 09:34:13 2015 +0100 @@ -0,0 +1,208 @@ +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']); + +end