Daniel@0: /* Part of DML (Digital Music Laboratory) Daniel@0: Copyright 2014-2015 Samer Abdallah, University of London Daniel@0: Daniel@0: This program is free software; you can redistribute it and/or Daniel@0: modify it under the terms of the GNU General Public License Daniel@0: as published by the Free Software Foundation; either version 2 Daniel@0: of the License, or (at your option) any later version. Daniel@0: Daniel@0: This program is distributed in the hope that it will be useful, Daniel@0: but WITHOUT ANY WARRANTY; without even the implied warranty of Daniel@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Daniel@0: GNU General Public License for more details. Daniel@0: Daniel@0: You should have received a copy of the GNU General Public Daniel@0: License along with this library; if not, write to the Free Software Daniel@0: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Daniel@0: */ Daniel@0: Daniel@0: :- module(cp_score, Daniel@0: [ score//2, score//3 Daniel@0: , sonify_ui//2 Daniel@0: , score_audio_player//1 Daniel@0: , score_audio_player//3 Daniel@0: , pitch_class_histogram//1 Daniel@0: ]). Daniel@0: Daniel@0: :- use_module(library(http/html_write)). Daniel@0: :- use_module(library(http/http_dispatch)). Daniel@0: :- use_module(library(dcg_core)). Daniel@0: :- use_module(library(musiclab)). Daniel@0: :- use_module(library(humdrum_p2r)). Daniel@0: :- use_module(library(mlserver)). Daniel@0: :- use_module(library(real)). Daniel@0: :- use_module(library(sandbox)). Daniel@0: :- use_module(components(matlab),[]). Daniel@0: :- use_module(components(r_fig),[]). Daniel@0: :- use_module(components(audio),[audio_player//2]). Daniel@0: :- use_module(api(score)). Daniel@0: Daniel@0: :- set_prolog_flag(double_quotes,string). Daniel@0: Daniel@0: %% score(+R:uri,+Width:number)// is det. Daniel@0: % Daniel@0: % Generates an HTML DIV element containing a rendered score. URI is assumed Daniel@0: % to refer to a Humdrum file. Width is in mm and is passed to Lilypond as Daniel@0: % the desired staff width. Daniel@0: score(URI,Width) --> score(URI,Width,[]). Daniel@0: score(URI,Width,Opts) --> Daniel@0: {option(transpose(T),Opts,'P1')}, Daniel@0: {http_link_to_id(score_render,[uri(URI),width(Width),layout(snip),format(svg),transpose(T)],URL)}, Daniel@0: html(div([id=score,width='100%',height=auto],[img([src=URL],[])])). Daniel@0: Daniel@0: Daniel@0: %% sonify_ui(+R:uri,+ID:hander_id)// is det Daniel@0: % Daniel@0: % Generates an interface for setting parameters and sonifying a Humdrum score. Daniel@0: sonify_ui(URI,HandlerID) --> Daniel@0: { http_link_to_id(HandlerID,[],AudioPlayerURL), Daniel@0: setting_property(score:fluidsynth_rc,type(oneof(RCs))), Daniel@0: setting(score:fluidsynth_rc,RC0), Daniel@0: Intervals=['-P5','-d5','-P4','-M3','-m3','-M2','-m2','P1','m2','M2','m3','M3','P4','d5','P5'] Daniel@0: }, Daniel@0: html([ form([class=forms,target=player,method=get,action=AudioPlayerURL], Daniel@0: [ input([type=hidden,name=uri,value=URI]) Daniel@0: , input([type=hidden,name=autoplay,value=true]) Daniel@0: %, input([type=hidden,name=format,value=ogg]) Daniel@0: , table([class=form], Daniel@0: [ tr([ th(class=label,"Tempo scaling factor"), Daniel@0: td(input([type=number,min=0,max=4,step=0.1,name=tempo,value=1],[]))]) Daniel@0: % , tr([ th(class=label,"Transposition in semitones"), Daniel@0: % td(input([type=text,name=transpose,value='P1'],[]))]) Daniel@0: , tr([ th(class=label,"Transposition interval"), Daniel@0: td(\html_select(transpose,Intervals,'P1'))]) Daniel@0: , tr([ th(class=label,"Fluidsynth initialisation"), Daniel@0: td(\html_select(fluidrc,RCs,RC0))]) Daniel@0: ]) Daniel@0: , input([type=submit,class=btn,value="Sonify"],[]) Daniel@0: , iframe([name=player,seamless=seamless,style="display:inline-block;height:3.2em"],[]) Daniel@0: ]) Daniel@0: ]). Daniel@0: Daniel@0: html_select(Name,Values,Initial) --> Daniel@0: html(select([name=Name], \seqmap(html_option(Initial),Values))). Daniel@0: Daniel@0: html_option(X,X) --> !, html(option(selected=selected,X)). Daniel@0: html_option(_,X) --> html(option(X)). Daniel@0: Daniel@0: Daniel@0: %% score_audio_player(+R:uri,+As:list(html_attrib),+Ps:list(http_param))// is det. Daniel@0: %% score_audio_player(+R:uri)// is det. Daniel@0: % Daniel@0: % Generates an HTML 5 audio player to play a sonified score. Ps is a list Daniel@0: % of HTTP parameters to be passed ultimately to score_sonify/1. As is a list Daniel@0: % of HTML element attributes to be added to the HTML AUDIO element. Daniel@0: score_audio_player(URI) --> score_audio_player(URI,[],[]). Daniel@0: score_audio_player(URI,Attr,Params) --> Daniel@0: {maplist(score_audio_link(URI,Params),[ogg],Links)}, Daniel@0: audio_player(Links, Attr). Daniel@0: Daniel@0: score_audio_link(URI,Params,Fmt,URL-just(Fmt)) :- get_link(URI,a(Params)-Fmt,URL). Daniel@0: Daniel@0: Daniel@0: %% pitch_class_histogram(+Lang:oneof([ml,r]),+R:uri)// is det. Daniel@0: % Daniel@0: % Generates a graphical rendering of the pitch class histogram computed Daniel@0: % from the given URI, assumed to refer to a Humdrum file. Figure is Daniel@0: % generated using Matlab. Daniel@0: pitch_class_histogram(URI) --> Daniel@0: cp_r_fig:figure( cp_score:pitch_class_histogram(r,URI), 12, 6, []). Daniel@0: % cp_matlab:figure( cp_score:pitch_class_histogram(ml,URI), 12, 6, []). Daniel@0: Daniel@0: pitch_class_histogram(Lang,URI) :- Daniel@0: hum_uri_path(URI,Path), Daniel@0: kern_pc_hist(Path,Hist1), Daniel@0: findall(PCN-X, (member(PC-X,Hist1), pitch_class_number(PC,PCN)), Hist2), Daniel@0: numlist(0,11,PCNs), Daniel@0: maplist(pc_number_name,PCNs,PCNames), Daniel@0: maplist(pcn_count(Hist2),PCNs,Counts), Daniel@0: ( Lang=r Daniel@0: -> r(par(ps=10,mar=[2.1,2.2,1.1,0])), Daniel@0: r(barplot(Counts,'names.arg'=PCNames,main="Pitch class histogram")) Daniel@0: ; Lang=ml Daniel@0: -> ?? ( bar(PCNs,Counts); Daniel@0: xticks(PCNs,cell(PCNames)); Daniel@0: title("Pitch class histogram"); Daniel@0: caxis([0,3])) Daniel@0: ). Daniel@0: Daniel@0: pcn_count(Hist,PCN,Count) :- member(PCN-Count,Hist) -> true; Count=0. Daniel@0: Daniel@0: Daniel@0: sandbox:safe_primitive(cp_score:pitch_class_histogram(_,_)).