Karya, built on Mon Jul 24 11:39:07 PDT 2017 (patch 33511aca01257b76b88de7c7a2763b7a965c084e)

Safe HaskellNone




Calls for gangsa techniques. Gangsa come in polos and sangsih pairs, and play either kotekan patterns or play unison or parallel parts.

Kotekan patterns have a number of features in common. They are all transpositions from a base pitch. Rhythmically, they consist of notes with a constant duration, that line up at the end of an event's range, and the last duration is negative (i.e. implicit, depending on the next note). They use polos and sangsih and may switch patterns when the a kotekan speed threshold is passed. Notes are also possibly muted.

There are a number of ways this can be extended:

  • Use any attribute instead of just mute.
  • More instruments than just polos and sangsih.
  • Multiple kotekan thresholds.

The first two are supported at the PatternNote level of abstraction. For the others, I have to either directly use Notes or create a new abstraction:

  • Variable durations.



instrument postproc

mute_postproc :: Attrs.Attributes -> Score.Event -> Score.Event Source #

Variable mute for gangsa. Intended for the inst_postproc field. This interprets Controls.mute and turns it into either a %mod control or mute_attr.



data KotekanPattern Source #

There are 4 ways to realize a kotekan:

  1. Undivided. Since it's undivided it could be unison or kempyung.
  2. Slow but divided. Play all the notes, but sangsih and polos are kempyung on the outer notes. 3, 4. Ngotek, in telu and pat versions.

data Pasang a Source #





Eq a => Eq (Pasang a) # 


(==) :: Pasang a -> Pasang a -> Bool #

(/=) :: Pasang a -> Pasang a -> Bool #

Show a => Show (Pasang a) # 


showsPrec :: Int -> Pasang a -> ShowS #

show :: Pasang a -> String #

showList :: [Pasang a] -> ShowS #

Pretty.Pretty a => Pretty.Pretty (Pasang a) # 

data Realization a Source #





Eq a => Eq (Realization a) # 
Show a => Show (Realization a) # 


c_norot :: Bool -> Maybe.Maybe Bool -> Generator Note Source #

Initially I implemented this as a postproc, but it now seems to me that it would be more convenient as a generator. In any case, as a postproc it gets really complicated.

norot_sequence :: Bool -> (BaseTypes.Transposed -> Cycle) -> (BaseTypes.Transposed -> Cycle) -> Maybe.Maybe BaseTypes.Pitch -> Maybe.Maybe BaseTypes.Pitch -> RealTime.RealTime -> Deriver (Maybe.Maybe PitchedCycle, Maybe.Maybe PitchedCycle, Maybe.Maybe PitchedCycle) Source #

Figure out the appropriate cycles for each norot phase. There are 3 phases: an optional preparation for the current pitch, a variable length sustain, and an optional preparation for the next pitch.

prepare_sustain :: Bool -> ScoreTime -> (Maybe.Maybe Bool, Bool) -> Event.Orientation -> (ScoreTime, ScoreTime) -> (Maybe.Maybe ((Bool, Bool), (ScoreTime, ScoreTime)), Maybe.Maybe ((Bool, Bool), (ScoreTime, ScoreTime))) Source #

Figure out parameters for the sustain and prepare phases. Why is this SO COMPLICATED.

TODO this is still used by Reyong. If I can simplify reyong norot too then I can get rid of it.

infer_prepare :: PassedArgs a -> Maybe.Maybe Bool -> Deriver (Maybe.Maybe BaseTypes.Pitch) Source #

Prepare for the next pitch if this note touches the next one.

norot_steps Source #


:: Scale 
-> Maybe.Maybe Pitch.Pitch 
-> NorotStyle 
-> BaseTypes.Transposed

this is to figure out if the sangsih part will be in range

-> Pasang (Pitch.Step, Pitch.Step) 



c_kotekan_regular :: Maybe.Maybe Text -> KotekanStyle -> Generator Note Source #

For regular kotekan, the sangsih can be automatically derived from the polos.


realize_kotekan_pattern Source #


:: (Bool, Bool)

include (initial, final)

-> (ScoreTime, ScoreTime) 
-> Event.Orientation 
-> ScoreTime 
-> BaseTypes.Pitch 
-> (ScoreTime -> Bool) 
-> Repeat 
-> Cycle 
-> NoteDeriver 

Take a Cycle, which is an abstract description of a pattern via KotekanNotes, to real notes in a NoteDeriver.

type Kernel = [Atom] Source #

data Atom Source #



a gap in the kotekan pattern


a rest will be filled in by the other part



Eq Atom # 


(==) :: Atom -> Atom -> Bool #

(/=) :: Atom -> Atom -> Bool #

Ord Atom # 


compare :: Atom -> Atom -> Ordering #

(<) :: Atom -> Atom -> Bool #

(<=) :: Atom -> Atom -> Bool #

(>) :: Atom -> Atom -> Bool #

(>=) :: Atom -> Atom -> Bool #

max :: Atom -> Atom -> Atom #

min :: Atom -> Atom -> Atom #

Show Atom # 


showsPrec :: Int -> Atom -> ShowS #

show :: Atom -> String #

showList :: [Atom] -> ShowS #

Pretty.Pretty Atom # 

end_on_zero :: Cycle -> Cycle Source #

Make both parts end on zero by subtracting the pitch of the final non-interlocking note.

rotate :: Int -> [a] -> [a] Source #

rotations :: [a] -> [[a]] Source #

all kernels

find_kernel :: Kernel -> Maybe.Maybe (Kernel, Bool, Int) Source #

Find a kernel as a rotation or inversion of one of the standard ones.


type Cycle = Realization [[KotekanNote]] Source #

(interlocking pattern, non-interlocking pattern)

Each list represents coincident notes. [] is a rest.

data Note a Source #




Functor Note # 


fmap :: (a -> b) -> Note a -> Note b #

(<$) :: a -> Note b -> Note a #

Show a => Show (Note a) # 


showsPrec :: Int -> Note a -> ShowS #

show :: Note a -> String #

showList :: [Note a] -> ShowS #

Pretty.Pretty a => Pretty.Pretty (Note a) # 


pretty :: Note a -> Text Source #

format :: Note a -> Doc Source #

formatList :: [Note a] -> Doc Source #

data KotekanNote Source #

High level description of a note. This goes into Note before it becomes a Derive.NoteDeriver.




under_threshold_function Source #


:: BaseTypes.ControlRef 
-> ScoreTime 
-> Deriver (ScoreTime -> Bool)

say if a note at this time with the given duration would be under the kotekan threshold

realize_pattern Source #


:: Repeat

Once will just call get_cycle at the start time. Repeat will start the cycle at t+1 because t is the initial, so it's the end of the cycle.

-> Event.Orientation

align to start or end

-> (Bool, Bool) 
-> ScoreTime 
-> ScoreTime 
-> ScoreTime 
-> (ScoreTime -> [[a]])

Get one cycle of notes, starting at the time.

-> [Note a] 

Repeatedly call a cycle generating function to create notes. The result will presumably be passed to realize_notes to convert the notes into NoteDerivers.

cycles :: (t -> [a]) -> [t] -> [(t, a)] Source #

Pair each t with an a, asking the function for more as as needed.

cycles_end :: (t -> [a]) -> [t] -> [(t, a)] Source #

This is like cycles, but the last cycle is aligned to the end of the ts, chopping off the front of the cycle if necessary.

zip_end :: [a] -> [b] -> [(a, b)] Source #

Like zip, but two sequences are aligned at at their ends, instead of their starts.

realize_notes :: (a -> NoteDeriver) -> [Note a] -> NoteDeriver Source #

Turn Notes into a NoteDeriver.

data NorotStyle Source #

Style for non-interlocking norot. Interlocking norot is always the upper neighbor (or lower on the top key).



Norot is emitted as the current instrument, which should be converted into kempyung or unison by a postproc.


Norot in the diamond pattern, where sangsih goes down.


c_kempyung :: Make.Calls Note Source #

I could do this in two different ways: Eval normally, then eval with +kempyung, and make instrument note call understand it. Or, postproc, transpose, and check if the nn is above a limit. The first one would let the instrument choose how it wants to interpret +kempyung while letting this call remain generic, but let's face it, it only really means one thing. The second seems a little simpler since it doesn't need a cooperating note call.

So postproc it is.

realize calls

type NoltolArg = (RealTime.RealTime, RealTime.RealTime) Source #

(noltol-time, kotekan-dur)

realize_noltol :: NoltolArg -> Score.Event -> Maybe.Maybe Score.Event -> [Score.Event] Source #

If the next note of the same instrument is below a threshold, the note's off time is replaced with a +mute.


cancel_strong_final :: [Score.Event] -> Either Text [Score.Event] Source #

Kotekan ends with a final, which cancels normal, but loses to strong. This is like Postproc.cancel_strong_weak, except it adds final_flag, so I can have the end of a kotekan override, but still be overidden with an explicit strong note.

pasang_key :: Postproc.Key (Either Instrument (Instrument, Instrument), Maybe.Maybe Text) Source #

Match any of polos, sangsih, and pasang to each other. Since polos and sangsih together are considered one voice, a sangsih start is note end for a polos note.


get_pitch :: PassedArgs a -> Deriver BaseTypes.Pitch Source #

Get pitch for a kotekan call.