Copyright | (c) 2022 Andrew A. Cashner |
---|---|
Stability | Experimental |
Safe Haskell | None |
Language | Haskell2010 |
Cogito
Contents
Description
This module processes data from the ark to convert it into music (cogito, Latin, "I think").
Overview
This module receives input from the Lectio
module in the form of a single
list of one or more LyricSection
s, which contain the parsed text to be set
to music and the parameters for setting it.
The module uses Kircher's rules to pull the appropriate data from the Arca
musarithmica, that is, from the Arca
built by the Aedifico
module. It
uses the Fortuna
module to get lists of random permutation indices.
The main function is makeMusicScore
, which applies all the necessary rules to
select music data from the ark for each phrase of text, using the random
permutations when a free choice would otherwise be needed. It takes the
numerals and rhythmic symbols from Kircher's pinakes (rods); converts the
numerals to pitches according to the tone, and combines the pitches and
rhythms (accounting for rests as well).
The module creates the MusicScore
data structure which contains all the data
for the music in hierarchical sections that the Scribo
module will convert
to MEI XML.
Text underlay
Pitches and syllables are stored together in the Note
type. In Syntagma I
(simple syllabic counterpoint), we store one syllable for each note, skipping
rests.
In Syntagma II, though, for florid counterpoint, Kircher does not specify how to underlay the text, and the settings have variable numbers of notes in the different voices and between different permutations in the same pinax. The underlay must be left to the human performer, then, and so we just lump all the lyrics for each phrase and put them under the first syllable as a textual incipit.
MEI vs. Lilypond output
We previously set up this module to feed data into the Scribo.Lilypond
module, using the main function getSymphonia
. It treated pitches and lyrics
completely separately, which worked in Syntagma I but not in Syntagma II.
These functions are archived in the test/
directory.
Synopsis
- zipFill :: [a] -> [b] -> (a -> Bool) -> b -> [(a, b)]
- pair2Pitch :: ToneList -> ToneSystem -> Tone -> (Dur, Int) -> Pitch
- isBflatInSignature :: Pnum -> Accid -> Tone -> ToneSystem -> Bool
- voice2octave :: Num p => VoiceName -> p
- ark2voice :: Arca -> ArkConfig -> PenultLength -> Int -> Int -> VoiceName -> Perm -> Voice
- makeSyllables :: Verbum -> [Syllable]
- blankSyllable :: Syllable
- makeMusicPhrase :: Arca -> ArkConfig -> VoiceName -> LyricPhrase -> Perm -> MusicPhrase
- makeMusicSentence :: Arca -> ArkConfig -> VoiceName -> LyricSentence -> SentencePerm -> MusicSentence
- makeMusicSection :: Arca -> LyricSection -> SectionPerm -> VoiceName -> MusicSection
- makeMusicChorus :: Arca -> LyricSection -> SectionPerm -> MusicChorus
- makeMusicScore :: Arca -> [LyricSection] -> [SectionPerm] -> MusicScore
Match pitches and rhythms
Get music data for a single voice
Arguments
:: [a] | list 1 |
-> [b] | list 2 |
-> (a -> Bool) | test |
-> b | substitute element to use instead of list 2 item, if list 1 item meets test |
-> [(a, b)] | return list of pairs made of list 1 and 2, in item order |
Take two lists and zip them together, that is, make a new list of ordered
pairs constructed from sequential items of the two lists, BUT:
if an element in the first list satisfies a given test
, make a pair of that
element and a sustitute element (sub
) instead of the corresponding
element from the second list.
Make a pitch from duration and pitch number. Start with dummy octave
number; we'll set it later using stepwiseVoiceInRange
.
Adjust the pitch for tone (pnumAccidInTone
).
isBflatInSignature :: Pnum -> Accid -> Tone -> ToneSystem -> Bool Source #
Is this note a B flat, and if so, is the flat already in the key signature?
voice2octave :: Num p => VoiceName -> p Source #
Get the right starting octave range for each voice type voice2octave :: VoiceName -> Int
From input parameters to music
Arguments
:: Arca | ark data structure |
-> ArkConfig | we pass this along to |
-> PenultLength | penultimate syllable length |
-> Int | syllable count |
-> Int | line count |
-> VoiceName | voice name enum |
-> Perm | contains random index for voice and rhythm permutation |
-> Voice |
Central functions of the ark: given all parameters required by Kircher (style, meter, syllable count, penultimate syllable length), select a voice permutation (Kircher's number tables) from the appropriate part of the ark and match it to a rhythm permutation (his tables of note values).
Return a Voice
with the pitches for a single voice part.
We use getVoice
and getRperm
from the Aedifico
module.
Because the rhythms can include rest, we have to match up pitches and
rhythms accordingly using zipFill
with the test isRest
.
Methods to create and populate data structures for music composed by the
makeSyllables :: Verbum -> [Syllable] Source #
blankSyllable :: Syllable Source #
Just a blank syllable for filler when needed
makeMusicPhrase :: Arca -> ArkConfig -> VoiceName -> LyricPhrase -> Perm -> MusicPhrase Source #
Compose the music for a whole LyricPhrase
with one permutation from the
ark, and package it into a MusicPhrase
. Note that this is for a single
voice only, not the four SATB voices.
Line up pitches and syllables, skipping rests. In Syntagma I, line up text and notes syllabically (one syllable per note); in syntagma II (florid), lump the text into a single syllable and put it as an incipit text at the beginning of the phrase. (See module description for why Kircher's specification makes this is necessary.)
makeMusicSentence :: Arca -> ArkConfig -> VoiceName -> LyricSentence -> SentencePerm -> MusicSentence Source #
Compose music for a LyricSentence
for a single voice.
makeMusicSection :: Arca -> LyricSection -> SectionPerm -> VoiceName -> MusicSection Source #
Put together all the music information for one LyricSection
, for a
single voice.
For a single voice:
- extract ArkConfig for whole section
for each sentence in section:
- extract list of perms, one per phrase
- extract list of lyric phrases
- apply same ArkConfig
for each phrase in sentence:
look up vperm according to config and perm
- (for some pinakes, choose column by stanza = section num)
look up rperm according to config and perm
- (for syntagma II, use same perm)
- convert vperm nums to pitch names
- (adjust pitches)
- make Pitches: match pitches and rhythms, accounting for rests
- match Notes: match each Pitch with PhraseVerbumSyllable according to syntagma
- return a MusicPhrase
- inside a MusicSentence
- inside a MusicSection
makeMusicChorus :: Arca -> LyricSection -> SectionPerm -> MusicChorus Source #
Compose music for all four SATB voices for one LyricSection
.
TODO experimental: also adjust for musica ficta
makeMusicScore :: Arca -> [LyricSection] -> [SectionPerm] -> MusicScore Source #
Compose the music for the whole document as a MusicScore
, pulling the
data from the Arca
.