Mercurial > hg > dml-open-cliopatria
comparison cpack/dml/lib/computations.pl @ 0:718306e29690 tip
commiting public release
author | Daniel Wolff |
---|---|
date | Tue, 09 Feb 2016 21:05:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:718306e29690 |
---|---|
1 /* Part of DML (Digital Music Laboratory) | |
2 Copyright 2014-2015 Samer Abdallah, University of London | |
3 | |
4 This program is free software; you can redistribute it and/or | |
5 modify it under the terms of the GNU General Public License | |
6 as published by the Free Software Foundation; either version 2 | |
7 of the License, or (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, | |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public | |
15 License along with this library; if not, write to the Free Software | |
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 */ | |
18 | |
19 :- module(computations, | |
20 [ computation/3 | |
21 , computation_memo/3 | |
22 , vamp/3 | |
23 , transform/2 | |
24 , transform_param/3 | |
25 , sparse_to_dense/4 | |
26 , fold_commutative/3 | |
27 , map_reduce/4 | |
28 , map_reduce/5 | |
29 , unzip/3 | |
30 , pair/3 | |
31 , add/3, mul/3, div_by/3 | |
32 , fst/3, snd/3 | |
33 , with_csv_rows/3 | |
34 , csv_op/3 | |
35 , (*)/4 | |
36 , array_list/2 | |
37 , microtone_map/4 | |
38 , rows_cols/3 | |
39 , tempo_curves_stats/3 | |
40 , map_edges/3 | |
41 , csv_pitch_count_prob/5 | |
42 , pitch_hist_prob/4 | |
43 , pitch_name_number/2 | |
44 , pitch_number_name/2 | |
45 , freq_note_number/2 | |
46 , histof/4 | |
47 , histof/3 | |
48 , weighted_histof/5 | |
49 , weighted_histof/4 | |
50 ]). | |
51 | |
52 :- use_module(library(rdfutils)). | |
53 :- use_module(library(dcg/basics)). | |
54 :- use_module(library(dcg_core)). | |
55 :- use_module(library(dcg_macros)). | |
56 :- use_module(library(csvutils)). | |
57 :- use_module(library(listutils)). | |
58 :- use_module(library(lambda)). | |
59 :- use_module(library(memo)). | |
60 :- use_module(library(mlserver)). | |
61 :- use_module(library(sandbox)). | |
62 :- use_module(library(backend_json)). | |
63 :- use_module(library(real)). | |
64 | |
65 :- volatile_memo pitch_name_number(+atom,-integer). | |
66 | |
67 :- initialization <-library(pracma). | |
68 | |
69 :- rdf_meta vamp(?,r,r). | |
70 | |
71 %% vamp(+T:transform_class, +R:uri, -X:uri) is nondet. | |
72 %% vamp(-T:transform_class, -R:uri, -X:uri) is nondet. | |
73 % | |
74 % See transform/2 for values transform_class type. | |
75 vamp(Class,In,Out) :- | |
76 transform(Class,F), | |
77 computation(F,In,Out). | |
78 | |
79 %% transform(+T:transform_class, -R:uri) is det. | |
80 %% transform(-T:transform_class, -R:uri) is nondet. | |
81 % | |
82 % Mapping between short transform descriptors and full VAMP transform URIs for | |
83 % transforms currently known to the system. Currently recognised transform classes are: | |
84 % == | |
85 % transform_class ---> transcription % equivalent to transcription(0) | |
86 % ; transcription({0,1}) % 0: semitone, 1:microtonal | |
87 % ; beats({beatroot,qm}) % beats using one of two plugins | |
88 % ; beats % beats using any plugin | |
89 % ; tempo | |
90 % ; chords | |
91 % ; chord_notes | |
92 % ; key | |
93 % ; tonic | |
94 % ; chromagram | |
95 % ; mfcc. | |
96 % == | |
97 transform(Class,Transform) :- | |
98 ground(Class), !, | |
99 transforms(Class,Transforms), | |
100 member(Transform,Transforms). | |
101 transform(Class,Transform) :- | |
102 transform1(Class,Transform). | |
103 | |
104 % memoised collection of all transforms | |
105 :- volatile_memo transforms(+ground,-list(atom)). | |
106 transforms(Class,Transforms) :- | |
107 findall(T,transform1(Class,T),Transforms). | |
108 | |
109 %% transform1(-Class:transform_class,-R:uri) is nondet. | |
110 % Searches the RDF database for resources of class vamp:Transform which | |
111 % match the various transform classes. See transform/2. | |
112 transform1(beats,Transform) :- transform1(beats(_),Transform). | |
113 transform1(transcription,Transform) :- transform1(transcription(0),Transform). | |
114 transform1(transcription(Fine),Transform) :- | |
115 transform1(notes,Transform), | |
116 transform_param(Transform,finetune,Lit), | |
117 literal_number(Lit,Fine). | |
118 | |
119 transform1(Class,Transform) :- | |
120 def_transform(Class,Plugin,Output), | |
121 rdf(Transform,vamp:plugin,Plugin), | |
122 rdf(Transform,vamp:output,Output). | |
123 | |
124 :- rdf_meta transform_param(r,r,-). | |
125 transform_param(Transform,ParamId,Value) :- | |
126 rdf(Transform,vamp:parameter_binding,Binding), | |
127 rdf(Binding,vamp:parameter,Param), | |
128 rdf(Param,vamp:identifier,literal(ParamId)), | |
129 rdf(Binding,vamp:value,literal(Value)). | |
130 | |
131 | |
132 :- rdf_meta def_transform(-,r,r). | |
133 | |
134 % transform class, plugin, output | |
135 def_transform(notes, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_notes'). | |
136 def_transform(pitch_activation, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_pitchactivation'). | |
137 def_transform(silvet_timefreq, vamp_plugins:'silvet#silvet', vamp_plugins:'silvet#silvet_output_timefreq'). | |
138 def_transform(beats(beatroot), vamp_plugins:'beatroot-vamp#beatroot', vamp_plugins:'beatroot-vamp#beatroot_output_beats'). | |
139 def_transform(beats(qm), vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_beats'). | |
140 def_transform(tempo, vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_tempo'). | |
141 def_transform(onset_dfn(tempo), vamp_plugins:'qm-vamp-plugins#qm-tempotracker', vamp_plugins:'qm-vamp-plugins#qm-tempotracker_output_detection_fn'). | |
142 def_transform(chords, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_simplechord'). | |
143 def_transform(chord_notes, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_chordnotes'). | |
144 def_transform(harmonic_change, vamp_plugins:'nnls-chroma#chordino', vamp_plugins:'nnls-chroma#chordino_output_harmonicchange'). | |
145 def_transform(key, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_key'). | |
146 def_transform(key_strength, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_keystrength'). | |
147 def_transform(tonic, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_tonic'). | |
148 def_transform(mode, vamp_plugins:'qm-vamp-plugins#qm-keydetector', vamp_plugins:'qm-vamp-plugins#qm-keydetector_output_mode'). | |
149 def_transform(mfcc, vamp_plugins:'qm-vamp-plugins#qm-mfcc', vamp_plugins:'qm-vamp-plugins#qm-mfcc_output_coefficients'). | |
150 def_transform(mfcc_means, vamp_plugins:'qm-vamp-plugins#qm-mfcc', vamp_plugins:'qm-vamp-plugins#qm-mfcc_output_means'). | |
151 def_transform(onsets, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_onsets'). | |
152 def_transform(onset_dfn, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_detection_fn'). | |
153 def_transform(onset_smoothed_dfn, vamp_plugins:'qm-vamp-plugins#qm-onsetdetector',vamp_plugins:'qm-vamp-plugins#qm-onsetdetector_output_smoothed_df'). | |
154 def_transform(chromagram, vamp_plugins:'qm-vamp-plugins#qm-chromagram', vamp_plugins:'qm-vamp-plugins#qm-chromagram_output_chromagram'). | |
155 def_transform(chromameans, vamp_plugins:'qm-vamp-plugins#qm-chromagram', vamp_plugins:'qm-vamp-plugins#qm-chromagram_output_chromameans'). | |
156 def_transform(chromagram(upper), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_chroma'). | |
157 def_transform(chromagram(bass), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_basschroma'). | |
158 def_transform(chromagram(both), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_bothchroma'). | |
159 def_transform(spectrogram(semitone), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_semitonespectrum'). | |
160 def_transform(spectrogram(log_freq), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_logfreqspec'). | |
161 def_transform(spectrogram(tuned), vamp_plugins:'nnls-chroma#nnls-chroma', vamp_plugins:'nnls-chroma#nnls-chroma_output_tunedlogfreqspec'). | |
162 def_transform(melody, vamp_plugins:'mtg-melodia#melodia', vamp_plugins:'mtg-melodai#melodia_output_melody'). | |
163 def_transform(spectrogram(const_q), vamp_plugins:'qm-vamp-plugins#qm-constantq', vamp_plugins:'qm-vamp-plugins#qm-constantq_output_constantq'). | |
164 def_transform(segments, vamp_plugins:'qm-vamp-plugins#qm-segmenter', vamp_plugins:'qm-vamp-plugins#qm-segmenter_output_segmentation'). | |
165 def_transform(speech_music, vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter', | |
166 vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter_output_segmentation'). | |
167 def_transform(speech_music_dfn, vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter', | |
168 vamp_plugins:'bbc-vamp-plugins#bbc-speechmusic-segmenter_output_skewness'). | |
169 | |
170 | |
171 %% computation_memo(+Transform:uri,+Input:uri,-Output:uri) is det. | |
172 % Memoised functional Relation between transforms, inputs and outputs. | |
173 | |
174 :- multifile do_computation/3. | |
175 | |
176 :- rdf_meta computation_memo(r,r,r). | |
177 computation_memo(Fn,Input,Output) :- | |
178 must_be(atom,Fn), | |
179 must_be(atom,Input), | |
180 must_be(var,Output), | |
181 ( computation(Fn,Input,Output) -> true | |
182 ; memo:timed(computations:do_computation(Fn,Input,Output),comp(_,Time,Dur)), | |
183 format_time(atom(Timestamp),'%FT%T%:z',Time), | |
184 memo:hostname(Host), | |
185 phrase( ( vamp:computation_triples(Comp,Input,Fn,Output), | |
186 vamp:rdf(Comp,dml:'comp/time',literal(type(xsd:dateTime,Timestamp))), | |
187 vamp:rdf(Comp,dml:'comp/duration',literal(type(xsd:float,Dur))), | |
188 vamp:rdf(Comp,dml:'comp/host',literal(Host)) | |
189 ), Triples,[]), | |
190 forall(member(rdf(S,P,O),Triples), rdf_assert(S,P,O,vamp_memo)) | |
191 ). | |
192 | |
193 | |
194 %% computation(-Transform:uri,-Input:uri,-Output:uri) is nondet. | |
195 % Relation between transforms, inputs and outputs using RDF database | |
196 % of existing computations. | |
197 | |
198 :- rdf_meta computation(r,r,r). | |
199 computation(Fn,Input,Output) :- nonvar(Output), !, | |
200 rdf(Comp,dml:'comp/output',Output), | |
201 rdf(Comp,dml:'comp/function',Fn), | |
202 rdf(Comp,dml:'comp/input',Input). | |
203 | |
204 computation(Fn,Input,Output) :- nonvar(Input), !, | |
205 rdf(Comp,dml:'comp/input',Input), | |
206 rdf(Comp,dml:'comp/function',Fn), | |
207 rdf(Comp,dml:'comp/output',Output). | |
208 | |
209 computation(Fn,Input,Output) :- | |
210 rdf(Comp,dml:'comp/input',Input), | |
211 rdf(Comp,dml:'comp/function',Fn), | |
212 rdf(Comp,dml:'comp/output',Output). | |
213 | |
214 % ------------ Framework for doing computations on CSV files ----------- | |
215 :- meta_predicate with_csv_rows(2,+,-). | |
216 with_csv_rows(Pred,CSV,Result) :- | |
217 insist(uri_to_csv(CSV,Rows)), | |
218 insist(call(Pred,Rows,Result), failed_on_csv(Pred,CSV)). | |
219 | |
220 csv_op(Op,CSV,Result) :- | |
221 ( memoise(Op) | |
222 -> csv_op_memo(Op,CSV,Result) % ,_-ok) | |
223 ; with_csv_rows(row_op(Op),CSV,Result) | |
224 ), | |
225 debug(computations(item),'Done csv_op(~q,~q).',[Op,CSV]). | |
226 | |
227 sandbox:safe_primitive(computations:csv_op(_,_,_)). | |
228 | |
229 :- persistent_memo csv_op_memo(+ground,+atom,-ground). | |
230 csv_op_memo(Op,CSV,Result) :- with_csv_rows(row_op(Op),CSV,Result). | |
231 | |
232 :- initialization time(memo_attach(memo(computations2),[])). | |
233 | |
234 memoise(pitch_hist(_)). | |
235 memoise(freq_hist(_,_)). | |
236 memoise(tempo_hist(_,_)). | |
237 memoise(uniform_tempo(_)). | |
238 memoise(uniform_tempo_r(_)). | |
239 memoise(normalised_tempo(_)). | |
240 memoise(normalised_tempo_r(_)). | |
241 | |
242 row_op(id,Rows,Rows) :- !. | |
243 row_op(column(N),Rows,Vals) :- !, maplist(arg(N),Rows,Vals). | |
244 row_op(array,Rows,Array) :- !, maplist(row_list(_),Rows,Array). | |
245 row_op(chord_hist,Rows,Hist) :- !, histof(Chord,T,member(row(T,Chord),Rows),Hist). | |
246 row_op(pitch_hist(none),Rows,Hist) :- !, histof(Pitch,t(T,Dur),note(Rows,T,Dur,Pitch),Hist). | |
247 row_op(pitch_hist(W),Rows,Hist) :- !, weighted_histof(Weight,Pitch,t(T,Dur),weighted_note(W,Rows,T,Dur,Pitch,Weight),Hist). | |
248 row_op(beat_times,Rows,Times) :- !, row_op(column(1),Rows,Times). | |
249 row_op(onset_times,Rows,Times) :- !, row_op(column(1),Rows,Times). | |
250 row_op(tempo,Rows,Tempo) :- !, maplist(row_pair(1,2),Rows,Tempo). | |
251 row_op(uniform_tempo(DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(ml,cubic,DT,Tempo,Samples). | |
252 row_op(uniform_tempo_r(DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(r,cubic,DT,Tempo,Samples). | |
253 row_op(uniform_tempo(Meth,DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(ml,Meth,DT,Tempo,Samples). | |
254 row_op(uniform_tempo_r(Meth,DT),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), uniform_sample(r,Meth,DT,Tempo,Samples). | |
255 row_op(normalised_tempo(N),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), normalised_sample(ml,N,Tempo,Samples). | |
256 row_op(normalised_tempo_r(N),Rows,Samples) :- !, row_op(tempo,Rows,Tempo), normalised_sample(r,N,Tempo,Samples). | |
257 row_op(tempo_hist(DT,Map),Rows,Edges-Counts) :- !, | |
258 row_op(uniform_tempo(DT),Rows,_-Tempo), | |
259 M===Map, | |
260 [arr(Counts), arr(Edges)] === | |
261 deal(accumhist(flatten(feval(M,Tempo)),1,cardr(M)), flatten(edges(M))). | |
262 | |
263 row_op(tempo_hist_r(DT,Map),Rows,Edges-Counts) :- !, | |
264 map_to_r_edges(Map,REdges), | |
265 row_op(uniform_tempo_r(DT),Rows,_-Tempo), | |
266 Counts <- table(cut(Tempo,breaks=REdges)), | |
267 Edges <- REdges. | |
268 % memberchk(counts=Counts,Hist), | |
269 % memberchk(breaks=Edges,Hist). | |
270 | |
271 row_op(freq_hist(Map1,W),Rows,Counts) :- | |
272 column(transcription,freq,J), | |
273 ( W=none | |
274 -> maplist(arg(J),Rows,Freqs), Weights=1 | |
275 ; column(transcription,W,I), | |
276 rows_cols([J,I],Rows,[Freqs,Weights]) | |
277 ), | |
278 Map===Map1, % evaluate map and keep in Matlab workspace | |
279 X=feval(Map,12*log2(Freqs)-(12*log2(440)-69)), | |
280 array_list(accumhist(flatten(X),flatten(Weights),cardr(Map)),Counts). | |
281 | |
282 row_op(freq_hist_r(Map1,W),Rows,Counts) :- | |
283 column(transcription,freq,J), | |
284 map_to_r_edges(Map1,REdges), | |
285 Pitches=12*log2(Freqs)-(12*log2(440)-69), | |
286 ( W=none | |
287 -> maplist(arg(J),Rows,Freqs), | |
288 Hist <- hist(Pitches,breaks=REdges,plot=0) | |
289 ; column(transcription,W,I), | |
290 rows_cols([J,I],Rows,[Freqs,Weights]), | |
291 Hist <- hist(Pitches,Weights,breaks=REdges,plot=0) | |
292 ), | |
293 memberchk(counts=Counts,Hist). | |
294 | |
295 map_edges(r,Map,Edges) :- | |
296 map_to_r_edges(Map,Expr), | |
297 Edges <- Expr. | |
298 map_edges(ml,Map,Edges) :- | |
299 array_list(edges(Map),Edges). | |
300 | |
301 map_to_r_edges(expmap(Min,Max,N),sapply(seq(log(Min),log(Max),len=N+1),exp)). | |
302 map_to_r_edges(binmap(Min,Max,N),seq(Min-HalfWidth,Max+HalfWidth,len=N+1)) :- HalfWidth=(Max-Min)/(2*(N-1)). | |
303 | |
304 column(Format, Name, Number) :- csv(Format,Row), arg(Number,Row,Name). | |
305 csv(transcription, row(time,dur,freq,vel,pitch)). | |
306 | |
307 gather(P,Rows,Xs) :- findall(X,(member(R,Rows),call(P,R,X)),Xs). | |
308 | |
309 | |
310 microtone_map(Min,Max,Res,binmap(Min,Max,N)) :- N is (Max-Min)*Res+1. | |
311 | |
312 % qfreq(Q,Rows,T,Dur,QFreq) :- member(row(T,Dur,Freq,_,_),Rows), qlogfreq(Q,Freq,QFreq). | |
313 % weighted_qfreq(dur,Q,Rows,T,Dur,QFreq,Dur) :- member(row(T,Dur,Freq,_,_),Rows), qlogfreq(Q,Freq,QFreq). | |
314 % weighted_qfreq(vel,Q,Rows,T,Dur,QFreq,Vel) :- member(row(T,Dur,Freq,Vel,_),Rows), qlogfreq(Q,Freq,QFreq). | |
315 % qlogfreq(Q,In,Out) :- B is 12/log(2), Out is 69+round(Q*B*(log(In)-log(440)))/Q. | |
316 % goal_expansion(qlogfreq(Q,In,Out), Out is 69+round(Q*B*(log(In)-A))/Q) :- B is 12/log(2), A=log(440). | |
317 | |
318 uniform_sample(DT,In,Out) :- uniform_sample(ml,linear,DT,In,Out). | |
319 | |
320 uniform_sample(_,_,_,[Time-Val],[Time]-[Val]) :- !. | |
321 uniform_sample(Lang,Meth,DT,Pairs,Times1-Vals1) :- | |
322 unzip(Pairs,Times,Vals), | |
323 aggregate(max(T), member(T,Times), MaxT), | |
324 interp1(Lang,Meth,0:DT:MaxT,Times,Vals,Times1,Vals1). | |
325 | |
326 normalised_sample(N,In,Out) :- normalised_sample(ml,N,In,Out). | |
327 | |
328 normalised_sample(_,N,[Time-Val],Times-Vals) :- !, | |
329 rep(N,Time,Times), | |
330 rep(N,Val,Vals). | |
331 normalised_sample(Lang,N,Pairs,Times1-Vals1) :- | |
332 unzip(Pairs,Times,Vals), | |
333 aggregate(max(T), member(T,Times), MaxT), | |
334 interp1(Lang,cubic,linspace(0,MaxT,N),Times,Vals,Times1,Vals1). | |
335 | |
336 interp1(ml,Meth,TSpec,Times,Vals,Times1,Vals1) :- | |
337 length(Times,N), | |
338 (N<4 -> Method=q(linear); Method=q(Meth)), | |
339 T1===flatten(TSpec), | |
340 [arr(Times1), arr(Vals1)]===deal(T1,interp1(Times,Vals,T1,Method)). | |
341 interp1(r,Meth,TSpec,Times,Vals,Times1,Vals1) :- | |
342 ml_r(TSpec,RTSpec), | |
343 length(Times,N), | |
344 (N<4 -> Method = +linear; Method = +Meth), | |
345 Times1 <- RTSpec, | |
346 Vals1 <- interp1(Times,Vals,Times1,Method). | |
347 | |
348 ml_r(X1:DX:X2, seq(X1,X2,DX)). | |
349 ml_r(linspace(X1,X2,N), seq(X1,X2,len=N)). | |
350 | |
351 array_list(Array,List) :- arr(List)===flatten(Array). | |
352 | |
353 :- meta_predicate '*'(2,2,+,-). | |
354 *(F1,F2,X,Y) :- call(F1,X,Z), call(F2,Z,Y). | |
355 | |
356 note(Rows,T,Dur,NN) :- member(row(T,Dur,_,_,Pitch),Rows), pitch_name_number(Pitch,NN). | |
357 | |
358 weighted_note(dur,Rows,T,Dur,NN,Dur) :- member(row(T,Dur,_,_,Pitch),Rows), pitch_name_number(Pitch,NN). | |
359 weighted_note(vel,Rows,T,Dur,NN,Vel) :- member(row(T,Dur,_,Vel,Pitch),Rows), pitch_name_number(Pitch,NN). | |
360 weighted_note(dur*vel,Rows,T,Dur,NN,Weight) :- | |
361 member(row(T,Dur,_,Vel,Pitch),Rows), pitch_name_number(Pitch,NN), | |
362 Weight is Dur*Vel. | |
363 | |
364 | |
365 tempo_curves_stats(ml,Curves, _{means:Means,std_devs:StdDevs}) :- | |
366 Data===arr(Curves), | |
367 array_list(mean(Data,2),Means), | |
368 array_list(std(Data,0,2),StdDevs). | |
369 | |
370 tempo_curves_stats(r,Curves, _{means:Means,std_devs:Stds}) :- | |
371 data <- Curves, | |
372 Means <- apply(data,2,mean), | |
373 Stds <- apply(data,2,sd). | |
374 | |
375 :- meta_predicate histof(-,0,-) | |
376 , histof(-,-,0,-) | |
377 , weighted_histof(-,-,0,-) | |
378 , weighted_histof(-,-,-,0,-) | |
379 . | |
380 | |
381 %% histof(@Dom:A,+Goal:callable,-Hist:list(pair(A,natural))) is nondet. | |
382 % Compile a histogram over values taken by the variable Dom while enumerating | |
383 % all solutions of Goal. Repeated solutions of Goal with the same values | |
384 % count as distinct observations. See also histof/4. | |
385 histof(Dom,Goal,Hist) :- | |
386 setof(Dom-N,aggregate(count,Goal,N),Hist). | |
387 | |
388 %% histof(@Dom:A,@Disc:_,+Goal:callable,-Hist:list(pair(A,natural))) is nondet. | |
389 % Compile a histogram over values taken by the variable Dom while enumerating | |
390 % all solutions of Goal. The value of Disc is used to discriminate between | |
391 % solutions of Goal with the same value of Dom. See also histof/3 and aggregate/4 | |
392 % for more information about discriminator variables. | |
393 histof(Dom,Disc,Goal,Hist) :- | |
394 setof(Dom-N,aggregate(count,Disc,Goal,N),Hist). | |
395 | |
396 weighted_histof(W,Dom,Goal,Hist) :- | |
397 setof(Dom-N,aggregate(sum(W),Goal,N),Hist). | |
398 | |
399 weighted_histof(W,Dom,Disc,Goal,Hist) :- | |
400 setof(Dom-N,aggregate(sum(W),Disc,Goal,N),Hist). | |
401 | |
402 sparse_to_dense(Min,Max,Hist,Counts) :- | |
403 s_to_d(Min,Max,Hist,Counts). | |
404 | |
405 s_to_d(I,Max,[],[]) :- I>Max, !. | |
406 s_to_d(I,Max,[],[0|Counts]) :- !, succ(I,J), s_to_d(J,Max,[],Counts). | |
407 s_to_d(I,Max,[I-C|Hist],[C|Counts]) :- !, succ(I,J), s_to_d(J,Max,Hist,Counts). | |
408 s_to_d(I,Max,Hist,[0|Counts]) :- succ(I,J), s_to_d(J,Max,Hist,Counts). | |
409 | |
410 | |
411 add(X,Y,Z) :- Z is X+Y. | |
412 | |
413 :- meta_predicate | |
414 map_reduce(1,2,3,-), | |
415 map_reduce(1,2,3,-,-), | |
416 fold_commutative(3,+,-). | |
417 | |
418 %% map_reduce(+Generator:pred(-R), +Mapper:pred(+R,-A), +Reducer:pred(+A,+A,-A), -Result:A, -Errors:list(error_report(R))) is det. | |
419 %% map_reduce(+Generator:pred(-R), +Mapper:pred(+R,-A), +Reducer:pred(+A,+A,-A), -Result:A) is semidet. | |
420 % | |
421 % Simple implementation of map-reduce: Mapper is applied to each item produced by Generator | |
422 % and the results all combined using Reducer. Mapper should be a deterministic predicate. | |
423 % Failures and exceptions encountered in the mapping phase are reported in Errors. | |
424 % However, if the items are successfully mapped, this predicate fails. | |
425 % Any choice points left by mapper after its first solution are cut. | |
426 % | |
427 % == | |
428 % error_report(R) ---> failed(R); error(R,exception). | |
429 % == | |
430 map_reduce(Finder,Mapper,Reducer,Result) :- | |
431 map_reduce(Finder,Mapper,Reducer,Result,_). | |
432 | |
433 map_reduce(Finder,Mapper,Reducer,Result,Errors-Failures) :- | |
434 setof(X,call(Finder,X),Xs), | |
435 maplist(safe_call(Mapper),Xs,Ys), | |
436 partition_ok(Ys,Ok,Errors,Failures), | |
437 insist(fold_commutative(Reducer,Ok,Result)). | |
438 | |
439 %% safe_call(+P:pred(+A,-B), +X:A, -Y:result(A,B)) is det. | |
440 % | |
441 % Call binary predicate P with arguments of type A and B. The result | |
442 % term Y is of type | |
443 % == | |
444 % result(A,B) ---> ok(B); failed(A); error(A,exception). | |
445 % == | |
446 % and encodes the result of the call, including the input value that | |
447 % caused any failure or exception. | |
448 safe_call(Mapper,X,Z) :- | |
449 ( catch((call(Mapper,X,Y), Z=ok(Y)), Ex, | |
450 (Ex=abort_map -> throw(map_aborted); Z=error(X,Ex))), ! | |
451 ; Z=failed(X) | |
452 ). | |
453 | |
454 partition_ok([],[],[],[]). | |
455 partition_ok([In|Ins],Goods,Bads,Uglies) :- | |
456 ( In=ok(X) | |
457 -> Goods=[X|Goods1], partition_ok(Ins,Goods1,Bads,Uglies) | |
458 ; In=error(_,_) | |
459 -> Bads=[In|Bads1], partition_ok(Ins,Goods,Bads1,Uglies) | |
460 ; In=failed(X) | |
461 -> Uglies=[X|Uglies1], partition_ok(Ins,Goods,Bads,Uglies1) | |
462 ). | |
463 | |
464 fold_commutative(Op,Items,Result) :- | |
465 Items=[I1|Rest], | |
466 seqmap(Op,Rest,I1,Result), !. | |
467 | |
468 freq_note_number(F,N) :- N is 69+round(12*log(F/440)/log(2)). | |
469 | |
470 pitch_name_number(Name,Number) :- | |
471 atom_codes(Name,Chars), | |
472 phrase(note(Number),Chars). | |
473 | |
474 pitch_number_name(Number,Name) :- | |
475 phrase(note(Number),Chars), | |
476 atom_codes(Name,Chars). | |
477 | |
478 :- use_module(library(clpfd)). | |
479 note(Num) --> | |
480 [Nom], ({Mod=0}; [0'#],{Mod=1}), | |
481 { PC in 0..11, | |
482 Num #= 12*(Oct+1)+PC+Mod, | |
483 nom_semis(Nom,PC) | |
484 }, | |
485 integer(Oct). | |
486 | |
487 nom_semis(0'C,0). | |
488 nom_semis(0'D,2). | |
489 nom_semis(0'E,4). | |
490 nom_semis(0'F,5). | |
491 nom_semis(0'G,7). | |
492 nom_semis(0'A,9). | |
493 nom_semis(0'B,11). | |
494 | |
495 unzip(Pairs,Xs,Ys) :- maplist(pair,Xs,Ys,Pairs). | |
496 pair(X,Y,X-Y). | |
497 | |
498 row_pair(I,J,Row,X-Y) :- arg(I,Row,X), arg(J,Row,Y). | |
499 row_list(N,Row,List) :- functor(Row,_,N), Row=..[_|List]. | |
500 rows_cols(Is,[],Cols) :- !, maplist(nil,Is,Cols). | |
501 rows_cols(Is,[R|Rs],Cols) :- | |
502 ( maplist(arg_cons(R),Is,Tails,Cols) | |
503 -> rows_cols(Is,Rs,Tails) | |
504 ; fail % rows_cols(Is,Rs,Cols) | |
505 ). | |
506 | |
507 arg_cons(Row,I,T,[X|T]) :- arg(I,Row,X). | |
508 nil(_,[]). | |
509 | |
510 fst(F,K1-V,K2-V) :- call(F,K1,K2). | |
511 snd(F,K-V1,K-V2) :- call(F,V1,V2). | |
512 div_by(K,X,Y) :- Y is X/K. | |
513 | |
514 mul(X,Y,Z) :- Z is round(X*Y). | |
515 | |
516 :- dynamic pitch_hist_table/5, pitch_hist_tabled/1. | |
517 | |
518 csv_pitch_count_prob(W,CSV,Pitch,Count,Prob) :- | |
519 must_be(ground,W), | |
520 ( pitch_hist_tabled(W) -> true | |
521 ; table_pitch_hist(W) | |
522 ), | |
523 pitch_hist_table(W,CSV,Pitch,Count,Prob). | |
524 | |
525 table_pitch_hist(W) :- | |
526 retractall(pitch_hist_table_cached(W)), | |
527 forall( browse(csv_op_memo(pitch_hist(W),CSV,Hist)), | |
528 ( retractall(pitch_hist_table(W,CSV,_,_,_)), | |
529 forall( pitch_hist_prob(Hist,Pitch,Count,Prob), | |
530 assert(pitch_hist_table(W,CSV,Pitch,Count,Prob))))), | |
531 assert(pitch_hist_tabled(W)). | |
532 | |
533 pitch_hist_prob(Hist,Pitch,Count,Prob) :- | |
534 unzip(Hist,_,Counts), | |
535 sumlist(Counts,Total), | |
536 member(Pitch-Count,Hist), | |
537 Prob is Count/Total. |