Daniel@0
|
1 /* Part of DML (Digital Music Laboratory)
|
Daniel@0
|
2 Copyright 2014-2015 Samer Abdallah, University of London
|
Daniel@0
|
3
|
Daniel@0
|
4 This program is free software; you can redistribute it and/or
|
Daniel@0
|
5 modify it under the terms of the GNU General Public License
|
Daniel@0
|
6 as published by the Free Software Foundation; either version 2
|
Daniel@0
|
7 of the License, or (at your option) any later version.
|
Daniel@0
|
8
|
Daniel@0
|
9 This program is distributed in the hope that it will be useful,
|
Daniel@0
|
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Daniel@0
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Daniel@0
|
12 GNU General Public License for more details.
|
Daniel@0
|
13
|
Daniel@0
|
14 You should have received a copy of the GNU General Public
|
Daniel@0
|
15 License along with this library; if not, write to the Free Software
|
Daniel@0
|
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
Daniel@0
|
17 */
|
Daniel@0
|
18
|
Daniel@0
|
19 :- module(cp_score,
|
Daniel@0
|
20 [ score//2, score//3
|
Daniel@0
|
21 , sonify_ui//2
|
Daniel@0
|
22 , score_audio_player//1
|
Daniel@0
|
23 , score_audio_player//3
|
Daniel@0
|
24 , pitch_class_histogram//1
|
Daniel@0
|
25 ]).
|
Daniel@0
|
26
|
Daniel@0
|
27 :- use_module(library(http/html_write)).
|
Daniel@0
|
28 :- use_module(library(http/http_dispatch)).
|
Daniel@0
|
29 :- use_module(library(dcg_core)).
|
Daniel@0
|
30 :- use_module(library(musiclab)).
|
Daniel@0
|
31 :- use_module(library(humdrum_p2r)).
|
Daniel@0
|
32 :- use_module(library(mlserver)).
|
Daniel@0
|
33 :- use_module(library(real)).
|
Daniel@0
|
34 :- use_module(library(sandbox)).
|
Daniel@0
|
35 :- use_module(components(matlab),[]).
|
Daniel@0
|
36 :- use_module(components(r_fig),[]).
|
Daniel@0
|
37 :- use_module(components(audio),[audio_player//2]).
|
Daniel@0
|
38 :- use_module(api(score)).
|
Daniel@0
|
39
|
Daniel@0
|
40 :- set_prolog_flag(double_quotes,string).
|
Daniel@0
|
41
|
Daniel@0
|
42 %% score(+R:uri,+Width:number)// is det.
|
Daniel@0
|
43 %
|
Daniel@0
|
44 % Generates an HTML DIV element containing a rendered score. URI is assumed
|
Daniel@0
|
45 % to refer to a Humdrum file. Width is in mm and is passed to Lilypond as
|
Daniel@0
|
46 % the desired staff width.
|
Daniel@0
|
47 score(URI,Width) --> score(URI,Width,[]).
|
Daniel@0
|
48 score(URI,Width,Opts) -->
|
Daniel@0
|
49 {option(transpose(T),Opts,'P1')},
|
Daniel@0
|
50 {http_link_to_id(score_render,[uri(URI),width(Width),layout(snip),format(svg),transpose(T)],URL)},
|
Daniel@0
|
51 html(div([id=score,width='100%',height=auto],[img([src=URL],[])])).
|
Daniel@0
|
52
|
Daniel@0
|
53
|
Daniel@0
|
54 %% sonify_ui(+R:uri,+ID:hander_id)// is det
|
Daniel@0
|
55 %
|
Daniel@0
|
56 % Generates an interface for setting parameters and sonifying a Humdrum score.
|
Daniel@0
|
57 sonify_ui(URI,HandlerID) -->
|
Daniel@0
|
58 { http_link_to_id(HandlerID,[],AudioPlayerURL),
|
Daniel@0
|
59 setting_property(score:fluidsynth_rc,type(oneof(RCs))),
|
Daniel@0
|
60 setting(score:fluidsynth_rc,RC0),
|
Daniel@0
|
61 Intervals=['-P5','-d5','-P4','-M3','-m3','-M2','-m2','P1','m2','M2','m3','M3','P4','d5','P5']
|
Daniel@0
|
62 },
|
Daniel@0
|
63 html([ form([class=forms,target=player,method=get,action=AudioPlayerURL],
|
Daniel@0
|
64 [ input([type=hidden,name=uri,value=URI])
|
Daniel@0
|
65 , input([type=hidden,name=autoplay,value=true])
|
Daniel@0
|
66 %, input([type=hidden,name=format,value=ogg])
|
Daniel@0
|
67 , table([class=form],
|
Daniel@0
|
68 [ tr([ th(class=label,"Tempo scaling factor"),
|
Daniel@0
|
69 td(input([type=number,min=0,max=4,step=0.1,name=tempo,value=1],[]))])
|
Daniel@0
|
70 % , tr([ th(class=label,"Transposition in semitones"),
|
Daniel@0
|
71 % td(input([type=text,name=transpose,value='P1'],[]))])
|
Daniel@0
|
72 , tr([ th(class=label,"Transposition interval"),
|
Daniel@0
|
73 td(\html_select(transpose,Intervals,'P1'))])
|
Daniel@0
|
74 , tr([ th(class=label,"Fluidsynth initialisation"),
|
Daniel@0
|
75 td(\html_select(fluidrc,RCs,RC0))])
|
Daniel@0
|
76 ])
|
Daniel@0
|
77 , input([type=submit,class=btn,value="Sonify"],[])
|
Daniel@0
|
78 , iframe([name=player,seamless=seamless,style="display:inline-block;height:3.2em"],[])
|
Daniel@0
|
79 ])
|
Daniel@0
|
80 ]).
|
Daniel@0
|
81
|
Daniel@0
|
82 html_select(Name,Values,Initial) -->
|
Daniel@0
|
83 html(select([name=Name], \seqmap(html_option(Initial),Values))).
|
Daniel@0
|
84
|
Daniel@0
|
85 html_option(X,X) --> !, html(option(selected=selected,X)).
|
Daniel@0
|
86 html_option(_,X) --> html(option(X)).
|
Daniel@0
|
87
|
Daniel@0
|
88
|
Daniel@0
|
89 %% score_audio_player(+R:uri,+As:list(html_attrib),+Ps:list(http_param))// is det.
|
Daniel@0
|
90 %% score_audio_player(+R:uri)// is det.
|
Daniel@0
|
91 %
|
Daniel@0
|
92 % Generates an HTML 5 audio player to play a sonified score. Ps is a list
|
Daniel@0
|
93 % of HTTP parameters to be passed ultimately to score_sonify/1. As is a list
|
Daniel@0
|
94 % of HTML element attributes to be added to the HTML AUDIO element.
|
Daniel@0
|
95 score_audio_player(URI) --> score_audio_player(URI,[],[]).
|
Daniel@0
|
96 score_audio_player(URI,Attr,Params) -->
|
Daniel@0
|
97 {maplist(score_audio_link(URI,Params),[ogg],Links)},
|
Daniel@0
|
98 audio_player(Links, Attr).
|
Daniel@0
|
99
|
Daniel@0
|
100 score_audio_link(URI,Params,Fmt,URL-just(Fmt)) :- get_link(URI,a(Params)-Fmt,URL).
|
Daniel@0
|
101
|
Daniel@0
|
102
|
Daniel@0
|
103 %% pitch_class_histogram(+Lang:oneof([ml,r]),+R:uri)// is det.
|
Daniel@0
|
104 %
|
Daniel@0
|
105 % Generates a graphical rendering of the pitch class histogram computed
|
Daniel@0
|
106 % from the given URI, assumed to refer to a Humdrum file. Figure is
|
Daniel@0
|
107 % generated using Matlab.
|
Daniel@0
|
108 pitch_class_histogram(URI) -->
|
Daniel@0
|
109 cp_r_fig:figure( cp_score:pitch_class_histogram(r,URI), 12, 6, []).
|
Daniel@0
|
110 % cp_matlab:figure( cp_score:pitch_class_histogram(ml,URI), 12, 6, []).
|
Daniel@0
|
111
|
Daniel@0
|
112 pitch_class_histogram(Lang,URI) :-
|
Daniel@0
|
113 hum_uri_path(URI,Path),
|
Daniel@0
|
114 kern_pc_hist(Path,Hist1),
|
Daniel@0
|
115 findall(PCN-X, (member(PC-X,Hist1), pitch_class_number(PC,PCN)), Hist2),
|
Daniel@0
|
116 numlist(0,11,PCNs),
|
Daniel@0
|
117 maplist(pc_number_name,PCNs,PCNames),
|
Daniel@0
|
118 maplist(pcn_count(Hist2),PCNs,Counts),
|
Daniel@0
|
119 ( Lang=r
|
Daniel@0
|
120 -> r(par(ps=10,mar=[2.1,2.2,1.1,0])),
|
Daniel@0
|
121 r(barplot(Counts,'names.arg'=PCNames,main="Pitch class histogram"))
|
Daniel@0
|
122 ; Lang=ml
|
Daniel@0
|
123 -> ?? ( bar(PCNs,Counts);
|
Daniel@0
|
124 xticks(PCNs,cell(PCNames));
|
Daniel@0
|
125 title("Pitch class histogram");
|
Daniel@0
|
126 caxis([0,3]))
|
Daniel@0
|
127 ).
|
Daniel@0
|
128
|
Daniel@0
|
129 pcn_count(Hist,PCN,Count) :- member(PCN-Count,Hist) -> true; Count=0.
|
Daniel@0
|
130
|
Daniel@0
|
131
|
Daniel@0
|
132 sandbox:safe_primitive(cp_score:pitch_class_histogram(_,_)).
|