Metadata-Version: 2.4
Name: lib-tracker
Version: 0.2.0
Summary: Cria e converte musicas de trackers MS-DOS (.mod/.xm/.it/.s3m) por codigo Python
Author: Enzo Xavier
License-Expression: CC0-1.0
Keywords: tracker,mod,xm,it,s3m,chiptune,music,dos,midi
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI
Classifier: Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 3 - Alpha
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# lib-tracker 0.2

Biblioteca Python (sem dependencias; `numpy`/`ffmpeg` so' nos testes de audio) para
**criar musicas de trackers da era MS-DOS por codigo** e **converter entre `.mod`, `.xm`,
`.it` e `.s3m`**.

```python
from lib_tracker import Song, Sample, synth

song = Song("Minha musica", channels=4, bpm=125)
lead = song.add_instrument(Sample.chip("square"))     # onda de 1 ciclo em loop
bass = song.add_instrument(Sample.chip("triangle"))
kick = song.add_instrument(synth.kick())              # percussao pronta
hat  = song.add_instrument(synth.hat())

p = song.new_pattern(64)                              # 64 linhas
p.melody(0, "C-4 E-4 G-4 C-5", inst=lead, step=4)     # canal 0
p.bassline(1, 0, ["C", "A", "F", "G"], bass, step=16) # canal 1
p.arpeggio(2, 0, "C", lead, rows=16, step=2)          # canal 2: arpejo de C
p.drums(3, {kick: "x...x...", hat: "..x...x."})       # canal 3: bateria por texto

song.save("musica.mod")      # tambem .xm / .it / .s3m
```

## O que tem

| Area | Recursos |
|---|---|
| Formatos | ler/escrever **.mod** (inclui MOD de 15 amostras na leitura), **.xm**, **.it**, **.s3m**; conversao entre todos (`lt.convert`) com avisos do que nao coube |
| Instrumentos | varias amostras por instrumento + mapa nota→amostra, **envelopes de volume/pan**, fadeout, vibrato automatico, NNA (IT), loop **ping-pong**, 8/16 bits, pan por amostra |
| IT | compressao/descompressao **IT214** (`itmod.dumps(song, compress=True)`; validada contra o libopenmpt) |
| Composicao | escalas (`compose.scale_notes`), acordes (`Am7`, `C/E`...), progressoes por graus romanos (`compose.progression("I vi IV V", "G")`), `Pattern.chord/arpeggio/drums/bassline`, caminhada melodica, copiar/colar/transpor/repetir, `Song.append_song` |
| Sons | ondas chip, kick/snare/hat/tom/clap/cymbal, pluck (Karplus-Strong), organ, **13 efeitos de jogo** (`synth.SFX`: coin jump hit laser explosion powerup select confirm error heal levelup gameover sword) |
| MIDI | `from_midi` (MIDI → tracker: melodia/baixo monofonicos + bateria GM) e `to_midi` |
| Qualidade no MOD | amostra fora do alcance do finetune e' **reamostrada** em vez de desafinar; 16→8 bits com **dither**; `tools.auto_gain` ajusta o volume pelo pico renderizado; tempo (speed/BPM) gravado como `Fxx` |
| Ferramentas | `lt.check(song, "mod")` (o que nao cabe), `lt.diff(a, b)`, `lt.analyze(path)` (pico/rms/clipping), `render_wav` (ffmpeg) |
| Projeto | `python -m lib_tracker build projeto.json` gera varias musicas + banco de SFX de uma vez |

## CLI

```
python -m lib_tracker info musica.xm
python -m lib_tracker convert musica.mod musica.it --compress     # IT214
python -m lib_tracker check musica.xm mod                         # o que se perde indo pra MOD
python -m lib_tracker dump musica.it all
python -m lib_tracker diff original.mod convertida.xm --loose
python -m lib_tracker render musica.mod musica.wav 30             # precisa do ffmpeg
python -m lib_tracker analyze musica.mod 30
python -m lib_tracker midi2tracker cancao.mid MUSICA.MOD 4
python -m lib_tracker tracker2midi MUSICA.MOD saida.mid 3         # 3 = canal de bateria
python -m lib_tracker build examples/square_swords_project.json music
python -m lib_tracker sfx SFX coin jump hit
```

## Convencoes (iguais ao FastTracker 2)

* Notas: `C-0`=1 ... `B-7`=96, `===` solta a nota. **C-4 toca a amostra na sua `rate`
  (8363 Hz)**; com `Sample.chip(cycle=32)` o C-4 sai em ~261 Hz (afinado).
* Efeitos: 3 caracteres, efeito + parametro hexa: `A08`, `E4F`, `F7D`, `C40`...
  (codigos do XM/MOD; `fx.py` converte de/para o IT/S3M).
* Volume de coluna: `vol=0..64`. No MOD vira efeito `Cxx` (se a celula ja tem efeito,
  a coluna e' descartada com aviso).
* MOD usa a faixa **C-3..B-5** (notas 37..72) nesta notacao.
* **MOD nao tem BPM/speed no cabecalho**: a lib grava `Fxx` na 1a linha (nos canais livres) e le de volta.

## Limites (nada some em silencio: veja `song.warnings` / `lt.check`)

| | MOD | XM | IT | S3M |
|---|---|---|---|---|
| canais | 1..32 | 1..32 | 1..64 | 1..32 |
| instrumentos | 31 | 128 | sem limite pratico | 99 |
| linhas/pattern | 64 | 1..256 | 1..200 | 64 |
| amostras/instr. | 1 | 16 | varias | 1 |
| envelopes/fadeout/vibrato | nao | sim | sim | nao |
| 16 bits | nao (dither p/ 8) | sim | sim | sim |
| volume de coluna | nao (vira Cxx) | sim | sim | sim |

* **turbo-package**: ela toca 1 amostra por instrumento e ignora envelopes; use instrumentos
  simples (o padrao) pra musica do jogo. O numero do instrumento e' o numero da amostra em
  todos os formatos.
* Leitura: envelopes de pitch/filtro do IT e instrumentos Adlib do S3M sao ignorados (aviso);
  samples estereo viram mono.

## Projeto JSON (musicas do jogo)

Veja `examples/square_swords_project.json`. Trilhas: `notes`, `arp`, `chord`, `bass`,
`drums`, `walk` (melodia aleatoria sobre a escala, determinista pela `seed`); acordes podem vir
de `progression` ("I vi IV V") + `key`/`scale`. `auto_gain: 0.9` ajusta o volume (precisa do ffmpeg).
`sfx_bank` gera `COIN.RAW`.. (PCM 8 bits com sinal, pro `tp_sfx_play_sample`), `SFX.H` e `SFX.MOD`.

## Testes

```
python3 tests/test_lib_tracker.py     # v0.1: formatos, efeitos, afinacao
python3 tests/test_v02.py             # v0.2: envelopes, keymap, IT214, S3M, MIDI, projeto, ganho...
```
Os testes de audio renderizam com o ffmpeg (libopenmpt) e conferem afinacao, envelope, mapa de notas,
ping-pong e a decodificacao do IT214 por um decodificador independente.

## Licenca

Dominio publico (CC0 1.0). Veja o arquivo LICENSE. Autor: Enzo Xavier.
