Metadata-Version: 2.3
Name: hyperscore-tablature
Version: 0.1.0
Summary: Tablature-style DSL for rendering guitar, drums, and custom events into hyperscore.
Author: inaba1115
Author-email: inaba1115 <inaba1115@gmail.com>
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Scientific/Engineering
Requires-Dist: hyperscore>=0.3.0
Requires-Dist: lark>=1.3.1
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# hyperscore-tablature

**hyperscore-tablature** is a compact tablature-style DSL for rendering guitar, drums, chords, and custom events into `hyperscore`.

It provides a small notation layer on top of `hyperscore` so that musical patterns can be written as tab-like strings, while timing and event generation remain explicit through `TimeSpan` and `Score`.

The library is designed for quick sketches, algorithmic composition, and custom event workflows rather than score engraving or full tablature transcription.

---

## Minimal example

This minimal example demonstrates the core workflow: define a token-to-event factory, write a tab-like pattern, and render it into a `hyperscore` `Score`.

```python
from hyperscore.core import NoteEvent, Score, TimeSpan, bpm_to_ms

from hyperscore_tablature import TUNINGS, TabRenderer

guitar = TabRenderer(
    factory=lambda line_index, token, span: NoteEvent(
        pitch=TUNINGS["guitar6"][line_index] + int(token, 32),
        velocity=80,
        span=span,
        channel=0,
    )
)

tab = [
    "____ ____ ____ ____ | ____ ____ ____ ____",
    "____ ____ ____ ____ | ____ ____ ____ ____",
    "____ ____ ____ ____ | ____ 2___ 4___ 5___",
    "____ ____ 2___ 3___ | 5___ ____ ____ ____",
    "3___ 5___ ____ ____ | ____ ____ ____ ____",
    "____ ____ ____ ____ | ____ ____ ____ ____",
]

bpm = 120
bar_ms = int(bpm_to_ms(bpm, 4))

score = Score()
guitar.render(score, TimeSpan(0, bar_ms * 2), tab)
```

This example intentionally keeps the mapping from tab tokens to musical events explicit. `hyperscore-tablature` parses the notation and allocates time spans; the factory decides what each token means.

---

## Tablature syntax

```text
0(12)2 01(2a)(8s) | 0_(4a)3 2(14)10
```

- One normal character is one token: `0`, `x`, `*`, `.`, ...
- Parenthesized text is one token: `(12)` becomes `"12"`
- `_` is a rest
- `-` extends the previous event by this token's duration
- `/` repeats the previous token
- `%` as a whole bar repeats the previous bar
- `|` separates equal-length bars
- `:` separates additive bars; each bar gets duration proportional to its token count
- Spaces and tabs outside parentheses are ignored

Reserved characters can be used as normal tokens by wrapping them:

```text
(-)(_)(/)(:)(|)(%)
```

---

## Multiple events per token

A factory may return either a single event or a sequence of events. This is useful for chords, layered drums, or unison parts.

```python
from hyperscore.core import NoteEvent, Score, TimeSpan

from hyperscore_tablature import TabRenderer

def chord_factory(line_index: int, token: str, span: TimeSpan) -> list[NoteEvent]:
    root = int(token)
    return [
        NoteEvent(pitch=60 + root, velocity=80, span=span, channel=0),
        NoteEvent(pitch=64 + root, velocity=80, span=span, channel=0),
        NoteEvent(pitch=67 + root, velocity=80, span=span, channel=0),
    ]

chords = TabRenderer(factory=chord_factory)

score = Score()
chords.render(score, TimeSpan(0, 1000), ["0 5 7 3"])
```

---

## Custom events

`hyperscore-tablature` is not limited to `NoteEvent`. The factory can return any event type that exposes a `span: TimeSpan` attribute.

```python
from dataclasses import dataclass

from hyperscore.core import Score, TimeSpan

from hyperscore_tablature import TabRenderer

@dataclass(frozen=True, slots=True)
class UserDefinedEvent:
    span: TimeSpan
    value: int

renderer: TabRenderer[UserDefinedEvent] = TabRenderer(
    factory=lambda line_index, token, span: UserDefinedEvent(span, int(token))
)

score: Score[UserDefinedEvent] = Score()
renderer.render(score, TimeSpan(0, 1000), ["1 | 2 | 3 | 4"])
```

---

## What this library demonstrates

- Tab-like strings can be used as a compact front-end for `hyperscore`
- Time is still represented explicitly using immutable `TimeSpan` objects
- Token interpretation is fully controlled by user-defined factories
- A single token may produce one event, multiple events, or no events
- `NoteEvent` and user-defined event types can share the same notation layer

For more advanced usage, see:

- `examples/guitar.py`
- `examples/drums.py`
- `examples/acid.py`
- `examples/chord_progression.py`
- `examples/user_defined_event.py`
- `tests/test_tablature.py`

---

## Project status

- Python >= 3.10
- Typed (`py.typed`)
- Experimental / research-oriented
- API may evolve between minor versions

`hyperscore-tablature` favors compact notation and explicit event generation over completeness or traditional tablature semantics.
