Metadata-Version: 2.4
Name: zvukodel
Version: 0.1.0
Summary: Музыка на Python: ноты, инструменты, песни — и распознавание музыки (темп, тональность, аккорды, ноты, узнавание песен как Shazam)
Author: markabrazuk336-maker
License-Expression: MIT
Keywords: music,synthesizer,audio,music recognition,shazam,chords,tempo,pitch,музыка
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
Classifier: Natural Language :: Russian
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.22
Provides-Extra: play
Requires-Dist: sounddevice>=0.4; extra == "play"
Provides-Extra: mp3
Requires-Dist: av>=10; extra == "mp3"
Provides-Extra: all
Requires-Dist: sounddevice>=0.4; extra == "all"
Requires-Dist: av>=10; extra == "all"
Dynamic: license-file

# Zvukodel

Музыка на Python. Ноты, инструменты, песни и эффекты. Внутри есть подбиблиотека
**slukh** («слух»), которая распознаёт музыку: темп, тональность, аккорды и ноты
мелодии. Ещё она умеет узнавать песню по кусочку, как Shazam.

Всё написано с нуля на `numpy`. Ни нейросетей, ни чужих звуков: инструменты
синтезируются, а распознавание сделано на классических алгоритмах (YIN,
спектральный поток, хрома, алгоритм Shazam).

```bash
pip install zvukodel            # только numpy
pip install zvukodel[all]       # + играть звук (sounddevice) и открывать mp3 (PyAV)
```

## Быстрый старт

```python
import zvukodel as zv

song = zv.Song(bpm=120)
song.track(zv.Piano()).melody("C4 E4 G4 C5:2 | B4 G4 D4:2")
song.save("hello.wav")
song.play()
```

### Мелодия строкой

| Запись | Что значит |
|---|---|
| `C4`, `F#3`, `Bb2` | нота с октавой (C4 — «до» посередине пианино) |
| `До4`, `Соль#`, `Ля` | то же по-русски; без октавы берётся прошлая |
| `C4:2`, `C4:1/2`, `C4:0.5` | длина в долях (по умолчанию 1 доля) |
| `r:2` или `-:2` | пауза |
| `[C4 E4 G4]:4` | несколько нот разом |
| `C4!` / `C4?` | громче / тише |
| `\|` | черта такта, просто для красоты |

### Целая песня

```python
song = zv.Song(bpm=100)
song.track(zv.EPiano()).chords("Am F C G", length=4, rhythm="x-x-x-x-")
song.track(zv.Bass()).chords("Am F C G", octave=2, rhythm="x.x.x.x.", root_only=True)
song.track(zv.Lead(), reverb=0.2).melody("E5 D5 C5 A4:2 r:2", beat=song.bar(1))

drums = song.drums()
drums.beat(bars=4, kick="x.......x.x.....", snare="....x.......x...", hat="x.x.x.x.x.x.x.x.")
song.save("pesnya.wav")
```

Ещё можно попросить песню сочинить себя саму: `zv.compose(seed=5, style="chip")`.
Стили: `pop`, `chip` (8-бит), `rock`, `phonk`, `calm`.

### Инструменты

`Piano`, `EPiano`, `Pluck` (гитара/арфа), `Organ`, `Bell`, `Flute`, `Chip` (NES/Game Boy),
`Lead`, `Pad`, `Strings`, `Bass`, `Bass808`, `Sine` и `Synth` с настройками для
всего на свете (волна, фильтр, огибающая, расстройка, вибрато).
Барабаны: `Kick`, `Snare`, `HiHat`, `Clap`, `Tom`, `Crash`, `Cowbell`.
Свой инструмент — это класс с методом `render(freq, seconds, vel, sr)` (см. `primery/03_svoy_instrument.py`).

### Эффекты

`lowpass`, `highpass`, `bandpass`, `eq`, `echo`, `reverb`, `distortion`, `bitcrush`,
`tremolo`, `fade_in`, `fade_out`, `speed`, `reverse`, `pan`, `mix`, `normalize`, `limiter`.
Звук здесь — обычный массив numpy, так что эффекты можно писать и свои.

### Теория

```python
zv.scale("A3", "минор")        # [A3 B3 C4 D4 E4 F4 G4 A4]
zv.chord("G7", octave=3)       # [G3 B3 D4 F4]
zv.key_chords("A minor")       # ['Am', 'Bdim', 'C', 'Dm', 'Em', 'F', 'G']
zv.Note("Ля4").freq            # 440.0
```

## slukh — распознавание музыки

```python
from zvukodel import slukh

print(slukh.analyze("song.mp3"))
```
```
Длина:        0:34.9
Громкость:    -12.1 дБ (самый громкий момент -1.0 дБ)
Темп:         110.0 BPM (63 долей)
Тональность:  Фа минор (F minor), уверенность 80%
Строй:        +0 центов от A4 = 440 Гц
Аккорды:      Fm Db Ab Eb Fm Db Ab Eb …
```

| Функция | Что делает |
|---|---|
| `slukh.tempo(x)` | темп в BPM |
| `slukh.beats(x)` | секунды каждой доли |
| `slukh.key(x)` | тональность (`Key`, печатается как «Ля минор (A minor)») |
| `slukh.chords(x)` | аккорды по времени: `[ChordSpan('Am', 0.0, 2.1), ...]` |
| `slukh.notes(x)` | ноты одноголосой мелодии (свист, пение, флейта) |
| `slukh.to_melody(notes, bpm)` | ноты → строка для `track.melody()` |
| `slukh.pitch(x)` | частота основного тона в каждый момент |
| `slukh.tuner()` | тюнер с микрофона |
| `slukh.listen(5)` | записать 5 секунд с микрофона |
| `slukh.Recognizer` | узнавалка песен, как Shazam |

`x` — это путь к файлу, массив numpy (тогда добавь `sr=`), пара `(массив, sr)` или `Song`.

### Узнавалка песен

```python
r = slukh.Recognizer("baza.npz")
r.add_folder("moi_pesni")       # запомнить все mp3/wav из папки
r.save()

print(r.recognize("kusochek.wav"))   # «Название» на 1:23, совпадений 57 (уверенность 100%)
print(r.listen(8))                   # то же с микрофона
```

Как это работает: из спектрограммы берутся самые яркие точки, соседние точки
соединяются в пары, и каждая пара превращается в число-«хэш». Шум и громкость
эти хэши почти не портят. У правильной песни много хэшей совпадают с одним и
тем же сдвигом по времени. Этот сдвиг и показывает, с какой секунды кусочек.

### Насколько точно

Проверено на 30 песнях, которые сочинил `compose()` (при настройке их не использовали):

| Что | Точность |
|---|---|
| Темп | 87 % (у песен с барабанами 100 %) |
| Доли | 88 % (F-мера, ±70 мс) |
| Тональность | 83 % (ошибки — в основном параллельная тональность или соседняя по квинте) |
| Аккорды | 97 % времени |
| Ноты одноголосой мелодии (9 инструментов) | 98–99 %, с шумом 15 дБ около 95 % |

Узнавалка (база из 40 песен):

| Кусочек | чистый | тише на 20 дБ | шум 10 дБ | шум 3 дБ | «телефон» | после mp3 | эхо комнаты |
|---|---|---|---|---|---|---|---|
| 5 секунд | 100 % | 100 % | 98 % | 90 % | 98 % | 100 % | 80 % |
| 8 секунд | 100 % | 100 % | 100 % | 100 % | 100 % | 100 % | 100 % |

Ложных узнаваний на чужих песнях и на шуме: 0 из 35. Один запрос — около 50 мс.

Честно о слабых местах:
- `notes()` разбирает только один голос. Мелодию прямо из готовой песни, где
  играет всё сразу, он не выделит.
- Мажор и параллельный минор (до мажор и ля минор) состоят из одних и тех же нот.
  Такие тональности иногда путаются, и это нормально даже для людей.
- Распознаются мажорные и минорные аккорды, септаккорды пока нет.
- Темп иногда получается вдвое меньше или больше (75 вместо 150). Музыканты тоже
  спорят, где тут доля.
- Узнавалка узнаёт запись. Если две песни сыграны одинаковыми нотами на одном
  инструменте в одном темпе, она может их спутать.

## Командная строка

```bash
zvukodel compose --style chip -o pesnya.wav
zvukodel analyze song.mp3
zvukodel notes svist.wav
zvukodel add moi_pesni/
zvukodel find kusochek.wav
zvukodel find --mic 8
zvukodel tuner
```

## Примеры и проверка

Папка `primery/`: первая мелодия, песня с барабанами, свой инструмент,
распознавание, Shazam и «напой мелодию». Проверка: `python tests/test_zvukodel.py`.

Лицензия MIT.
