Functor defines means for output, e.g. means to output a Strasheela score to a csound score and play the result.
Functor
Out ("/Users/torsten/oz/music/Strasheela/strasheela/trunk/strasheela/source/Output.oz ")
Import
Open OS Tk System Compiler FD FS Browser(browse:Browse) OPIEnv at "x-oz://system/OPIEnv.ozf"
Path at "x-ozlib://anders/tmp/Path/Path.ozf"
GUtils at "GeneralUtils.ozf"
LUtils at "ListUtils.ozf"
MUtils at "MusicUtils.ozf"
Score at "ScoreCore.ozf"
Init at "Init.ozf"
Midi at "MidiOutput.ozf"
HS at "x-ozlib://anders/strasheela/HarmonisedScore/HarmonisedScore.ozf"
Export
Define
proc {Show X}
Simple tool for showing results in the emulator. The idea is, that sometimes we need to copy/paste results. Note that values without a print-representation (e.g., FD ints, procedures, objects) are *not* transformed into any contructor call, but output similarily to how they would be shown in the Browser.
proc {WriteToFile Output Path}
Writes/overwrites Output (a virtual string) to file at Path.
proc {ReadFromFile Path Result}
Reads the content of the text file at Path and returns it as string.
fun {RecordToVS X}
Transforms a (possibly nested) record into a single virtual string with Oz record syntax. RecordToVS also transforms the special Oz records with the labels '|' (i.e. lists) and '#' into their shorthand syntax. The virtual string output is not indented, but every record feature (or list element) starts a new line. As the output is basically a text value (i.e. no 'normal' Oz value anymore), FD and FS variables are transformed into a constructor call (FD.int and FS.var.bounds) which would create these variables when evaluated.
NB: Value.toVirtualString does something very similar: it transforms nested data into their print representation. However, RecordToVS tries to create code which when executed results in same value, whereas Value.toVirtualString creates print representation. Also, RecordToVS does not expect any max width/depth arguments and attempts to format the output.
NB: if X (or some value in X) is not of any of the types record (or list or #-pair) or virtual string, Value.toVirtualString is called on this value and the result is output as atom (i.e. surrounded by 'quotes').
fun {RecordToVS_simple X}
A simpler form of RecordToVS which does not handle variables, and virtual strings are preseved as is.
fun {ListToVS Xs Delimiter}
Transforms Xs, a list of virtual strings, into a single virtual string. Delimiter is the virtual string between all list elements.
fun {ListToLines Xs}
Transforms a list of virtual strings into a single virtual string, every list element starts at a new line.
fun {FormatVS X}
If X is a virtual string, it will be surrounded by explicit double-quotes, \ and " in strings must be escaped.
fun {FormatString X}
If X is a string, it will be surrounded by explicit double-quotes, \ and " in strings must be escaped.
fun {MakeEventlist Score EventOut ScoreOut}
[Temp def? Def. not general enough] MakeEventlist generates a virtual string for output from Score. The unary function EventOut generates the output of a single event. The binary function ScoreOut combines all events to a score.
proc {OutputEventlist Score EventOut ScoreOut Path}
[Temp def -- use WriteToFile directly instead] OutputEventlist transforms Score for output and outputs it at Path. The unary function EventOut generates the output of a single event. The binary function ScoreOut combines all events to a score.
fun {ScoreToEvents MyScore Specs Args}
Transforms MyScore (a Strasheela score) into a list of events. Specs is a list of pairs in the form [Test1#Transform1 ...]. Each Test is a unary function (or method) expecting a score object and returning a boolean. Each Transform is a unary function expecting a score object and returning a list of events.
The record Args expects the only optional argument test, a unary boolean function used to filter the set of score objects in MyScore: only objects for which the test returns true are considered for processing. This test defaults to
fun {Test X} {X isEvent($)} andthen {X isDet($)} andthen {X getDuration($)} > 0 end
For every score object in MyScore which passes this Test, the appropriate Test#Transform pair is found out (i.e. the first pair whose test returns true for the score object). If no matching pair is found, the object is skipped. Otherwise, the respective Transform is applied to this score object and the result appended to the full result of ScoreToEvents.
The following example implements a simple Strasheela score -> Csound score transformation. Only the notes in the Strasheela score are considered (everything else is ignored) and these notes are transformed into a csound score event.
{Out.scoreToEvents MyScore [isNote#fun {$ MyNote}
[{Out.listToVS
[i1
{MyNote getStartTimeInSeconds($)}
{MyNote getDurationInSeconds($)}
{MyNote getPitchInMidi($)}
{MyNote getAmplitudeInVelocity($)}]
" "}]
end]
unit}
For example, the result returned could look like this:
["i1 0.0 1.0 60.0"
"i1 1.0 2.0 62.0"
"i1 2.0 4.0 64.0"]
fun {MakeHierarchicVSScore Score EventOut SimOut SeqOut FurtherClauses}
[Temp def? Def. not general enough] Translates Score into some hierarchic score (a tree, not a graph) for output. EventOut, SimOut, and SeqOut are all functions which output a VS representation of the output format. The functions SimOut and SeqOut return something in the form [BeginVS Delimiter EndVS] -- the representation of their items will be placed between these "tags". FurtherClauses is a list to define additional output alternatives as in the form [testFnOrMeth1#Fn1 ..].
fun {ToScoreConstructor MyScore Spec}
Creates an Oz program (as a VS) which re-constructs MyScore.
proc {OutputScoreConstructor MyScore Spec}
Stores an Oz program in a file which re-constructs MyScore. For example, this file can also be used for editing purposes.
Args
'prefix' and 'postfix': VSs added before and after code for creating score object
'exclude' and 'clauses': arguments of method toInitRecord
Defaults:
unit(file:"test"
extension:".ssco"
dir:{Init.getStrasheelaEnv defaultSScoDir}
prefix:"declare \n MyScore \n = "
postfix:""
)
proc {SaveScore MyScore Args}
Saves MyScore into a text file which can be compiled and loaded again later with LoadScore.
SaveScore internally uses toInitRecord (because a stateful data structure like an object can not be pickled). Therefore, all present restrictions of toInitRecord apply: getInitInfo must be defined correctly for all classes and only tree-form score topologys are supported.
Use this definition if you want to edit the resulting Oz code, otherwise better use PickleScore/UnpickleScore.
fun {LoadScore Args}
Loads a score saved as an Oz program from path.
If the class definitions for the classes used in the score will have changed meanwhile, the loaded score will use the new class definitions (it is re-created from the textual specification).
Loading large scores can be veeeeeery slooooowww.
BUG: SaveScore by default saves a statement starting with "declare MyScore =". LoadScore only works with this default.
BUG: Seemingly LoadScore does not work at all right now
proc {PickleScore MyScore Args}
Stores MyScore (a score object) as persistent data in a file as specified in Args, which can be retrieved by UnpickleScore. For large scores, UnpickleScore is much faster than LoadScore (where the Oz compiler needs to parse etc an Oz program written by SaveScore).
PickleScore uses a customised pickling process (proposed by Denys Duchier). The buildin pickling of Oz does not support undetermined variables (e.g., FD ints), but PickleScore supports these.
Args defaults:
unit(file:"test"
extension:".psco"
dir:{Init.getStrasheelaEnv defaultSScoDir})
fun {UnpickleScore Args}
Restores persistent score data stored in a file by PickleScore.
If the class definitions for the classes used in the score will have changed meanwhile, the loaded score will use the new class definitions (it is re-created from the textual specification).
A score can be restored in different formats, as specified by the argument format:
'initialised': a fully initialised score object is returned (the result was createdw with Score.make).
'uninitialised': a partially initialised score object is returned, which can still be integrated into a larger score (the result was createdw with Score.make2).
'text': a "textual" score is retured (i.e. a nested record that can be an argument for Score.make).
The startTime of the returned score can be specified. If startTime is set to false, then no start time is included. If it is an FD int (or an int) then this FD int is used as start time. If startTime is set to 'orig', then the original start time of the saved score is retained.
Unpickling a score in the "textual" format is very fast, but creating the score object takes time (likely for the constraint propagation).
Args defaults:
unit(file:"test"
extension:".psco"
dir:{Init.getStrasheelaEnv defaultSScoDir}
format: initialised
startTime: 0)
fun {MakeEvent2CsoundFn Instrument Spec}
Outputs unary function which transforms an Score.event into a csound note virtual string.
Spec is a list of accessor functions/methods. However, for every accessor function/method a transformation function/method for the accessed data can be specified using the syntax Accessor#Transformator. All accessors mmust return a parameters (e.g. use getPitchParameter instead of getPitch).
fun {MakeCsoundScore EventVSs Header}
Returns a Csound score as a virtual string. EventVSs is a note list. Each note is a virtual string. Header is the Csound header, e.g. f statements.
proc {OutputCsoundScore MyScore Spec}
Create a csound score file of MyScore, but only include fully determined events. The defaults for Spec are:
unit(file:"test" % without extension
scoDir:{Init.getStrasheelaEnv defaultCsoundScoDir}
header:nil
event2CsoundFn:<see source>
test:<see source>)
header is the csound header VS (e.g. for f-tables).
The default event2CsoundFn of OutputCsoundScore supports parameter unit specifications for the transformation process (see the Parameter documentation). Without determined Parameter unit the unit defaults to seconds for TimeParameters and midi for Pitches. The event2CsoundFn always returns seconds and midi pitches.
always transforms timing parameters into seconds and
proc {RenderCsound MyScore Spec}
Creates a csound score of all (determined) events in MyScore, and renders the score. See the documentation of OutputCsoundScore, CallCsound, and PlaySound for arguments in Spec (the PlaySound argument extension is substituted by the argument soundExtension).
proc {RenderAndPlayCsound MyScore Spec}
Creates a csound score of all (determined) events in MyScore, renders the score and plays the resulting sound. See the documentation of OutputCsoundScore, CallCsound, and PlaySound for arguments in Spec (the PlaySound argument extension is substituted by the argument soundExtension).
proc {CallCsound Spec}
Calls Csound with args in Spec and writes Csound messages on standard output (Oz emulator). Spec is a record with optional arguments. The defaults are:
unit(orc:{Init.getStrasheelaEnv defaultOrcFile} % with extension!, e.g. "pluck.orc"
file:"test" % without extension!
soundExtension:{Init.getStrasheelaEnv defaultCsoundSoundExtension} % ".aiff"
orcDir:{Init.getStrasheelaEnv defaultCsoundOrcDir}
scoDir:{Init.getStrasheelaEnv defaultCsoundScoDir}
soundDir:{Init.getStrasheelaEnv defaultSoundDir}
csound:{Init.getStrasheelaEnv csound}
flags:{Init.getStrasheelaEnv defaultCsoundFlags})
fun {ToLilypond MyScore Args}
ToLilypond transforms a score object into a Lilypond score virtual string.
By default, Strasheela supports the following cases for Lilypond score output. Strasheela temporal containers are transformed into their Lilypond counterpart. A simultaneous container becomes "<< .. >>" and a sequential container becomes "{ ... }". Nevertheless, there are a few special cases supported by default.
By default, a staff is implicitly created for a sequential container which is either at the top-level or contained in a top-level simultaneous container. In typical Strasheela score topology for Lilypond output, a simultaneous is the top-level container and its items are sequential containers corresponding to staffs. If top-level is a sequential, then there is only a single staff. You can define arbitrary other nestings, but in such cases you should explicitly specify which container corresponds to a staff using the lily info-tag (see below). Moreover, you can also explicitly create staff or staff groups which last for the duration of their container only with the lily info-tag. The implicit staff creation can be switched off entirely by setting the optional argument 'implicitStaffs' to false.
A simultaneous container within a staff containing only notes with common start and end times result in a chord (notes on a single staff sharing a stem). Single staff polyphony is supported: multiple (nested) sequentials and simultaneous container representing chords which are contained in a simultaneous (and which corresponds to or is situated in a staff) are output as single staff polyphony. Note that the description of these special cases is slightly simplified in this explanation, see the clause test function sources in Output.oz, when exactly these clauses apply.
Note and pause objects (rests) are notated as expected, including ties for complex durations. However, their duration must exceed the minimum duration value supported (a 64th), shorted durations (or shorter tired fractions) are ignored. Also, offset times of score objects are notated as rests in front of the objects (again, except its duration is less than the minimum duration value supported (offset time notation is not supported by default for a top-level simultaneous container).
Enharmonic notation is supported for enharmonic note objects (subclasses of HS.score.enharmonicSpellingMixinForNote such as HS.score.enharmonicNote). Tuplet output is supported via clauses conveniently created with the function MakeLilyTupletClauses (see there).
Args:
'clauses' (list of function or method pairs): The optional argument 'clauses' provides much control on how the Lilypond output is conducted. Internally, almost all functionality of ToLilypond is also defined by such clauses: further special cases (as described above) can be defined, or the default ones overwritten. 'clauses' expects a list of the form [Test1#ProcessingFun1 ...]. TestN and ProcessingFunN are both unary functions expecting a score object (an item instance such as notes or containers). If the Boolean function TestN is the first clause test which returns true for a score object in MyScore, then ProcessingFunN will create the Lilypond VS for this object. For example, the user may define a subclass of Score.note with an additional articulation attribute (e.g. values may be staccato, tenuto etc.) and the user then defines a clause which causes Lilypond to show the articulation by its common sign in the printed score.
'wrapper' (list of two strings): The argument 'wrapper' expects a list of two VSs with legal Lilypond code. These VSs are inserted at the beginning and the end respecitively of the Lilypond score. Note that the Lilypond version statement is hardwired -- you should not add a version statement to your header (there is a 'version' argument expecting the version number as a VS, use at own risk).
'implicitStaffs' (Boolean): whether staff declarations are created automatically.
'hasImplicitStaff' (unary Boolan function): test for which containers staff declarations are created automatically (only supported for containers).
'hasBreak' (Boolean): test after which container \break is inserted.
'getClef' (default AveragePitchClef): unary function expecting a container representing a staff and returning a Lily clef (a VS). If the function returns nil, then no clef declaration is inserted.
Arbitrary Lilypond code can be added to container and note objects via a tuple with the label 'lily' given to the info attribute of the score object. This tuple must only contain VSs which are legal Lilypond code. For containers, this lilypond code is always inserted in the Lilypond output before the container, for notes it is inserted after the note.
The argument defaults are shown below.
unit(clauses:nil
wrapper:["\\paper {}\n\n\\score{\n{" %% empty paper def
"\n}\n}"]
implicitStaffs:true
hasImplicitStaff: IsOutmostSeq
hasBreak: fun {$ X} false end
version:"2.12.0")
fun {ToLilypond2 MyScore Args}
[for clause definitions] like ToLilypond, except only the bare Lilypond score is created. That is, no Lilypond version number is inserted in the output, nor is the wrapper Lilypond code inserted (see wrapper argument of ToLilypond).
proc {OutputLilypond MyScore Args}
Transforms MyScore into a Lilypond score and writes it to a file. The default values for the optional arguments are shown below. See the documentation of ToLilypond for an explanation of additional arguments.
unit(dir: {Init.getStrasheelaEnv defaultLilypondDir}
file: "test" % !! file name without extention
)
proc {CallLilypond Args}
Calls Lilypond on a Lilypond file specified by Args. The defaults of Args are:
unit(dir: {Init.getStrasheelaEnv defaultLilypondDir}
file: test) % !! file name without extention
proc {ViewPDF Args}
Calls a PDF viewer on a PDF file specified by Args. The name of the PDF file is given without extension. The PDF viewer application defaults to the value of the Strasheela environment variable pdfViewer. The defaults of Spec are:
unit(dir: {Init.getStrasheelaEnv defaultLilypondDir}
file: test
pdfViewer: {Init.getStrasheelaEnv pdfViewer}
extension:".pdf")
proc {RenderLilypond MyScore Args}
Outputs a Lilypond file for MyScore and calls Lilypond to process it. See ToLilypond, OutputLilypond and CallLilypond for details on Spec.
proc {RenderAndShowLilypond MyScore Args}
Outputs a Lilypond file for MyScore, calls Lilypond to process it, and calls the PDF viewer with the result. See ToLilypond, OutputLilypond, CallLilypond, and ViewPDF for details on Args.
fun {MakeLilyTupletClauses Fractions}
[for clause definitions] MakeLilyTupletClauses creates a list of Lilypond clauses for tuplet output. Fractions is a list of pairs Numerator#Denominator indicating the fractions of the tuplets. For example, clauses for triplets are created with he fraction 2#3 and clauses for quintuplets with the fraction 2#5. Tuplets are recognised automatically in the score by the duration of score elements (notes and pause objects). The time unit must be set to beats(N), where N is some quarter note division which allows to express all required durations. For example, if the time unit is beats(60) then the duration 60 indicates a quarter note, 30 indicates an eigth note, three notes of duration 20 form an eigth note triplet and 5 notes of duration 6 form a sixteenth note quintuplet.
LIMITATIONS: Rests must be expressed explicitly with pause objects, rests expressed by the offset time of score objects are not notated correctly if their duration should be part of a tuplet. Dotted notes at the beginning of a tuplet do not work. Tuplets only work correctly for score elements within a single sequential container: a tuplet must not extend across container boundaries. Also, tuplets cannot be nested. Due to these shortcomings, the default Lilypond output does not support tuplets.
fun {SeqToLily Seq Args}
[for clause definitions] creates Lilypond output (a VS) for a sequential container. Args is a record of optional args (clauses and implicitStaffs).
Default Lilypond output uses this definition. Using this function may simplify writing custom output clauses which overwrite the default output.
fun {SimToLily Sim Args}
[for clause definitions] creates Lilypond output (a VS) for a simultaneous container. Args is a record of optional args (clauses and implicitStaffs).
Default Lilypond output uses this definition. Using this function may simplify writing custom output clauses which overwrite the default output.
fun {MakeNoteToLily MakeAddedSigns}
[for clause definitions] Returns unary function which expects a note object and a and a unary function expecting the note and returning a VS of arbitrary Lilypond code, typically an expression, a markup etc. It returns a Lilypond note output (a VS). Simplified version of MakeNoteToLily2.
fun {MakeNoteToLily2 Args}
[for clause definitions] Returns unary function which expects a note object and returns a Lilypond note output (a VS). MakeNoteToLily2 adds the rhythmic information and cares for ties.
Args:
'makePitch': a unary function expecting a note object and returning a Lilypond pitch (a VS).
'makeCodeBefore': a unary function expecting the note and returning a VS of arbitrary Lilypond code (a VS) placed directly before the note (e.g. for setting some attributes of the note). A whitespace is implicitly added between this code and the note.
'makeCodeAfter' a unary function expecting the note and returning a VS of arbitrary Lilypond code (a VS) placed directly after the note (e.g. for fingering marks, articulation marks, markup etc.). No whitespace is added between the note and this code.
'makeCodeBefore_tie'/'makeCodeAfter_tie': a unary function expecting the note and returning a VS of arbitrary Lilypond code (a VS). In case the Strasheela note is split into multiple Lilypond notes connected by ties, this code is inserted before/after each tied Lilypond note.
fun {LilyMakePitch PitchParam}
[for clause definitions] creates Lilypond pitch output (a VS) for a pitch parameter.
fun {LilyMakeFromMidiPitch MidiPitch}
[for clause definitions] creates Lilypond pitch output (a VS) for a midi pitch value (an integer).
fun {LilyMakeMicroPitch PitchParam}
[for clause definitions] creates Lilypond 72 ET microtonal pitch output (a VS) for a pitch parameter. Note: works only if the pitch unit is et72.
fun {LilyMakeEt72MarkFromMidiPitch MidiPitch}
[for clause definitions] Returns a Lily fingering mark (a virtual string) which represents a micro-tonal tuning deviation in 72 ET temperament.
fun {PauseToLily MyPause}
[for clause definitions] Expects a pause object and returns a Lilypond rest (a VS).
fun {LilyRest PauseDurInBeats}
[for clause definitions] Expects a pause duration in beats (a float) and returns a Lilypond rest (a VS).
fun {LilyMakeRhythms DurationParam}
[for clause definitions] creates Lilypond duration output (a list of Lilypond rhythm values, which in the end are tied together) for a duration parameter.
fun {LilyMakeRhythms2 DurationInBeats}
[for clause definitions] creates Lilypond duration output (a list of Lilypond rhythm values, which in the end are tied together) for a duration measured in beats (a float).
fun {IsOutmostSeq X}
[for clause definitions and arg hasImplicitStaff] Tests whether X is an Outmost sequential container, i.e. a container which has no direct or indirect temporal container which is also a sequential container. X is either the top-level container, or (the most common case) contained in a top-level simultaneous container.
An outmost sequential implicitly creates a staff by default. %%
fun {IsOutmostSim X}
[for clause definitions and arg hasImplicitStaff] Tests whether X is a simultaneous container and there is no simultaneous container in which X is nested.
fun {IsSingleStaffPolyphony X}
[for clause definitions] Returns true if X is a simultaneous container which containes multiple voices; each voice is a sequential which contains only (i) notes, (ii) simultaneous containers which are chords or (iii) sequentials which in turn contain only notes or chords.
By default, such a simultaneous container creates a single staff polyphony.
fun {SingleStaffPolyphonyToLily Sim Args}
[for clause definitions] Outputs X (for which IsSingleStaffPolyphony must return true) as a single staff polyphony Lily VS.
fun {IsLilyChord X}
[for clause definitions] Returns true if X can be notated as a chord, i.e. X is a simultaneous which contains only notes with equal offset time, start and end times
fun {SimToLilyChord Sim}
[for clause definitions] Outputs Sim (for which IsLilyChord must return true) as a Lilypond chord VS.
fun {GetUserLily X}
[for clause definitions] Accesses tuple with label 'lily' in info feature of X, and returns VS (concatenating all lily tuple elements). The lily tuple must only contain VSs.
fun {AveragePitchClef X}
Expects a container and returns a Lilypond clef declaration based on the average value of pitch parameters in this container.
proc {SetMaxLilyRhythm Dur}
When outputting a Lilypond file, Strasheela automatically splits very long notes (or other score objects notated by notes such as chords or scales) into multiple notes connected by ties. The maximum duration notated by a single note can be set with this procedure. Dur is a float measured in quarternotes. For example, 2.0 indicates a halve note and 0.5 an eighth note. The maximum duration supported by Lilypond is a longa (16.0). The default is 4.0 (a whole note).
It is recommended to set Dur to the length of your bars (e.g., 4.0 for 4/4).
proc {OutputSCScore Score SCEventOut Spec}
fun {MakeSCScore Score SCEventOut MkContainerOut FurtherClauses}
Generate a SuperCollider score in hierarchic score format (a VS). SCEventOut is a unary function transforming a single SDL event into a SC event (a VS). The TimeParameter units must be determined.
fun {MakeSCEventOutFn PlayerOut}
[aux means for MakeSCScore] Outputs a unary function which transforms a SDL event into a SC event (a VS). PlayerOut is a unary function with the event a argument which returns a SC player call (a VS). The TimeParameter units must be determined.
proc {SendOsc Host Port OSCcmd}
NB: the network address must be set by setting the environment var REMOTE_ADDR (defaults to '127.0.0.1').
proc {SendSCserver OSCcmd}
[tmp restricted def?]
proc {SendSClang OSCcmd}
[tmp restricted def?]
fun {ToNonmensuralENP TheScore Args}
Exports TheScore (a Strasheela score) into a non-mensural ENP score (a VS). The ENP format is rather fixed, whereas the information contained in the Strasheela score format is highly user-customisable. Therefore, the export-process is also highly user-customisable.
An ENP score has a fixed topology. The non-mensural ENP has the following nesting: score(part(voice(chord(note+)+)+)+)
. See the PWGL documentation for details.
Strasheela, on the other hand, supports various topologies. However, ToNonmensuralENP does not automatically perform a score topology transformation into the ENP topology. Instead, ToNonmensuralENP expects a number of optional accessor functions as arguments (e.g. getScore, getParts, getVoices) which allow for a user-defined topology transformation. These functions expect a (subpart of the) score and return the contained objects according to the ENP topology. For instance, the function getVoices expects a Strasheela object corresponding to an ENP part and returns a list of Strasheela object corresponding to ENP voices. The default values for these accessor functions require that the topology of TheScore fully corresponds with the ENP score topology. That is, for the default accessor functions, TheScore must have the following topology: sim(sim(seq(sim(note+)+)+)+)
. The set of all supported accessor functions (together with their default values) is given below.
Any ENP attribute of a score object can be specified by the user. For this purpose, ToNonmensuralENP expects a number of optional attribute accessor functions (e.g. getScoreKeywords, getPartKeywords). These functions expect a Strasheela object corresponding to an ENP part and returns an Oz record whose features are the ENP keywords for this objects and the feature values are the values for these ENP keywords. See the default of getNoteKeywords for an example.
In addition, enp syntax can be given directly to score objects via an info tag/record with the label 'enp' where the keywords are the record features with their associated values (e.g., enp(expression: [accent])). In case a keyword is defined both with an acessor function (e.g., getVoiceKeywords) and directly as an enp info tag, then the info tag is taken instead.
Default arguments:
unit(getScore:fun {$ X} X end
getParts:fun {$ MyScore} {MyScore getItems($)} end
getVoices:fun {$ MyPart} {MyPart getItems($)} end
getChords:fun {$ MyVoice} {MyVoice getItems($)} end
getNotes:fun {$ MyChord} {MyChord getItems($)} end
getScoreKeywords:fun {$ MyScore}
unit % put further ENP score keywords here
end
getPartKeywords:fun {$ MyPart}
unit % put further ENP part keywords here
end
getVoiceKeywords:fun {$ MyVoice}
unit % put further ENP voice keywords here
end
getChordKeywords:fun {$ MyChord}
unit % put further ENP chord keywords here
end
getNoteKeywords:fun {$ MyNote}
put further ENP note keywords here
unit('offset-time': {MyNote getOffsetTimeInSeconds($)})
end)
Note: this function also works for the format expected by the simple format of the PWGL library KSQuant. You need to set the argument toKSQuant to true for this purpose.
proc {OutputNonmensuralENP MyScore Args}
Exports MyScore (a Strasheela score) into a text file with a non-mensural ENP score. The file path is specified with the arguments file, extension and dir. For further arguments see the ToNonmensuralENP documentation.
fun {ToFomus MyScore Args}
ToFomus exports MyScore into Fomus format (http://fomus.sourceforge.net/). More specifically, ToFomus returns a VS that corresponds to a .fms file (the procedures OutputFomus and RenderFomus are extensions of ToFomus that output a Fomus file and call Fomus on resulting files). Fomus can translate .fms files into the music notation formats MusicXML (for import into Sibelius or Finale) and Lilypond.
Strasheela export to Fomus is demonstrated by many examples in the file examples/ControllingOutput-Examples/Fomus-Examples.oz.
Fomus supports many settings that customise the resulting score. These settings can occur at several hierarchic levels, e.g., globally at the score level, at the part level and at the event level (see the Fomus documentation at http://fomus.sourceforge.net/doc.html/). (Almost?) any Fomus setting can be specified in Strasheela by an info record with the label 'fomus' and with feature value pairs that correspond to the settings given to Strasheela score objects that correspond to the Fomus score, its parts and Fomus events (see below). For example, the title of a score is declared with the global setting title: the corresponding info record is given to the top-level Strasheela container.
sim(info: fomus(title: "My Composition")
...)
Global settings like the title are output with the Fomus syntax setting = value, e.g., title = "My Composition". Global Fomus declarations that do not follow this format can be specified (quasi) without an explicit feature as follows.
sim(info: fomus("inst ")
...)
Marks for events (e.g., articulation signs, see http://fomus.sourceforge.net/doc.html/Marks.html) are given in the fomus info record using the feature 'marks', which expects either an individual mark (a VS) or a list of marks (a list of VSs).
note(duration:4 pitch:60 info:fomus(marks: ".")) % staccato note
note(duration:4 pitch:60 info:fomus(marks: ['-' '>'])) %
Fomus code can be inserted before and after events and parts with the info tags fomus_before and fomus_after. These info tags are tuples where each element is output directly as a fomus code line. The following example inserts a measure declaration directly before the note such that the start time of this measure is taken from the end of the preceding note.
note(info:fomus_before("time = + dur = 3 ||")
duration:4 pitch:60)
ToFomus tries to make a good guess which of the Strasheela items in a given score correspond to which Fomus hierarchy level such as the Fomus score, part or event. The top-level Strasheela container always corresponds to the Fomus score, and Strasheela elements as well certain containers correspond to Fomus events (these containers are simultaneous containers that only contain notes with the same start/end times, so it can be notated as a chord).
However, Strasheela supports more hierarchic levels than Fomus, and therefore getting parts correctly assigned can be tricky. Users can therefore manually declare certain Strasheela containers as part by tagging it with the info tag fomusPart. Optionally, this info tag can be a record with the Fomus part name at its feature 1 (see example below). Multiple Strasheela containers can that way be assigned to the same Fomus part, a useful features for Strasheela scores with complex nesting (e.g., if the top-level container is a sequential that holds multiple sections and each section should be notated in multiple parts).
seq(info: [fomusPart(violin)
fomus(inst: violin)]
...)
BUG: in the combination above, instrument setting is ignored.
Note that the info tag fomusPart(nil) results in no fomus part declaration, useful for exporting measures at the beginning of the score.
Note that in principle Strasheela objects can correspond to multiple Fomus hierarchic levels (e.g., when outputting a single Strasheela note it corresponds to the score, a part and an event). However, for many Fomus settings it is necessary to have different Strasheela objects for different Fomus hierarchic levels, because certain settings are only permitted at certain Fomus hierarchic levels.
If tagging parts with the info tag fomusPart is not sufficient for your purpose to locate the Strasheela containers that correspond to parts, then the argument 'getParts' makes an alternative approach possible (recommended only for expert users).
Args:
'output' (possible values: lilypond, xml, midi, default lilypond): sets the output format of Fomus.
'file' (default "test"): sets the basename of the resulting fomus file, and the files created by fomus.
'dir' (default {Init.getStrasheelaEnv defaultFomusDir}): sets the directory of the resulting fomus file and files created by fomus.
'eventClauses' (default nil): [for advanced users]
A list of pairs of Boolean function/method and binary event processing functions
[Test1#fun {$ MyEvent PartId} ... end ...]
This argument is in its effect very similar to the 'clauses' argument of other export procedures (e.g., for Lilypond output). For every Strasheela item that corresponds to a Fomus event (see above) *and* for which some test function/method returns true, the corresponding event processing function is used to create its Fomus output VS. If multiple tests (would) return true, then the first corresponding processing function is used.
'getParts' (unary function): [for expert users]
This function can be used to customise the way Strasheela containers are identified to correspond to Fomus parts. The function expects the top-level score item and returns a list of items corresponding to the Fomus parts. For an example, see the function GetFomusParts in source/Output.oz, which defines the default
'getScoreSettings'/'getPartSettings': [for advanced users] Unary function that expects the Strasheela item corresponding to a score/part and returns a record of Fomus settings (same format as the fomus info record).
proc {OutputFomus MyScore Args}
Outputs a fomus file. See the doc of ToFomus for further information.
proc {RenderFomus MyScore Args}
Creates a fomus file from MyScore and calls the fomus command-line application on this file. The argument flags expects a list of fomus flags (default is nil). See the doc of ToFomus and OutputFomus for further information.
fun {GetUserFomus X}
[for clause definitions etc] Accesses info tag (record) with label 'fomus'.
fun {GetUserFomus_Before X}
[for clause definitions etc] Accesses info tag (record) with label 'fomus_before'.
fun {GetUserFomus_After X}
[for clause definitions etc] Accesses info tag (record) with label 'fomus_after'.
fun {Record2FomusEvent X}
[for clause definitions etc] Transforms a record into a VS of the form "feat1 val1 ... featn valn ;"
The required features time and dur are always put at the beginning, and possible marks at the end.
fun {Record2FomusEvent_Untimed X}
[for clause definitions etc] Transforms a record into a VS of the form "feat1 val1 ... featn valn ;"
Variant of Record2FomusEvent without time and marking processing.
fun {Record2FomusNote R MyItem}
[for clause definitions etc] Expects a record R, whose features are the Fomus settings of a note and MyItem (typically the note itself). MyItem is used to add the settings in its fomus info tag, if MyNote is nil then these are left out. Record2FomusNote returns the corresponding Fomus code (a VS).
Required features in R: part, time, dur.
fun {Record2FomusObject X}
[for clause definitions etc] Transforms a record into a VS of the form ""
fun {Record2FomusSetting X}
[for clause definitions etc] Transforms a record into a VS of the form "feat1=val1\n ... featn=valN\n". An exception are integer features, where instead only the corresponding value is output like "val1\n ... valN\n".
fun {Record2FomusCode X}
[for clause definitions etc] Transforms a record into a VS of the form "val1\n ... valN\n" (i.e. the record features are ignored, in contrast to Record2FomusSetting).
fun {Record2FomusMeasure X}
[for clause definitions etc] Transforms a record into a VS of the form "time dur | | ".
The features time and dur are required.
fun {MakeFomusNote MyNote PartId}
[for clause definitions etc] note processing function for note-eventClause. Returns the Fomus code for a note where the pitch is the MIDI float of the note.
fun {MakeCMEvent Note Spec}
Returns CM note VS. Spec is a record of the form class(keywordSymbol1: noteAccessor1 ..). class is an atom, each keywordSymbol are an atom and each noteAccessor is funtions or method.
fun {MakeCMScore Score Args}
Transforms Score to Common Music score (VS). Common Music in turn can be used to output to various formats (e.g. MIDI, SuperCollider, Csound, music notation formats via FOMUS) or used to edit the score (e.g. with the CM Plotter). Optional Args features are containerOut (unary function, expecting a container and outputting a list of VS in the form [BeginVS Delimiter EndVS]), eventOut (unary function, expecting an event and outputting a VS), and furtherClauses (list of declarations, see MakeHierarchicVSScore for further details). The default eventOut outputs a CM 'midi' (i.e. events must be notes), the default containerOut outputs a CM 'seq' with the contained items as 'subobjects'.
proc {OutputCMScore Score Args}
Outputs Score into a CM score file. Optional Args features are dir (a VS, defaults to default CM dir in Strasheela env), file (VS, defaults to test), extension (VS, defaults to '.cm'), wrapper (a list of two VS as [WrapperHeader WrapperFooter]) and ioExtension (a VS). The Args feature wrapper specifies a Lisp expression surrounding the CM score in the output, it defaults to a var binding and an 'events' call for output with the same file name as specified by Args or Defaults and an extension as specified by ioExtension.
Additionally, Args features are the Args supported by MakeCMScore (see there).
fun {ToDottedList X}
Recursively transform X into virtual string representing a Lisp list (a dotted list). X is a (possibly nested) list of virtual strings or a virtual string.
fun {LispList X}
Outputs virtual string with round paranthesis wrapped around X. X is either a virtual string or an Oz list of virtual strings
fun {RecordToLispKeywordList X}
This functions transforms a 'literal' Oz value (i.e. a value with a textual representation) into a corresponding literal Lisp value. It transforms an Oz record or list (possibly nested) into a virtual strings representing a Lisp keyword list. Each Oz record feature is transformed into a Lisp keyword (i.e. there is a colon in front of it) and the Oz value into a the corresponding Lisp value. Any record label is omitted (except the whole record is a plain Oz atom). In case a feature is an integer the keyword is omitted.
!! NB: Currently, a value must be either (i) a literal which can be used directly in a VS and doesn't need to be further translated into a Lisp value (e.g. an atom, number, or string), (ii) an Oz list of supported values, or (iii) a record of supported values.
A record feature can only be an integer or a symbol
NB: The list is output without any line breaks. Use the pprint Lisp function for a more human-readable format.
NB: Oz strings are lists of integers between 0 and 255, i.e. it can not be distinguished from a plain list of integers (e.g. denoting an all-interval series). Therefore, strings are not transformed into Lisp syntax!
NB: Oz atoms can contain whitespace list 'Hi there' which result into two Lisp values!
fun {ToLispKeywordList X Spec}
Returns a lisp keyword list (a VS). X is a Strasheela score object (e.g. a note) and Spec is a record of the form unit(keyword1: accessor1 ..). The returned keyword list contains the record features as keywords and at these keywords the values of returned by the accessor (a unary function or method expecting X), i.e. ToLispKeywordList returns a VS of the form '(:keyword1'#{accessor1 X}# .. #')'
fun {OzToLisp X Args}
OzToLisp transforms a literal Oz value (i.e. a value with a textual representation) into a corresponding literal Lisp value expressed by a VS.
Supported Oz values are integers, floats, atoms, records/tuples, lists and virtual strings. These values can be freely nested. In principle, characters and strings are supported as well, see below. Not supported are Oz values without a textual representation (e.g. names, procedures, and chunks).
Oz characters are equivalent to integers and Oz strings are equivalent to lists of integers. Therefore, the users must decide for either integer or character/string transformation. For this purpose, Arg expects the optional arguments charTransform and stringTransform (both default to false, i.e. characters and strings are per default transformed into Lisp integers / integers lists).
The following list details how values are transformed:
boolean -> boolean: true -> T, false -> nil [NB: Lisp2Oz: nil can also be empty list..]
integer -> integer: 1 -> 1 [only decimal notation supported, NB: tilde ~ as unary minus for int and float supported]
float -> float: 1.0 -> 1.0 [exponential notation supported]
atom -> symbol: abc -> abc
record -> keyword list: unit(a:1 b:2) -> (:a 1 :b 2 :record-label unit)
tuple -> keyword list: test(a b) -> (a b :record-label test)
list -> list: [a b c] -> (a b c)
VS -> unaltered VS: "("#'some Test'#")" -> (some Test)
character -> character: &a -> (code-char 97) equivalent to 97 -> #\a
string -> string: "Hi there" -> "Hi there"
NB: Virtual strings are passed unaltered: the user is responsible that any (composite) VS results in a valid Lisp value.
NB: the keyword-value pair :record-label is always the last two elements in a record/tuple list.
NB: OzToLisp is very similar to RecordToLispKeywordList. The main difference is that OzToLisp can handle more cases truely in Lisp syntax (e.g. outputs something as 'Hi there' as |Hi there|). Moreover, the values are transformed in such a way that no information is lost and backtransformation (LispToOz) would be possible as well (e.g. the label of a record is preserved and the presence of the label marks a difference to a plain list).
TODO:
* Lisp does not distinguish between cases, but for back-transformation of symbols etc in CamelCase I should possibly use symbols like |CamelCase|.
fun {Note2ClmP Note}
fun {MakeClmScoreFn WithSoundArgs}
[a quick and probably temp. hack]
proc {PlaySound Spec}
If a sndPlayer is specified, Strasheela assumes it has an own GUI and just calls it with the sound file. If a cmdlineSndPlayer is specified, Strasheela provides a minimal GUI for the cmdline soundPlayer. Spec is a record with optional arguments, the defaults are:
unit(file:"test" % without extension
extension:".aiff"
soundDir:{Init.getStrasheelaEnv defaultSoundDir}
title:"Play Sound")
proc {Exec Cmd Args}
Execute shell Cmd with Args, show standard out/error in the emulator and exit.
proc {ExecNonQuitting Cmd Args}
Execute shell Cmd with Args, show standard out/error in the emulator and exit. This is very similar to Exec, however the application Cmd does not automatically quit after finishing.
proc {ExecWithOutput Cmd Args Output}
Execute shell Cmd with Args, bind standard out/error to Output and exit.
Provides an interface to interactive commandline programs like a shell or an interpreter. Start interactive program with the method init (see below), close it with the method close. The Shell object features cmd and args bind the respective init arguments.
More specialised classes (e.g. an interface to Common Lisp) may be obtained by subclasses..
class Shell from Open.pipe Open.text
feat cmd args
init (args:Args cmd:Cmd)
cmd (Cmd)
showAll ()
outputLine ($)
end
End