moduleHaskore.Interface.SuperCollider.PerformancewhereimportqualifiedHaskore.Interface.SuperCollider.NoteasNoteimportqualifiedHaskore.Interface.SuperCollider.SoundMapasInstrMapimportqualifiedHaskore.Music.StandardasStdMusicimportqualifiedHaskore.Music.RhythmicasRhyMusicimportqualifiedHaskore.MusicasMusicimportqualifiedHaskore.MelodyasMelodyimportqualifiedHaskore.PerformanceasPfimportqualifiedHaskore.Performance.BackEndasPfBEimportqualifiedHaskore.Performance.FancyasFancyPfimportqualifiedHaskore.RealTime.EventList.TimeBodyasTimeListimportqualifiedHaskore.RealTime.EventList.TimeTimeasTimeListPadimportqualifiedHaskore.General.IdGeneratorasIdGenimportqualifiedNumeric.NonNegative.ClassasNonNegfromMelody::(NonNeg.Ctime,Floatingtime,RealFractime)=>Melody.T()->PfBE.PaddedtimeNote.TfromMelody={-
PfBE.fromPaddedPerformance
(Note.fromRhythmicNote
(const "no drum")
(const "no instrument")) .
-}PfBE.fromPaddedPerformance(Note.fromRhythmicNote(error"no drum defined")(error"no instrument defined")).fancyPaddedPerformanceFromMusic.StdMusic.fromMelodyNullAttrundefinedfancyPaddedPerformanceFromMusic::(Ordnote,NonNeg.Ctime,RealFractime)=>Music.Tnote->Pf.PaddedtimeDoublenotefancyPaddedPerformanceFromMusic=FancyPf.paddedFromMusictypeNodeId=Int-- cf. PlayEasytypeNodeIdGena=IdGen.TNodeIdatypeTtime=TimeListPad.Ttime(NodeId,Maybe(time,Note.T))eventsFromNotes,eventsFromNotesQueue,eventsFromNotesEither::(NonNeg.Ctime)=>PfBE.PaddedtimeNote.T->NodeIdGen(Ttime)eventsFromNotes=eventsFromNotesEithereventsFromNotesQueue=eventsFromNotesQueueAuxTimeList.empty{- |
This variant does not need a list of 'Either's,
instead it uses two separate lists for start and stop events.
We would like to use a standard datatype for priority queues,
however it must be efficient to remove the first element
which means that the time stamp of all following elements must be decreased.
Since we have no such data structure, we simply use a TimeList.
But then again, without the 'Either' list,
we have to merge the queue of stop events and the list of start events manually.
This makes the implementation less beautiful.
-}eventsFromNotesQueueAux::(NonNeg.Ctime)=>TimeList.TtimeNodeId->PfBE.PaddedtimeNote.T->NodeIdGen(Ttime)eventsFromNotesQueueAuxqueuextt=let(qExists,(~(qTime,oldSId),qs))=maybe(False,(error"no q",error"no qs"))(\q'->(True,q'))(TimeList.viewLqueue)(xTime,xs0)=TimeListPad.viewTimeLxtt(xExists,(note,xs))=maybe(False,(error"no x",error"no xs"))(\x'->(True,x'))(TimeListPad.viewBodyLxs0)qFirst=doIdGen.freeoldSIdfmap(TimeListPad.consqTime(oldSId,Nothing))(eventsFromNotesQueueAuxqs(TimeListPad.decreaseStartqTimextt))xFirst=donewSId<-IdGen.allocletnoteDur=PfBE.eventDurnotefmap(TimeListPad.consxTime(newSId,Just(noteDur,PfBE.eventNotenote)))(eventsFromNotesQueueAux(TimeList.insertnoteDurnewSId(TimeList.decreaseStartxTimequeue))xs)inifqExists&&(notxExists||qTime<=xTime)thenqFirstelseifxExiststhenxFirstelsereturn(TimeListPad.pausexTime)eventsFromNotesEither=eventsFromNotesEitherAux.TimeListPad.mapBodyRight{-
It seems not to be possible to implement that with foldM,
because one recursive call to eventsFromNotes
requires modifying the events list.
-}eventsFromNotesEitherAux::(NonNeg.Ctime)=>TimeListPad.Ttime(EitherNodeId(PfBE.EventtimeNote.T))->NodeIdGen(Ttime)eventsFromNotesEitherAux=(\(dur,xss)->fmap(TimeListPad.consTimedur)$maybe(returnTimeListPad.empty)(\(x,xs)->letdoRestevrestAct=fmap(TimeListPad.consBodyev)restActineither(\sid->doIdGen.freesiddoRest(sid,Nothing)(eventsFromNotesEitherAuxxs))(\note->dosid<-IdGen.allocletnoteDur=PfBE.eventDurnotedoRest(sid,Just(noteDur,PfBE.eventNotenote))(eventsFromNotesEitherAux(TimeListPad.insertnoteDur(Leftsid)xs)))x)$TimeListPad.viewBodyLxss).TimeListPad.viewTimeLinstrStartNodeId::NodeIdinstrStartNodeId=2-- succ Sound.SC3.Server.Play.homeIdfixNodeIds::NodeIdGena->afixNodeIds=IdGen.runinstrStartNodeIdfromMusic::(Ordnote,NonNeg.Ctime,RealFractime)=>Note.FromNotetimenote->Music.Tnote->NodeIdGen(Ttime)fromMusicmakeNote=eventsFromNotes.PfBE.fromPaddedPerformancemakeNote.FancyPf.paddedFromMusic{- needed for Play.Install, Play.Channel, Live -}{-
fromRhythmicMusic ::
(Show drum, Show instr, Ord drum, Ord instr,
Floating time, RealFrac time) =>
RhyMusic.T drum instr ->
NodeIdGen (T time)
fromRhythmicMusic =
fromMusic (Note.fromRhythmicNote show show)
-}fromRhythmicMusicWithAttributes::(Orddrum,Ordinstr,NonNeg.Ctime,Floatingtime,RealFractime)=>InstrMap.ToSounddrum->InstrMap.ToSoundinstr->RhyMusic.Tdruminstr->NodeIdGen(Ttime)fromRhythmicMusicWithAttributesdMapiMap=fromMusic(Note.fromRhythmicNoteWithAttributesdMapiMap)