Table Of ContentProgramming Mixed Music in ReactiveML
Guillaume Baudart, Louis Mandel, Marc Pouzet
To cite this version:
Guillaume Baudart, Louis Mandel, Marc Pouzet. Programming Mixed Music in ReactiveML. FARM
’13 - ACM SIGPLAN Workshop on Functional Art, Music, Modeling and Design, Sep 2013, Boston,
United States. pp.11-22, 10.1145/2505341.2505344. hal-00850294
HAL Id: hal-00850294
https://hal.inria.fr/hal-00850294
Submitted on 6 Aug 2013
HAL is a multi-disciplinary open access L’archive ouverte pluridisciplinaire HAL, est
archive for the deposit and dissemination of sci- destinée au dépôt et à la diffusion de documents
entific research documents, whether they are pub- scientifiques de niveau recherche, publiés ou non,
lished or not. The documents may come from émanant des établissements d’enseignement et de
teaching and research institutions in France or recherche français ou étrangers, des laboratoires
abroad, or from public or private research centers. publics ou privés.
Programming Mixed Music in ReactiveML
GuillaumeBaudart LouisMandel MarcPouzet
E´colenormalesupe´rieuredeCachan Univ.Paris-Sud11 Univ.PierreetMarieCurie
AntennedeBretagne DI,E´colenormalesupe´rieure DI,E´colenormalesupe´rieure
DI,E´colenormalesupe´rieure INRIAParis-Rocquencourt INRIAParis-Rocquencourt
Guillaume.Baudart@ens-cachan.org Louis.Mandel@lri.fr Marc.Pouzet@ens.fr
Abstract
signal
Mixed music is about live musicians interacting with electronic
Antescofo
partswhicharecontrolledbyacomputerduringtheperformance.It
score
allowscomposerstouseandcombinetraditionalinstrumentswith
complex synthesized sounds and other electronic devices. There
are several languages dedicated to the writing of mixed music Antescofo
saacdsopvreaecnstc.seoAdfmsmcoounrsegicfaothlllepomewr,feortrhmaellaoAnwcnestsea:shccooowfmopelolaesncegtrruotoangimceapcnaoarutgspeilnethtdeerwareciatthcwtiiavthne ListSeenqiunegn cMearchine tempopositio
amusician.Howeverthesedomainspecificlanguagesdonotoffer n
theexpressivenessoffunctionalprogramming.
control
WeembedtheAntescofolanguageinareactivefunctionalpro-
messages
gramminglanguage,ReactiveML.Thisapproachofferstothecom- Audio
poser recursion, higher order, inductive types, as well as a sim-
plewaytoprogramcomplexreactivebehaviorsthankstothesyn- Figure1. ArchitectureoftheAntescofosystem.Continuousarrow
chronous model of concurrency on which ReactiveML is built. representpre-treatment,anddottedonesreal-timecommunications
ThisarticlepresentshowtoprogrammixedmusicinReactiveML
throughseveralexamples.
PierreBoulez,PhilippeManoury,MarcoStroppa,NewYorkPhil-
CategoriesandSubjectDescriptors D.3.2[LanguageClassifica- harmonics,BerlinPhilharmonics,andtheRadioFranceOrchestra.
tions]: Concurrent, distributed, parallel languages; H.5.5 [Infor- Figure1describestheorganizationoftheAntescofosystem.It
mationInterfacesandPresentation]:SoundandMusicComputing. iscomposedoftwodistinctsubsystems:alisteningmachineanda
sequencer.Duringaperformance,thelisteningmachineestimates
Keywords Synchronous Programming; Language Embedding; the tempo (i.e., execution speed) and the position of the live per-
MixedMusic;LiveCoding. formersinthescore.Theroleofthesequenceristousetheseinfor-
mationtotriggerelectronicactionsbysendingcontrolmessagesto
1. Introduction amusicprogrammingenvironment.e.g.,Max/MSP.2Then,theen-
vironmentusesthesemessagestohandlecomplexsoundsynthesis,
Technicalprogressessincethe1950’shaveledcomposerstowrite managelights,etc.
music mixing live performers with electronic parts. At first, per- ThelanguageofAntescofo[9]isadescriptivelanguageinspired
formers simply followed a pre-registered magnetic band. But the by classical western music notation: a score is an interleaving of
advances in computing rapidly allowed real interaction between instrumental notes and electronic actions. An original aspect of
musiciansandelectronicparts. thislanguageisthatitspecifiessynchronizationanderror-handling
DevelopedatIRCAM,Antescofo[5]1isastate-of-the-artscore strategiesfortheelectronicactions.Itmeansthatduringtheperfor-
followingsystemdedicatedtomixedmusic.Since2008,Antescofo mance,dependingonthetempovariationsandtheerrorsmadeby
hasbeenusedinthecreationofmorethan40originalmixedelec- themusicianorthelisteningmachine,thesequencerwillreactina
tronicpiecesbyworldrenownedartistsandensembles,including waywhichisdefinedbythecomposer.
ThesequencerofAntescofoisasynchronousreactivesystem:
1http://repmus.ircam.fr/antescofo itcontinuouslyreadsinputsfromthelisteningmachine,produces
outputs to the musical environment and is subject to the strong
timingrequirementrelatedtoeartolerance(typically30ms).Syn-
chronous languages [2] have been invented and are used widely3
Permissiontomakedigitalorhardcopiesofallorpartofthisworkforpersonalor forprogrammingawiderangeofcriticalcontrolsoftware:onboard
classroomuseisgrantedwithoutfeeprovidedthatcopiesarenotmadeordistributed
controloftrainsandtrackinterlocking,fly-by-wireandcockpitdis-
forprofitorcommercialadvantageandthatcopiesbearthisnoticeandthefullcitation
onthefirstpage.CopyrightsforcomponentsofthisworkownedbyothersthanACM playsforplanes,etc.Therefore,theywouldhavebeenwellsuited
mustbehonored.Abstractingwithcreditispermitted.Tocopyotherwise,orrepublish, forprogrammingthesequencer.But,toensurestaticallythatpro-
topostonserversortoredistributetolists,requirespriorspecificpermissionand/ora grams execute in bounded time and memory, synchronous lan-
fee.Requestpermissionsfrompermissions@acm.org.
FARM’13, September28,2013,Boston,MA,USA.
Copyright(cid:13)c 2013ACM978-1-4503-2386-4/13/09...$15.00. 2http://cycling74.com/
http://dx.doi.org/10.1145/2505341.2505344 3http://www.esterel-technologies.com
guageslikeLustreandEsterelintentionallyforbidthedynamiccre-
aoqtvuieoernnccooemfrpienrotRhceiesascsleitmisviewtMahtiiLcohn[1,is]w,aaenfeheaaxtvuteerneismoiofpntlheomefAethnnetteefduscnaocnftoiAolnnaantelgsluacanoggfoeu.asTgeoe- ""!!4444 ## ## ## ## ## ## ## ## ## ## $$ ## ## $$
5
OCaml4withsynchronousparallelism.Notethatweareinterested
irneltiheseolanntghueaagcetuanaldAthnetessecqoufeonlcisetre,nthineglimnkacwhiitnhe.livemusiciansstill 5"! # # # # # # # # # # # # # $ # $
Contribution of the Paper The main contribution of this paper "le[!t 1#j.a#0c,q#u(e#Fs,#4=);# 1.0#,#(#G,#4)#; 1#.0,#(A##,4)$; 1.0#, (##F,$4);
is to show, through a collection of examples, the benefit of the
1.0, (F,4); 1.0, (G,4); 1.0, (A,4); 1.0, (F,4);
embedding of Antescofo in ReactiveML for programming mixed
1.0, (A,4); 1.0, (Bf,4); 2.0, (C,5); ... ]
music.Thisembeddingcombinestheexpressivenessofthetwo.It
facilitates the creation process for the composer by using higher- Figure2. ThetraditionalFrenchmusicalroundFre`reJacquesand
ordercombinators.Itcanbeusedtoprototypenewprogramming thebeginningofitsrepresentationinourdatastructures.
constructs for Antescofo. In all our experiments, response times
were less than the reaction time of human ear, using the current
versionoftheReactiveMLcompilerandrun-time. Now that we can represent musical structures, we write func-
The paper is organized as follows. Section 2 presents Reac- tionstomanipulatethem.Forinstance,thefollowingdefinesfunc-
tiveMLthroughasimplelibraryforelectronicmusic.InSection3, tionstotransposeasequence.5
weintroducethemainfeaturesofthe Antescofo language.Then,
let move_pitch inter p =
Section4illustratesourapproachonacompleteexample.InSec-
pitch_of_int ((int_of_pitch p) + inter)
tion5,weshowhowthisworkcanbeusedtodesignnewkindsof
val move_pitch: int -> pitch -> pitch
interactionsbetweenaliveperformerandelectronicparts.Related
workisdiscussedinSection6andweconcludeonSection7.
let transpose inter sequence =
The code presented in the article is available on a companion
List.map
web site: http://reactiveml.org/farm13. Links to music or
(fun (d, p) -> d, (move_pitch inter p))
videodemosareindicatedwiththesymbol .
sequence
(cid:15) val transpose: int -> note list -> note list
2. MusicinReactiveML
Thefunctionmove_pitchtransposesasymbolicpitchbyaninter-
ReactiveML [17] is a synchronous reactive language built as an
valinterinsemi-tones.Totransposeanentiremelody,weusethe
extensionofthefunctionalprogramminglanguageOCaml.There-
higher-orderfunctionList.mapfromthestandardOCamllibrary
fore,followingtheworkofHudak[12]wecaneasilydefinemusi-
thatappliesmove_pitchtoeverynoteinasequence.
calstructures,inafunctionalprogrammingstyle.
ThissectionpresentsthelanguageReactiveMLanditsconcur-
2.2 TimeinReactiveML
rencymodelthroughasimplemusiclibrary.
ReactiveMLisasynchronouslanguagebasedonthereactivemodel
2.1 Musicdatatypes introduced by Boussinot [4]. It relies on the notion of a global
logical time. Time is viewed as a sequence of logical instants.
Traditionally, in western music, a melody is a sequence of notes,
RegularOCamlfunctionsareconsideredtobeinstantaneous,i.e.,
where a note is a sound event characterized by a pitch and a
whencalleditreturnsitsresultintheverysameinstant.Inaddition,
duration.Notescanbedefinedwiththefollowingtypes.
wecandefineprocessesthatmaylastoverseverallogicalinstants.
type pitch_class = Itisintroducedbythekeywordprocess.
| A | B | C | D | E | F | G Tostartwith,considertheprogrammingofasimplecountdown.
| As | Bs | Cs | Ds | Es | Fs | Gs Thefollowingprogramawaitsagivenamountoftimevaluegiven
| Af | Bf | Cf | Df | Ef | Ff | Gf inseconds.
type octave = int let process countdown value =
type pitch = pitch_class * octave let deadline = Unix.gettimeofday () +. value in
type dur = float while Unix.gettimeofday () < deadline do
type note = dur * pitch pause
done
The pitch is represented by a pair (pitch_class, octave), val countdown: float -> unit process
where pitch_class denotes one of the twelve semi-tones, e.g.,
A,A#,A(cid:91),B,B#...,andoctaveisaninteger.Forinstance(A,4) First, the date of the deadline is computed using the function
denotesthefamousA440Hz.Here,asinHudak’swork,Asstands gettimeofdayoftheUnixmodule6.Then,whilethecurrentdate
forAsharpandAfforAflat. if less than the deadline, the process countdown awaits the next
A classic melody is just a sequence, or list, of notes. For in- logicalinstant(pause).
stance,Figure2presentsthethemeofatraditionalFrenchmusical Communications between processes are made through signals
round:Fre`reJacquesandthebeginningofitsrepresentationinour that are values characterized by a status defined at every logical
datastructure. instant:presentorabsent.Forinstance,thefollowingprocessim-
It is often convenient to treat pitches as integers. Functions plementastandardtimersimilartotheUnixtimer.Itawaitsafirst
int_of_pitch and pitch_of_int convert a symbolic pitch,
e.g., (A,4) to an integer and vice versa (one can, for example, 5Thetypeofthefunctionsgiveninitaliccanbelessgeneralthanthe
associatethecorrespondingMIDInote,e.g.,A4=69). oneinferredbythecompiler.
6+.,*.,/.arefloating-pointaddition,multiplicationanddivisionopera-
4http://caml.inria.fr tors.
durationvalue,andthenperiodicallyemitsthesignalalarmwith To play a note, the program sends it on the signal perf. Then,
aperiodinterval.7 it waits for the delay corresponding to the note duration before
sendingthenextnote.
let rec process timer value interval alarm = Toproducesound,notesemittedonsignalperfaresenttothe
run (countdown value); audioenvironment.
emit alarm ();
run (timer interval interval alarm) let process sender perf =
val timer: loop
float -> float -> (unit, unit) event -> await perf (notes) in
unit process List.iter (fun n -> send_to_audio n) notes
end
The process timer is the interface between physical time and
val sender: (note, note list) event -> unit process
synchronous logical time. This process is non-deterministic: the
number of logical instants between two emissions of the signal This process loops infinitely: it waits for an emission on signal
alarm is not necessarily constant. Yet, if the duration of every perf and sends all received notes to the audio environment, by
logicalinstantismuchsmallerthaninterval,theerrorbetween callingthefunctionsend_to_audio.
twoemissionofthesignalalarmwillbenegligiblewithrespectto A musical performance is the parallel composition of the two
thereactiontimeofthehumanear,i.e.,30ms[10].Theimportant previousprocesses.
pointisthatwehaveisolatedthesourceofnon-determinisminthe
(cid:15)
program. Now, it is possible to express delays with respect to a 2.3 ParallelandSequentialExecution
signalwhichissupposedtobeperiodic.
Thankstothenotionofgloballogicaltimeinheritedfromthesyn-
Inthefollowing,alarmdenotesaglobalsignal.Itwillbegen-
chronousmodel,itiseasytocombineprocesses.Twoexpressions
eratedbytheprocesstimerdescribedabove,withperiodperiod
canbeevaluatedinsequence(e1; e2)orinparallel(e1 || e2).
definedasaglobalconstant.Usingthissignal,onecanwriteapro-
Inthelattercase,theyexecutesynchronously(orlockstep).There-
cessthatdoesnothingbutwaitforadurationdur.Forsimplicity,
fore,theyremainsynchronousduringanexecution.
we assume in this section that all durations are expressed in sec-
Imaginewewanttodoubleavoiceonethirdhigher(i.e.,four
onds:
semi-tones).Ofcourse,itispossibletowriteafunctionthattakes
let process wait dur = a list of notes and returns a new list of notes containing the two
let d = int_of_float (dur /. period) in voices. But, we can also use the deterministic parallel execution
for i = 1 to d do providedbyReactiveMLtoplayinparallelthevoiceanditstrans-
await alarm position.Thisconstructwillbeveryusefultocombinethemusical
done performancewithotherprocesses(seeforinstanceSection5.2).
val wait: dur -> unit process
let process double sequence =
Thisprocesswaitsfordoccurrencesofthesignalalarmwhered run (play sequence) ||
isthedurationdurexpressedasanumberofinstants. run (play (transpose 4 sequence))
InReactiveML,signalscanalsocarryvalues.Differentvalues val double: note list -> unit process
canbeemittedduringaninstant,whichistermedmulti-emission.
In ReactiveML, processes are first class citizens. Thus, it is
Inthiscase,whenthesignalisdeclared,afunctiondefininghowto
possibletowritehigherorderprocesses.Forinstance,thefollowing
combinethemultipleemissionsmustbeprovided.Here,wedeclare
codedelaystheexecutionofaprocesspbyadurationinseconds.
asignalperfwhichaccumulatesinalistthemultiplesimultaneous
emissions. let process delayed p dur =
run (wait dur);
signal perf default [] gather (fun x y -> x::y)
run p
val perf: (note, note list) event
val delayed: unit process -> dur -> unit process
The default value is set to the empty list, [], and the gathering
Finallyprocessescanbeiteratedwiththeclassicalconstructs:
function(fun x y -> x::y)appendsthevaluextotheheadof
loop/endforaninfiniteloop,for/do/doneforafinitesequential
thelisty.Thisfunctionisusedtofoldallthevaluesemittedduring
loopandfor/dopar/doneforafiniteparallelloop.
aninstantintoalist,startingfromthedefaultvalue.
With these constructs, we are able to execute the round pre-
Now,wewriteaprocessplaywhichiterativelyemitsthenotes
sentedinFigure2. Fourdifferentvoicesplaythethemeinloop.
fromasequencesequenceonthesignalperf.
Eachvoicestartstwomeasures,i.e.,8safterthepreviousone.
(cid:15)
let rec process play sequence perf =
match sequence with let process theme =
| [] -> () loop
| ((dur, pitch) as note) :: s -> run (play jacques)
emit perf note; end
run (wait dur); val theme: unit process
run (play s)
val play: let process round =
note list -> (note, note list) event -> run theme ||
unit process run (delayed theme 8.0) ||
run (delayed theme 16.0) ||
run (delayed theme 24.0)
7Inordertoavoidtimeshiftingandfloatingpointerrors,theactualimple- val round: unit process
mentationisslightlydifferent.
e e e stantaneous;theyarenotcharacterizedbyadurationbutbythede-
1 2 3
layneededbeforetheiractivation.Moreover,delaysbetweenelec-
Voice tronicactions,likenotedurations,canbespecifiedinrelativetime.
4 Thus,electro!nicpartscanfollowthespeedoftheliveperformeras
"
4 # # $ atrainedmusicianswould.
0.5 Sequences of electronic actions are linked to an instrumental
a0
group event,thetriggeringevent.Forinstance,inFigure3,actiona0is
1.0 1.0 boundtothefirstnotewithadelayof0.0.Whenthefirstnoteis
a1 a2 a3
detected,actiona issentimmediately.
0
Actionscanberegroupedintostructurescalledgroups.Groups
Figure 3. Representation of an Antescofo score. Musical notes
aretreatedasatomicactionsandareboundtoaninstrumentalevent
correspondtothemusician’spartandtheresttoelectronicactions.
andcharacterizedbyadelay.OntheexampleofFigure3,agroup
containingasequenceofthreeactionsisboundtoevente .
2
Furthermore,groupscanbearbitrarilynested.Itallowstofaith-
Thisprocesscanalsobewrittenwithaparallelloop:
fullycapturethehierarchicalstructureofamusicalpiece.Actions
let process round = containedinanestedgroupareexecutedinparallelwiththeactions
for i = 0 to 3 dopar followingthemintheembeddinggroup,notinsequence.
run (delayed theme (float (i*8))) Ascorecanbedescribedwiththefollowingtypes:
done
val round: unit process type score_event =
or, using a recursive process taking the number of voices as an { event : instr_event_label;
argument. seq : sequence; }
let rec process round nb_voices = and sequence = delay * asco_event list
if nb_voices <= 0 then ()
else begin and asco_event =
run theme || | Action of action
run (delayed (round (nb_voices - 1)) 8.0) | Group of group
end
val round: int -> unit process and action =
| Message of audio_message
We are now able to describe and execute electronic music in
| Signal of (unit, unit list) event
ReactiveML.Butwhataboutmixedmusic?
and group =
3. TowardMixedMusic
{ group_synchro: sync;
Mixedmusicisaboutinteractionbetweenalivemusicianandelec- group_error: err;
tronic parts. The Antescofo language [9] allows a composer to group_seq: sequence }
specifyelectronicpartsandhowtheyinteractwithmusiciansdur-
(cid:15)
ingaperformance.Thislanguageistheresultofaclosecollabora- and sync = Tight | Loose
tionbetweencomposersandcomputerscientists.Figure3showsa and err = Local | Global | Causal | Partial
graphicalrepresentationofaverysimpleAntescofoscore.
The type score_event represents a sequence of electronic
3.1 RelativeTimeinMusic
actionsseqboundtoaninstrumentaleventevent.Asequenceis
Inmostclassicalwesternscores,durationsanddelaysareexpressed justalistofelectronicactionscharacterizedbyadelayrelativeto
relativetothetempoi.e.,theexecutionspeedexpressedinbeatsper thetempo(seeSection3.1).
minute(bpm).OntheexampleofFigure3,thedurationofthefirst Atomicactionscanbeeithersimplecontrolmessagesdestined
twonotesissetto1.0beat,i.e.,aquarternote.Ifthecurrenttempo totheaudioenvironment,Message,orclassicReactiveMLsignals
is60bpmitmeans1s,but0.5sifthetempois120bpm.Musicians tocontrolotherprocesses,Signal.ReactiveMLsignalsareuseful
arefreetointerpretascorewithamovingtempo.Indeed,inclassi- to couple the electronic accompaniment with other reactive pro-
calwesternmusic,tempoisoneofthemostprominentdegreesof cesses(seeSection5).
freedomforinterpretation.Itpartiallyexplainsthehugedifference Theproblemisthatduringaperformance,thecomputerissup-
betweenarealinterpretationbyalivemusicianandanautomatic posedtoactasatrainedmusician,followingtheotherperformers.
executionofthesamescorebyacomputer. Thus,thespecificationofmixedmusicscoresfacestwomajorchal-
OneofthemainfeaturesoftheAntescofosystemistempoin- lenges:
ference.Duringaperformance,thelisteningmachinedecodesboth
thepositioninthescoreandtheexecutionspeed.Thetempoisnot • Duringaliveperformanceamusiciancanmakeamistake,or
estimatedfromthelastdurationalonebutratherfromalldurations worse,thelisteningmachinemayfailtorecognizeanevent.In
detected since the beginning of the performance. In this way, the bothcases,anexpectedeventismissing.Butwhathappensto
listeningmachineaddssomeinertiatotempochangeswhichcor- actionsboundtothisevent?
respondstotherealbehaviorofmusiciansplayingtogether[5,15]. • Sometimes, a sequence of actions bound to an instrumental
eventmaylastlongerthanthedurationofthetriggeringevent.
3.2 TheAntescofolanguage
Forinstance,onourexample,actionsa2anda3shouldoccur
Inthisframework,themostbasicelectronicactions,calledatomic after event e although they are triggered by event e . In this
3 2
actions are simple control messages destined for the audio envi- case,thequestionis:howshouldanelectronicpartsynchronize
ronment. Unlike traditional musical notes, atomic actions are in- withinstrumentaleventthatoccurduringitsexecution?
3.4 SynchronizationStrategies
e1 δ0 e2 Acomposerisallowedtospecifyhowactionscontainedinagroup
δ1 willsynchronizewithinstrumentaleventsthatoccurduringtheex-
group ecutionofthegroup.Currently,thelanguageproposestwodistinct
a0 a1 strategies:TightandLoose.
δ2 IfthesynchronizationattributeissettoTight,everyactioncon-
tainedinthegroupistriggeredbythemostrecentcorrespondingin-
eX1
strumentalevent.Thenearesteventiscomputedwithrespecttothe
idealtimingofthescoreregardlessoftempochanges.Thisstrat-
group partial egy is ideal when electronic parts and the musician must remain
eX1 δ1+δ2−δ0 a1 ahsarsmynocnhizraotnioonusoafsthpeospseirbfloer,mee.gr.’,sipfaarnt.eInlecthtreoenxicamvopilceeoifsFaigsuimrep3le,
if the group has a synchronization attribute set to Tight, actions
a2anda3willbetriggeredbye eventhoughtheentiregroupis
3
group causal boundtothesecondinstrumentalevent.
a0 a1 ThestrategyLooseallowsthecomposertodefinegroupsthat,
δ1+δ2−δ0 oncetriggered,onlysynchronizewiththetempo.Duetotheinertia
eX1 of the tempo inference, an electronic action contained in such a
groupandaninstrumentaleventthatseemstobesimultaneousin
group global thescoremaybedesynchronizedduringtheperformance.Indeed,
a0 a1 aperformermayaccelerateordeceleratebetweentwoevents.This
δ2 strategy is used to preserve temporal relations between actions
eX1 contained in the group. For instance, it can be very useful when
theelectronicpartistreatedasanindependentbackgroundsound.
group local
4. AFirstExample:Thehouseoftherisingsun
Asafirstexample,letustakeaclassicalfolksong,Thehouseof
Figure 4. Illustration of the four error-handling attributes on a
therisingsun.ThescoreispresentedinFigure5.Inthisexample,
simple score (on top). e and e represent instrumental events.
1 2 wewanttodefineanelectronicaccompanimentwhichfollowsthe
Supposethate ismissedande isdetected.
1 2 mainthemeplayedbyarealmusician.
First, we need to create and initia(cid:15)lize the asco environment
thatcontainstheinstrumentalscore.Thisenvironmentallowsusto
manageinputsfromthelisteningmachineandtheoutputsdestined
Error-handling and synchronization strategies depend very
fortheaudioenvironment.
much on the musical context. The Antescofo language proposes
solutions to reflect different musical behaviors. Groups are char- let asco = create_asco "rising_sun.asco" 120.
acterized by two attributes [6], a synchronization attribute (see val asco: Ascolib.asco
Section3.4)andanerrorhandlingattribute(seeSection3.3).
Tocreatetheenvironment,weneedtheinstrumentalscoreofthefu-
tureperformance,here"rising_sun.asco"andaninitialtempo,
3.3 Errorhandling typically120bpm.
Theerror-handlingattributedefinesthebehaviorofthegroupwhen 4.1 Thebasics
theexpectedtriggeringeventisabsent.Thereareseveralwaysto
Theaccompanimentisroughlydescribedinthescorebyasequence
dealwitherrorsdependingonthemusicalcontext.Wepresenthere
ofchords:Am,C,D...boundtoinstrumentalevents.Forinstance,
fourexclusiveerrorhandlingstrategies:Partial,Causal,Local
the first chord is related to the second instrumental event, the
andGlobal.Figure4illustratesthefourdifferentbehaviors.
secondtothefourthoneandsoon.
Themostbasicaccompanimentisperhapsasimpleharmoniza-
First, we need a symbolic description of chords. Like pitch
tion of the musician’s voice. In this case, if a triggering event is
describeinSection2.1,achordischaracterizedbyapitchclass:
missed,electronicpartmustkeepongoingasiftheerrorneveroc-
A,C,D...andacolor:majororminor.
curred.Thisis,forinstance,thebehaviorofapianistaccompanying
abeginner.Thus,attributesPartialandCausalaimtopreserve type color = Maj | Min
asimpleproperty:thefutureofaperformancedoesnotdependon type chord = pitch_class * color
pasterrors.
We can define the bass line of our example as a sequence of
Now, the question is: what about actions that should already
chordscharacterizedbyadelay:
have been launched when the error was detected? If the error-
handlingattributeissettoPartial,theseactionsaresimplydis- let bass = [0.0, (A, Min); 2.0, (C, Maj); ...]
carded. On the other hand, if the error handling-attribute is set val bass: (delay * chord) list
toCausal,theseactionsareimmediatelylaunched.Thisstrategy
Then,weneedtoturnthissequenceofchordsintoasequence
could be useful if some actions are used to initialize an external
ofelectronicactions.Perhapsthemostsimpleaccompanimentisto
process,e.g.,turnonthelight.
playonlytherootsofthebassline.
Moreover,agroupcanbeusedtodefineacomplexcontrolunit,
e.g,parametersneededtosynthesizedthesoundofagong.Then, let root_of_chord chord octave =
theintegrityofthegroupmustbepreserved.Thus,whenanerroris let (pitch_class, color) = chord in
detected,Globalgroupsarelaunchedwithazerodelay,whereas (pitch_class, octave)
Localgroupsarecompletelyignored. val root_of_chord: chord -> octave -> pitch
"" $$ $$%% $$ $$%% $$
## 4444 $$ A$$m%% $$ $$C%% $$!! $$D%% $$ $$ $$F%% !! Am !! C $$ $$ &&E $$%% !!
!!
55
$$%% $$ $$%% $$ $$%% $$ ''$$ ''$$ && $$%%
$$ $$%% $$
## Am !! C D $$ $$ $$F%% !! Am !! E!! !! Am
!!
Figure5. Scoreofthehouseoftherisingsun(classicalfolksong)
let only_roots chords octave dur = detected,eachchordoftheaccompanimentislinkedtoitsclosest
List.map precedinginstrumentalevent.
(fun (delay, chord) -> Thelastthingtodoistolaunchthelisteningmachineandthe
let root = root_of_chord chord octave in reactiveaccompaniment.
(delay, action_note (dur, root)))
chords let process main =
val only_roots: run (init_asco asco);
(delay * chord) list -> octave -> dur -> sequence begin
run (listener asco) ||
Given an octave, the function root_of_chord returns the pitch
run (tight_accomp) ||
correspondingtotherootofachord.Then,thefunctiononly_roots
run (sender asco)
defines the sequence of electronic actions corresponding to the
end
roots of a sequence of chords, chords. Function action_note
val main: unit process
convertsanoteintoanatomicactiondestinedfortheaudioenvi-
ronment (a value Action message where the message contains
Itfirstinitializestheenvironment.Then,theprocesslistener
thecharacteristicsofthenote).
links the listening machine of Antescofo to the environment. In
RemarkthatinFigure5,nooctaveisspecifiedonthescorefor
parallel, it executes the accompaniment part, and sends it to the
thebass.Wechoosetoinstantiatethebasswiththeoctavesetto3
audioenvironmentsender asco.
(i.e.,thefirstrootofthebassissettoA3=220Hz)andtheduration
to2.0beatswhichcorrespondstothedelaybetweentwochords.
4.2 Hierarchicalstructure
let roots = only_roots bass 3 2.0
Theharmonizationdefinedaboveisabitminimalist.Onesolution
val roots: sequence
couldbetoaddseveralothervoicesfollowingthepreviousmethod.
The next thing to do is to build the link between the in- Butwecandobetter.
strumental part and the electronic accompaniment. The process In the original song, the accompaniment is made with arpeg-
link asco evt seqlinksasequenceofactionsseqtoaninstru- giooverthebassline.Thankstofunctionalcomposition,suchan
mentaleventevt,intheenvironmentasco.Thisprocesswaitsfor accompanimentisveryeasytodefine.
theeventtobedetectedormissedandittriggersthesequence.For First,wedefinethearpeggiostylewewanttoapply:
instance,ontheexampleofFigure5,thefirstchordisboundtothe
secondinstrumentalevent.Wecanlinkthesequencerootstothis let arpeggio chord octave =
eventtoobtainabasicaccompaniment. let fond = root_of_chord chord octave in
let third =
let process basic_accomp =
match color with
run (link asco 2 roots)
| Min -> move_pitch 3 fond
val basic_accomp: unit process
| Maj -> move_pitch 4 fond
Iftheperformerdoesnotplayatconstantspeed,theaccompa- in
niment part may become desynchronized at some point. We can let fifth = move_pitch 7 fond in
easily avoid this behavior if we put the bass line inside a Tight let dur = 0.125 in
group(seeSection3.4).Moreover,itallowsustospecifyanerror- group Loose Local
handlingstrategyfortheaccompaniment.Inourcase,ifaninstru- [0.0, action_note (dur, fond);
mentaleventismissedwedonotwanttoheartheassociatedchord. 0.625, action_note (dur, third);
ThereforeweusethePartialstrategy(seeSection3.3). 0.125, action_note (dur, fifth);
0.125, action_note (dur, move_octave 1 fond);
let process tight_accomp =
0.125, action_note (dur, move_octave 1 third);
let g = group Tight Partial roots in
0.333, action_note (dur, move_octave 1 fond);
run (link asco 2 [(0.0, g)])
0.333, action_note (dur, fifth);]
val tight_accomp: unit process
val arpeggio : chord -> octave -> asco_event
Here, the function group sync err seq is a simple constructor
foragroupwithattributessyncanderrcontainingthesequence An arpeggio corresponds to a Loose Local group. Thus, an
ofactionsseq. arpeggiorelatedtoamissingeventisentirelydismissed(Local).
Notethatthesequenceboundtothesecondinstrumentalevent Besides, the synchronization strategy preserves the rhythm of
containsonlyonezerodelayelectronicaction:thegroupthatde- the arpeggio (Loose). The function move_octave is similar to
fines the entire accompaniment. When this instrumental event is move_pitchandshiftthepitchagivennumberofoctaves.
Then,wecandefinetheaccompanimentbyapplyingthefunc- let process killable k p =
tionarpeggiotothebassline. do
run p
let arpeggio_bass chords octave =
until k done
List.map
val killable:
(fun (delay, chord) ->
(’a, ’b) event -> unit process -> unit process
(delay, arpeggio chord octave))
chords Theconstructiondo/untilisnotaloopingstructure.Itstopsthe
val arpeggio_bass: executionofitsbodywhenthesignalisemitted.
(delay * chord) list -> octave -> sequence Now,wecandefineasignalkill_druminthetoplevel:
As for the basic accompaniment, we encompass the resulting signal kill_drum default () gather (fun x y -> ())
sequenceinsideaTightPartialgroup. val kill_drum: (unit, unit) event
let process arpeggio_accomp =
Insteadofsimplyexecutingthepercussionpart,weexecuteitunder
let chords = arpeggio_bass bass 3 in
thesupervisionofthekillablecombinator.
let g = group Tight Partial chords in
run (link asco 2 [0.0, g]) #run (killable kill_drum drum_accomp)
val arpeggio_accomp: unit process
Then,wecanstopthedrumpartduringtheperformancewhenever
Thisaccompanimentsillustratesthepossibilityofdefininghierar-
wewant.
chical structures in the score. Indeed, a global Tight group con-
tainsasuccessionofarpeggiosalsodefinedasgroups. emit kill_drum ()
Finallywecanreplacetheprocesstight_accompinthemain
processbyarpeggio_accomp. A more interesting example is to dynamically replace an ac-
companiment. First, let us define a signal replace on which we
4.3 LiveCoding cansendtheprocesses.
A benefit of the embedding of Antescofo in ReactiveML is the
signal replace
ability to use its read–eval–print loop, called toplevel [16]. For
default (process ())
example,ifweexecutetheexampleoftherisingsuninthetoplevel,
gather (fun x y -> process (run x || run y))
whileitisplaying,wecandefineapercussionpart(weassumehere
val replace: (unit process, unit process) event
that the environment asco has been properly initialized and that
processeslistenerandsenderarealreadyrunning):
Note that if several emissions occur during the same instant, the
let process drums_accomp = resultwillbetheparallelcompositionofalltheemittedprocesses.
let rhythm = [0.0; 0.625; 0.5; 0.5; ... ] in Usingtheprevioussignal,wecandefineanotherhigherorder
let drums = process replaceable which executes processes emitted on the
List.map (fun d -> d, action_beat) rhythm signalreplace.
in
let rec process replaceable replace p =
let accomp = group Tight Partial drums in
do
run (link asco 2 [0.0, accomp])
run p
val drums_accomp: unit process
until replace (q) ->
First, we define a sequence of delays, rhythm, to represent run (replaceable replace q)
the rhythm of the drum part. Then, we turn this rhythm into a done
sequence of electronic actions, drums. Here, action_beat is a val replaceable:
valueAction messagesuchthatwhenevertheaudioenvironment (unit process, unit process) event ->
receives one of these messages, it plays a drum beat. Finally the unit process ->
resultisaTightPartialgroupcontainingtheentirepercussion unit process
partboundtothesecondinstrumentalevent.
First, the process replaceable launches the process p. Then,
Dynamicallyduringtheperformance,wecanaskthatthispart
beplayed:8 wheneveraprocessqisemittedonsignalreplace,theexecution
ofpstopsandtheprocessqislaunchedinturn.
#run drums_accomp For instance, we can use this feature to dynamically switch
betweenthedifferentstylesofaccompaniment:basic,arpeggioor
Thisnewvoicewillsynchronizeautomaticallywiththeothers,even
drums.
ifthetriggeringeventalreadypassed,thankstotheerror-handling
strategy. #run (replaceable replace tight_accomp)
The expressiveness of the language and this dynamic aspect emit replace arpeggio_accomp
allowsustobuildmorecomplexinteractionswithmusiciansduring emit replace drums_accomp
aperformance.
Let us start with a simple example: a higher order process The first instruction launches the basic accompaniment (see
killablethatallowsaprocessgivenasargumenttobestopped Section 4.1). After a while, we can evaluate the second or the
whenasignalkisemitted.Thisprocesscanbeusedtocontrolthe third instruction to stop the electronic part and start the com-
executionofanaccompaniment. plete accompaniment, arpeggio_accomp or the percussion part,
drums_accomp.
8The #run is a toplevel directive which executes the process given as Thus, it is possible to compose, correct and interact with the
argumentinbackground. scoreduringtheperformance.
tronicactionstoaninstrumentaleventevtintheenvironmentand
loopsntimesoverthesequenceseqwhereeachiterationissepa-
ratedbyadelayperiod.Iftheperiodisshorterthantheduration
" #" " #" " " #"
! " #" #" " #" ofthepattern,theexecutionoftheloopleadstooverlappingexe-
cutionsofthepattern.
Figure6. ThemelodicfigureofSteveReich’sPianoPhase TheelectronicpartresynchronizewhenBobplaysthek-thnote
ofthesequenceastheelectronicpartisplayingthefirstnote.Thus,
weneedtotrackthek-thnoteofBob’spart.
5. ReactiveInteractions
ThemainadvantageofembeddingtheAntescofolanguageinRe- let process track k kth_note =
activeMListhatthereactiveaccompanimentisnowabletointeract let ie = instr_event asco in
withregularReactiveMLprocesses.Indeed,atomicactionsofthe loop
Antescofo language can be ReactiveML signals. This feature can await ie (evt) when (evt.index mod 12 = k) in
beusedtoprogrammusicalpieceswheretheinteractionbetween emit kth_note ()
the performer and the accompaniment is more subtle than in the end
previousexamples. val track:
int -> (unit, unit) event -> unit process
5.1 PianoPhase
PianoPhaseisapiecewrittenin1967bytheminimalistcomposer Thefunctioninstr_eventreturnsthesignalcarryingtheoutput
Steve Reich. In this piece, two pianists, Alice and Bob, begin by of the listening machine. Whenever an instrumental event is de-
playing the melodic figure presented in Figure 6 over and over tectedtheindexoftheeventinthescoreandtheestimatedtempo
againinunison.Then,oneofthepianists,letussayAlice,begins issentonthissignal.Theconstructawait ie (evt) when ...
to play her part slightly faster than Bob. When Alice plays the bindsthevaluereceivedonietoevtwhenthesignalisemitted.
first note of the melody as Bob is playing the second note, they Theexecutioncanthencontinueonlyiftheconditionofthewhen
resynchronizeforawhile,i.e.,Aliceslowsdowntoplayatthesame issatisfied.Here,ifthedetectedpositionevt.indexcorresponds
speedasBob.Theprocessisrepeated.Aliceacceleratesagainand tothek-thnoteofthesequence,thesignalkth_noteisemitted.
thenresynchronizeswhensheplaysherfirstnoteasBobisplaying The last thing to do is to compare the emissions of the two
thethird,thenthefourth,etc. signals first_note and kth_note. If two emissions are close
Ifplayingasimplemelodyatconstantspeedisrelativelyeasy enoughitemitsasignalsync.Wecansplitthisprocessintothree
(Bob’s part), Alice’s part which alternatively desynchronizes and steps.
resynchronizes is much harder to achieve. Fortunately, we can Theprocessstamp s r ascoassociatesadatetoeachemis-
programthispartasanelectronicaccompanimentofapianistthat sionofsignalsandemitstheresultonasignalr.
alwaysplaysatconstantspeed,hereBob.
Thedifficultycomesfromthefactthatwecannoteasilycom- let process stamp s r =
puteaprioriwhenAliceandBobwillresynchronize.Eveninthe loop
originalscore,thecomposeronlyspecifiesboundsonthenumber await s;
ofiterationsofthesequenceduringthedesynchronization(between emit r (date asco)
fourandsixteentimes).Howcanweprogramthisbehavior? end
Let us start with a simple process that plays the twelve note val stamp:
(cid:15)
melodyatagivenspeedandsendsasignalfirst_noteeachtime (unit, unit) event -> (delay, delay) event ->
thefirstnoteisplayed.ThiscodecorrespondstoAlice’spart. unit process
let process melody evt n delay first_note =
The function date returns a date relative to the tempo. It corre-
let pattern =
spondstotheelapseddelaysincethebeginningoftheperformance.
group Tight Partial
Thereforetheprocessstampisresponsivetotheexecutionspeed.
[0.0, action_note (delay, (E,4));
Then,thefollowingprocessemitsasignalsynceachtimethe
0.0, action_signal first_note;
lastvaluesemittedonsignalsr1andr2areapproximatelyequal,
delay, action_note (delay, (Ff,4));
i.e.,wheneverthedifferencebetweenthetwovaluesislessthana
delay, action_note (delay, (B,4));
constanteps.
...]
in
let process spy r1 r2 sync eps =
let seq = [0.0, pattern]
loop
let period = 12.0 *. delay in
await (r1 \/ r2);
run (link_and_loop asco evt period n seq)
let t1 = last ?r1
val melody:
and t2 = last ?r2 in
instr_event_label -> int -> delay ->
if abs_float (t1 -. t2) < eps then
(unit, unit) event -> unit process
emit sync ()
First, we define a simple Tight Partial group that contains end
the melodic pattern presented in Figure 6. The second action, val spy:
introduced with the function action_signal sends the signal (float, float) event -> (float, float) event ->
first_note.Sincethedelayofthisactionissetto0.0,thesignal (unit, unit) event -> float -> unit process
willbeemittedsimultaneouslywiththefirstnoteofthesequence.
Then we compute the period of the pattern which is the dura- Theconstructawait (r1 \/ r2)awaitsforoneofthetwosig-
tionofthetwelvenotemelody,i.e.,12.0 *. delay.Theprocess nalsr1orr2tobeemitted.Theexpressionlast ?r1evaluatesto
link_and_loop evt n period seq links a sequence of elec- thelastvalueemittedonsignalr1.
Finally we can combine the previous processes to achieve the alteringitsbehavior.Forinstance,itisrelativelyeasytoprograma
desiredbehavior. graphicalinterfaceforthepreviousexample.Thissectionissimply
aproofofconcept.Wedonotclaimthatthisinterfaceisespecially
let process compare s1 s2 sync eps =
aesthetic.
signal r1 default -.eps gather (fun x y -> x) in
Let us start with a very simple process that draws a rectangle
signal r2 default -.eps gather (fun x y -> x) in
atagivenposition,Left,RightorFull,eachtimeasignalsis
run (stamp s1 r1) ||
emitted.
run (stamp s2 r2) ||
run (spy r1 r2 sync eps) let process draw_sig s pos color =
val compare: loop
(unit, unit) event -> (unit, unit) event -> await s;
(unit, unit) event -> float -> unit process draw_rect pos color;
run (wait asco 0.2);
Thisprocess,associatesadatetoeachemissionofsignalss1and Graphics.clear_graph ()
s2takenasarguments.Resultsareemittedonsignalsr1andr2, end
respectively. Then, in parallel, we launch the process spy on r1 val draw_sig:
andr2,whichemitsthesignalsyncwheneveranemissionofs1 (unit, unit) event -> position -> color ->
iscloseenoughtoanemissionofs2.Sincetheprocessstampis unit process
responsivetothetempo,thetolerancerepresentedbytheconstant
eps increases when the tempo decelerates and decreases when The process wait waits for a duration specified relative to the
it accelerates. It corresponds to the behavior of actual musicians tempooftheenvironment.Thus,theinterfaceisresponsivetothe
playingtogether. speedoftheperformance.
Signalsr1andr2areinitializedinordertoavoidinitialization Then,wecanwriteagraphicobserverthatreactstotheemis-
conflicts.Indeed,ifasignalhasneverbeenemitted,thelastvalue sionoftwosignalss1ands2byalternatingbetweentwomodes
isthedefaultvalue.Besides,multipleemissionsareinthiscontext triggeredbythesignalsm1andm2.
very unlikely since the entire sequence is played between two
let process graphic_observer s1 s2 m1 m2 =
emissionoffirst_noteorkth_note.Therefore,thecombination loop
function chooses arbitrarily one of the values emitted during the
do
sameinstant.
Graphics.clear_graph ();
Finallytheentirepieceisdescribedbythefollowingcode.
run (draw_sig s1 Full Graphics.green)
let piano_phase sync desync first_note kth_note = until m1 done;
let rec process piano_phase k = do
let ev = last_event asco in Graphics.clear_graph ();
run (melody ev 4 0.25 first_note); begin
emit desync (); run (draw_sig s1 Left Graphics.blue) ||
do run (draw_sig s2 Right Graphics.red)
let ev = last_event asco in end
run (melody (ev+1) 16 0.246 first_note) || until m2 done
run (track k kth_note) || end
run (compare first_note kth_note sync 0.05) val graphic_observer:
until sync done; (unit, unit) event -> (unit, unit) event ->
run (piano_phase ((k + 1) mod 12)) (unit, unit) event -> (unit, unit) event ->
in unit process
piano_phase 1 Inthefirstmode,wedrawagreenrectangleontheentiregraphic
val piano_phase: windoweachtimethesignals1isemitted.Whenanemissionof
(unit, unit) event -> (unit, unit) event -> signalm1occurs,weswitchtothesecondmode.Then,wedrawa
(unit, unit) event -> (unit, unit) event -> bluerectangleontheleftsideofthewindoweachtimethesignal
unit process s1isemitted,andaredrectangleontherightsideifthesignals2
isemitted.Then,werestartthewholeprocesswhenthesignalm2
First,weplaythesequencefourtimeswiththedurationofthenotes
isemitted.
setto0.25(asixteenthnote)i.e.,synchronouslywiththepianist.
We can run the process graphic_observer with signals
Duringthisphase,theloopislinkedtothelastdetectedinstrumen-
first_note, kth_note, desync and sync in parallel with the
talevent:last_event asco.Thenweemitthesignaldesyncand
processpiano_phasetoobtainasimplegraphicalvisualizationof
starttoplaythesequenceslightlyfasterwiththenextinstrumental
PianoPhase.Duringthesynchronousphase,greenflashesindicate
event (the duration of the notes is set to 0.246). In parallel, we
that Alice, i.e., the electronic part, is playing the first note of the
compareemissionsofsignalsfirst_noteandkth_note.When
sequence.Duringthedesynchronization,wecanseeredflasheson
theyarecloseenough(hereepsissetto0.05),thesignalsyncis
therighteachtimeBob,i.e.,theactualpianist,isplayingthek-th
emitted.Thenweincrementk andrestartthewholeprocess.The
note,andblueonesonthelefteachtimetheaccompanimentpart
numberofiterationsinthedesynchronizedmodeissetto16.After
isplayingthefirstnote.
that,ifthetwopianistshavenotresynchronized,theelectronicpart
stops.
6. RelatedWork
5.2 SynchronousObserver
Comparison with the actual Antescofo language We focused
In ReactiveML, signals are broadcast communication channels. here on a subset of the actual language of Antescofo. However,
Therefore, one can easily write synchronous observers [11], i.e., constructs that we left aside can be easily encoded using our li-
processesthatlistentotheinputsandoutputsofaprocesswithout brary.Forinstance,anoriginalcontrolstructurewasaddedtothe
Description:Aug 6, 2013 Score of the house of the rising sun (classical folk song) let only_roots First, we define the arpeggio style we want to apply: let arpeggio chord