├── .gitignore ├── COPYRIGHT.txt ├── LICENSE.txt ├── MATLAB ├── ComputeMapping.m ├── ComputeScore.m ├── TSAM.m ├── distmeshnd_sfa.m ├── elmMOD.m ├── elmMODmap.m ├── oscsend.m ├── period_detection.m ├── relative_mean_difference.m └── unique_sfast.m ├── Max ├── TSAM.maxpat └── TSAM_3DOGL.maxpat └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | The Timbre Space Analyzer & Mapper (TSAM) is a collection of MAX patches 2 | and MATLAB functions for the analysis, modeling and malling of the 3 | timbre if siund synthesizers. 4 | 5 | The TSAM can be obtained at http://stefanofasciani.com/tsam.html 6 | TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 7 | Inquiries: stefanofasciani@stefanofasciani.com 8 | 9 | The TSAM is free software: you can redistribute it and/or modify it under the 10 | terms of the GNU Lesser General Public License as published by the Free Software 11 | Foundation, either version 3 of the License, or (at your option) any later version. 12 | 13 | The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 14 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | See the GNU Less General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public License along with TSAM. 18 | If not, see . 19 | 20 | If you use the TSAM or any part of it in any program or publication, please acknowledge 21 | its authors by adding a reference to this pubblication: 22 | 23 | S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 24 | synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /MATLAB/ComputeMapping.m: -------------------------------------------------------------------------------- 1 | % This file is part of the Timbre Space Analyzer & Mapper (TSAM) 2 | % 3 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 4 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 5 | % Inquiries: stefanofasciani@stefanofasciani.com 6 | % 7 | % The TSAM is free software: you can redistribute it and/or modify it under the terms 8 | % of the GNU Lesser General Public License as published by the Free Software Foundation, 9 | % either version 3 of the License, or (at your option) any later version. 10 | % 11 | % The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 12 | % without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | % See the GNU Less General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU Lesser General Public License along with TSAM. 16 | % If not, see . 17 | % 18 | % If you use the TSAM or any part of it in any program or publication, please acknowledge 19 | % its authors by adding a reference to this pubblication: 20 | % 21 | % S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 22 | % synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. 23 | 24 | 25 | 26 | function [ret]=ComputeMapping(MAXoscclient,MATLABoscserver,args) 27 | 28 | 29 | fignum=1; 30 | 31 | old=0; 32 | 33 | outfile=sprintf('%s%sMap.mat',args{8},args{7}); 34 | featfile=sprintf('%s%sFeat.txt',args{8},args{7}); 35 | paramfile=sprintf('%s%sParams.txt',args{8},args{7}); 36 | if exist(outfile, 'file') 37 | delete(outfile); 38 | end 39 | 40 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',1); 41 | 42 | D=load(featfile); 43 | I=load(paramfile); 44 | 45 | if old 46 | I=I'; 47 | end 48 | 49 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',15); 50 | 51 | num_params=std(I); 52 | num_params=size((num_params(num_params~=0)),2); 53 | 54 | num_combs=size(I,1); 55 | 56 | analysis_mode=args{1}; 57 | range_enabled=args{2}; 58 | period_enabled=args{3}(1); 59 | winsize=args{3}(2); 60 | hopsize=args{3}(3); 61 | dimensionality=args{4}; 62 | mergegap=args{5}; 63 | vectperstate=args{6}; 64 | mask=args{10}; 65 | actfuncid=args{11}; 66 | actfunclist={'sig','sin','hardlim','tribas','radbas'}; 67 | actfuncname=actfunclist{actfuncid}; 68 | dimredfunct=args{12}; 69 | sr=args{14}; 70 | 71 | switch args{13} 72 | case 0 73 | featselect=args{9}; 74 | featselect=featselect(featselect~=0); 75 | case 1 76 | featselect=1:108; 77 | case 2 78 | featselect=1:35; 79 | case 3 80 | featselect=3:18; 81 | case 4 82 | featselect=19:31; 83 | case 5 84 | featselect=[19:31 85:108]; 85 | case 6 86 | featselect=36:47; 87 | case 7 88 | featselect=48:60; 89 | case 8 90 | featselect=61:84; 91 | case 9 92 | featselect=85:108; 93 | case 10 94 | featselect=args{15}+1; 95 | otherwise 96 | featselect=1:108; 97 | end 98 | 99 | %apply mask 100 | D=D.*repmat(mask,size(D,1),1); 101 | 102 | D=D(:,featselect); 103 | 104 | if ((analysis_mode==0)||(analysis_mode==2)) 105 | 106 | cnt=1; 107 | average=[]; 108 | range=[]; 109 | period=[]; 110 | D_post=[]; 111 | if (analysis_mode==2) 112 | I=I(1:vectperstate:(size(D,1)),:); 113 | end 114 | %COMPUTING MEAN RANGE AND PERIOD FOR EACH SUB MATRIX PER STATE 115 | if vectperstate > 2 116 | for i=1:vectperstate:(size(D,1)) 117 | temp=D(i:i+vectperstate-1,:); 118 | average=[average ; mean(temp)]; 119 | if range_enabled 120 | range=[range ; (max(temp)-min(temp))]; 121 | end 122 | if period_enabled 123 | period=[period ; period_detection(winsize,hopsize,temp,sr)]; 124 | end 125 | cnt=cnt+1; 126 | end 127 | 128 | 129 | period_post=[]; 130 | if period_enabled 131 | %removing zeros in period 132 | if numel(period(period==0)) > (numel(period)/2) 133 | for i=1:num_combs 134 | temp=period(i,:); 135 | period_post(i,1)=median(temp(temp~=0)); 136 | end 137 | else 138 | for i=1:num_combs 139 | temp=period(i,:); 140 | temp(temp==0)=median(temp(temp~=0)); 141 | period_post(i,:)=temp; 142 | end 143 | end 144 | %fprintf('feat period detected min = %f max = %f\n',min(min(period_post)),max(max(period_post))); 145 | end 146 | if (period_enabled==1 || range_enabled==1) 147 | average=average./max(max(abs(average))); 148 | range=range./max(max(abs(range))); 149 | period_post=period_post./max(max(abs(period_post))); 150 | end 151 | D_post=[average range period_post]; 152 | 153 | else 154 | 155 | D_post=D; 156 | 157 | end 158 | 159 | D_post(:,all(isnan(D_post),1))=[]; 160 | D_post(isnan(D_post))=0; 161 | D_post(:,find(sum(abs(D_post))==0))=[]; 162 | 163 | 164 | elseif ((analysis_mode==1)||(analysis_mode==3)) 165 | 166 | cnt=1; 167 | D_post=[]; 168 | if (analysis_mode==3) 169 | I=I(1:vectperstate:(size(D,1)),:); 170 | end 171 | %PUTTING TEMPORAL ENVELOPE OF FEATURES IN A SINGLE VECTOR 172 | for i=1:vectperstate:(size(D,1)) 173 | temp=[]; 174 | for j=1:vectperstate 175 | temp=[temp D(i+j-1,:)]; 176 | end 177 | D_post(cnt,:)=temp; 178 | cnt=cnt+1; 179 | end 180 | D_post(:,find(sum(abs(D_post))==0))=[]; 181 | 182 | elseif (analysis_mode==4) 183 | 184 | average=[]; 185 | range=[]; 186 | D_post=[]; 187 | 188 | for j=1:numel(mergegap) 189 | ranges=0:mergegap(j):(1+mergegap(j)); 190 | for i=1:(numel(ranges)-1) 191 | I(find((I(:,j)<=ranges(i+1))&(I(:,j)>ranges(i))),j)=(ranges(i+1)+ranges(i))/2; 192 | end 193 | end 194 | 195 | Iuniq=unique(I,'rows'); 196 | 197 | for i=1:size(Iuniq,1) 198 | idx=find(ismember(I,Iuniq(i,:),'rows')); 199 | temp=D(idx,:); 200 | if size(temp,1)>1 201 | average=[average ; mean(temp)]; 202 | if range_enabled 203 | range=[range ; (max(temp)-min(temp))]; 204 | end 205 | else 206 | average=[average ; temp]; 207 | if range_enabled 208 | fprintf('Warning: range on single descriptors vector\n'); 209 | range=[range ; temp-temp]; 210 | end 211 | end 212 | end 213 | 214 | if (range_enabled==1) 215 | average=average./max(max(abs(average))); 216 | range=range./max(max(abs(range))); 217 | end 218 | 219 | D_post=[average range]; 220 | D_post(:,all(isnan(D_post),1))=[]; 221 | D_post(isnan(D_post))=0; 222 | D_post(:,find(sum(abs(D_post))==0))=[]; 223 | 224 | I=Iuniq; 225 | 226 | end 227 | 228 | num_combs=size(I,1); 229 | 230 | if num_combs<8 231 | fprintf('number of parameter combination is lower than 8'); 232 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',-1); 233 | return 234 | end 235 | 236 | num_feat=size(D_post,2); 237 | 238 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',25); 239 | 240 | %COMPUTING AND REMOVING THE MEAN FROM EACH FEATURE 241 | mean_vect=mean(D_post); 242 | 243 | for i=1:num_combs 244 | D_post(i,:)=D_post(i,:)-mean_vect; 245 | end 246 | 247 | D_post=D_post./(max(max(D_post))); 248 | 249 | if dimensionality0.01)) 311 | net=elmMOD(distmeshout',D_star',hiddenneurons,actfuncname); 312 | net.accuracy=net.accuracy/sqrt(size(D_star,1)); 313 | hiddenneurons=hiddenneurons+10; 314 | accuracy=net.accuracy; 315 | end 316 | 317 | 318 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',90); 319 | 320 | 321 | %MAX AND MIN FOR DIRECT D STAR NAVIGATION 322 | for i=1:size(D_star,2) 323 | D_star_minmax(1,i)=min(D_star(:,i)); 324 | D_star_minmax(2,i)=max(D_star(:,i)); 325 | end 326 | 327 | for i=1:size(D_star_minmax,2) 328 | D_star_map_min(i)=D_star_minmax(1,i); 329 | D_star_map_range(i)=D_star_minmax(2,i)-D_star_minmax(1,i); 330 | end 331 | 332 | D_star_min_range=[D_star_map_min;D_star_map_range]; 333 | 334 | 335 | outfile=sprintf('%s%sMap-DS.txt',args{8},args{7}); 336 | save(outfile,'D_star','-ASCII','-double'); 337 | 338 | outfile=sprintf('%s%sMap-DU.txt',args{8},args{7}); 339 | save(outfile,'distmeshout','-ASCII','-double'); 340 | 341 | outfile=sprintf('%s%sMap-I.txt',args{8},args{7}); 342 | save(outfile,'I','-ASCII','-double'); 343 | 344 | outfile=sprintf('%s%sMap-Dmnrg.txt',args{8},args{7}); 345 | save(outfile,'D_star_min_range','-ASCII','-double'); 346 | 347 | %minIdist maxIdist accuracy 348 | info=[max(pdist((I))) min(pdist((I)))+0.1*min(pdist((I))) net.accuracy]; 349 | outfile=sprintf('%s%sMap-Info.txt',args{8},args{7}); 350 | save(outfile,'info','-ASCII','-double'); 351 | 352 | temp=net.inweight; 353 | outfile=sprintf('%s%sMap-Iw.txt',args{8},args{7}); 354 | save(outfile,'temp','-ASCII','-double'); 355 | 356 | temp=net.outweight; 357 | outfile=sprintf('%s%sMap-Ow.txt',args{8},args{7}); 358 | save(outfile,'temp','-ASCII','-double'); 359 | 360 | temp=net.bias; 361 | outfile=sprintf('%s%sMap-Bs.txt',args{8},args{7}); 362 | save(outfile,'temp','-ASCII','-double'); 363 | 364 | temp=find((strcmp(net.actfunct,actfunclist))==1); 365 | outfile=sprintf('%s%sMap-Act.txt',args{8},args{7}); 366 | save(outfile,'temp','-ASCII','-double'); 367 | 368 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',100); 369 | 370 | return 371 | 372 | 373 | 374 | 375 | %EXTRA FUNCTIONS 376 | 377 | function h=huniform_sfa(p,varargin) 378 | 379 | % Copyright (C) 2004-2012 Per-Olof Persson. See COPYRIGHT.TXT for details. 380 | 381 | % The original file was modified for the integration with the 382 | % Timbre Space Mapping for VST Synthesizers (TSM4VSTS). 383 | 384 | h=ones(size(p,1),1); 385 | 386 | function d=drectangle2D_sfa(p,x1,x2,y1,y2) 387 | 388 | % Copyright (C) 2004-2012 Per-Olof Persson. See COPYRIGHT.TXT for details. 389 | 390 | % The original file was modified for the integration with the 391 | % Timbre Space Mapping for VST Synthesizers (TSM4VSTS). 392 | 393 | d=-min(min(min(-y1+p(:,2),y2-p(:,2)),-x1+p(:,1)),x2-p(:,1)); 394 | 395 | function d=drectangle3D_sfa(p,x1,x2,y1,y2,z1,z2) 396 | 397 | % Copyright (C) 2004-2012 Per-Olof Persson. See COPYRIGHT.TXT for details. 398 | 399 | % The original file was modified for the integration with the 400 | % Timbre Space Mapping for VST Synthesizers (TSM4VSTS). 401 | 402 | d=-min(min(min(min(min(-z1+p(:,3),z2-p(:,3)),-y1+p(:,2)),y2-p(:,2)),-x1+p(:,1)),x2-p(:,1)); 403 | -------------------------------------------------------------------------------- /MATLAB/ComputeScore.m: -------------------------------------------------------------------------------- 1 | % This file is part of the Timbre Space Analyzer & Mapper (TSAM) 2 | % 3 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 4 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 5 | % Inquiries: stefanofasciani@stefanofasciani.com 6 | % 7 | % The TSAM is free software: you can redistribute it and/or modify it under the terms 8 | % of the GNU Lesser General Public License as published by the Free Software Foundation, 9 | % either version 3 of the License, or (at your option) any later version. 10 | % 11 | % The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 12 | % without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | % See the GNU Less General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU Lesser General Public License along with TSAM. 16 | % If not, see . 17 | % 18 | % If you use the TSAM or any part of it in any program or publication, please acknowledge 19 | % its authors by adding a reference to this pubblication: 20 | % 21 | % S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 22 | % synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. 23 | 24 | 25 | 26 | function [ret]=ComputeScore(MAXoscclient,MATLABoscserver,args) 27 | 28 | fignum=1; 29 | 30 | old=0; 31 | 32 | featfile=sprintf('%s%sFeat.txt',args{8},args{7}); 33 | paramfile=sprintf('%s%sParams.txt',args{8},args{7}); 34 | 35 | 36 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',1); 37 | 38 | D=load(featfile); 39 | I=load(paramfile); 40 | 41 | if old 42 | I=I'; 43 | end 44 | 45 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',15); 46 | 47 | num_params=std(I); 48 | num_params=size((num_params(num_params~=0)),2); 49 | num_desc=size(D,2); 50 | 51 | analysis_mode=args{1}; 52 | range_enabled=1; 53 | winsize=args{3}(2); 54 | hopsize=args{3}(3); 55 | dimensionality=args{4}; 56 | mergegap=args{5}; 57 | vectperstate=args{6}; 58 | mask=args{10}; 59 | sr=args{14}; 60 | 61 | %apply mask 62 | D=D.*repmat(mask,size(D,1),1); 63 | 64 | param_score=zeros(1,10); 65 | corrmat=zeros(10,108*2); 66 | 67 | if ((analysis_mode==0)||(analysis_mode==2)) 68 | 69 | noisiness_sustain=zeros(num_desc,1); 70 | variance_sustain=zeros(num_desc,1); 71 | independence_sustain=zeros(num_desc,1); 72 | paramcorrelation_sustain=zeros(num_desc,1); 73 | 74 | variance_sustain_range=zeros(num_desc,1); 75 | independence_sustain_range=zeros(num_desc,1); 76 | paramcorrelation_sustain_range=zeros(num_desc,1); 77 | 78 | num_combs=size(I,1); 79 | 80 | cnt=1; 81 | average=[]; 82 | range=[]; 83 | D_post=[]; 84 | if (analysis_mode==2) 85 | I=I(1:vectperstate:(size(D,1)),:); 86 | end 87 | 88 | %COMPUTING MEAN AND RANGE FOR EACH SUB MATRIX PER STATE 89 | if vectperstate > 2 90 | for i=1:vectperstate:(size(D,1)) 91 | temp=D(i:i+vectperstate-1,:); 92 | noisiness_sustain=noisiness_sustain+relative_mean_difference(temp'); 93 | average=[average ; mean(temp)]; 94 | if range_enabled 95 | range=[range ; (max(temp)-min(temp))]; 96 | end 97 | end 98 | 99 | noisiness_sustain=noisiness_sustain./num_combs; 100 | 101 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',65); 102 | 103 | D_post=[average range]; 104 | D_post(:,all(isnan(D_post),1))=[]; 105 | D_post(isnan(D_post))=0; 106 | variance_sustain=(relative_mean_difference((D_post(:,1:num_desc))')); 107 | variance_sustain_range=(relative_mean_difference((D_post(:,1+num_desc:2*num_desc))')); 108 | 109 | else 110 | 111 | D_post=D; 112 | D_post(:,all(isnan(D_post),1))=[]; 113 | D_post(isnan(D_post))=0; 114 | variance_sustain=(relative_mean_difference(D_post')); 115 | 116 | end 117 | 118 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',70); 119 | 120 | %INDEPENDENCE 121 | %on average 122 | temp1=D_post(:,1:num_desc); 123 | independence_sustain=((nansum(abs(corr(temp1,temp1)))-1)/(num_desc-1))'; 124 | independence_sustain=1-independence_sustain; 125 | 126 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',75); 127 | 128 | %on on range 129 | temp1=D_post(:,1+num_desc:2*num_desc); 130 | independence_sustain_range=((nansum(abs(corr(temp1,temp1)))-1)/(num_desc-1))'; 131 | independence_sustain_range=1-independence_sustain_range; 132 | 133 | 134 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',80); 135 | 136 | %CORRELATION WITH PARAM 137 | %on average 138 | temp1=D_post(:,1:num_desc); 139 | for i=1:(size(temp1,2)) 140 | cnt=0; 141 | temp4=0; 142 | temp2=temp1(:,i); 143 | for j=1:size(I,2) 144 | if sum(I(:,j))~=0 145 | temp3=I(:,j); 146 | temp5=nansum(abs(corr(temp2,temp3))); 147 | paramcorrelation_sustain(i)=paramcorrelation_sustain(i)+temp5; 148 | param_score(j)=param_score(j)+temp5; 149 | corrmat(j,i)=temp5; 150 | cnt=cnt+1; 151 | end 152 | end 153 | paramcorrelation_sustain(i)=paramcorrelation_sustain(i)/cnt; 154 | end 155 | 156 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',85); 157 | 158 | %on on range 159 | temp1=D_post(:,1+num_desc:2*num_desc); 160 | for i=1:(size(temp1,2)) 161 | cnt=0; 162 | temp4=0; 163 | temp2=temp1(:,i); 164 | for j=1:size(I,2) 165 | if sum(I(:,j))~=0 166 | temp3=I(:,j); 167 | temp5=nansum(abs(corr(temp2,temp3))); 168 | paramcorrelation_sustain_range(i)=paramcorrelation_sustain_range(i)+temp5; 169 | param_score(j)=param_score(j)+temp5; 170 | corrmat(j,i+108)=temp5; 171 | cnt=cnt+1; 172 | end 173 | end 174 | paramcorrelation_sustain_range(i)=paramcorrelation_sustain_range(i)/cnt; 175 | end 176 | 177 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',95); 178 | 179 | outmat=[noisiness_sustain' ; variance_sustain' ; independence_sustain' ; paramcorrelation_sustain' ; zeros(1,num_desc) ; variance_sustain_range' ; independence_sustain_range' ; paramcorrelation_sustain_range']; 180 | outfile=sprintf('%s%sScoreDsc.txt',args{8},args{7}); 181 | if exist(outfile, 'file') 182 | delete(outfile); 183 | end 184 | save(outfile,'outmat','-ASCII','-double'); 185 | 186 | outmat=param_score./(abs(max(param_score))); 187 | outfile=sprintf('%s%sScorePrm.txt',args{8},args{7}); 188 | if exist(outfile, 'file') 189 | delete(outfile); 190 | end 191 | save(outfile,'outmat','-ASCII','-double'); 192 | 193 | outmat=corrmat; 194 | outfile=sprintf('%s%sCorrMat.txt',args{8},args{7}); 195 | if exist(outfile, 'file') 196 | delete(outfile); 197 | end 198 | save(outfile,'outmat','-ASCII','-double'); 199 | 200 | oscsend(MAXoscclient,'/score','i',1); 201 | 202 | elseif ((analysis_mode==1)||(analysis_mode==3)) 203 | 204 | noisiness_envelope=zeros(num_desc,1); 205 | variance_envelope=zeros(num_desc,1); 206 | independence_envelope=zeros(num_desc,1); 207 | paramcorrelation_envelope=zeros(num_desc,1); 208 | 209 | num_combs=size(I,1); 210 | 211 | cnt=1; 212 | D_post=[]; 213 | range=[]; 214 | if (analysis_mode==3) 215 | I=I(1:vectperstate:(size(D,1)),:); 216 | end 217 | %PUTTING TEMPORAL ENVELOPE OF FEATURES IN A SINGLE VECTOR 218 | 219 | for i=1:vectperstate:(size(D,1)) 220 | temp=D(i:i+vectperstate-1,:); 221 | for j=1:num_desc 222 | noisiness_envelope(j)=noisiness_envelope(j)+sum(abs(diff(diff(temp(:,j))>0)))/(length(diff(temp(:,j)))-1); 223 | variance_envelope(j)=variance_envelope(j)+relative_mean_difference(temp(:,j)'); 224 | end 225 | independence_envelope=independence_envelope+((nansum(abs(corr(temp,temp)))-1)/(num_desc-1))'; 226 | end 227 | 228 | noisiness_envelope=noisiness_envelope./num_combs; 229 | variance_envelope=variance_envelope./num_combs; 230 | independence_envelope=independence_envelope./num_combs; 231 | independence_envelope=1-independence_envelope; 232 | 233 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',80); 234 | 235 | for i=1:vectperstate:(size(D,1)) 236 | temp=[]; 237 | for j=1:vectperstate 238 | temp=[temp D(i+j-1,:)]; 239 | end 240 | D_post(cnt,:)=temp; 241 | cnt=cnt+1; 242 | end 243 | %D_post(:,find(sum(abs(D_post))==0))=[]; 244 | 245 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',85); 246 | 247 | cnt=0; 248 | for j=1:size(I,2) 249 | if sum(I(:,j))~=0 250 | temp1=I(:,j); 251 | for k=1:num_desc 252 | temp2=D_post(:,k:num_desc:num_desc*vectperstate); 253 | temp5=(nansum(abs(corr(temp1,temp2)))/vectperstate); 254 | paramcorrelation_envelope(k)=paramcorrelation_envelope(k)+temp5; 255 | param_score(j)=param_score(j)+temp5; 256 | corrmat(j,k)=temp5; 257 | end 258 | cnt=cnt+1; 259 | end 260 | end 261 | paramcorrelation_envelope=paramcorrelation_envelope/cnt; 262 | 263 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',95); 264 | 265 | outmat=[noisiness_envelope' ; variance_envelope' ; independence_envelope' ; paramcorrelation_envelope' ; zeros(1,num_desc) ; zeros(1,num_desc) ; zeros(1,num_desc) ; zeros(1,num_desc)]; 266 | outfile=sprintf('%s%sScoreDsc.txt',args{8},args{7}); 267 | if exist(outfile, 'file') 268 | delete(outfile); 269 | end 270 | save(outfile,'outmat','-ASCII','-double'); 271 | 272 | outmat=param_score./(abs(max(param_score))); 273 | outfile=sprintf('%s%sScorePrm.txt',args{8},args{7}); 274 | if exist(outfile, 'file') 275 | delete(outfile); 276 | end 277 | save(outfile,'outmat','-ASCII','-double'); 278 | 279 | outmat=corrmat; 280 | outfile=sprintf('%s%sCorrMat.txt',args{8},args{7}); 281 | if exist(outfile, 'file') 282 | delete(outfile); 283 | end 284 | save(outfile,'outmat','-ASCII','-double'); 285 | 286 | oscsend(MAXoscclient,'/score','i',1); 287 | 288 | 289 | elseif (analysis_mode==4) 290 | 291 | noisiness_sustain=zeros(num_desc,1); 292 | variance_sustain=zeros(num_desc,1); 293 | independence_sustain=zeros(num_desc,1); 294 | paramcorrelation_sustain=zeros(num_desc,1); 295 | 296 | variance_sustain_range=zeros(num_desc,1); 297 | independence_sustain_range=zeros(num_desc,1); 298 | paramcorrelation_sustain_range=zeros(num_desc,1); 299 | 300 | cnt=0; 301 | average=[]; 302 | range=[]; 303 | D_post=[]; 304 | 305 | for j=1:numel(mergegap) 306 | ranges=0:mergegap(j):(1+mergegap(j)); 307 | for i=1:(numel(ranges)-1) 308 | I(find((I(:,j)<=ranges(i+1))&(I(:,j)>ranges(i))),j)=(ranges(i+1)+ranges(i))/2; 309 | end 310 | end 311 | 312 | Iuniq=unique(I,'rows'); 313 | 314 | num_combs=size(I,Iuniq); 315 | 316 | for i=1:size(Iuniq,1) 317 | idx=find(ismember(I,Iuniq(i,:),'rows')); 318 | temp=D(idx,:); 319 | if size(temp,1)>1 320 | noisiness_sustain=noisiness_sustain+relative_mean_difference(temp'); 321 | cnt=cnt+1; 322 | average=[average ; mean(temp)]; 323 | if range_enabled 324 | range=[range ; (max(temp)-min(temp))]; 325 | end 326 | else 327 | noisiness_sustain=noisiness_sustain+relative_mean_difference(temp'); 328 | average=[average ; temp]; 329 | if range_enabled 330 | fprintf('Warning: range on single descriptors vector\n'); 331 | range=[range ; temp-temp]; 332 | end 333 | end 334 | end 335 | 336 | noisiness_sustain=noisiness_sustain./cnt; 337 | 338 | D_post=[average range]; 339 | D_post(:,all(isnan(D_post),1))=[]; 340 | D_post(isnan(D_post))=0; 341 | %D_post(:,find(sum(abs(D_post))==0))=[]; 342 | 343 | variance_sustain=(relative_mean_difference((D_post(:,1:num_desc))')); 344 | variance_sustain_range=(relative_mean_difference((D_post(:,1+num_desc:2*num_desc))')); 345 | 346 | I=Iuniq; 347 | 348 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',70); 349 | 350 | %INDEPENDENCE 351 | %on average 352 | temp1=D_post(:,1:num_desc); 353 | independence_sustain=((nansum(abs(corr(temp1,temp1)))-1)/(num_desc-1))'; 354 | independence_sustain=1-independence_sustain; 355 | 356 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',75); 357 | 358 | %on on range 359 | temp1=D_post(:,1+num_desc:2*num_desc); 360 | independence_sustain_range=((nansum(abs(corr(temp1,temp1)))-1)/(num_desc-1))'; 361 | independence_sustain_range=1-independence_sustain_range; 362 | 363 | 364 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',80); 365 | 366 | %CORRELATION WITH PARAM 367 | %on average 368 | temp1=D_post(:,1:num_desc); 369 | for i=1:(size(temp1,2)) 370 | cnt=0; 371 | temp4=0; 372 | temp2=temp1(:,i); 373 | for j=1:size(I,2) 374 | if sum(I(:,j))~=0 375 | temp3=I(:,j); 376 | temp5=nansum(abs(corr(temp2,temp3))); 377 | paramcorrelation_sustain(i)=paramcorrelation_sustain(i)+temp5; 378 | param_score(j)=param_score(j)+temp5; 379 | corrmat(j,i)=temp5; 380 | cnt=cnt+1; 381 | end 382 | end 383 | paramcorrelation_sustain(i)=paramcorrelation_sustain(i)/cnt; 384 | end 385 | 386 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',85); 387 | 388 | %on on range 389 | temp1=D_post(:,1+num_desc:2*num_desc); 390 | for i=1:(size(temp1,2)) 391 | cnt=0; 392 | temp4=0; 393 | temp2=temp1(:,i); 394 | for j=1:size(I,2) 395 | if sum(I(:,j))~=0 396 | temp3=I(:,j); 397 | temp5=nansum(abs(corr(temp2,temp3))); 398 | paramcorrelation_sustain_range(i)=paramcorrelation_sustain_range(i)+temp5; 399 | param_score(j)=param_score(j)+temp5; 400 | corrmat(j,i+108)=temp5; 401 | cnt=cnt+1; 402 | end 403 | end 404 | paramcorrelation_sustain_range(i)=paramcorrelation_sustain_range(i)/cnt; 405 | end 406 | 407 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',95); 408 | 409 | outmat=[noisiness_sustain' ; variance_sustain' ; independence_sustain' ; paramcorrelation_sustain' ; zeros(1,num_desc) ; variance_sustain_range' ; independence_sustain_range' ; paramcorrelation_sustain_range']; 410 | outfile=sprintf('%s%sScoreDsc.txt',args{8},args{7}); 411 | if exist(outfile, 'file') 412 | delete(outfile); 413 | end 414 | save(outfile,'outmat','-ASCII','-double'); 415 | 416 | outmat=param_score./(abs(max(param_score))); 417 | outfile=sprintf('%s%sScorePrm.txt',args{8},args{7}); 418 | if exist(outfile, 'file') 419 | delete(outfile); 420 | end 421 | save(outfile,'outmat','-ASCII','-double'); 422 | 423 | outmat=corrmat; 424 | outfile=sprintf('%s%sCorrMat.txt',args{8},args{7}); 425 | if exist(outfile, 'file') 426 | delete(outfile); 427 | end 428 | save(outfile,'outmat','-ASCII','-double'); 429 | 430 | oscsend(MAXoscclient,'/score','i',1); 431 | 432 | 433 | end 434 | 435 | 436 | oscsend(MAXoscclient,'/status/cmpt/percentage','f',100); 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | -------------------------------------------------------------------------------- /MATLAB/TSAM.m: -------------------------------------------------------------------------------- 1 | % This file is part of the Timbre Space Analyzer & Mapper (TSAM) 2 | % 3 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 4 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 5 | % Inquiries: stefanofasciani@stefanofasciani.com 6 | % 7 | % The TSAM is free software: you can redistribute it and/or modify it under the terms 8 | % of the GNU Lesser General Public License as published by the Free Software Foundation, 9 | % either version 3 of the License, or (at your option) any later version. 10 | % 11 | % The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 12 | % without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | % See the GNU Less General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU Lesser General Public License along with TSAM. 16 | % If not, see . 17 | % 18 | % If you use the TSAM or any part of it in any program or publication, please acknowledge 19 | % its authors by adding a reference to this pubblication: 20 | % 21 | % S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 22 | % synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. 23 | 24 | 25 | %global variables 26 | matlab_osc_port=9001; 27 | max_osc_port=9002; 28 | max_ip_address='127.0.0.1'; 29 | quit=0; 30 | function_id=0; 31 | 32 | fprintf('Starting TSAM Engine\n'); 33 | 34 | 35 | %OSC client communication initialization 36 | MAXoscclient=udp(max_ip_address,max_osc_port); 37 | fopen(MAXoscclient); 38 | oscsend(MAXoscclient,'/status/run','i',1); 39 | 40 | %OSC server communication initialization 41 | MATLABoscserver=osc_new_server(matlab_osc_port); 42 | 43 | %{1}anamode {2}range {3}period {4}dim {5}merge {6}name {7}path 44 | cmpt_args=[]; 45 | rt_args=[]; 46 | 47 | a=[]; 48 | while quit==0 49 | 50 | 51 | 52 | %receive OSC message 53 | oscrm=osc_recv(MATLABoscserver); 54 | %check message validity 55 | if ~isempty(oscrm) 56 | % process all messages in cue 57 | for m=1:length(oscrm) 58 | %route OSC data 59 | oscpath=oscrm{m}.path; 60 | oscdata=cell2mat(oscrm{m}.data); 61 | if (isequal(oscpath,'/cmd/quit')) 62 | quit=oscdata; 63 | elseif (isequal(oscpath,'/cmpt/funct')) 64 | function_id=oscdata; %id=1 mapping; id=2 score 65 | elseif (isequal(oscpath,'/cmpt/anamode')) 66 | cmpt_args{1}=oscdata; 67 | elseif (isequal(oscpath,'/cmpt/range')) 68 | cmpt_args{2}=oscdata; 69 | elseif (isequal(oscpath,'/cmpt/period')) 70 | cmpt_args{3}=oscdata; 71 | elseif (isequal(oscpath,'/cmpt/dim')) 72 | cmpt_args{4}=oscdata; 73 | elseif (isequal(oscpath,'/cmpt/merge')) 74 | cmpt_args{5}=oscdata; 75 | elseif (isequal(oscpath,'/cmpt/vcprst')) 76 | cmpt_args{6}=oscdata; 77 | elseif (isequal(oscpath,'/cmpt/name')) 78 | cmpt_args{7}=oscdata; 79 | elseif (isequal(oscpath,'/cmpt/path')) 80 | cmpt_args{8}=oscdata; 81 | elseif (isequal(oscpath,'/cmpt/manualdesc')) 82 | cmpt_args{9}=oscdata; 83 | elseif (isequal(oscpath,'/cmpt/mskvect')) 84 | cmpt_args{10}=oscdata; 85 | elseif (isequal(oscpath,'/cmpt/actfunc')) 86 | cmpt_args{11}=oscdata; 87 | elseif (isequal(oscpath,'/cmpt/dimred')) 88 | cmpt_args{12}=oscdata; 89 | elseif (isequal(oscpath,'/cmpt/descsel')) 90 | cmpt_args{13}=oscdata; 91 | elseif (isequal(oscpath,'/cmpt/sr')) 92 | cmpt_args{14}=oscdata; 93 | elseif (isequal(oscpath,'/cmpt/topdesc')) 94 | cmpt_args{15}=oscdata; 95 | elseif (isequal(oscpath,'/cmpt/run')) 96 | if function_id==1 97 | ComputeMapping(MAXoscclient,MATLABoscserver,cmpt_args); 98 | oscsend(MAXoscclient,'/status/cmpt/run','i',0); 99 | elseif function_id==2 100 | ComputeScore(MAXoscclient,MATLABoscserver,cmpt_args); 101 | oscsend(MAXoscclient,'/status/cmpt/run','i',0); 102 | else 103 | fprintf('TSAM-MAIN function id = %d not valid\n',function_id); 104 | end 105 | else 106 | fprintf('TSAM-MAIN message not valid: path = %s; data = %f \n',oscpath,oscdata); 107 | end 108 | end 109 | end 110 | 111 | 112 | 113 | 114 | end 115 | 116 | 117 | %OSC server communication termination 118 | osc_free_server(MATLABoscserver); 119 | %OSC client communication termination 120 | oscsend(MAXoscclient,'/status/run','i',0); 121 | fclose(MAXoscclient); 122 | 123 | 124 | fprintf('Terminating TSAM Engine\n'); 125 | 126 | -------------------------------------------------------------------------------- /MATLAB/distmeshnd_sfa.m: -------------------------------------------------------------------------------- 1 | function [p,t,maxdp]=distmeshnd_sfa(moviefile,fdist,fh,h,box,fix,varargin) 2 | %DISTMESHND N-D Mesh Generator using Distance Functions. 3 | % [P,T]=DISTMESHND(FDIST,FH,H,BOX,FIX,FDISTPARAMS) 4 | % 5 | % P: Node positions (NxNDIM) 6 | % T: Triangle indices (NTx(NDIM+1)) 7 | % FDIST: Distance function 8 | % FH: Edge length function 9 | % H: Smallest edge length 10 | % BOX: Bounding box [xmin,xmax;ymin,ymax; ...] (NDIMx2) 11 | % FIX: Fixed node positions (NFIXxNDIM) 12 | % FDISTPARAMS: Additional parameters passed to FDIST 13 | % 14 | % Example: Unit ball 15 | % dim=3; 16 | % d=inline('sqrt(sum(p.^2,2))-1','p'); 17 | % [p,t]=distmeshnd(d,@huniform,0.2,[-ones(1,dim);ones(1,dim)],[]); 18 | % 19 | % See also: DISTMESH2D, DELAUNAYN, TRIMESH, MESHDEMOND. 20 | 21 | % Copyright (C) 2004-2012 Per-Olof Persson. See COPYRIGHT.TXT for details. 22 | 23 | 24 | % The original file was modified for the integration with the 25 | % Timbre Space Analyzer and Mapper (TSAM). 26 | % 27 | % The TSAM is free software: you can redistribute it and/or modify 28 | % it under the terms of the GNU Lesser General Public License as published by 29 | % the Free Software Foundation, either version 3 of the License, or 30 | % (at your option) any later version. 31 | % 32 | % The TSAM is distributed in the hope that it will be useful, 33 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 34 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 35 | % GNU Less General Public License for more details. 36 | % 37 | % You should have received a copy of the GNU Lesser General Public License 38 | % along with TSAM. If not, see . 39 | % 40 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 41 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 42 | % Inquiries: stefanofasciani@stefanofasciani.com 43 | 44 | 45 | 46 | 47 | dim=size(box,2); 48 | ptol=.01; ttol=.1; L0mult=1+.4/2^(dim-1); deltat=.1; geps=1e-1*h; deps=sqrt(eps)*h; 49 | min_term=1000000000000000; 50 | term_check=0; 51 | framecount=1; 52 | % 1. Create initial distribution in bounding box 53 | if dim==1 54 | p=(box(1):h:box(2))'; 55 | else 56 | cbox=cell(1,dim); 57 | for ii=1:dim 58 | cbox{ii}=box(1,ii):h:box(2,ii); 59 | end 60 | pp=cell(1,dim); 61 | [pp{:}]=ndgrid(cbox{:}); 62 | p=zeros(prod(size(pp{1})),dim); 63 | for ii=1:dim 64 | p(:,ii)=pp{ii}(:); 65 | end 66 | end 67 | 68 | % 2. Remove points outside the region, apply the rejection method 69 | p=p(feval(fdist,p,varargin{:})ttol*h 79 | p0=p; 80 | t=delaunayn(p); 81 | pmid=zeros(size(t,1),dim); 82 | for ii=1:dim+1 83 | pmid=pmid+p(t(:,ii),:)/(dim+1); 84 | end 85 | t=t(feval(fdist,pmid,varargin{:})<-geps,:); 86 | % 4. Describe each edge by a unique pair of nodes 87 | pair=zeros(0,2); 88 | localpairs=nchoosek(1:dim+1,2); 89 | for ii=1:size(localpairs,1) 90 | pair=[pair;t(:,localpairs(ii,:))]; 91 | end 92 | pair=unique(sort(pair,2),'rows'); 93 | % 5. Graphical output of the current mesh 94 | if dim==2 95 | if mod(count,10)==0 96 | cla,patch('vertices',p,'faces',t,'edgecol','k','facecol',[0.9,0.9,0.9]); 97 | hold on 98 | scatter(p(:,1),p(:,2),10,[1 0.1 0.4]); 99 | hold off 100 | axis on 101 | axis([-0.1 1.1 -0.1 1.1]); 102 | drawnow 103 | movie(framecount)=getframe(gcf); 104 | framecount=framecount+1; 105 | end 106 | elseif dim==3 107 | if mod(count,20)==0 108 | simpplot(p,t,'p(:,2)>0'); 109 | title(['Retriangulation #',int2str(count)]) 110 | hold on 111 | scatter3(p(:,1),p(:,2),p(:,3),10,[1 0.1 0.4]); 112 | hold off 113 | axis on 114 | axis([-0.1 1.1 -0.1 1.1 -0.1 1.1]); 115 | drawnow 116 | movie(framecount)=getframe(gcf); 117 | framecount=framecount+1; 118 | end 119 | else 120 | disp(sprintf('Retriangulation #%d',count)) 121 | end 122 | count=count+1; 123 | end 124 | 125 | % 6. Move mesh points based on edge lengths L and forces F 126 | bars=p(pair(:,1),:)-p(pair(:,2),:); 127 | L=sqrt(sum(bars.^2,2)); 128 | L0=feval(fh,(p(pair(:,1),:)+p(pair(:,2),:))/2); 129 | L0=L0*L0mult*(sum(L.^dim)/sum(L0.^dim))^(1/dim); 130 | F=max(L0-L,0); 131 | Fbar=[bars,-bars].*repmat(F./L,1,2*dim); 132 | dp=full(sparse(pair(:,[ones(1,dim),2*ones(1,dim)]), ... 133 | ones(size(pair,1),1)*[1:dim,1:dim], ... 134 | Fbar,N,dim)); 135 | p=p+deltat*dp; 136 | 137 | % 7. Bring outside points back to the boundary 138 | d=feval(fdist,p,varargin{:}); ix=d>0; 139 | gradd=zeros(sum(ix),dim); 140 | for ii=1:dim 141 | a=zeros(1,dim); 142 | a(ii)=deps; 143 | d1x=feval(fdist,p(ix,:)+ones(sum(ix),1)*a,varargin{:}); 144 | gradd(:,ii)=(d1x-d(ix))/deps; 145 | end 146 | p(ix,:)=p(ix,:)-d(ix)*ones(1,dim).*gradd; 147 | 148 | % 8. Termination criterion 149 | maxdp=max(deltat*sqrt(sum(dp(d<-geps,:).^2,2))); 150 | treshold=ptol*h; 151 | 152 | if maxdp500 167 | break; 168 | end 169 | 170 | end 171 | 172 | end 173 | 174 | %%save movie to avi file 175 | %movie2avi(movie, moviefile, 'compression', 'None','fps',10); 176 | 177 | -------------------------------------------------------------------------------- /MATLAB/elmMOD.m: -------------------------------------------------------------------------------- 1 | function [out_struct] = elmMOD(regr_in,regr_out,NumberofHiddenNeurons,ActivationFunction) 2 | 3 | 4 | %%%% Authors: MR QIN-YU ZHU AND DR GUANG-BIN HUANG 5 | %%%% NANYANG TECHNOLOGICAL UNIVERSITY, SINGAPORE 6 | %%%% EMAIL: EGBHUANG@NTU.EDU.SG; GBHUANG@IEEE.ORG 7 | %%%% WEBSITE: http://www.ntu.edu.sg/eee/icis/cv/egbhuang.htm 8 | %%%% DATE: APRIL 2004 9 | 10 | 11 | 12 | % The original file was modified for the integration with the 13 | % Timbre Space Analyzer and Mapper (TSAM). 14 | % 15 | % The TSAM is free software: you can redistribute it and/or modify 16 | % it under the terms of the GNU Lesser General Public License as published by 17 | % the Free Software Foundation, either version 3 of the License, or 18 | % (at your option) any later version. 19 | % 20 | % The TSAM is distributed in the hope that it will be useful, 21 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | % GNU Less General Public License for more details. 24 | % 25 | % You should have received a copy of the GNU Lesser General Public License 26 | % along with TSAM. If not, see . 27 | % 28 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 29 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 30 | % Inquiries: stefanofasciani@stefanofasciani.com 31 | 32 | 33 | %%%%%%%%%%% Load training dataset 34 | T=regr_out; 35 | P=regr_in; 36 | clear train_data; % Release raw training data array 37 | 38 | NumberofTrainingData=size(P,2); 39 | NumberofInputNeurons=size(P,1); % end if of Elm_Type 40 | 41 | %%%%%%%%%%% Random generate input weights InputWeight (w_i) and biases BiasofHiddenNeurons (b_i) of hidden neurons 42 | InputWeight=rand(NumberofHiddenNeurons,NumberofInputNeurons)*2-1; 43 | BiasofHiddenNeurons=rand(NumberofHiddenNeurons,1); 44 | tempH=InputWeight*P; 45 | clear P; % Release input of training data 46 | ind=ones(1,NumberofTrainingData); 47 | BiasMatrix=BiasofHiddenNeurons(:,ind); % Extend the bias matrix BiasofHiddenNeurons to match the demention of H 48 | tempH=tempH+BiasMatrix; 49 | 50 | %%%%%%%%%%% Calculate hidden neuron output matrix H 51 | switch lower(ActivationFunction) 52 | case {'sig','sigmoid'} 53 | %%%%%%%% Sigmoid 54 | H = 1 ./ (1 + exp(-tempH)); 55 | case {'sin','sine'} 56 | %%%%%%%% Sine 57 | H = sin(tempH); 58 | case {'hardlim'} 59 | %%%%%%%% Hard Limit 60 | %H_test = hardlim(tempH); 61 | H = double(tempH >= 0); 62 | case {'tribas'} 63 | %%%%%%%% Triangular basis function 64 | %H = tribas(tempH); 65 | H = max(0,1-abs(tempH)); 66 | case {'radbas'} 67 | %%%%%%%% Radial basis function 68 | H = exp(-(tempH.*tempH)); 69 | %%%%%%%% More activation functions can be added here 70 | end 71 | clear tempH; % Release the temparary array for calculation of hidden neuron output matrix H 72 | 73 | %%%%%%%%%%% Calculate output weights OutputWeight (beta_i) 74 | OutputWeight=pinv(H') * T'; % implementation without regularization factor //refer to 2006 Neurocomputing paper 75 | 76 | %%%%%%%%%%% Calculate the training accuracy 77 | Y=(H' * OutputWeight)'; % Y: the actual output of the training data 78 | 79 | TrainingAccuracy=sqrt(mse(T - Y)); % Calculate training accuracy (RMSE) for regression case 80 | 81 | clear H; 82 | 83 | out_struct.accuracy=TrainingAccuracy; 84 | out_struct.outweight=OutputWeight; 85 | out_struct.inweight=InputWeight; 86 | out_struct.bias=BiasofHiddenNeurons; 87 | out_struct.actfunct=ActivationFunction; 88 | 89 | 90 | -------------------------------------------------------------------------------- /MATLAB/elmMODmap.m: -------------------------------------------------------------------------------- 1 | function [out] = elmMODmap(in,struct) 2 | 3 | %%%% Authors: MR QIN-YU ZHU AND DR GUANG-BIN HUANG 4 | %%%% NANYANG TECHNOLOGICAL UNIVERSITY, SINGAPORE 5 | %%%% EMAIL: EGBHUANG@NTU.EDU.SG; GBHUANG@IEEE.ORG 6 | %%%% WEBSITE: http://www.ntu.edu.sg/eee/icis/cv/egbhuang.htm 7 | %%%% DATE: APRIL 2004 8 | 9 | 10 | % The original file was modified for the integration with the 11 | % Timbre Space Analyzer and Mapper (TSAM). 12 | % 13 | % The TSAM is free software: you can redistribute it and/or modify 14 | % it under the terms of the GNU Lesser General Public License as published by 15 | % the Free Software Foundation, either version 3 of the License, or 16 | % (at your option) any later version. 17 | % 18 | % The TSAM is distributed in the hope that it will be useful, 19 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | % GNU Less General Public License for more details. 22 | % 23 | % You should have received a copy of the GNU Lesser General Public License 24 | % along with TSAM. If not, see . 25 | % 26 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 27 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 28 | % Inquiries: stefanofasciani@stefanofasciani.com 29 | 30 | 31 | tempH=struct.inweight*in'; % Extend the bias matrix BiasofHiddenNeurons to match the demention of H 32 | tempH=tempH + struct.bias; 33 | switch lower(struct.actfunct) 34 | case {'sig','sigmoid'} 35 | %%%%%%%% Sigmoid 36 | H_test = 1 ./ (1 + exp(-tempH)); 37 | case {'sin','sine'} 38 | %%%%%%%% Sine 39 | H_test = sin(tempH); 40 | case {'hardlim'} 41 | %%%%%%%% Hard Limit 42 | %H_test = hardlim(tempH); 43 | H_test = double(tempH >= 0); 44 | case {'tribas'} 45 | %%%%%%%% Triangular basis function 46 | %H_test = tribas(tempH); 47 | H_test = max(0,1-abs(tempH)); 48 | case {'radbas'} 49 | %%%%%%%% Radial basis function 50 | %H_test = radbas(tempH); 51 | H_test = exp(-(tempH.*tempH)); 52 | %%%%%%%% More activation functions can be added here 53 | end 54 | out=(H_test' * struct.outweight)'; % TY: the actual output of the testing data 55 | -------------------------------------------------------------------------------- /MATLAB/oscsend.m: -------------------------------------------------------------------------------- 1 | function oscsend(u,path,varargin) 2 | % Sends a Open Sound Control (OSC) message through a UDP connection 3 | % 4 | % oscsend(u,path) 5 | % oscsend(u,path,types,arg1,arg2,...) 6 | % oscsedn(u,path,types,[args]) 7 | % 8 | % u = UDP object with open connection. 9 | % path = path-string 10 | % types = string with types of arguments, 11 | % supported: 12 | % i = integer 13 | % f = float 14 | % s = string 15 | % N = Null (ignores corresponding argument) 16 | % I = Impulse (ignores corresponding argument) 17 | % T = True (ignores corresponding argument) 18 | % F = False (ignores corresponding argument) 19 | % B = boolean (not official: converts argument to T/F in the type) 20 | % not supported: 21 | % b = blob 22 | % 23 | % args = arguments as specified by types. 24 | % 25 | % EXAMPLE 26 | % u = udp('127.0.0.1',7488); 27 | % fopen(u); 28 | % oscsend(u,'/test','ifsINBTF', 1, 3.14, 'hello',[],[],false,[],[]); 29 | % fclose(u); 30 | % 31 | % See http://opensoundcontrol.org/ for more information about OSC. 32 | 33 | % MARK MARIJNISSEN 10 may 2011 (markmarijnissen@gmail.com) 34 | 35 | 36 | 37 | % The original file was modified for the integration with the 38 | % Timbre Space Analyzer and Mapper (TSAM). 39 | % 40 | % The TSAM is free software: you can redistribute it and/or modify 41 | % it under the terms of the GNU Lesser General Public License as published by 42 | % the Free Software Foundation, either version 3 of the License, or 43 | % (at your option) any later version. 44 | % 45 | % The TSAM is distributed in the hope that it will be useful, 46 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 47 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 48 | % GNU Less General Public License for more details. 49 | % 50 | % You should have received a copy of the GNU Lesser General Public License 51 | % along with TSAM. If not, see . 52 | % 53 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 54 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 55 | % Inquiries: stefanofasciani@stefanofasciani.com 56 | 57 | 58 | 59 | %figure out little endian for int/float conversion 60 | [~, ~, endian] = computer; 61 | littleEndian = endian == 'L'; 62 | 63 | % set type 64 | if nargin >= 3, 65 | types = oscstr([',' varargin{1}]); 66 | else 67 | types = oscstr(','); 68 | end; 69 | 70 | % set args (either a matrix, or varargin) 71 | if nargin == 3 && length(types) > 2 72 | args = varargin{2}; 73 | else 74 | args = varargin(2:end); 75 | end; 76 | 77 | % convert arguments to the right bytes 78 | data = []; 79 | for i=1:length(args) 80 | switch(types(i+1)) 81 | case 'i' 82 | data = [data oscint(args{i},littleEndian)]; 83 | case 'f' 84 | data = [data oscfloat(args{i},littleEndian)]; 85 | case 's' 86 | data = [data oscstr(args{i})]; 87 | case 'B' 88 | if args{i} 89 | types(i+1) = 'T'; 90 | else 91 | types(i+1) = 'F'; 92 | end; 93 | case {'N','I','T','F'} 94 | %ignore data 95 | otherwise 96 | warning(['Unsupported type: ' types(i+1)]); 97 | end; 98 | end; 99 | 100 | %write data to UDP 101 | data = [oscstr(path) types data]; 102 | fwrite(u,data); 103 | end 104 | 105 | %Conversion from double to float 106 | function float = oscfloat(float,littleEndian) 107 | if littleEndian 108 | float = typecast(swapbytes(single(float)),'uint8'); 109 | else 110 | float = typecast(single(float),'uint8'); 111 | end; 112 | end 113 | 114 | %Conversion to int 115 | function int = oscint(int,littleEndian) 116 | if littleEndian 117 | int = typecast(swapbytes(int32(int)),'uint8'); 118 | else 119 | int = typecast(int32(int),'uint8'); 120 | end; 121 | end 122 | 123 | %Conversion to string (null-terminated, in multiples of 4 bytes) 124 | function string = oscstr(string) 125 | string = [string 0 0 0 0]; 126 | string = string(1:end-mod(length(string),4)); 127 | end -------------------------------------------------------------------------------- /MATLAB/period_detection.m: -------------------------------------------------------------------------------- 1 | function [period_hz] = period_detection(window,hop,d,sr) 2 | 3 | % This file is part of the Timbre Space Analyzer & Mapper (TSAM) 4 | % 5 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 6 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 7 | % Inquiries: stefanofasciani@stefanofasciani.com 8 | % 9 | % The TSAM is free software: you can redistribute it and/or modify it under the terms 10 | % of the GNU Lesser General Public License as published by the Free Software Foundation, 11 | % either version 3 of the License, or (at your option) any later version. 12 | % 13 | % The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 14 | % without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | % See the GNU Less General Public License for more details. 16 | % 17 | % You should have received a copy of the GNU Lesser General Public License along with TSAM. 18 | % If not, see . 19 | % 20 | % If you use the TSAM or any part of it in any program or publication, please acknowledge 21 | % its authors by adding a reference to this pubblication: 22 | % 23 | % S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 24 | % synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. 25 | 26 | 27 | period_hz=zeros(1,size(d,2)); 28 | 29 | for i=1:size(d,2) 30 | 31 | temp=d(:,i); 32 | temp=temp-max(temp); 33 | fil_out=filter(((window)/sr), [1 ((window)/sr)-1], temp); 34 | autocx=xcorr(fil_out,size(d,1),'coeff'); 35 | [pk_loc,pk_val]=findpeaks(autocx(1:size(d,1))); 36 | pk_val(pk_val==1)=0; 37 | [~,idx]=max(pk_val); 38 | pk_loc=pk_loc(idx); 39 | if ~isempty(pk_loc) 40 | period_smp=((size(d,1)-pk_loc+2)*hop); 41 | period_time=(period_smp/sr); 42 | period_hz(i)=(1.0/period_time); 43 | else 44 | period_hz(i)=0; 45 | end 46 | 47 | end 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /MATLAB/relative_mean_difference.m: -------------------------------------------------------------------------------- 1 | function[relmeandiff]=relative_mean_difference(in) 2 | 3 | % This file is part of the Timbre Space Analyzer & Mapper (TSAM) 4 | % 5 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 6 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 7 | % Inquiries: stefanofasciani@stefanofasciani.com 8 | % 9 | % The TSAM is free software: you can redistribute it and/or modify it under the terms 10 | % of the GNU Lesser General Public License as published by the Free Software Foundation, 11 | % either version 3 of the License, or (at your option) any later version. 12 | % 13 | % The TSAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 14 | % without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | % See the GNU Less General Public License for more details. 16 | % 17 | % You should have received a copy of the GNU Lesser General Public License along with TSAM. 18 | % If not, see . 19 | % 20 | % If you use the TSAM or any part of it in any program or publication, please acknowledge 21 | % its authors by adding a reference to this pubblication: 22 | % 23 | % S. Fasciani, 2016, "TSAM: a tool for analyzing, modeling, and mapping the timbre of sound 24 | % synthesizers" in proceedings of the 13th Sound and Music Computing Conference, Hamburg, Germany. 25 | 26 | 27 | relmeandiff=zeros(size(in,1),1); 28 | n=size(in,2); 29 | 30 | for i=1:n 31 | for j=1:n 32 | relmeandiff=relmeandiff+(abs(in(:,i)-in(:,j))); 33 | end 34 | end 35 | 36 | relmeandiff=(relmeandiff./(n*(n-1).*abs(mean(in,2)))); 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /MATLAB/unique_sfast.m: -------------------------------------------------------------------------------- 1 | function [b,ndx,pos] = unique_sfast(a,flag1,flag2) 2 | %UNIQUE Set unique. 3 | % B = UNIQUE(A) for the array A returns the same values as in A but 4 | % with no repetitions. B will also be sorted. A can be a cell array of 5 | % strings. 6 | % 7 | % UNIQUE(A,'rows') for the matrix A returns the unique rows of A. 8 | % 9 | % [B,I,J] = UNIQUE(...) also returns index vectors I and J such 10 | % that B = A(I) and A = B(J) (or B = A(I,:) and A = B(J,:)). 11 | % 12 | % [B,I,J] = UNIQUE(...,'first') returns the vector I to index the 13 | % first occurrence of each unique value in A. UNIQUE(...,'last'), 14 | % the default, returns the vector I to index the last occurrence. 15 | % 16 | % See also UNION, INTERSECT, SETDIFF, SETXOR, ISMEMBER, SORT, ISSORTED. 17 | 18 | % Copyright 1984-2009 The MathWorks, Inc. 19 | % $Revision: 1.24.4.9 $ $Date: 2010/08/23 23:11:33 $ 20 | 21 | % Cell array implementation in @cell/unique.m 22 | 23 | 24 | % The original file was modified for the integration with the 25 | % Timbre Space Analyzer and Mapper (TSAM). 26 | % 27 | % The TSAM is free software: you can redistribute it and/or modify 28 | % it under the terms of the GNU Lesser General Public License as published by 29 | % the Free Software Foundation, either version 3 of the License, or 30 | % (at your option) any later version. 31 | % 32 | % The TSAM is distributed in the hope that it will be useful, 33 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 34 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 35 | % GNU Less General Public License for more details. 36 | % 37 | % You should have received a copy of the GNU Lesser General Public License 38 | % along with TSAM. If not, see . 39 | % 40 | % The TSAM can be obtained at http://stefanofasciani.com/tsam.html 41 | % TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 42 | % Inquiries: stefanofasciani@stefanofasciani.com 43 | 44 | 45 | flagvals = {'rows' 'first' 'last'}; 46 | if nargin > 1 47 | options = strcmpi(flag1,flagvals); 48 | if nargin > 2 49 | options = options + strcmpi(flag2,flagvals); 50 | if any(options > 1) || (options(2)+options(3) > 1) 51 | error(message('MATLAB:UNIQUE:RepeatedFlag')); 52 | end 53 | end 54 | if sum(options) < nargin-1 55 | error(message('MATLAB:UNIQUE:UnknownFlag')); 56 | end 57 | byrow = (options(1) > 0); 58 | if options(2) > 0 59 | order = 'first'; 60 | else % if options(3) > 0 || sum(options(2:3) == 0) 61 | order = 'last'; 62 | end 63 | elseif nargin == 1 64 | byrow = false; 65 | order = 'last'; 66 | else 67 | error(message('MATLAB:UNIQUE:NotEnoughInputs')); 68 | end 69 | 70 | rows = size(a,1); 71 | cols = size(a,2); 72 | 73 | rowvec = (rows == 1) && (cols > 1); 74 | 75 | numelA = numel(a); 76 | nOut = nargout; 77 | 78 | if ~isa(a,'opaque') 79 | 80 | if ~byrow 81 | 82 | % Handle empty: no elements. 83 | 84 | if (numelA == 0) 85 | % Predefine b to be of the correct type. 86 | b = a([]); 87 | if max(size(a)) > 0 88 | b = reshape(b,0,1); 89 | ndx = zeros(0,1); 90 | pos = zeros(0,1); 91 | else 92 | ndx = []; 93 | pos = []; 94 | end 95 | return 96 | 97 | elseif (numelA == 1) 98 | % Scalar A: return the existing value of A. 99 | b = a; ndx = 1; pos = 1; 100 | return 101 | 102 | % General handling. 103 | else 104 | 105 | % Convert to columns 106 | a = a(:); 107 | 108 | % Convert to double array for purposes of faster sorting. 109 | % Additionally, UNIQUE calls DIFF, which requires double input. 110 | 111 | whichclass = class(a); 112 | isdouble = strcmp(whichclass,'double'); 113 | 114 | if ~isdouble 115 | a = double(a); 116 | end 117 | 118 | % Sort if unsorted. Only check this for long lists. 119 | 120 | checksortcut = 1000; 121 | 122 | if numelA <= checksortcut || ~(issorted(a)) 123 | if nOut <= 1 124 | b = sort(a); 125 | else 126 | [b,ndx] = sort(a); 127 | end 128 | else 129 | b = a; 130 | if nOut > 1 131 | ndx = (1:numelA)'; % If presorted, indices are 1,2,3,... 132 | end 133 | end 134 | 135 | % d indicates the location of non-matching entries. 136 | 137 | db = diff(b); 138 | 139 | % Since DIFF returns NaN in both Inf and NaN cases, 140 | % use slower method of detection if NaN's detected in DIFF(b). 141 | % After sort, Infs or NaNs will be at ends of list only. 142 | 143 | if (isnan(db(1)) || isnan(db(numelA-1))) 144 | d = b(1:numelA-1) ~= b(2:numelA); 145 | else 146 | d = db ~= 0; 147 | end 148 | 149 | if order(1) == 'l' % 'last' 150 | d(numelA,1) = true; % Final element is always a member of unique list. 151 | else % order == 'first' 152 | d = [true; d]; % First element is always a member of unique list. 153 | end 154 | 155 | b = b(d); % Create unique list by indexing into sorted list. 156 | 157 | if nOut == 3 158 | if order(1) == 'l' % 'last' 159 | pos = cumsum([1;full(d)]); % Lists position, starting at 1. 160 | pos(numelA+1) = []; % Remove extra element introduced by d. 161 | else % order == 'first' 162 | pos = cumsum(full(d)); % Lists position, starting at 1. 163 | end 164 | pos(ndx) = pos; % Re-reference POS to indexing of SORT. 165 | end 166 | 167 | % Create indices if needed. 168 | if nOut > 1 169 | ndx = ndx(d); 170 | end 171 | 172 | % Re-convert to correct output data type using FEVAL. 173 | if ~isdouble 174 | b = feval(whichclass,b); 175 | end 176 | end 177 | 178 | % If row vector, return as row vector. 179 | if rowvec 180 | b = b.'; 181 | if nOut > 1 182 | ndx = ndx.'; 183 | if nOut > 2 184 | pos = pos.'; 185 | end 186 | end 187 | end 188 | 189 | else % 'rows' case 190 | 191 | % Handle empty: no rows. 192 | 193 | if (rows == 0) 194 | % Predefine b to be of the correct type. 195 | b = a([]); 196 | ndx = []; 197 | pos = []; 198 | b = reshape(b,0,cols); 199 | if cols > 0 200 | ndx = reshape(ndx,0,1); 201 | end 202 | return 203 | 204 | % Handle scalar: one row. 205 | 206 | elseif (rows == 1) 207 | b = a; ndx = 1; pos = 1; 208 | return 209 | end 210 | 211 | % General handling. 212 | % Conversion to double not done: SORTROWS is slower for doubles 213 | % than other types. 214 | 215 | if nOut > 1 216 | [b,ndx] = sortrows(a); 217 | else 218 | bbb = sortrows(a); 219 | [~,srtidx]=sort(a(:,1)); 220 | b = a(srtidx,:); 221 | 222 | end 223 | 224 | % d indicates the location of non-matching entries. 225 | 226 | d = b(1:rows-1,:)~=b(2:rows,:); 227 | 228 | % d = 1 if differences between rows. d = 0 if the rows are equal. 229 | 230 | d = any(d,2); 231 | if order(1) == 'l' % 'last' 232 | d(rows,1) = true; % Final row is always member of unique list. 233 | else % order = 'first' 234 | d = [true; d]; % First row is always a member of unique list. 235 | end 236 | 237 | b = b(d,:); % Create unique list by indexing into sorted list. 238 | 239 | % Create position mapping vector using CUMSUM. 240 | 241 | if nOut == 3 242 | if order(1) == 'l' % 'last' 243 | pos = cumsum([1;full(d)]); % Lists position, starting at 1. 244 | pos(rows+1) = []; % Remove extra element introduced by d. 245 | else % order == 'first' 246 | pos = cumsum(full(d)); % Lists position, starting at 1. 247 | end 248 | pos(ndx) = pos; % Re-reference POS to indexing of SORT. 249 | end 250 | 251 | % Create indices if needed. 252 | if nOut > 1 253 | ndx = ndx(d); 254 | end 255 | end 256 | 257 | else 258 | % Handle objects that cannot be converted to doubles 259 | if ~byrow 260 | 261 | % Handle empty: no elements. 262 | 263 | if (numelA == 0) 264 | % Predefine b to be of the correct type. 265 | b = a([]); 266 | if max(size(a)) > 0 267 | b = reshape(b,0,1); 268 | ndx = zeros(0,1); 269 | pos = zeros(0,1); 270 | else 271 | ndx = []; 272 | pos = []; 273 | end 274 | return 275 | 276 | elseif (numelA == 1) 277 | % Scalar A: return the existing value of A. 278 | b = a; ndx = 1; pos = 1; 279 | return 280 | 281 | % General handling. 282 | else 283 | 284 | % Convert to columns 285 | a = a(:); 286 | 287 | % Sort if unsorted. Only check this for long lists. 288 | 289 | if nOut <= 1 290 | b = sort(a); 291 | else 292 | [b,ndx] = sort(a); 293 | end 294 | 295 | % d indicates the location of non-matching entries. 296 | 297 | d = b(1:numelA-1) ~= b(2:numelA); 298 | 299 | if order(1) == 'l' % 'last' 300 | d(numelA,1) = true; % Final element is always a member of unique list. 301 | else % order == 'first' 302 | d = [true; d]; % First element is always a member of unique list. 303 | end 304 | 305 | b = b(d); % Create unique list by indexing into sorted list. 306 | 307 | if nOut == 3 308 | if order(1) == 'l' % 'last' 309 | pos = cumsum([1;d]); % Lists position, starting at 1. 310 | pos(numelA+1) = []; % Remove extra element introduced by d. 311 | else % order == 'first' 312 | pos = cumsum(d); % Lists position, starting at 1. 313 | end 314 | pos(ndx) = pos; % Re-reference POS to indexing of SORT. 315 | end 316 | 317 | % Create indices if needed. 318 | if nOut > 1 319 | ndx = ndx(d); 320 | end 321 | end 322 | 323 | % If row vector, return as row vector. 324 | if rowvec 325 | b = b.'; 326 | if nOut > 1 327 | ndx = ndx.'; 328 | if nOut > 2 329 | pos = pos.'; 330 | end 331 | end 332 | end 333 | 334 | else % 'rows' case 335 | 336 | % Handle empty: no rows. 337 | 338 | if (rows == 0) 339 | % Predefine b to be of the correct type. 340 | b = a([]); 341 | ndx = []; 342 | pos = []; 343 | b = reshape(b,0,cols); 344 | if cols > 0 345 | ndx = reshape(ndx,0,1); 346 | end 347 | return 348 | 349 | % Handle scalar: one row. 350 | 351 | elseif (rows == 1) 352 | b = a; ndx = 1; pos = 1; 353 | return 354 | end 355 | 356 | % General handling. 357 | 358 | if nOut > 1 359 | [b,ndx] = sortrows(a); 360 | else 361 | b = sortrows(a); 362 | end 363 | 364 | % d indicates the location of non-matching entries. 365 | 366 | d = b(1:rows-1,:)~=b(2:rows,:); 367 | 368 | % d = 1 if differences between rows. d = 0 if the rows are equal. 369 | 370 | d = any(d,2); 371 | if order(1) == 'l' % 'last' 372 | d(rows,1) = true; % Final row is always member of unique list. 373 | else % order == 'first' 374 | d = [true; d]; % First row is always a member of unique list. 375 | end 376 | 377 | b = b(d,:); % Create unique list by indexing into sorted list. 378 | 379 | % Create position mapping vector using CUMSUM. 380 | 381 | if nOut == 3 382 | pos = cumsum([1;d]); % Lists position, starting at 1. 383 | pos(rows+1) = []; % Remove extra element introduced by d. 384 | pos(ndx) = pos; % Re-reference POS to indexing of SORT. 385 | end 386 | 387 | % Create indices if needed. 388 | if nOut > 1 389 | ndx = ndx(d); 390 | end 391 | end 392 | end 393 | -------------------------------------------------------------------------------- /Max/TSAM.maxpat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanofasciani/TSAM/502b29feb48a85b51c469e699e11993e6de592fb/Max/TSAM.maxpat -------------------------------------------------------------------------------- /Max/TSAM_3DOGL.maxpat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanofasciani/TSAM/502b29feb48a85b51c469e699e11993e6de592fb/Max/TSAM_3DOGL.maxpat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ======================================= 3 | TSAM - Timbre Space Analyzer and Mapper 4 | ======================================= 5 | 6 | ============================================================================== 7 | 8 | The Timbre Space Analyzer & Mapper (TSAM) is a collection of MAX patches 9 | and MATLAB functions for the analysis, modeling and controlling of the 10 | timbre of sound synthesizers. 11 | The TSAM can be obtained at http://stefanofasciani.com/tsam.html 12 | TSAM Copyright (C) 2016 Stefano Fasciani, University of Wollongong 13 | Inquiries: stefanofasciani@stefanofasciani.com 14 | 15 | ============================================================================== 16 | 17 | 18 | ============ 19 | REQUIREMENTS 20 | ============ 21 | 22 | The TSAM is implemented in Cycling '74 Max 7 and MATLAB (OSX only). 23 | 24 | The TSAM has been developed and tested on the following platform: 25 | OSX 10.7.5 26 | MAX 7.2.4 (32-bit) 27 | MATLAB 7.12.0 (R2011a) 28 | 29 | 30 | The following Cycling '74 Max 7 libraries are required: 31 | (download the externals and include these in your Max path) 32 | 33 | - FTM http://ftm.ircam.fr/index.php/Main_Page 34 | - SFA-MaxLib http://stefanofasciani.com/?p=865 35 | - CNMAT Max/MSP Externals (Opensoundcontrol and OSC-route only)http://cnmat.berkeley.edu/downloads 36 | - Max Sound Box (ircamdescriptor~.mxo only) http://forumnet.ircam.fr/product/max-sound-box-en/ 37 | 38 | 39 | The following MATLAB libraries/toolboxes are required : 40 | (download the files.m and include these in your MATLAB path) 41 | 42 | - Instrument Control Toolbox http://www.mathworks.com/products/instrument/ 43 | - Statistics and Machine Learning Toolbox http://www.mathworks.com/products/statistics/ 44 | - Signal Processing Toolbox ttp://www.mathworks.com/products/signal/ 45 | 46 | ============ 47 | INSTRUCTIONS 48 | ============ 49 | 50 | The TSAM.maxpat and TSAM_3DOGL.maxpat are equivalent. The only difference is in the timbre space visualization. 51 | The TSAM.maxpat provides a 2D timbre space visualization, which is less CPU demanding. 52 | The TSAM_3DOGL.maxpat provides a 3D timbre space visualization (OpenGL), which is more CPU demanding. 53 | Both TSAM.maxpat and TSAM_3DOGL.maxpat provides 2D and 3D mapping capabilities. 54 | 55 | Run the TSAM.maxpat (or TSAM_3DOGL.maxpat) and run the TSAM.m script in MATLAB. 56 | The TSAM.m script communicates with the TSAM.maxpat via OSC. 57 | To terminate the TSAM.m push the "Stop Engine" button in the TSAM.maxpat main tab. 58 | When TSAM.m is running "Engine Stopped" changes state to "Engine Running". 59 | The TSAM.maxpat request to the TSAM.m sctipt the mapping computation and scoe computation 60 | (only when pressing the buttons "Compute Mapping" and "Compute Score" in the TSAM.maxpat main tab. 61 | For any other operation the TSAM.maxpat do not require the TSAM.m to run in background (e.g. for analysis 62 | or real time mapping). 63 | 64 | In MATLAB you can compile the TSAM.m into a matlab executable and run it from the terminal. 65 | To compile in MATLAB use the command below. 66 | 67 | mcc -m -v -I full_path_to_TSAM_MATLAB_folder -o compiled full_path_to_TSAM_MATLAB_folder/TSAM.m 68 | 69 | Matlab will generate automatically a shell script run_compiled.sh, then you can run the TSAM.m runing 70 | sudo run_compiled.sh from the terminal (you need superuser credentials) 71 | 72 | --------------------------------------------------------------------------------