# recite


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

[`recite`](https://vedicreader.github.io/vachaka/recite.html#recite)
takes a passage as the lines a reader sees and returns one audio file
with timings for every line and word. This page builds it up in steps.

## Pieces

Vāgdhenu renders text in pieces, and expects the two pādas
(quarter-verses) of a half-verse as one piece, even when the book prints
them on two lines. `pieces(lines)` groups the display lines accordingly:
a piece ends after a word that contains a daṇḍa. In prose (`prose=True`)
a piece also ends before it would pass `max_syll` (24) akṣaras, and in
verse before a line that would take it past `max_verse` (44). Each piece
is a list of `(line_index, word)` pairs, so word timings can be mapped
back to their lines. A word that cleans to nothing, such as a daṇḍa or a
verse number, stays in its piece and gets no time of its own.
[`piece_text`](https://vedicreader.github.io/vachaka/recite.html#piece_text)
gives the cleaned text of a piece for rendering.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L23"
target="_blank" style="float:right; font-size:smaller">source</a>

### pieces

``` python
def pieces(
    lines, prose:bool=False, max_syll:int=24, max_verse:int=44
):
```

*Group display `lines` into render pieces, each a list of
`(line_index, word)`.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L21"
target="_blank" style="float:right; font-size:smaller">source</a>

### word_text

``` python
def word_text(
    w
):
```

``` python
ls = ['नित्यानन्दकरी वराभयकरी सौन्दर्यरत्नाकरी', 'निर्धूताखिलघोरपावनकरी प्रत्यक्षमाहेश्वरी ।', 'प्रालेयाचलवंशपावनकरी काशीपुराधीश्वरी', 'भिक्षां देहि कृपावलम्बनकरी मातान्नपूर्णेश्वरी ॥ १ ॥']
ps = pieces(ls)
test_eq(len(ps), 2)
test_eq({i for i,_ in ps[0]}, {0, 1})
test_eq(ps[1][-1], (3, '॥'))
test_eq(len(pieces(['उपदेशं व्याख्यास्यामः॥'], prose=True)), 1)
assert all(sum(n_syll(word_text(w)) for _,w in p) <= 24 for p in pieces(['क '*60], prose=True))
```

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L43"
target="_blank" style="float:right; font-size:smaller">source</a>

### piece_text

``` python
def piece_text(
    p
):
```

## Lines from words

Word timings come back per piece. `line_times(n, ps, words)` turns them
into one `dict(s, e, w)` per display line: the start of its first timed
word, the end of its last, and the list of its words with their times. A
line with no words gets None.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L46"
target="_blank" style="float:right; font-size:smaller">source</a>

### line_times

``` python
def line_times(
    n, ps, words
):
```

*One `dict(s, e, w)` per line from the pieces’ word timings, or None for
a line with no words.*

``` python
ps = [[(0,'क'), (0,'ख'), (1,'ग')], [(1,'॥')]]
lt = line_times(3, ps, [[['क',0,100], ['ख',100,200], ['ग',300,400]], [['॥',400,400]]])
test_eq([lt[0]['s'], lt[0]['e'], lt[1]['s'], lt[1]['e']], [0, 200, 300, 400])
test_eq(lt[2], None)
```

## Reciting sections

A section is a passage, such as a verse with its commentary, that
becomes one stretch of audio.
[`recite_section`](https://vedicreader.github.io/vachaka/recite.html#recite_section)
splits it into parts, each recited in a single voice, either chanted or
read. By default the section is split into verses with
[`verses`](https://vedicreader.github.io/vachaka/recite.html#verses),
each ending on a line with a double daṇḍa, and each verse is scanned by
[ganapati](https://github.com/vedicreader/ganapati) to find its metre.
ganapati applies the rules of the śloka, where Vāgdhenu’s own detector
accepted a 32-syllable prose sentence as anuṣṭubh, and it recognises the
āryā family, whose metres count syllable lengths instead of syllables.

[`part_voice`](https://vedicreader.github.io/vachaka/recite.html#part_voice)
then picks the voice. A metre with a reference in Vāgdhenu’s bank is
chanted against that reference, another syllable-counted metre (a vṛtta)
is chanted against vasantatilakā, and an āryā-family metre, or no metre
at all, is read against the anuṣṭubh reference. You can give the parts
yourself as `parts=[dict(lines=[...], meter=...)]`, with line indices,
and `kind='chant'` or `kind='read'` makes the whole section one voice.
[`recite_part`](https://vedicreader.github.io/vachaka/recite.html#recite_part)
renders one part, keeping the best of `tries` seeds by Su-śrotā’s
character error rate, and returns the timings of its lines.
[`shift`](https://vedicreader.github.io/vachaka/recite.html#shift) moves
a set of timings later, so that each part’s timings count from the start
of the whole recording.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L60"
target="_blank" style="float:right; font-size:smaller">source</a>

### part_voice

``` python
def part_voice(
    ch, meter
):
```

*The voice `(kind, ref)` for a part in metre `meter`, where None means
prose.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L75"
target="_blank" style="float:right; font-size:smaller">source</a>

### closes

``` python
def closes(
    l
):
```

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L66"
target="_blank" style="float:right; font-size:smaller">source</a>

### verses

``` python
def verses(
    lines
):
```

*Group line indices into verses, each ending on a line with a double
daṇḍa.*

``` python
test_eq(verses(['क ।', 'ख ॥ १ ॥', 'ग', 'घ']), [[0, 1], [2, 3]])
```

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L78"
target="_blank" style="float:right; font-size:smaller">source</a>

### recite_part

``` python
def recite_part(
    ch, ear, lines, kind:NoneType=None, ref:NoneType=None, tries:int=3, max_cer:float=0.08
):
```

*Render `lines` in one voice, returning the
[`Recitation`](https://vedicreader.github.io/vachaka/core.html#recitation)
and its kind, reference, error rate and line timings.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L92"
target="_blank" style="float:right; font-size:smaller">source</a>

### recite_section

``` python
def recite_section(
    ch, ear, lines, kind:NoneType=None, ref:NoneType=None, parts:NoneType=None, gap:float=0.8, **kw
):
```

*Recite one section’s lines, returning the
[`Recitation`](https://vedicreader.github.io/vachaka/core.html#recitation)
and its parts, error rates and line timings.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L109"
target="_blank" style="float:right; font-size:smaller">source</a>

### shift

``` python
def shift(
    info, off
):
```

*Move all the timings in `info` `off` milliseconds later.*

The cell below checks this bookkeeping with a stand-in chanter and ear,
without the models. A verse that scans is chanted, the prose line after
it is read, and the second part’s timings start after the first part
plus the gap. Parts given explicitly get the voice their metre calls
for.

`recite(ch, ear, sections)` is the top-level call. Each section is a
dict with `lines` and optionally `kind`, `ref` and `parts`. It recites
every section, joins them with `gap` (1.2) seconds of silence, and
returns the
[`Recitation`](https://vedicreader.github.io/vachaka/core.html#recitation)
and a list with one dict per section: its `kind` (`chant`, `read` or
`mixed`), its first part’s `ref`, its worst
[`cer`](https://vedicreader.github.io/vachaka/check.html#cer), its
`parts`, and its `lines` timings.

``` python
from vachaka.core import Recitation
from vachaka.check import Ear
class FakeCh:
    gap, prose_gap = 0.5, 0.3
    def meter(self, lines): return 'anushtubh' if len(lines) == 2 else ''
    def bank_ref(self, name): return {'anuṣṭubh': 'anuṣṭubh', 'mālinī': 'mālinī'}.get(name)
    def render(self, ps, ref, seed, gap): return Recitation(np.zeros(len(ps)*24000, np.float32), [(i*1000, i*1000+900) for i in range(len(ps))], ps)
class FakeEar:
    def hear(self, audio, sr): return ''
    heard = Ear.heard   # best_of hears a render a piece at a time
    def words(self, rec, ws): return [[[w, s, e] for w in p] for (s,e),p in zip(rec.spans, ws)]
r, info = recite_section(FakeCh(), FakeEar(), ['धर्मक्षेत्रे कुरुक्षेत्रे समवेता युयुत्सवः ।', 'मामकाः पाण्डवाश्चैव किमकुर्वत सञ्जय ॥ १ ॥', 'इति प्रश्नः ॥'])
test_eq([p['kind'] for p in info['parts']], ['chant', 'read'])
test_eq(info['kind'], 'mixed')
test_eq(info['lines'][2]['s'], 2000 + 800)           # two 1 s pieces, then the gap
_, info = recite_section(FakeCh(), FakeEar(), ['क ख ग', 'घ ङ च ॥', 'छ ज झ ।'])
test_eq([p['kind'] for p in info['parts']], ['chant', 'read'])  # the line after the verse is its own part, and scans as nothing
ps = [dict(lines=[0, 1], meter='mālinī'), dict(lines=[2], meter='āryā'), dict(lines=[3], meter='śikhariṇī'), dict(lines=[4], meter=None)]
_, info = recite_section(FakeCh(), FakeEar(), ['क ।', 'ख ॥', 'ग ॥', 'घ ॥', 'ङ ।'], parts=ps)
test_eq([(p['kind'], p['ref']) for p in info['parts']], [('chant', 'mālinī'), ('read', 'anuṣṭubh'), ('chant', 'vasantatilaka'), ('read', 'anuṣṭubh')])
```

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L118"
target="_blank" style="float:right; font-size:smaller">source</a>

### recite

``` python
def recite(
    ch, ear, sections, gap:float=1.2, **kw
):
```

*Recite `sections`, each `dict(lines=..., kind=..., ref=...)`, as one
[`Recitation`](https://vedicreader.github.io/vachaka/core.html#recitation)
with timings per section.*

## CLI

`vachaka-recite jobs.jsonl results.jsonl` renders a file of jobs, one
JSON object per line. Each job is `dict(id, out, sections)`, where
`sections` is what
[`recite`](https://vedicreader.github.io/vachaka/recite.html#recite)
takes. It writes the audio to `out` (mp3 or wav) and appends
`dict(id, out, ms, sections)` to the results file, with `sections`
holding the timings. A job whose id is already in the results is
skipped, so a stopped run carries on where it left off.

The options are `--voice` (`steer`), `--tries` (3) and `--max_cer`
(0.08) for re-rendering, `--pace` (1.15), `--pitch` (1.0, so one
semitone up by default) and `--fx`, the sound treatment from `core.FX`
(`warm`, or `none` for the raw render).

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/vachaka/blob/main/vachaka/recite.py#L128"
target="_blank" style="float:right; font-size:smaller">source</a>

### recite_cli

``` python
def recite_cli(
    jobs:str, results:str, voice:str='steer', tries:int=3, max_cer:float=0.08, fx:str='warm', pace:float=1.15,
    pitch:float=1.0
):
```

*Render each job in the JSON lines file `jobs` and append its timings to
`results`.*
