Class DottedNotationExpander

java.lang.Object
eu.bandm.tscore.base.DottedNotationExpander

public class DottedNotationExpander extends Object
For musical purposes it is utmost convenient to support the "dotted notation", using "prolongation dots", short "dots". This is a shorthand notation for changing a 2-to-2 proportion into a 3-to-1 or 1-to-3, 1-to-7, 7-to-1, etc., directly when defining the events by their main parameters.
In a CWN tscore context, you want to write e.g.
     T         1                         2
     VOX Alt   c. d   e. (f fis)   g ..a 
  
Exactly two(<=2) events are affected by dot notation: an event with trailing dots and its successor, or an event with leading dots and its predecessor. The cases are called "positive" and "negative" dotting; the involved events are called "dotted" and "shortened". If both of two neighbouring events carry a dot, then the dots must point outwards as in ".a b.". The event with the dots will become longer. The later of the involved events must have a "floating" notation of its starting time, i.e. must not be bound to a time point in the time line, because this start time will be changed by the dotting.
     T         1       2           3       4       5
     VOX Alt   a.  b   c  .d       e  f.   g   h   i
     //        posit.  negative    invalid, because "g" is fixed to a point in the time line "T"

     //      allowed, "event g" is NOT positioned at "Tp 4":  FIXME CHECK vaild !??! 
     VOX Ten                       e  (f.  g ) h   i
  

In their concrete appearance, the dots must follow without intervening whitespace and may only appear in one single line (the first resp. last line), not broken to more than one line.
From the frontend lexer syntax, dots as input symbols are only allowed as part of the (otherwise unspecified) parameter text. Thus, only "events" and not parenthesized groups may be extended by dots. But the shortened event in the pair may be replaced by a parenthesized group, as in the example. This corresponds to normal practice in CWN.

For this behaviour, an instance of this class can be constructed and applied to a voice (more precisely: to the list of events of this voice in source order), after this voice has been built when the containing Part has been parsed by Util.parseTimeScape(File, Modifiers, MessageReceiver) and before the start time information of the events of this voice are calculated. (E.g. by Util.getRationalValue(Function, Map,Tp,MessageReceiver,Map). --- see the source text of Score_cwn as an example.)

The implementation here is somehow hacky: A text transformation is applied to a sequence of events which is still in source text sequential order of one monodic voice. The dotted event and its shortened counterpart must lie in the same time division and occupy the same duration.
(The latter is currently not yet checked !)
Then a new division is created, which divides their sum duration by four/eight/sixteen, etc., depending on the number of dots.
Then it distributes the interval in the requested proportion:
1+3, 1+7, 1+15, etc., for negative dotting, iff the dots are leading in the second event,
or 3+1 , 7+1, 15+1 etc., for positive dotting, iff the dots are trailing in the first event.
This transformation has to be called before any "duration per event" is calculated.
The dots characters are removed from the parameter values, and all further processing can happen as if the proportions had been notated explicitly, e.g by parentheses:

     a.. b    ==> a(-(- b))
  
The following situations can occur:
     ALLOWED:
        a  .b
        a.  b
        .a b. 
     ERRORS:
        .a. 
        a. b.
        a. .b 
     ALLOWED
        a. (b.    )
       ( .b) .a 
     ERRORS:
        a   (.b    )
       (   a.) b 
 
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    (package private) final String
    The terminal string representing the prolongation dot.
    (package private) final String
    The name of the main parameter of the voice, corrsponding to the "VOX .." line and defining the time points of the events.
    (package private) final MessageReceiver<SimpleMessage<eu.bandm.tools.util.xml.XMLDocumentIdentifier>>
    Drain of all messages.
    (package private) boolean
    Output register of parseOne(Event): if dot combinations are legal.
    (package private) int
    Output register of parseOne(Event): dots to the right of the current event.
    (package private) int
    Output register of parseOne(Event): dots to the left of the current event.
    (package private) final Map<TDivision,TDivision>
    Temporary map for all time divisions affected by a dotting.
    (package private) final Map<TpSub,TpSub>
    Temporary map for all time points affected by a dotting.
  • Constructor Summary

    Constructors
    Constructor
    Description
    DottedNotationExpander(MessageReceiver<SimpleMessage<eu.bandm.tools.util.xml.XMLDocumentIdentifier>> msg, String dotString, String mainParamName)
    Public constructor, must be called before calling apply(List).
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    apply(List<Event> events)
    Service access point, called from outside.
    protected void
    clearDots(Event ev, boolean leftIsDotted, int dotcount)
    The dotted event must be a simple one (no parenthesis), and the dots part must be part of the text of the main parameter.
    protected @Opt TDivision
    Return new, shifted divison, or null iff tdivision is NOT affected by shift.
    protected @Opt TpSub
    Returns new, shifted TpSub, or null iff tdivision is NOT affected by shift.
    (package private) boolean
    Returns whether the time point is the very last in its containing division.
    protected void
    Sets global output values and makes some syntax check.
    protected void
    replace(List<Event> events, int indexRight, Event left, Event right, int dotcount, boolean leftIsDotted)
    Central function for adjusting the time structure according to a dotted rhythm.
    (package private) boolean
    sameLevel(Event left, Event right)
    Returns whether both events have their time point in the same time point division.
    protected final boolean
    Returns whether the Event is affected.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • msg

      final MessageReceiver<SimpleMessage<eu.bandm.tools.util.xml.XMLDocumentIdentifier>> msg
      Drain of all messages.
    • dotString

      final String dotString
      The terminal string representing the prolongation dot.
    • mainParamName

      final String mainParamName
      The name of the main parameter of the voice, corrsponding to the "VOX .." line and defining the time points of the events.
    • preDots

      int preDots
      Output register of parseOne(Event): dots to the left of the current event.
    • postDots

      int postDots
      Output register of parseOne(Event): dots to the right of the current event.
    • ok

      boolean ok
      Output register of parseOne(Event): if dot combinations are legal.
    • tpsub2shifted

      final Map<TpSub,TpSub> tpsub2shifted
      Temporary map for all time points affected by a dotting. Valid during the processing of one particular dotter pair of neighbouring events.
    • tdiv2shifted

      final Map<TDivision,TDivision> tdiv2shifted
      Temporary map for all time divisions affected by a dotting. Valid during the processing of one particular dotter pair of neighbouring events.
  • Constructor Details

    • DottedNotationExpander

      public DottedNotationExpander(MessageReceiver<SimpleMessage<eu.bandm.tools.util.xml.XMLDocumentIdentifier>> msg, String dotString, String mainParamName)
      Public constructor, must be called before calling apply(List).
      Parameters:
      dotString - a String of length=1 which represents one single dot (normally = ".")
      mainParamName - the paramter track name to which the modifications will be applied.
  • Method Details

    • parseOne

      protected void parseOne(Event ev)
      Sets global output values and makes some syntax check.
    • sameLevel

      boolean sameLevel(Event left, Event right)
      Returns whether both events have their time point in the same time point division. (This implies that the later Tp is "floating", i.e. not bound by a time line column.)
    • apply

      public void apply(List<Event> events)
      Service access point, called from outside. Analyses the main parameter of all events, makes initial syntax and context checks (eg no a. .b), and applies timepoint adjustment.
    • isLastInDivision

      boolean isLastInDivision(Tp tp)
      Returns whether the time point is the very last in its containing division. (Thus the next currently known time point is the right limit of that division, and itself defined in a higher-level division or an top-level.)
    • replace

      protected void replace(List<Event> events, int indexRight, Event left, Event right, int dotcount, boolean leftIsDotted)
      Central function for adjusting the time structure according to a dotted rhythm. The right event must lie on a event-defined (flexible) time-point in the same division level as the left event: either both are contained in a parentheses group, or the second lies on a text column not defined in its time line. The non-dotted partner of the pair may by a parentheses group. In all cases all events but the very first must be shifted to a new TDivision.
           a.     b                   x    
           a.     (b c )              x
           a.     (b  (c. d) )        x
       //OR negative case
           a      .b                  x    
           (a a)  .b                  x
       // ERROR, not the same TDivision:
           a.     (b  (.c d) )        x
           (a a.) b
       
      Search process is as follows:
                                                        tpSomewhere
            tpLeft          tpRight --> tpNewRight             |
                  tpNewRight<----                              |
              ------tDDiv------                                |
                  tp         tp                                |
                              --tDDiv--------------------------|
                                          tp   tp    tp        |
                    -----tDiv---                               tX
       
      ALL events at ALL tp's must be shifted, up to the first "tX" which lies totally to the right side of tpRight, thus is not affected by shifting.
    • testEvent

      protected final boolean testEvent(Event ev)
      Returns whether the Event is affected. Since we follow the source text order, first false result signals that all ncessary Events habe been processed.
    • getTpsubshifted

      @Opt protected @Opt TpSub getTpsubshifted(TpSub tpsub)
      Returns new, shifted TpSub, or null iff tdivision is NOT affected by shift.
    • getTdivshifted

      @Opt protected @Opt TDivision getTdivshifted(TDivision tdiv)
      Return new, shifted divison, or null iff tdivision is NOT affected by shift.
    • clearDots

      protected void clearDots(Event ev, boolean leftIsDotted, int dotcount)
      The dotted event must be a simple one (no parenthesis), and the dots part must be part of the text of the main parameter. So they can and must be removed there!