├── .gitignore ├── game ├── pydub │ ├── __init__.py │ ├── logging_utils.py │ ├── exceptions.py │ ├── playback.py │ ├── generators.py │ ├── silence.py │ ├── scipy_effects.py │ ├── effects.py │ ├── utils.py │ ├── pyaudioop.py │ └── pywave.py ├── gui │ ├── nvl.png │ ├── frame.png │ ├── skip.png │ ├── bar │ │ ├── left.png │ │ ├── top.png │ │ ├── bottom.png │ │ └── right.png │ ├── namebox.png │ ├── notify.png │ ├── textbox.png │ ├── game_menu.png │ ├── main_menu.png │ ├── phone │ │ ├── nvl.png │ │ ├── bar │ │ │ ├── top.png │ │ │ ├── left.png │ │ │ ├── right.png │ │ │ └── bottom.png │ │ ├── textbox.png │ │ ├── overlay │ │ │ ├── game_menu.png │ │ │ └── main_menu.png │ │ ├── button │ │ │ ├── idle_background.png │ │ │ ├── check_foreground.png │ │ │ ├── hover_background.png │ │ │ ├── radio_foreground.png │ │ │ ├── slot_idle_background.png │ │ │ ├── choice_idle_background.png │ │ │ ├── slot_hover_background.png │ │ │ ├── check_selected_foreground.png │ │ │ ├── choice_hover_background.png │ │ │ └── radio_selected_foreground.png │ │ ├── slider │ │ │ ├── vertical_idle_bar.png │ │ │ ├── horizontal_hover_bar.png │ │ │ ├── horizontal_idle_bar.png │ │ │ ├── vertical_hover_bar.png │ │ │ ├── vertical_hover_thumb.png │ │ │ ├── vertical_idle_thumb.png │ │ │ ├── horizontal_hover_thumb.png │ │ │ └── horizontal_idle_thumb.png │ │ └── scrollbar │ │ │ ├── vertical_idle_bar.png │ │ │ ├── horizontal_idle_bar.png │ │ │ ├── vertical_hover_bar.png │ │ │ ├── vertical_idle_thumb.png │ │ │ ├── horizontal_hover_bar.png │ │ │ ├── horizontal_hover_thumb.png │ │ │ ├── horizontal_idle_thumb.png │ │ │ └── vertical_hover_thumb.png │ ├── window_icon.png │ ├── overlay │ │ ├── confirm.png │ │ ├── game_menu.png │ │ └── main_menu.png │ ├── button │ │ ├── check_foreground.png │ │ ├── hover_background.png │ │ ├── idle_background.png │ │ ├── radio_foreground.png │ │ ├── quick_idle_background.png │ │ ├── slot_hover_background.png │ │ ├── slot_idle_background.png │ │ ├── choice_hover_background.png │ │ ├── choice_idle_background.png │ │ ├── quick_hover_background.png │ │ ├── check_selected_foreground.png │ │ └── radio_selected_foreground.png │ ├── slider │ │ ├── vertical_hover_bar.png │ │ ├── vertical_idle_bar.png │ │ ├── horizontal_hover_bar.png │ │ ├── horizontal_idle_bar.png │ │ ├── horizontal_idle_thumb.png │ │ ├── vertical_hover_thumb.png │ │ ├── vertical_idle_thumb.png │ │ └── horizontal_hover_thumb.png │ └── scrollbar │ │ ├── vertical_hover_bar.png │ │ ├── vertical_idle_bar.png │ │ ├── horizontal_hover_bar.png │ │ ├── horizontal_idle_bar.png │ │ ├── vertical_hover_thumb.png │ │ ├── vertical_idle_thumb.png │ │ ├── horizontal_hover_thumb.png │ │ └── horizontal_idle_thumb.png ├── script.rpyc ├── speak.rpyc ├── audio │ ├── output.wav │ └── beeps │ │ ├── eileen │ │ ├── a.wav │ │ ├── b.wav │ │ ├── c.wav │ │ ├── ch.wav │ │ ├── d.wav │ │ ├── dot.wav │ │ ├── e.wav │ │ ├── f.wav │ │ ├── g.wav │ │ ├── h.wav │ │ ├── i.wav │ │ ├── j.wav │ │ ├── k.wav │ │ ├── l.wav │ │ ├── m.wav │ │ ├── n.wav │ │ ├── o.wav │ │ ├── p.wav │ │ ├── ph.wav │ │ ├── q.wav │ │ ├── r.wav │ │ ├── s.wav │ │ ├── sh.wav │ │ ├── t.wav │ │ ├── th.wav │ │ ├── u.wav │ │ ├── v.wav │ │ ├── w.wav │ │ ├── wh.wav │ │ ├── x.wav │ │ ├── y.wav │ │ └── z.wav │ │ ├── eileen2 │ │ ├── a.wav │ │ ├── b.wav │ │ ├── c.wav │ │ ├── ch.wav │ │ ├── d.wav │ │ ├── e.wav │ │ ├── f.wav │ │ ├── g.wav │ │ ├── h.wav │ │ ├── i.wav │ │ ├── j.wav │ │ ├── k.wav │ │ ├── l.wav │ │ ├── m.wav │ │ ├── n.wav │ │ ├── o.wav │ │ ├── p.wav │ │ ├── ph.wav │ │ ├── q.wav │ │ ├── r.wav │ │ ├── s.wav │ │ ├── sh.wav │ │ ├── t.wav │ │ ├── th.wav │ │ ├── u.wav │ │ ├── v.wav │ │ ├── w.wav │ │ ├── wh.wav │ │ ├── x.wav │ │ ├── y.wav │ │ ├── z.wav │ │ └── dot.wav │ │ └── letters.txt ├── saves │ ├── persistent │ ├── auto-1-LT1.save │ ├── _reload-2-LT1.save │ └── navigation.json ├── cache │ ├── screens.rpyb │ ├── bytecode.rpyb │ └── pyanalysis.rpyb ├── tl │ └── None │ │ ├── common.rpymc │ │ └── common.rpym ├── default renpy scripts │ ├── gui.rpyc │ ├── options.rpyc │ ├── screens.rpyc │ ├── options.rpy │ └── gui.rpy ├── script.rpy └── speak.rpy └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/settings.json 2 | -------------------------------------------------------------------------------- /game/pydub/__init__.py: -------------------------------------------------------------------------------- 1 | from .audio_segment import AudioSegment -------------------------------------------------------------------------------- /game/gui/nvl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/nvl.png -------------------------------------------------------------------------------- /game/script.rpyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/script.rpyc -------------------------------------------------------------------------------- /game/speak.rpyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/speak.rpyc -------------------------------------------------------------------------------- /game/gui/frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/frame.png -------------------------------------------------------------------------------- /game/gui/skip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/skip.png -------------------------------------------------------------------------------- /game/audio/output.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/output.wav -------------------------------------------------------------------------------- /game/gui/bar/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/bar/left.png -------------------------------------------------------------------------------- /game/gui/bar/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/bar/top.png -------------------------------------------------------------------------------- /game/gui/namebox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/namebox.png -------------------------------------------------------------------------------- /game/gui/notify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/notify.png -------------------------------------------------------------------------------- /game/gui/textbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/textbox.png -------------------------------------------------------------------------------- /game/saves/persistent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/saves/persistent -------------------------------------------------------------------------------- /game/cache/screens.rpyb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/cache/screens.rpyb -------------------------------------------------------------------------------- /game/gui/bar/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/bar/bottom.png -------------------------------------------------------------------------------- /game/gui/bar/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/bar/right.png -------------------------------------------------------------------------------- /game/gui/game_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/game_menu.png -------------------------------------------------------------------------------- /game/gui/main_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/main_menu.png -------------------------------------------------------------------------------- /game/gui/phone/nvl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/nvl.png -------------------------------------------------------------------------------- /game/cache/bytecode.rpyb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/cache/bytecode.rpyb -------------------------------------------------------------------------------- /game/cache/pyanalysis.rpyb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/cache/pyanalysis.rpyb -------------------------------------------------------------------------------- /game/gui/phone/bar/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/bar/top.png -------------------------------------------------------------------------------- /game/gui/phone/textbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/textbox.png -------------------------------------------------------------------------------- /game/gui/window_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/window_icon.png -------------------------------------------------------------------------------- /game/saves/auto-1-LT1.save: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/saves/auto-1-LT1.save -------------------------------------------------------------------------------- /game/tl/None/common.rpymc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/tl/None/common.rpymc -------------------------------------------------------------------------------- /game/gui/overlay/confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/overlay/confirm.png -------------------------------------------------------------------------------- /game/gui/phone/bar/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/bar/left.png -------------------------------------------------------------------------------- /game/gui/phone/bar/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/bar/right.png -------------------------------------------------------------------------------- /game/audio/beeps/eileen/a.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/a.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/b.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/b.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/c.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/c.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/ch.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/ch.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/d.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/d.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/dot.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/dot.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/e.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/e.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/f.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/f.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/g.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/g.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/h.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/h.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/i.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/i.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/j.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/j.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/k.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/k.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/l.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/l.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/m.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/m.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/n.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/n.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/o.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/o.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/p.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/p.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/ph.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/ph.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/q.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/q.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/r.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/r.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/s.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/s.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/sh.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/sh.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/t.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/t.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/th.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/th.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/u.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/u.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/v.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/v.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/w.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/w.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/wh.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/wh.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/x.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/x.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/y.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/y.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen/z.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen/z.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/a.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/a.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/b.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/b.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/c.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/c.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/ch.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/ch.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/d.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/d.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/e.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/e.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/f.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/f.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/g.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/g.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/h.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/h.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/i.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/i.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/j.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/j.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/k.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/k.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/l.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/l.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/m.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/m.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/n.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/n.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/o.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/o.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/p.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/p.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/ph.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/ph.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/q.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/q.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/r.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/r.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/s.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/s.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/sh.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/sh.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/t.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/t.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/th.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/th.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/u.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/u.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/v.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/v.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/w.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/w.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/wh.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/wh.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/x.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/x.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/y.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/y.wav -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/z.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/z.wav -------------------------------------------------------------------------------- /game/gui/overlay/game_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/overlay/game_menu.png -------------------------------------------------------------------------------- /game/gui/overlay/main_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/overlay/main_menu.png -------------------------------------------------------------------------------- /game/gui/phone/bar/bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/bar/bottom.png -------------------------------------------------------------------------------- /game/saves/_reload-2-LT1.save: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/saves/_reload-2-LT1.save -------------------------------------------------------------------------------- /game/audio/beeps/eileen2/dot.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/audio/beeps/eileen2/dot.wav -------------------------------------------------------------------------------- /game/default renpy scripts/gui.rpyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/default renpy scripts/gui.rpyc -------------------------------------------------------------------------------- /game/gui/button/check_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/check_foreground.png -------------------------------------------------------------------------------- /game/gui/button/hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/hover_background.png -------------------------------------------------------------------------------- /game/gui/button/idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/idle_background.png -------------------------------------------------------------------------------- /game/gui/button/radio_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/radio_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/overlay/game_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/overlay/game_menu.png -------------------------------------------------------------------------------- /game/gui/phone/overlay/main_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/overlay/main_menu.png -------------------------------------------------------------------------------- /game/gui/slider/vertical_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/vertical_hover_bar.png -------------------------------------------------------------------------------- /game/gui/slider/vertical_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/vertical_idle_bar.png -------------------------------------------------------------------------------- /game/default renpy scripts/options.rpyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/default renpy scripts/options.rpyc -------------------------------------------------------------------------------- /game/default renpy scripts/screens.rpyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/default renpy scripts/screens.rpyc -------------------------------------------------------------------------------- /game/gui/button/quick_idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/quick_idle_background.png -------------------------------------------------------------------------------- /game/gui/button/slot_hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/slot_hover_background.png -------------------------------------------------------------------------------- /game/gui/button/slot_idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/slot_idle_background.png -------------------------------------------------------------------------------- /game/gui/phone/button/idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/idle_background.png -------------------------------------------------------------------------------- /game/gui/scrollbar/vertical_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/vertical_hover_bar.png -------------------------------------------------------------------------------- /game/gui/scrollbar/vertical_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/vertical_idle_bar.png -------------------------------------------------------------------------------- /game/gui/slider/horizontal_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/horizontal_hover_bar.png -------------------------------------------------------------------------------- /game/gui/slider/horizontal_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/horizontal_idle_bar.png -------------------------------------------------------------------------------- /game/gui/slider/horizontal_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/horizontal_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/slider/vertical_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/vertical_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/slider/vertical_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/vertical_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/button/choice_hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/choice_hover_background.png -------------------------------------------------------------------------------- /game/gui/button/choice_idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/choice_idle_background.png -------------------------------------------------------------------------------- /game/gui/button/quick_hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/quick_hover_background.png -------------------------------------------------------------------------------- /game/gui/phone/button/check_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/check_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/button/hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/hover_background.png -------------------------------------------------------------------------------- /game/gui/phone/button/radio_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/radio_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/slider/vertical_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/vertical_idle_bar.png -------------------------------------------------------------------------------- /game/gui/scrollbar/horizontal_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/horizontal_hover_bar.png -------------------------------------------------------------------------------- /game/gui/scrollbar/horizontal_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/horizontal_idle_bar.png -------------------------------------------------------------------------------- /game/gui/scrollbar/vertical_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/vertical_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/scrollbar/vertical_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/vertical_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/slider/horizontal_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/slider/horizontal_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/button/check_selected_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/check_selected_foreground.png -------------------------------------------------------------------------------- /game/gui/button/radio_selected_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/button/radio_selected_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/button/slot_idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/slot_idle_background.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/vertical_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/vertical_idle_bar.png -------------------------------------------------------------------------------- /game/gui/phone/slider/horizontal_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/horizontal_hover_bar.png -------------------------------------------------------------------------------- /game/gui/phone/slider/horizontal_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/horizontal_idle_bar.png -------------------------------------------------------------------------------- /game/gui/phone/slider/vertical_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/vertical_hover_bar.png -------------------------------------------------------------------------------- /game/gui/phone/slider/vertical_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/vertical_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/slider/vertical_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/vertical_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/scrollbar/horizontal_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/horizontal_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/scrollbar/horizontal_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/scrollbar/horizontal_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/button/choice_idle_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/choice_idle_background.png -------------------------------------------------------------------------------- /game/gui/phone/button/slot_hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/slot_hover_background.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/horizontal_idle_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/horizontal_idle_bar.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/vertical_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/vertical_hover_bar.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/vertical_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/vertical_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/slider/horizontal_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/horizontal_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/slider/horizontal_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/slider/horizontal_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/button/check_selected_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/check_selected_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/button/choice_hover_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/choice_hover_background.png -------------------------------------------------------------------------------- /game/gui/phone/button/radio_selected_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/button/radio_selected_foreground.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/horizontal_hover_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/horizontal_hover_bar.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/horizontal_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/horizontal_hover_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/horizontal_idle_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/horizontal_idle_thumb.png -------------------------------------------------------------------------------- /game/gui/phone/scrollbar/vertical_hover_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abrookst/Renpy8-Animalese/HEAD/game/gui/phone/scrollbar/vertical_hover_thumb.png -------------------------------------------------------------------------------- /game/audio/beeps/letters.txt: -------------------------------------------------------------------------------- 1 | Seperate files for each would be probably easier in the long run. Please use the samples in the folder "letters" as an example for the correct sound to make. Have fun! 2 | 3 | a- 4 | b- 5 | c- 6 | d- 7 | e- 8 | f- 9 | g- 10 | h- 11 | i- 12 | j- 13 | k- 14 | l- 15 | m- 16 | n- 17 | o- 18 | p- 19 | q- 20 | r- 21 | s- 22 | t- 23 | u- 24 | v- 25 | w- 26 | x- 27 | y- 28 | z- 29 | th- 30 | ch- 31 | sh- 32 | ph- 33 | wh- -------------------------------------------------------------------------------- /game/pydub/logging_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | """ 4 | import logging 5 | 6 | converter_logger = logging.getLogger("pydub.converter") 7 | 8 | def log_conversion(conversion_command): 9 | converter_logger.debug("subprocess.call(%s)", repr(conversion_command)) 10 | 11 | def log_subprocess_output(output): 12 | if output: 13 | for line in output.rstrip().splitlines(): 14 | converter_logger.debug('subprocess output: %s', line.rstrip()) 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Renpy8 Animalese 2 | Zach Coleman (ztc0611) adapted HenryIsHuman's Animalese script to work with Renpy using Jiaaro (James Robert)'s Pydub. And now I came in and made it work with Renpy 8.0.0/Python 3. 3 | Check out everyone below! 4 | * https://github.com/jiaaro 5 | * https://github.com/ztc0611 6 | * https://www.youtube.com/c/henryishuman 7 | 8 | Installing is the same as ztc0611's original. Just drag over: 9 | * The full "pydub" folder 10 | * the full "audio" folder 11 | * The character callbacks in script.rpy, modified for the names of your own characters. 12 | * speak.rpy 13 | -------------------------------------------------------------------------------- /game/pydub/exceptions.py: -------------------------------------------------------------------------------- 1 | class PydubException(Exception): 2 | """ 3 | Base class for any Pydub exception 4 | """ 5 | 6 | 7 | class TooManyMissingFrames(PydubException): 8 | pass 9 | 10 | 11 | class InvalidDuration(PydubException): 12 | pass 13 | 14 | 15 | class InvalidTag(PydubException): 16 | pass 17 | 18 | 19 | class InvalidID3TagVersion(PydubException): 20 | pass 21 | 22 | 23 | class CouldntDecodeError(PydubException): 24 | pass 25 | 26 | 27 | class CouldntEncodeError(PydubException): 28 | pass 29 | 30 | 31 | class MissingAudioParameter(PydubException): 32 | pass 33 | -------------------------------------------------------------------------------- /game/script.rpy: -------------------------------------------------------------------------------- 1 | 2 | init python: 3 | 4 | #Generate seperate audio channel from voice for beeps. 5 | renpy.music.register_channel(name='beeps', mixer='voice') 6 | 7 | #Character callback that generates the sound. 8 | def e(event, **kwargs): 9 | if event == "show": #When the text is shown 10 | build_sentence(_last_say_what, "eileen") 11 | renpy.sound.play("audio/output.wav", channel="beeps", loop=False) 12 | elif event == "slow_done" or event == "end": #When the text is finished displaying or you open a menu. 13 | renpy.sound.stop(channel="beeps") 14 | 15 | #Example of an alternate character callback 16 | def e2(event, **kwargs): 17 | if event == "show": #When the text is shown 18 | build_sentence(_last_say_what, "eileen2") 19 | renpy.sound.play("audio/output.wav", channel="beeps", loop=False) 20 | elif event == "slow_done" or event == "end": #When the text is finished displaying or you open a menu. 21 | renpy.sound.stop(channel="beeps") 22 | 23 | define e = Character("Eileen", callback=e) 24 | define e2 = Character("Eileen", callback=e2) 25 | 26 | 27 | label start: 28 | 29 | scene bg room 30 | show eileen happy 31 | 32 | e "Hello, welcome to the Ren'py \"Animalese\" textgarble generator!" 33 | e "Importing these scripts and files into your VN can allow you to produce this effect!" 34 | "..." 35 | e2 "The E and A sounds of this voice is different, for an example of how to make a second set of voice samples." 36 | e2 "Try making your own samples for different characters in your own projects!" 37 | 38 | return 39 | -------------------------------------------------------------------------------- /game/pydub/playback.py: -------------------------------------------------------------------------------- 1 | """ 2 | Support for playing AudioSegments. Pyaudio will be used if it's installed, 3 | otherwise will fallback to ffplay. Pyaudio is a *much* nicer solution, but 4 | is tricky to install. See my notes on installing pyaudio in a virtualenv (on 5 | OSX 10.10): https://gist.github.com/jiaaro/9767512210a1d80a8a0d 6 | """ 7 | 8 | import subprocess 9 | from tempfile import NamedTemporaryFile 10 | from .utils import get_player_name, make_chunks 11 | 12 | def _play_with_ffplay(seg): 13 | PLAYER = get_player_name() 14 | with NamedTemporaryFile("w+b", suffix=".wav") as f: 15 | seg.export(f.name, "wav") 16 | subprocess.call([PLAYER, "-nodisp", "-autoexit", "-hide_banner", f.name]) 17 | 18 | 19 | def _play_with_pyaudio(seg): 20 | import pyaudio 21 | 22 | p = pyaudio.PyAudio() 23 | stream = p.open(format=p.get_format_from_width(seg.sample_width), 24 | channels=seg.channels, 25 | rate=seg.frame_rate, 26 | output=True) 27 | 28 | # Just in case there were any exceptions/interrupts, we release the resource 29 | # So as not to raise OSError: Device Unavailable should play() be used again 30 | try: 31 | # break audio into half-second chunks (to allows keyboard interrupts) 32 | for chunk in make_chunks(seg, 500): 33 | stream.write(chunk._data) 34 | finally: 35 | stream.stop_stream() 36 | stream.close() 37 | 38 | p.terminate() 39 | 40 | 41 | def _play_with_simpleaudio(seg): 42 | import simpleaudio 43 | return simpleaudio.play_buffer( 44 | seg.raw_data, 45 | num_channels=seg.channels, 46 | bytes_per_sample=seg.sample_width, 47 | sample_rate=seg.frame_rate 48 | ) 49 | 50 | 51 | def play(audio_segment): 52 | try: 53 | playback = _play_with_simpleaudio(audio_segment) 54 | try: 55 | playback.wait_done() 56 | except KeyboardInterrupt: 57 | playback.stop() 58 | except ImportError: 59 | pass 60 | else: 61 | return 62 | 63 | try: 64 | _play_with_pyaudio(audio_segment) 65 | return 66 | except ImportError: 67 | pass 68 | else: 69 | return 70 | 71 | _play_with_ffplay(audio_segment) 72 | -------------------------------------------------------------------------------- /game/pydub/generators.py: -------------------------------------------------------------------------------- 1 | """ 2 | Each generator will return float samples from -1.0 to 1.0, which can be 3 | converted to actual audio with 8, 16, 24, or 32 bit depth using the 4 | SiganlGenerator.to_audio_segment() method (on any of it's subclasses). 5 | 6 | See Wikipedia's "waveform" page for info on some of the generators included 7 | here: http://en.wikipedia.org/wiki/Waveform 8 | """ 9 | 10 | import math 11 | import array 12 | import itertools 13 | import random 14 | from .audio_segment import AudioSegment 15 | from .utils import ( 16 | db_to_float, 17 | get_frame_width, 18 | get_array_type, 19 | get_min_max_value 20 | ) 21 | 22 | 23 | 24 | class SignalGenerator(object): 25 | def __init__(self, sample_rate=44100, bit_depth=16): 26 | self.sample_rate = sample_rate 27 | self.bit_depth = bit_depth 28 | 29 | def to_audio_segment(self, duration=1000.0, volume=0.0): 30 | """ 31 | Duration in milliseconds 32 | (default: 1 second) 33 | Volume in DB relative to maximum amplitude 34 | (default 0.0 dBFS, which is the maximum value) 35 | """ 36 | minval, maxval = get_min_max_value(self.bit_depth) 37 | sample_width = get_frame_width(self.bit_depth) 38 | array_type = get_array_type(self.bit_depth) 39 | 40 | gain = db_to_float(volume) 41 | sample_count = int(self.sample_rate * (duration / 1000.0)) 42 | 43 | sample_data = (int(val * maxval * gain) for val in self.generate()) 44 | sample_data = itertools.islice(sample_data, 0, sample_count) 45 | 46 | data = array.array(array_type, sample_data) 47 | 48 | try: 49 | data = data.tobytes() 50 | except: 51 | data = data.tostring() 52 | 53 | return AudioSegment(data=data, metadata={ 54 | "channels": 1, 55 | "sample_width": sample_width, 56 | "frame_rate": self.sample_rate, 57 | "frame_width": sample_width, 58 | }) 59 | 60 | def generate(self): 61 | raise NotImplementedError("SignalGenerator subclasses must implement the generate() method, and *should not* call the superclass implementation.") 62 | 63 | 64 | 65 | class Sine(SignalGenerator): 66 | def __init__(self, freq, **kwargs): 67 | super(Sine, self).__init__(**kwargs) 68 | self.freq = freq 69 | 70 | def generate(self): 71 | sine_of = (self.freq * 2 * math.pi) / self.sample_rate 72 | sample_n = 0 73 | while True: 74 | yield math.sin(sine_of * sample_n) 75 | sample_n += 1 76 | 77 | 78 | 79 | class Pulse(SignalGenerator): 80 | def __init__(self, freq, duty_cycle=0.5, **kwargs): 81 | super(Pulse, self).__init__(**kwargs) 82 | self.freq = freq 83 | self.duty_cycle = duty_cycle 84 | 85 | def generate(self): 86 | sample_n = 0 87 | 88 | # in samples 89 | cycle_length = self.sample_rate / float(self.freq) 90 | pulse_length = cycle_length * self.duty_cycle 91 | 92 | while True: 93 | if (sample_n % cycle_length) < pulse_length: 94 | yield 1.0 95 | else: 96 | yield -1.0 97 | sample_n += 1 98 | 99 | 100 | 101 | class Square(Pulse): 102 | def __init__(self, freq, **kwargs): 103 | kwargs['duty_cycle'] = 0.5 104 | super(Square, self).__init__(freq, **kwargs) 105 | 106 | 107 | 108 | class Sawtooth(SignalGenerator): 109 | def __init__(self, freq, duty_cycle=1.0, **kwargs): 110 | super(Sawtooth, self).__init__(**kwargs) 111 | self.freq = freq 112 | self.duty_cycle = duty_cycle 113 | 114 | def generate(self): 115 | sample_n = 0 116 | 117 | # in samples 118 | cycle_length = self.sample_rate / float(self.freq) 119 | midpoint = cycle_length * self.duty_cycle 120 | ascend_length = midpoint 121 | descend_length = cycle_length - ascend_length 122 | 123 | while True: 124 | cycle_position = sample_n % cycle_length 125 | if cycle_position < midpoint: 126 | yield (2 * cycle_position / ascend_length) - 1.0 127 | else: 128 | yield 1.0 - (2 * (cycle_position - midpoint) / descend_length) 129 | sample_n += 1 130 | 131 | 132 | 133 | class Triangle(Sawtooth): 134 | def __init__(self, freq, **kwargs): 135 | kwargs['duty_cycle'] = 0.5 136 | super(Triangle, self).__init__(freq, **kwargs) 137 | 138 | 139 | class WhiteNoise(SignalGenerator): 140 | def generate(self): 141 | while True: 142 | yield (random.random() * 2) - 1.0 143 | -------------------------------------------------------------------------------- /game/speak.rpy: -------------------------------------------------------------------------------- 1 | ############################################################################################ 2 | ### Animalese/Animal Crossing style speech generation for Ren'py 3 | ############################################################################################ 4 | ### Large thank you to Henry of harryishuman for the original version of this code! 5 | ### Modified for use in Ren'py by CoolerMudkip/Zach Coleman from Lemmasoft Fourms 6 | ############################################################################################ 7 | 8 | init python: 9 | 10 | #Needed Libraries for use. If this is being imported into your project, do not forget to copy over the pydub folder! 11 | import pydub 12 | import os, math, sys, random, string, re 13 | from pydub import AudioSegment 14 | from pydub import effects 15 | from pydub.playback import play 16 | 17 | TEMP_FILE_NAME = config.gamedir+"/audio/temp_garble.ogg" 18 | 19 | #List of letters/Diagraphs. This only works for english sounds by default but could be modified to include Spanish/etc sounds. 20 | letter_graphs = [ 21 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", 22 | "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", 23 | "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", 24 | "7", "8", "9" 25 | ] 26 | digraphs = [ 27 | "ch", "sh", "ph", "th", "wh" 28 | ] 29 | 30 | dots = "dot" 31 | 32 | #Builds the sentence when given a sentence and a character's name using their speech garble. 33 | def build_sentence(sentence, name): 34 | 35 | #If the player isn't skipping and the voice volume setting isn't 0/muted, then generate the text sounds. 36 | if renpy.get_skipping() == None and preferences.volumes['voice'] > 0: 37 | sentence_wav = AudioSegment.empty() 38 | sentence = sentence.lower() 39 | sentence = replace_swear_words(sentence) 40 | sentence = replace_parentheses(sentence) 41 | sentence = replace_numbers(sentence) 42 | i = 0 43 | while (i < len(sentence)): 44 | char = None 45 | if (i < len(sentence)-1) and ((sentence[i] + sentence[i+1]) in digraphs): 46 | char = sentence[i] + sentence[i+1] 47 | i+=1 48 | elif sentence[i] in letter_graphs: 49 | char = sentence[i] 50 | elif sentence[i] in string.punctuation: 51 | char = dots 52 | i+=2 53 | 54 | if char != None: 55 | new_segment = AudioSegment.from_wav(config.gamedir+"/audio/beeps/"+name+"/{}.wav".format(char)) 56 | sentence_wav += new_segment 57 | 58 | sentence_wav = change_playback_speed(sentence_wav, voice) 59 | sentence_wav.export(config.gamedir+"/audio/output.wav", format="wav") 60 | 61 | #Replaces swear words with a "dot" sound effect. Can be disabled by commenting out line 36. 62 | def replace_swear_words(sentence): 63 | swear_words = ["fuck", "shit", "piss", "crap", "bugger", "hell", "damn", "dick", "bastard", "asshole"] 64 | for word in swear_words: 65 | sentence = sentence.replace(word, "*"*len(word)) 66 | return sentence 67 | 68 | #makes text in parentheses also be dot noises. This is inpsired by how text works in Animal Crossing. 69 | def replace_parentheses(sentence): 70 | while "(" in sentence or ")" in sentence: 71 | start = sentence.index("(") 72 | end = sentence.index(")") 73 | sentence = sentence[:start] + "*"*(end-start) + sentence[end+1:] 74 | return sentence 75 | 76 | #Replaces numbers with their spoken equivilent. 77 | def replace_numbers(sentence): 78 | numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] 79 | for word in numbers: 80 | if word == "1": 81 | sentence = sentence.replace(word, "one") 82 | if word == "2": 83 | sentence = sentence.replace(word, "two") 84 | if word == "3": 85 | sentence = sentence.replace(word, "three") 86 | if word == "4": 87 | sentence = sentence.replace(word, "four") 88 | if word == "5": 89 | sentence = sentence.replace(word, "five") 90 | if word == "6": 91 | sentence = sentence.replace(word, "six") 92 | if word == "7": 93 | sentence = sentence.replace(word, "seven") 94 | if word == "8": 95 | sentence = sentence.replace(word, "eight") 96 | if word == "9": 97 | sentence = sentence.replace(word, "nine") 98 | if word == "0": 99 | sentence = sentence.replace(word, "zero") 100 | return sentence 101 | 102 | #Speeds up the playback to make it sound more garbled and less decipherable. 103 | def change_playback_speed(sound, speed_change): 104 | export = sound.speedup(6.0, 200, 30) 105 | return export 106 | -------------------------------------------------------------------------------- /game/pydub/silence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Various functions for finding/manipulating silence in AudioSegments 3 | """ 4 | import itertools 5 | 6 | from .utils import db_to_float 7 | 8 | 9 | def detect_silence(audio_segment, min_silence_len=1000, silence_thresh=-16, seek_step=1): 10 | """ 11 | Returns a list of all silent sections [start, end] in milliseconds of audio_segment. 12 | Inverse of detect_nonsilent() 13 | 14 | audio_segment - the segment to find silence in 15 | min_silence_len - the minimum length for any silent section 16 | silence_thresh - the upper bound for how quiet is silent in dFBS 17 | seek_step - step size for interating over the segment in ms 18 | """ 19 | seg_len = len(audio_segment) 20 | 21 | # you can't have a silent portion of a sound that is longer than the sound 22 | if seg_len < min_silence_len: 23 | return [] 24 | 25 | # convert silence threshold to a float value (so we can compare it to rms) 26 | silence_thresh = db_to_float(silence_thresh) * audio_segment.max_possible_amplitude 27 | 28 | # find silence and add start and end indicies to the to_cut list 29 | silence_starts = [] 30 | 31 | # check successive (1 sec by default) chunk of sound for silence 32 | # try a chunk at every "seek step" (or every chunk for a seek step == 1) 33 | last_slice_start = seg_len - min_silence_len 34 | slice_starts = range(0, last_slice_start + 1, seek_step) 35 | 36 | # guarantee last_slice_start is included in the range 37 | # to make sure the last portion of the audio is searched 38 | if last_slice_start % seek_step: 39 | slice_starts = itertools.chain(slice_starts, [last_slice_start]) 40 | 41 | for i in slice_starts: 42 | audio_slice = audio_segment[i:i + min_silence_len] 43 | if audio_slice.rms <= silence_thresh: 44 | silence_starts.append(i) 45 | 46 | # short circuit when there is no silence 47 | if not silence_starts: 48 | return [] 49 | 50 | # combine the silence we detected into ranges (start ms - end ms) 51 | silent_ranges = [] 52 | 53 | prev_i = silence_starts.pop(0) 54 | current_range_start = prev_i 55 | 56 | for silence_start_i in silence_starts: 57 | continuous = (silence_start_i == prev_i + seek_step) 58 | 59 | # sometimes two small blips are enough for one particular slice to be 60 | # non-silent, despite the silence all running together. Just combine 61 | # the two overlapping silent ranges. 62 | silence_has_gap = silence_start_i > (prev_i + min_silence_len) 63 | 64 | if not continuous and silence_has_gap: 65 | silent_ranges.append([current_range_start, 66 | prev_i + min_silence_len]) 67 | current_range_start = silence_start_i 68 | prev_i = silence_start_i 69 | 70 | silent_ranges.append([current_range_start, 71 | prev_i + min_silence_len]) 72 | 73 | return silent_ranges 74 | 75 | 76 | def detect_nonsilent(audio_segment, min_silence_len=1000, silence_thresh=-16, seek_step=1): 77 | """ 78 | Returns a list of all nonsilent sections [start, end] in milliseconds of audio_segment. 79 | Inverse of detect_silent() 80 | 81 | audio_segment - the segment to find silence in 82 | min_silence_len - the minimum length for any silent section 83 | silence_thresh - the upper bound for how quiet is silent in dFBS 84 | seek_step - step size for interating over the segment in ms 85 | """ 86 | silent_ranges = detect_silence(audio_segment, min_silence_len, silence_thresh, seek_step) 87 | len_seg = len(audio_segment) 88 | 89 | # if there is no silence, the whole thing is nonsilent 90 | if not silent_ranges: 91 | return [[0, len_seg]] 92 | 93 | # short circuit when the whole audio segment is silent 94 | if silent_ranges[0][0] == 0 and silent_ranges[0][1] == len_seg: 95 | return [] 96 | 97 | prev_end_i = 0 98 | nonsilent_ranges = [] 99 | for start_i, end_i in silent_ranges: 100 | nonsilent_ranges.append([prev_end_i, start_i]) 101 | prev_end_i = end_i 102 | 103 | if end_i != len_seg: 104 | nonsilent_ranges.append([prev_end_i, len_seg]) 105 | 106 | if nonsilent_ranges[0] == [0, 0]: 107 | nonsilent_ranges.pop(0) 108 | 109 | return nonsilent_ranges 110 | 111 | 112 | def split_on_silence(audio_segment, min_silence_len=1000, silence_thresh=-16, keep_silence=100, 113 | seek_step=1): 114 | """ 115 | Returns list of audio segments from splitting audio_segment on silent sections 116 | 117 | audio_segment - original pydub.AudioSegment() object 118 | 119 | min_silence_len - (in ms) minimum length of a silence to be used for 120 | a split. default: 1000ms 121 | 122 | silence_thresh - (in dBFS) anything quieter than this will be 123 | considered silence. default: -16dBFS 124 | 125 | keep_silence - (in ms or True/False) leave some silence at the beginning 126 | and end of the chunks. Keeps the sound from sounding like it 127 | is abruptly cut off. 128 | When the length of the silence is less than the keep_silence duration 129 | it is split evenly between the preceding and following non-silent 130 | segments. 131 | If True is specified, all the silence is kept, if False none is kept. 132 | default: 100ms 133 | 134 | seek_step - step size for interating over the segment in ms 135 | """ 136 | 137 | # from the itertools documentation 138 | def pairwise(iterable): 139 | "s -> (s0,s1), (s1,s2), (s2, s3), ..." 140 | a, b = itertools.tee(iterable) 141 | next(b, None) 142 | return zip(a, b) 143 | 144 | if isinstance(keep_silence, bool): 145 | keep_silence = len(audio_segment) if keep_silence else 0 146 | 147 | output_ranges = [ 148 | [ start - keep_silence, end + keep_silence ] 149 | for (start,end) 150 | in detect_nonsilent(audio_segment, min_silence_len, silence_thresh, seek_step) 151 | ] 152 | 153 | for range_i, range_ii in pairwise(output_ranges): 154 | last_end = range_i[1] 155 | next_start = range_ii[0] 156 | if next_start < last_end: 157 | range_i[1] = (last_end+next_start)//2 158 | range_ii[0] = range_i[1] 159 | 160 | return [ 161 | audio_segment[ max(start,0) : min(end,len(audio_segment)) ] 162 | for start,end in output_ranges 163 | ] 164 | 165 | 166 | def detect_leading_silence(sound, silence_threshold=-50.0, chunk_size=10): 167 | """ 168 | Returns the millisecond/index that the leading silence ends. 169 | 170 | audio_segment - the segment to find silence in 171 | silence_threshold - the upper bound for how quiet is silent in dFBS 172 | chunk_size - chunk size for interating over the segment in ms 173 | """ 174 | trim_ms = 0 # ms 175 | assert chunk_size > 0 # to avoid infinite loop 176 | while sound[trim_ms:trim_ms+chunk_size].dBFS < silence_threshold and trim_ms < len(sound): 177 | trim_ms += chunk_size 178 | 179 | # if there is no end it should return the length of the segment 180 | return min(trim_ms, len(sound)) 181 | 182 | 183 | -------------------------------------------------------------------------------- /game/pydub/scipy_effects.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module provides scipy versions of high_pass_filter, and low_pass_filter 3 | as well as an additional band_pass_filter. 4 | 5 | Of course, you will need to install scipy for these to work. 6 | 7 | When this module is imported the high and low pass filters from this module 8 | will be used when calling audio_segment.high_pass_filter() and 9 | audio_segment.high_pass_filter() instead of the slower, less powerful versions 10 | provided by pydub.effects. 11 | """ 12 | from scipy.signal import butter, sosfilt 13 | from .utils import (register_pydub_effect,stereo_to_ms,ms_to_stereo) 14 | 15 | 16 | def _mk_butter_filter(freq, type, order): 17 | """ 18 | Args: 19 | freq: The cutoff frequency for highpass and lowpass filters. For 20 | band filters, a list of [low_cutoff, high_cutoff] 21 | type: "lowpass", "highpass", or "band" 22 | order: nth order butterworth filter (default: 5th order). The 23 | attenuation is -6dB/octave beyond the cutoff frequency (for 1st 24 | order). A Higher order filter will have more attenuation, each level 25 | adding an additional -6dB (so a 3rd order butterworth filter would 26 | be -18dB/octave). 27 | 28 | Returns: 29 | function which can filter a mono audio segment 30 | 31 | """ 32 | def filter_fn(seg): 33 | assert seg.channels == 1 34 | 35 | nyq = 0.5 * seg.frame_rate 36 | try: 37 | freqs = [f / nyq for f in freq] 38 | except TypeError: 39 | freqs = freq / nyq 40 | 41 | sos = butter(order, freqs, btype=type, output='sos') 42 | y = sosfilt(sos, seg.get_array_of_samples()) 43 | 44 | return seg._spawn(y.astype(seg.array_type)) 45 | 46 | return filter_fn 47 | 48 | 49 | @register_pydub_effect 50 | def band_pass_filter(seg, low_cutoff_freq, high_cutoff_freq, order=5): 51 | filter_fn = _mk_butter_filter([low_cutoff_freq, high_cutoff_freq], 'band', order=order) 52 | return seg.apply_mono_filter_to_each_channel(filter_fn) 53 | 54 | 55 | @register_pydub_effect 56 | def high_pass_filter(seg, cutoff_freq, order=5): 57 | filter_fn = _mk_butter_filter(cutoff_freq, 'highpass', order=order) 58 | return seg.apply_mono_filter_to_each_channel(filter_fn) 59 | 60 | 61 | @register_pydub_effect 62 | def low_pass_filter(seg, cutoff_freq, order=5): 63 | filter_fn = _mk_butter_filter(cutoff_freq, 'lowpass', order=order) 64 | return seg.apply_mono_filter_to_each_channel(filter_fn) 65 | 66 | 67 | @register_pydub_effect 68 | def _eq(seg, focus_freq, bandwidth=100, mode="peak", gain_dB=0, order=2): 69 | """ 70 | Args: 71 | focus_freq - middle frequency or known frequency of band (in Hz) 72 | bandwidth - range of the equalizer band 73 | mode - Mode of Equalization(Peak/Notch(Bell Curve),High Shelf, Low Shelf) 74 | order - Rolloff factor(1 - 6dB/Octave 2 - 12dB/Octave) 75 | 76 | Returns: 77 | Equalized/Filtered AudioSegment 78 | """ 79 | filt_mode = ["peak", "low_shelf", "high_shelf"] 80 | if mode not in filt_mode: 81 | raise ValueError("Incorrect Mode Selection") 82 | 83 | if gain_dB >= 0: 84 | if mode == "peak": 85 | sec = band_pass_filter(seg, focus_freq - bandwidth/2, focus_freq + bandwidth/2, order = order) 86 | seg = seg.overlay(sec - (3 - gain_dB)) 87 | return seg 88 | 89 | if mode == "low_shelf": 90 | sec = low_pass_filter(seg, focus_freq, order=order) 91 | seg = seg.overlay(sec - (3 - gain_dB)) 92 | return seg 93 | 94 | if mode == "high_shelf": 95 | sec = high_pass_filter(seg, focus_freq, order=order) 96 | seg = seg.overlay(sec - (3 - gain_dB)) 97 | return seg 98 | 99 | if gain_dB < 0: 100 | if mode == "peak": 101 | sec = high_pass_filter(seg, focus_freq - bandwidth/2, order=order) 102 | seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB 103 | sec = low_pass_filter(seg, focus_freq + bandwidth/2, order=order) 104 | seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB 105 | return seg 106 | 107 | if mode == "low_shelf": 108 | sec = high_pass_filter(seg, focus_freq, order=order) 109 | seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB 110 | return seg 111 | 112 | if mode=="high_shelf": 113 | sec=low_pass_filter(seg, focus_freq, order=order) 114 | seg=seg.overlay(sec - (3 + gain_dB)) +gain_dB 115 | return seg 116 | 117 | 118 | @register_pydub_effect 119 | def eq(seg, focus_freq, bandwidth=100, channel_mode="L+R", filter_mode="peak", gain_dB=0, order=2): 120 | """ 121 | Args: 122 | focus_freq - middle frequency or known frequency of band (in Hz) 123 | bandwidth - range of the equalizer band 124 | channel_mode - Select Channels to be affected by the filter. 125 | L+R - Standard Stereo Filter 126 | L - Only Left Channel is Filtered 127 | R - Only Right Channel is Filtered 128 | M+S - Blumlien Stereo Filter(Mid-Side) 129 | M - Only Mid Channel is Filtered 130 | S - Only Side Channel is Filtered 131 | Mono Audio Segments are completely filtered. 132 | filter_mode - Mode of Equalization(Peak/Notch(Bell Curve),High Shelf, Low Shelf) 133 | order - Rolloff factor(1 - 6dB/Octave 2 - 12dB/Octave) 134 | 135 | Returns: 136 | Equalized/Filtered AudioSegment 137 | """ 138 | channel_modes = ["L+R", "M+S", "L", "R", "M", "S"] 139 | if channel_mode not in channel_modes: 140 | raise ValueError("Incorrect Channel Mode Selection") 141 | 142 | if seg.channels == 1: 143 | return _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) 144 | 145 | if channel_mode == "L+R": 146 | return _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) 147 | 148 | if channel_mode == "L": 149 | seg = seg.split_to_mono() 150 | seg = [_eq(seg[0], focus_freq, bandwidth, filter_mode, gain_dB, order), seg[1]] 151 | return AudioSegment.from_mono_audio_segements(seg[0], seg[1]) 152 | 153 | if channel_mode == "R": 154 | seg = seg.split_to_mono() 155 | seg = [seg[0], _eq(seg[1], focus_freq, bandwidth, filter_mode, gain_dB, order)] 156 | return AudioSegment.from_mono_audio_segements(seg[0], seg[1]) 157 | 158 | if channel_mode == "M+S": 159 | seg = stereo_to_ms(seg) 160 | seg = _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) 161 | return ms_to_stereo(seg) 162 | 163 | if channel_mode == "M": 164 | seg = stereo_to_ms(seg).split_to_mono() 165 | seg = [_eq(seg[0], focus_freq, bandwidth, filter_mode, gain_dB, order), seg[1]] 166 | seg = AudioSegment.from_mono_audio_segements(seg[0], seg[1]) 167 | return ms_to_stereo(seg) 168 | 169 | if channel_mode == "S": 170 | seg = stereo_to_ms(seg).split_to_mono() 171 | seg = [seg[0], _eq(seg[1], focus_freq, bandwidth, filter_mode, gain_dB, order)] 172 | seg = AudioSegment.from_mono_audio_segements(seg[0], seg[1]) 173 | return ms_to_stereo(seg) 174 | 175 | 176 | -------------------------------------------------------------------------------- /game/default renpy scripts/options.rpy: -------------------------------------------------------------------------------- 1 | ## This file contains options that can be changed to customize your game. 2 | ## 3 | ## Lines beginning with two '#' marks are comments, and you shouldn't uncomment 4 | ## them. Lines beginning with a single '#' mark are commented-out code, and you 5 | ## may want to uncomment them when appropriate. 6 | 7 | 8 | ## Basics ###################################################################### 9 | 10 | ## A human-readable name of the game. This is used to set the default window 11 | ## title, and shows up in the interface and error reports. 12 | ## 13 | ## The _() surrounding the string marks it as eligible for translation. 14 | 15 | define config.name = _("Animalese") 16 | 17 | 18 | ## Determines if the title given above is shown on the main menu screen. Set 19 | ## this to False to hide the title. 20 | 21 | define gui.show_name = True 22 | 23 | 24 | ## The version of the game. 25 | 26 | define config.version = "1.0" 27 | 28 | 29 | ## Text that is placed on the game's about screen. Place the text between the 30 | ## triple-quotes, and leave a blank line between paragraphs. 31 | 32 | define gui.about = _p(""" 33 | """) 34 | 35 | 36 | ## A short name for the game used for executables and directories in the built 37 | ## distribution. This must be ASCII-only, and must not contain spaces, colons, 38 | ## or semicolons. 39 | 40 | define build.name = "Animalese" 41 | 42 | 43 | ## Sounds and music ############################################################ 44 | 45 | ## These three variables control which mixers are shown to the player by 46 | ## default. Setting one of these to False will hide the appropriate mixer. 47 | 48 | define config.has_sound = True 49 | define config.has_music = True 50 | define config.has_voice = True 51 | 52 | 53 | ## To allow the user to play a test sound on the sound or voice channel, 54 | ## uncomment a line below and use it to set a sample sound to play. 55 | 56 | # define config.sample_sound = "sample-sound.ogg" 57 | # define config.sample_voice = "sample-voice.ogg" 58 | 59 | 60 | ## Uncomment the following line to set an audio file that will be played while 61 | ## the player is at the main menu. This file will continue playing into the 62 | ## game, until it is stopped or another file is played. 63 | 64 | # define config.main_menu_music = "main-menu-theme.ogg" 65 | 66 | 67 | ## Transitions ################################################################# 68 | ## 69 | ## These variables set transitions that are used when certain events occur. 70 | ## Each variable should be set to a transition, or None to indicate that no 71 | ## transition should be used. 72 | 73 | ## Entering or exiting the game menu. 74 | 75 | define config.enter_transition = dissolve 76 | define config.exit_transition = dissolve 77 | 78 | 79 | ## Between screens of the game menu. 80 | 81 | define config.intra_transition = dissolve 82 | 83 | 84 | ## A transition that is used after a game has been loaded. 85 | 86 | define config.after_load_transition = None 87 | 88 | 89 | ## Used when entering the main menu after the game has ended. 90 | 91 | define config.end_game_transition = None 92 | 93 | 94 | ## A variable to set the transition used when the game starts does not exist. 95 | ## Instead, use a with statement after showing the initial scene. 96 | 97 | 98 | ## Window management ########################################################### 99 | ## 100 | ## This controls when the dialogue window is displayed. If "show", it is always 101 | ## displayed. If "hide", it is only displayed when dialogue is present. If 102 | ## "auto", the window is hidden before scene statements and shown again once 103 | ## dialogue is displayed. 104 | ## 105 | ## After the game has started, this can be changed with the "window show", 106 | ## "window hide", and "window auto" statements. 107 | 108 | define config.window = "auto" 109 | 110 | 111 | ## Transitions used to show and hide the dialogue window 112 | 113 | define config.window_show_transition = Dissolve(.2) 114 | define config.window_hide_transition = Dissolve(.2) 115 | 116 | 117 | ## Preference defaults ######################################################### 118 | 119 | ## Controls the default text speed. The default, 0, is infinite, while any other 120 | ## number is the number of characters per second to type out. 121 | 122 | default preferences.text_cps = 70 123 | 124 | 125 | ## The default auto-forward delay. Larger numbers lead to longer waits, with 0 126 | ## to 30 being the valid range. 127 | 128 | default preferences.afm_time = 15 129 | 130 | 131 | ## Save directory ############################################################## 132 | ## 133 | ## Controls the platform-specific place Ren'Py will place the save files for 134 | ## this game. The save files will be placed in: 135 | ## 136 | ## Windows: %APPDATA\RenPy\ 137 | ## 138 | ## Macintosh: $HOME/Library/RenPy/ 139 | ## 140 | ## Linux: $HOME/.renpy/ 141 | ## 142 | ## This generally should not be changed, and if it is, should always be a 143 | ## literal string, not an expression. 144 | 145 | define config.save_directory = "Animalese-1586478174" 146 | 147 | 148 | ## Icon ######################################################################## 149 | ## 150 | ## The icon displayed on the taskbar or dock. 151 | 152 | define config.window_icon = "gui/window_icon.png" 153 | 154 | 155 | ## Build configuration ######################################################### 156 | ## 157 | ## This section controls how Ren'Py turns your project into distribution files. 158 | 159 | init python: 160 | 161 | ## The following functions take file patterns. File patterns are case- 162 | ## insensitive, and matched against the path relative to the base directory, 163 | ## with and without a leading /. If multiple patterns match, the first is 164 | ## used. 165 | ## 166 | ## In a pattern: 167 | ## 168 | ## / is the directory separator. 169 | ## 170 | ## * matches all characters, except the directory separator. 171 | ## 172 | ## ** matches all characters, including the directory separator. 173 | ## 174 | ## For example, "*.txt" matches txt files in the base directory, "game/ 175 | ## **.ogg" matches ogg files in the game directory or any of its 176 | ## subdirectories, and "**.psd" matches psd files anywhere in the project. 177 | 178 | ## Classify files as None to exclude them from the built distributions. 179 | 180 | build.classify('**~', None) 181 | build.classify('**.bak', None) 182 | build.classify('**/.**', None) 183 | build.classify('**/#**', None) 184 | build.classify('**/thumbs.db', None) 185 | 186 | ## To archive files, classify them as 'archive'. 187 | 188 | # build.classify('game/**.png', 'archive') 189 | # build.classify('game/**.jpg', 'archive') 190 | 191 | ## Files matching documentation patterns are duplicated in a mac app build, 192 | ## so they appear in both the app and the zip file. 193 | 194 | build.documentation('*.html') 195 | build.documentation('*.txt') 196 | 197 | 198 | ## A Google Play license key is required to download expansion files and perform 199 | ## in-app purchases. It can be found on the "Services & APIs" page of the Google 200 | ## Play developer console. 201 | 202 | # define build.google_play_key = "..." 203 | 204 | 205 | ## The username and project name associated with an itch.io project, separated 206 | ## by a slash. 207 | 208 | # define build.itch_project = "renpytom/test-project" 209 | -------------------------------------------------------------------------------- /game/pydub/effects.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import math 3 | import array 4 | 5 | from game.pydub import pyaudioop 6 | from .utils import ( 7 | db_to_float, 8 | ratio_to_db, 9 | register_pydub_effect, 10 | make_chunks, 11 | get_min_max_value 12 | ) 13 | from .silence import split_on_silence 14 | from .exceptions import TooManyMissingFrames, InvalidDuration 15 | 16 | if sys.version_info >= (3, 0): 17 | xrange = range 18 | 19 | 20 | @register_pydub_effect 21 | def apply_mono_filter_to_each_channel(seg, filter_fn): 22 | n_channels = seg.channels 23 | 24 | channel_segs = seg.split_to_mono() 25 | channel_segs = [filter_fn(channel_seg) for channel_seg in channel_segs] 26 | 27 | out_data = seg.get_array_of_samples() 28 | for channel_i, channel_seg in enumerate(channel_segs): 29 | for sample_i, sample in enumerate(channel_seg.get_array_of_samples()): 30 | index = (sample_i * n_channels) + channel_i 31 | out_data[index] = sample 32 | 33 | return seg._spawn(out_data) 34 | 35 | 36 | @register_pydub_effect 37 | def normalize(seg, headroom=0.1): 38 | """ 39 | headroom is how close to the maximum volume to boost the signal up to (specified in dB) 40 | """ 41 | peak_sample_val = seg.max 42 | 43 | # if the max is 0, this audio segment is silent, and can't be normalized 44 | if peak_sample_val == 0: 45 | return seg 46 | 47 | target_peak = seg.max_possible_amplitude * db_to_float(-headroom) 48 | 49 | needed_boost = ratio_to_db(target_peak / peak_sample_val) 50 | return seg.apply_gain(needed_boost) 51 | 52 | 53 | @register_pydub_effect 54 | def speedup(seg, playback_speed=1.5, chunk_size=150, crossfade=25): 55 | # we will keep audio in 150ms chunks since one waveform at 20Hz is 50ms long 56 | # (20 Hz is the lowest frequency audible to humans) 57 | 58 | # portion of AUDIO TO KEEP. if playback speed is 1.25 we keep 80% (0.8) and 59 | # discard 20% (0.2) 60 | atk = 1.0 / playback_speed 61 | 62 | if playback_speed < 2.0: 63 | # throwing out more than half the audio - keep 50ms chunks 64 | ms_to_remove_per_chunk = int(chunk_size * (1 - atk) / atk) 65 | else: 66 | # throwing out less than half the audio - throw out 50ms chunks 67 | ms_to_remove_per_chunk = int(chunk_size) 68 | chunk_size = int(atk * chunk_size / (1 - atk)) 69 | 70 | # the crossfade cannot be longer than the amount of audio we're removing 71 | crossfade = min(crossfade, ms_to_remove_per_chunk - 1) 72 | 73 | # DEBUG 74 | #print("chunk: {0}, rm: {1}".format(chunk_size, ms_to_remove_per_chunk)) 75 | 76 | chunks = make_chunks(seg, chunk_size + ms_to_remove_per_chunk) 77 | if len(chunks) < 2: 78 | raise Exception("Could not speed up AudioSegment, it was too short {2:0.2f}s for the current settings:\n{0}ms chunks at {1:0.1f}x speedup".format( 79 | chunk_size, playback_speed, seg.duration_seconds)) 80 | 81 | # we'll actually truncate a bit less than we calculated to make up for the 82 | # crossfade between chunks 83 | ms_to_remove_per_chunk -= crossfade 84 | 85 | # we don't want to truncate the last chunk since it is not guaranteed to be 86 | # the full chunk length 87 | last_chunk = chunks[-1] 88 | chunks = [chunk[:-ms_to_remove_per_chunk] for chunk in chunks[:-1]] 89 | 90 | out = chunks[0] 91 | for chunk in chunks[1:]: 92 | out = out.append(chunk, crossfade=crossfade) 93 | 94 | out += last_chunk 95 | return out 96 | 97 | 98 | @register_pydub_effect 99 | def strip_silence(seg, silence_len=1000, silence_thresh=-16, padding=100): 100 | if padding > silence_len: 101 | raise InvalidDuration("padding cannot be longer than silence_len") 102 | 103 | chunks = split_on_silence(seg, silence_len, silence_thresh, padding) 104 | crossfade = padding / 2 105 | 106 | if not len(chunks): 107 | return seg[0:0] 108 | 109 | seg = chunks[0] 110 | for chunk in chunks[1:]: 111 | seg = seg.append(chunk, crossfade=crossfade) 112 | 113 | return seg 114 | 115 | 116 | @register_pydub_effect 117 | def compress_dynamic_range(seg, threshold=-20.0, ratio=4.0, attack=5.0, release=50.0): 118 | """ 119 | Keyword Arguments: 120 | 121 | threshold - default: -20.0 122 | Threshold in dBFS. default of -20.0 means -20dB relative to the 123 | maximum possible volume. 0dBFS is the maximum possible value so 124 | all values for this argument sould be negative. 125 | 126 | ratio - default: 4.0 127 | Compression ratio. Audio louder than the threshold will be 128 | reduced to 1/ratio the volume. A ratio of 4.0 is equivalent to 129 | a setting of 4:1 in a pro-audio compressor like the Waves C1. 130 | 131 | attack - default: 5.0 132 | Attack in milliseconds. How long it should take for the compressor 133 | to kick in once the audio has exceeded the threshold. 134 | 135 | release - default: 50.0 136 | Release in milliseconds. How long it should take for the compressor 137 | to stop compressing after the audio has falled below the threshold. 138 | 139 | 140 | For an overview of Dynamic Range Compression, and more detailed explanation 141 | of the related terminology, see: 142 | 143 | http://en.wikipedia.org/wiki/Dynamic_range_compression 144 | """ 145 | 146 | thresh_rms = seg.max_possible_amplitude * db_to_float(threshold) 147 | 148 | look_frames = int(seg.frame_count(ms=attack)) 149 | def rms_at(frame_i): 150 | return seg.get_sample_slice(frame_i - look_frames, frame_i).rms 151 | def db_over_threshold(rms): 152 | if rms == 0: return 0.0 153 | db = ratio_to_db(rms / thresh_rms) 154 | return max(db, 0) 155 | 156 | output = [] 157 | 158 | # amount to reduce the volume of the audio by (in dB) 159 | attenuation = 0.0 160 | 161 | attack_frames = seg.frame_count(ms=attack) 162 | release_frames = seg.frame_count(ms=release) 163 | for i in xrange(int(seg.frame_count())): 164 | rms_now = rms_at(i) 165 | 166 | # with a ratio of 4.0 this means the volume will exceed the threshold by 167 | # 1/4 the amount (of dB) that it would otherwise 168 | max_attenuation = (1 - (1.0 / ratio)) * db_over_threshold(rms_now) 169 | 170 | attenuation_inc = max_attenuation / attack_frames 171 | attenuation_dec = max_attenuation / release_frames 172 | 173 | if rms_now > thresh_rms and attenuation <= max_attenuation: 174 | attenuation += attenuation_inc 175 | attenuation = min(attenuation, max_attenuation) 176 | else: 177 | attenuation -= attenuation_dec 178 | attenuation = max(attenuation, 0) 179 | 180 | frame = seg.get_frame(i) 181 | if attenuation != 0.0: 182 | frame = pyaudioop.mul(frame, 183 | seg.sample_width, 184 | db_to_float(-attenuation)) 185 | 186 | output.append(frame) 187 | 188 | return seg._spawn(data=b''.join(output)) 189 | 190 | 191 | # Invert the phase of the signal. 192 | 193 | @register_pydub_effect 194 | 195 | def invert_phase(seg, channels=(1, 1)): 196 | """ 197 | channels- specifies which channel (left or right) to reverse the phase of. 198 | Note that mono AudioSegments will become stereo. 199 | """ 200 | if channels == (1, 1): 201 | inverted = pyaudioop.mul(seg._data, seg.sample_width, -1.0) 202 | return seg._spawn(data=inverted) 203 | 204 | else: 205 | if seg.channels == 2: 206 | left, right = seg.split_to_mono() 207 | else: 208 | raise Exception("Can't implicitly convert an AudioSegment with " + str(seg.channels) + " channels to stereo.") 209 | 210 | if channels == (1, 0): 211 | left = left.invert_phase() 212 | else: 213 | right = right.invert_phase() 214 | 215 | return seg.from_mono_audiosegments(left, right) 216 | 217 | 218 | 219 | # High and low pass filters based on implementation found on Stack Overflow: 220 | # http://stackoverflow.com/questions/13882038/implementing-simple-high-and-low-pass-filters-in-c 221 | 222 | @register_pydub_effect 223 | def low_pass_filter(seg, cutoff): 224 | """ 225 | cutoff - Frequency (in Hz) where higher frequency signal will begin to 226 | be reduced by 6dB per octave (doubling in frequency) above this point 227 | """ 228 | RC = 1.0 / (cutoff * 2 * math.pi) 229 | dt = 1.0 / seg.frame_rate 230 | 231 | alpha = dt / (RC + dt) 232 | 233 | original = seg.get_array_of_samples() 234 | filteredArray = array.array(seg.array_type, original) 235 | 236 | frame_count = int(seg.frame_count()) 237 | 238 | last_val = [0] * seg.channels 239 | for i in range(seg.channels): 240 | last_val[i] = filteredArray[i] = original[i] 241 | 242 | for i in range(1, frame_count): 243 | for j in range(seg.channels): 244 | offset = (i * seg.channels) + j 245 | last_val[j] = last_val[j] + (alpha * (original[offset] - last_val[j])) 246 | filteredArray[offset] = int(last_val[j]) 247 | 248 | return seg._spawn(data=filteredArray) 249 | 250 | 251 | @register_pydub_effect 252 | def high_pass_filter(seg, cutoff): 253 | """ 254 | cutoff - Frequency (in Hz) where lower frequency signal will begin to 255 | be reduced by 6dB per octave (doubling in frequency) below this point 256 | """ 257 | RC = 1.0 / (cutoff * 2 * math.pi) 258 | dt = 1.0 / seg.frame_rate 259 | 260 | alpha = RC / (RC + dt) 261 | 262 | minval, maxval = get_min_max_value(seg.sample_width * 8) 263 | 264 | original = seg.get_array_of_samples() 265 | filteredArray = array.array(seg.array_type, original) 266 | 267 | frame_count = int(seg.frame_count()) 268 | 269 | last_val = [0] * seg.channels 270 | for i in range(seg.channels): 271 | last_val[i] = filteredArray[i] = original[i] 272 | 273 | for i in range(1, frame_count): 274 | for j in range(seg.channels): 275 | offset = (i * seg.channels) + j 276 | offset_minus_1 = ((i-1) * seg.channels) + j 277 | 278 | last_val[j] = alpha * (last_val[j] + original[offset] - original[offset_minus_1]) 279 | filteredArray[offset] = int(min(max(last_val[j], minval), maxval)) 280 | 281 | return seg._spawn(data=filteredArray) 282 | 283 | 284 | @register_pydub_effect 285 | def pan(seg, pan_amount): 286 | """ 287 | pan_amount should be between -1.0 (100% left) and +1.0 (100% right) 288 | 289 | When pan_amount == 0.0 the left/right balance is not changed. 290 | 291 | Panning does not alter the *perceived* loundness, but since loudness 292 | is decreasing on one side, the other side needs to get louder to 293 | compensate. When panned hard left, the left channel will be 3dB louder. 294 | """ 295 | if not -1.0 <= pan_amount <= 1.0: 296 | raise ValueError("pan_amount should be between -1.0 (100% left) and +1.0 (100% right)") 297 | 298 | max_boost_db = ratio_to_db(2.0) 299 | boost_db = abs(pan_amount) * max_boost_db 300 | 301 | boost_factor = db_to_float(boost_db) 302 | reduce_factor = db_to_float(max_boost_db) - boost_factor 303 | 304 | reduce_db = ratio_to_db(reduce_factor) 305 | 306 | # Cut boost in half (max boost== 3dB) - in reality 2 speakers 307 | # do not sum to a full 6 dB. 308 | boost_db = boost_db / 2.0 309 | 310 | if pan_amount < 0: 311 | return seg.apply_gain_stereo(boost_db, reduce_db) 312 | else: 313 | return seg.apply_gain_stereo(reduce_db, boost_db) 314 | 315 | 316 | @register_pydub_effect 317 | def apply_gain_stereo(seg, left_gain=0.0, right_gain=0.0): 318 | """ 319 | left_gain - amount of gain to apply to the left channel (in dB) 320 | right_gain - amount of gain to apply to the right channel (in dB) 321 | 322 | note: mono audio segments will be converted to stereo 323 | """ 324 | if seg.channels == 1: 325 | left = right = seg 326 | elif seg.channels == 2: 327 | left, right = seg.split_to_mono() 328 | 329 | l_mult_factor = db_to_float(left_gain) 330 | r_mult_factor = db_to_float(right_gain) 331 | 332 | left_data = pyaudioop.mul(left._data, left.sample_width, l_mult_factor) 333 | left_data = pyaudioop.tostereo(left_data, left.sample_width, 1, 0) 334 | 335 | right_data = pyaudioop.mul(right._data, right.sample_width, r_mult_factor) 336 | right_data = pyaudioop.tostereo(right_data, right.sample_width, 0, 1) 337 | 338 | output = pyaudioop.add(left_data, right_data, seg.sample_width) 339 | 340 | return seg._spawn(data=output, 341 | overrides={'channels': 2, 342 | 'frame_width': 2 * seg.sample_width}) 343 | -------------------------------------------------------------------------------- /game/pydub/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | import json 4 | import os 5 | import re 6 | import sys 7 | from subprocess import Popen, PIPE 8 | from math import log, ceil 9 | from tempfile import TemporaryFile 10 | from warnings import warn 11 | from functools import wraps 12 | 13 | if sys.version_info >= (3, 0): 14 | basestring = str 15 | 16 | FRAME_WIDTHS = { 17 | 8: 1, 18 | 16: 2, 19 | 32: 4, 20 | } 21 | ARRAY_TYPES = { 22 | 8: "b", 23 | 16: "h", 24 | 32: "i", 25 | } 26 | ARRAY_RANGES = { 27 | 8: (-0x80, 0x7f), 28 | 16: (-0x8000, 0x7fff), 29 | 32: (-0x80000000, 0x7fffffff), 30 | } 31 | 32 | 33 | def get_frame_width(bit_depth): 34 | return FRAME_WIDTHS[bit_depth] 35 | 36 | 37 | def get_array_type(bit_depth, signed=True): 38 | t = ARRAY_TYPES[bit_depth] 39 | if not signed: 40 | t = t.upper() 41 | return t 42 | 43 | 44 | def get_min_max_value(bit_depth): 45 | return ARRAY_RANGES[bit_depth] 46 | 47 | 48 | def _fd_or_path_or_tempfile(fd, mode='w+b', tempfile=True): 49 | close_fd = False 50 | if fd is None and tempfile: 51 | fd = TemporaryFile(mode=mode) 52 | close_fd = True 53 | 54 | if isinstance(fd, basestring): 55 | fd = open(fd, mode=mode) 56 | close_fd = True 57 | 58 | try: 59 | if isinstance(fd, os.PathLike): 60 | fd = open(fd, mode=mode) 61 | close_fd = True 62 | except AttributeError: 63 | # module os has no attribute PathLike, so we're on python < 3.6. 64 | # The protocol we're trying to support doesn't exist, so just pass. 65 | pass 66 | 67 | return fd, close_fd 68 | 69 | 70 | def db_to_float(db, using_amplitude=True): 71 | """ 72 | Converts the input db to a float, which represents the equivalent 73 | ratio in power. 74 | """ 75 | db = float(db) 76 | if using_amplitude: 77 | return 10 ** (db / 20) 78 | else: # using power 79 | return 10 ** (db / 10) 80 | 81 | 82 | def ratio_to_db(ratio, val2=None, using_amplitude=True): 83 | """ 84 | Converts the input float to db, which represents the equivalent 85 | to the ratio in power represented by the multiplier passed in. 86 | """ 87 | ratio = float(ratio) 88 | 89 | # accept 2 values and use the ratio of val1 to val2 90 | if val2 is not None: 91 | ratio = ratio / val2 92 | 93 | # special case for multiply-by-zero (convert to silence) 94 | if ratio == 0: 95 | return -float('inf') 96 | 97 | if using_amplitude: 98 | return 20 * log(ratio, 10) 99 | else: # using power 100 | return 10 * log(ratio, 10) 101 | 102 | 103 | def register_pydub_effect(fn, name=None): 104 | """ 105 | decorator for adding pydub effects to the AudioSegment objects. 106 | example use: 107 | @register_pydub_effect 108 | def normalize(audio_segment): 109 | ... 110 | or you can specify a name: 111 | @register_pydub_effect("normalize") 112 | def normalize_audio_segment(audio_segment): 113 | ... 114 | """ 115 | if isinstance(fn, basestring): 116 | name = fn 117 | return lambda fn: register_pydub_effect(fn, name) 118 | 119 | if name is None: 120 | name = fn.__name__ 121 | 122 | from .audio_segment import AudioSegment 123 | setattr(AudioSegment, name, fn) 124 | return fn 125 | 126 | 127 | def make_chunks(audio_segment, chunk_length): 128 | """ 129 | Breaks an AudioSegment into chunks that are milliseconds 130 | long. 131 | if chunk_length is 50 then you'll get a list of 50 millisecond long audio 132 | segments back (except the last one, which can be shorter) 133 | """ 134 | number_of_chunks = ceil(len(audio_segment) / float(chunk_length)) 135 | return [audio_segment[i * chunk_length:(i + 1) * chunk_length] 136 | for i in range(int(number_of_chunks))] 137 | 138 | 139 | def which(program): 140 | """ 141 | Mimics behavior of UNIX which command. 142 | """ 143 | # Add .exe program extension for windows support 144 | if os.name == "nt" and not program.endswith(".exe"): 145 | program += ".exe" 146 | 147 | envdir_list = [os.curdir] + os.environ["PATH"].split(os.pathsep) 148 | 149 | for envdir in envdir_list: 150 | program_path = os.path.join(envdir, program) 151 | if os.path.isfile(program_path) and os.access(program_path, os.X_OK): 152 | return program_path 153 | 154 | 155 | def get_encoder_name(): 156 | """ 157 | Return enconder default application for system, either avconv or ffmpeg 158 | """ 159 | if which("avconv"): 160 | return "avconv" 161 | elif which("ffmpeg"): 162 | return "ffmpeg" 163 | else: 164 | # should raise exception 165 | warn("Couldn't find ffmpeg or avconv - defaulting to ffmpeg, but may not work", RuntimeWarning) 166 | return "ffmpeg" 167 | 168 | 169 | def get_player_name(): 170 | """ 171 | Return enconder default application for system, either avconv or ffmpeg 172 | """ 173 | if which("avplay"): 174 | return "avplay" 175 | elif which("ffplay"): 176 | return "ffplay" 177 | else: 178 | # should raise exception 179 | warn("Couldn't find ffplay or avplay - defaulting to ffplay, but may not work", RuntimeWarning) 180 | return "ffplay" 181 | 182 | 183 | def get_prober_name(): 184 | """ 185 | Return probe application, either avconv or ffmpeg 186 | """ 187 | if which("avprobe"): 188 | return "avprobe" 189 | elif which("ffprobe"): 190 | return "ffprobe" 191 | else: 192 | # should raise exception 193 | warn("Couldn't find ffprobe or avprobe - defaulting to ffprobe, but may not work", RuntimeWarning) 194 | return "ffprobe" 195 | 196 | 197 | def fsdecode(filename): 198 | """Wrapper for os.fsdecode which was introduced in python 3.2 .""" 199 | 200 | if sys.version_info >= (3, 2): 201 | PathLikeTypes = (basestring, bytes) 202 | if sys.version_info >= (3, 6): 203 | PathLikeTypes += (os.PathLike,) 204 | if isinstance(filename, PathLikeTypes): 205 | return os.fsdecode(filename) 206 | else: 207 | if isinstance(filename, bytes): 208 | return filename.decode(sys.getfilesystemencoding()) 209 | if isinstance(filename, basestring): 210 | return filename 211 | 212 | raise TypeError("type {0} not accepted by fsdecode".format(type(filename))) 213 | 214 | 215 | def get_extra_info(stderr): 216 | """ 217 | avprobe sometimes gives more information on stderr than 218 | on the json output. The information has to be extracted 219 | from stderr of the format of: 220 | ' Stream #0:0: Audio: flac, 88200 Hz, stereo, s32 (24 bit)' 221 | or (macOS version): 222 | ' Stream #0:0: Audio: vorbis' 223 | ' 44100 Hz, stereo, fltp, 320 kb/s' 224 | 225 | :type stderr: str 226 | :rtype: list of dict 227 | """ 228 | extra_info = {} 229 | 230 | re_stream = r'(?P +)Stream #0[:\.](?P([0-9]+))(?P.+)\n?(?! *Stream)((?P +)(?P.+))?' 231 | for i in re.finditer(re_stream, stderr): 232 | if i.group('space_end') is not None and len(i.group('space_start')) <= len( 233 | i.group('space_end')): 234 | content_line = ','.join([i.group('content_0'), i.group('content_1')]) 235 | else: 236 | content_line = i.group('content_0') 237 | tokens = [x.strip() for x in re.split('[:,]', content_line) if x] 238 | extra_info[int(i.group('stream_id'))] = tokens 239 | return extra_info 240 | 241 | 242 | def mediainfo_json(filepath, read_ahead_limit=-1): 243 | """Return json dictionary with media info(codec, duration, size, bitrate...) from filepath 244 | """ 245 | prober = get_prober_name() 246 | command_args = [ 247 | "-v", "info", 248 | "-show_format", 249 | "-show_streams", 250 | ] 251 | try: 252 | command_args += [fsdecode(filepath)] 253 | stdin_parameter = None 254 | stdin_data = None 255 | except TypeError: 256 | if prober == 'ffprobe': 257 | command_args += ["-read_ahead_limit", str(read_ahead_limit), 258 | "cache:pipe:0"] 259 | else: 260 | command_args += ["-"] 261 | stdin_parameter = PIPE 262 | file, close_file = _fd_or_path_or_tempfile(filepath, 'rb', tempfile=False) 263 | file.seek(0) 264 | stdin_data = file.read() 265 | if close_file: 266 | file.close() 267 | 268 | command = [prober, '-of', 'json'] + command_args 269 | res = Popen(command, stdin=stdin_parameter, stdout=PIPE, stderr=PIPE) 270 | output, stderr = res.communicate(input=stdin_data) 271 | output = output.decode("utf-8", 'ignore') 272 | stderr = stderr.decode("utf-8", 'ignore') 273 | 274 | info = json.loads(output) 275 | 276 | if not info: 277 | # If ffprobe didn't give any information, just return it 278 | # (for example, because the file doesn't exist) 279 | return info 280 | 281 | extra_info = get_extra_info(stderr) 282 | 283 | audio_streams = [x for x in info['streams'] if x['codec_type'] == 'audio'] 284 | if len(audio_streams) == 0: 285 | return info 286 | 287 | # We just operate on the first audio stream in case there are more 288 | stream = audio_streams[0] 289 | 290 | def set_property(stream, prop, value): 291 | if prop not in stream or stream[prop] == 0: 292 | stream[prop] = value 293 | 294 | for token in extra_info[stream['index']]: 295 | m = re.match('([su]([0-9]{1,2})p?) \(([0-9]{1,2}) bit\)$', token) 296 | m2 = re.match('([su]([0-9]{1,2})p?)( \(default\))?$', token) 297 | if m: 298 | set_property(stream, 'sample_fmt', m.group(1)) 299 | set_property(stream, 'bits_per_sample', int(m.group(2))) 300 | set_property(stream, 'bits_per_raw_sample', int(m.group(3))) 301 | elif m2: 302 | set_property(stream, 'sample_fmt', m2.group(1)) 303 | set_property(stream, 'bits_per_sample', int(m2.group(2))) 304 | set_property(stream, 'bits_per_raw_sample', int(m2.group(2))) 305 | elif re.match('(flt)p?( \(default\))?$', token): 306 | set_property(stream, 'sample_fmt', token) 307 | set_property(stream, 'bits_per_sample', 32) 308 | set_property(stream, 'bits_per_raw_sample', 32) 309 | elif re.match('(dbl)p?( \(default\))?$', token): 310 | set_property(stream, 'sample_fmt', token) 311 | set_property(stream, 'bits_per_sample', 64) 312 | set_property(stream, 'bits_per_raw_sample', 64) 313 | return info 314 | 315 | 316 | def mediainfo(filepath): 317 | """Return dictionary with media info(codec, duration, size, bitrate...) from filepath 318 | """ 319 | 320 | prober = get_prober_name() 321 | command_args = [ 322 | "-v", "quiet", 323 | "-show_format", 324 | "-show_streams", 325 | filepath 326 | ] 327 | 328 | command = [prober, '-of', 'old'] + command_args 329 | res = Popen(command, stdout=PIPE) 330 | output = res.communicate()[0].decode("utf-8") 331 | 332 | if res.returncode != 0: 333 | command = [prober] + command_args 334 | output = Popen(command, stdout=PIPE).communicate()[0].decode("utf-8") 335 | 336 | rgx = re.compile(r"(?:(?P.*?):)?(?P.*?)\=(?P.*?)$") 337 | info = {} 338 | 339 | if sys.platform == 'win32': 340 | output = output.replace("\r", "") 341 | 342 | for line in output.split("\n"): 343 | # print(line) 344 | mobj = rgx.match(line) 345 | 346 | if mobj: 347 | # print(mobj.groups()) 348 | inner_dict, key, value = mobj.groups() 349 | 350 | if inner_dict: 351 | try: 352 | info[inner_dict] 353 | except KeyError: 354 | info[inner_dict] = {} 355 | info[inner_dict][key] = value 356 | else: 357 | info[key] = value 358 | 359 | return info 360 | 361 | 362 | def cache_codecs(function): 363 | cache = {} 364 | 365 | @wraps(function) 366 | def wrapper(): 367 | try: 368 | return cache[0] 369 | except: 370 | cache[0] = function() 371 | return cache[0] 372 | 373 | return wrapper 374 | 375 | 376 | @cache_codecs 377 | def get_supported_codecs(): 378 | encoder = get_encoder_name() 379 | command = [encoder, "-codecs"] 380 | res = Popen(command, stdout=PIPE, stderr=PIPE) 381 | output = res.communicate()[0].decode("utf-8") 382 | if res.returncode != 0: 383 | return [] 384 | 385 | if sys.platform == 'win32': 386 | output = output.replace("\r", "") 387 | 388 | 389 | rgx = re.compile(r"^([D.][E.][AVS.][I.][L.][S.]) (\w*) +(.*)") 390 | decoders = set() 391 | encoders = set() 392 | for line in output.split('\n'): 393 | match = rgx.match(line.strip()) 394 | if not match: 395 | continue 396 | flags, codec, name = match.groups() 397 | 398 | if flags[0] == 'D': 399 | decoders.add(codec) 400 | 401 | if flags[1] == 'E': 402 | encoders.add(codec) 403 | 404 | return (decoders, encoders) 405 | 406 | 407 | def get_supported_decoders(): 408 | return get_supported_codecs()[0] 409 | 410 | 411 | def get_supported_encoders(): 412 | return get_supported_codecs()[1] 413 | 414 | def stereo_to_ms(audio_segment): 415 | ''' 416 | Left-Right -> Mid-Side 417 | ''' 418 | channel = audio_segment.split_to_mono() 419 | channel = [channel[0].overlay(channel[1]), channel[0].overlay(channel[1].invert_phase())] 420 | return AudioSegment.from_mono_audiosegments(channel[0], channel[1]) 421 | 422 | def ms_to_stereo(audio_segment): 423 | ''' 424 | Mid-Side -> Left-Right 425 | ''' 426 | channel = audio_segment.split_to_mono() 427 | channel = [channel[0].overlay(channel[1]) - 3, channel[0].overlay(channel[1].invert_phase()) - 3] 428 | return AudioSegment.from_mono_audiosegments(channel[0], channel[1]) 429 | 430 | -------------------------------------------------------------------------------- /game/pydub/pyaudioop.py: -------------------------------------------------------------------------------- 1 | try: 2 | from __builtin__ import max as builtin_max 3 | from __builtin__ import min as builtin_min 4 | except ImportError: 5 | from builtins import max as builtin_max 6 | from builtins import min as builtin_min 7 | import math 8 | import struct 9 | try: 10 | from fractions import gcd 11 | except ImportError: # Python 3.9+ 12 | from math import gcd 13 | from ctypes import create_string_buffer 14 | 15 | 16 | class error(Exception): 17 | pass 18 | 19 | 20 | def _check_size(size): 21 | if size != 1 and size != 2 and size != 4: 22 | raise error("Size should be 1, 2 or 4") 23 | 24 | 25 | def _check_params(length, size): 26 | _check_size(size) 27 | if length % size != 0: 28 | raise error("not a whole number of frames") 29 | 30 | 31 | def _sample_count(cp, size): 32 | return len(cp) / size 33 | 34 | 35 | def _get_samples(cp, size, signed=True): 36 | for i in range(int(_sample_count(cp, size))): 37 | yield _get_sample(cp, size, i, signed) 38 | 39 | 40 | def _struct_format(size, signed): 41 | if size == 1: 42 | return "b" if signed else "B" 43 | elif size == 2: 44 | return "h" if signed else "H" 45 | elif size == 4: 46 | return "i" if signed else "I" 47 | 48 | 49 | def _get_sample(cp, size, i, signed=True): 50 | fmt = _struct_format(size, signed) 51 | start = i * size 52 | end = start + size 53 | return struct.unpack_from(fmt, memoryview(cp)[start:end])[0] 54 | 55 | 56 | def _put_sample(cp, size, i, val, signed=True): 57 | fmt = _struct_format(size, signed) 58 | struct.pack_into(fmt, cp, i * size, val) 59 | 60 | 61 | def _get_maxval(size, signed=True): 62 | if signed and size == 1: 63 | return 0x7f 64 | elif size == 1: 65 | return 0xff 66 | elif signed and size == 2: 67 | return 0x7fff 68 | elif size == 2: 69 | return 0xffff 70 | elif signed and size == 4: 71 | return 0x7fffffff 72 | elif size == 4: 73 | return 0xffffffff 74 | 75 | 76 | def _get_minval(size, signed=True): 77 | if not signed: 78 | return 0 79 | elif size == 1: 80 | return -0x80 81 | elif size == 2: 82 | return -0x8000 83 | elif size == 4: 84 | return -0x80000000 85 | 86 | 87 | def _get_clipfn(size, signed=True): 88 | maxval = _get_maxval(size, signed) 89 | minval = _get_minval(size, signed) 90 | return lambda val: builtin_max(min(val, maxval), minval) 91 | 92 | 93 | def _overflow(val, size, signed=True): 94 | minval = _get_minval(size, signed) 95 | maxval = _get_maxval(size, signed) 96 | if minval <= val <= maxval: 97 | return val 98 | 99 | bits = size * 8 100 | if signed: 101 | offset = 2**(bits-1) 102 | return ((val + offset) % (2**bits)) - offset 103 | else: 104 | return val % (2**bits) 105 | 106 | 107 | def getsample(cp, size, i): 108 | _check_params(len(cp), size) 109 | if not (0 <= i < len(cp) / size): 110 | raise error("Index out of range") 111 | return _get_sample(cp, size, i) 112 | 113 | 114 | def max(cp, size): 115 | _check_params(len(cp), size) 116 | 117 | if len(cp) == 0: 118 | return 0 119 | 120 | return builtin_max(abs(sample) for sample in _get_samples(cp, size)) 121 | 122 | 123 | def minmax(cp, size): 124 | _check_params(len(cp), size) 125 | 126 | max_sample, min_sample = 0, 0 127 | for sample in _get_samples(cp, size): 128 | max_sample = builtin_max(sample, max_sample) 129 | min_sample = builtin_min(sample, min_sample) 130 | 131 | return min_sample, max_sample 132 | 133 | 134 | def avg(cp, size): 135 | _check_params(len(cp), size) 136 | sample_count = _sample_count(cp, size) 137 | if sample_count == 0: 138 | return 0 139 | return sum(_get_samples(cp, size)) / sample_count 140 | 141 | 142 | def rms(cp, size): 143 | _check_params(len(cp), size) 144 | 145 | sample_count = _sample_count(cp, size) 146 | if sample_count == 0: 147 | return 0 148 | 149 | sum_squares = sum(sample**2 for sample in _get_samples(cp, size)) 150 | return int(math.sqrt(sum_squares / sample_count)) 151 | 152 | 153 | def _sum2(cp1, cp2, length): 154 | size = 2 155 | total = 0 156 | for i in range(length): 157 | total += getsample(cp1, size, i) * getsample(cp2, size, i) 158 | return total 159 | 160 | 161 | def findfit(cp1, cp2): 162 | size = 2 163 | 164 | if len(cp1) % 2 != 0 or len(cp2) % 2 != 0: 165 | raise error("Strings should be even-sized") 166 | 167 | if len(cp1) < len(cp2): 168 | raise error("First sample should be longer") 169 | 170 | len1 = _sample_count(cp1, size) 171 | len2 = _sample_count(cp2, size) 172 | 173 | sum_ri_2 = _sum2(cp2, cp2, len2) 174 | sum_aij_2 = _sum2(cp1, cp1, len2) 175 | sum_aij_ri = _sum2(cp1, cp2, len2) 176 | 177 | result = (sum_ri_2 * sum_aij_2 - sum_aij_ri * sum_aij_ri) / sum_aij_2 178 | 179 | best_result = result 180 | best_i = 0 181 | 182 | for i in range(1, len1 - len2 + 1): 183 | aj_m1 = _get_sample(cp1, size, i - 1) 184 | aj_lm1 = _get_sample(cp1, size, i + len2 - 1) 185 | 186 | sum_aij_2 += aj_lm1**2 - aj_m1**2 187 | sum_aij_ri = _sum2(memoryview(cp1)[i*size:], cp2, len2) 188 | 189 | result = (sum_ri_2 * sum_aij_2 - sum_aij_ri * sum_aij_ri) / sum_aij_2 190 | 191 | if result < best_result: 192 | best_result = result 193 | best_i = i 194 | 195 | factor = _sum2(memoryview(cp1)[best_i*size:], cp2, len2) / sum_ri_2 196 | 197 | return best_i, factor 198 | 199 | 200 | def findfactor(cp1, cp2): 201 | size = 2 202 | 203 | if len(cp1) % 2 != 0: 204 | raise error("Strings should be even-sized") 205 | 206 | if len(cp1) != len(cp2): 207 | raise error("Samples should be same size") 208 | 209 | sample_count = _sample_count(cp1, size) 210 | 211 | sum_ri_2 = _sum2(cp2, cp2, sample_count) 212 | sum_aij_ri = _sum2(cp1, cp2, sample_count) 213 | 214 | return sum_aij_ri / sum_ri_2 215 | 216 | 217 | def findmax(cp, len2): 218 | size = 2 219 | sample_count = _sample_count(cp, size) 220 | 221 | if len(cp) % 2 != 0: 222 | raise error("Strings should be even-sized") 223 | 224 | if len2 < 0 or sample_count < len2: 225 | raise error("Input sample should be longer") 226 | 227 | if sample_count == 0: 228 | return 0 229 | 230 | result = _sum2(cp, cp, len2) 231 | best_result = result 232 | best_i = 0 233 | 234 | for i in range(1, sample_count - len2 + 1): 235 | sample_leaving_window = getsample(cp, size, i - 1) 236 | sample_entering_window = getsample(cp, size, i + len2 - 1) 237 | 238 | result -= sample_leaving_window**2 239 | result += sample_entering_window**2 240 | 241 | if result > best_result: 242 | best_result = result 243 | best_i = i 244 | 245 | return best_i 246 | 247 | 248 | def avgpp(cp, size): 249 | _check_params(len(cp), size) 250 | sample_count = _sample_count(cp, size) 251 | 252 | prevextremevalid = False 253 | prevextreme = None 254 | avg = 0 255 | nextreme = 0 256 | 257 | prevval = getsample(cp, size, 0) 258 | val = getsample(cp, size, 1) 259 | 260 | prevdiff = val - prevval 261 | 262 | for i in range(1, sample_count): 263 | val = getsample(cp, size, i) 264 | diff = val - prevval 265 | 266 | if diff * prevdiff < 0: 267 | if prevextremevalid: 268 | avg += abs(prevval - prevextreme) 269 | nextreme += 1 270 | 271 | prevextremevalid = True 272 | prevextreme = prevval 273 | 274 | prevval = val 275 | if diff != 0: 276 | prevdiff = diff 277 | 278 | if nextreme == 0: 279 | return 0 280 | 281 | return avg / nextreme 282 | 283 | 284 | def maxpp(cp, size): 285 | _check_params(len(cp), size) 286 | sample_count = _sample_count(cp, size) 287 | 288 | prevextremevalid = False 289 | prevextreme = None 290 | max = 0 291 | 292 | prevval = getsample(cp, size, 0) 293 | val = getsample(cp, size, 1) 294 | 295 | prevdiff = val - prevval 296 | 297 | for i in range(1, sample_count): 298 | val = getsample(cp, size, i) 299 | diff = val - prevval 300 | 301 | if diff * prevdiff < 0: 302 | if prevextremevalid: 303 | extremediff = abs(prevval - prevextreme) 304 | if extremediff > max: 305 | max = extremediff 306 | prevextremevalid = True 307 | prevextreme = prevval 308 | 309 | prevval = val 310 | if diff != 0: 311 | prevdiff = diff 312 | 313 | return max 314 | 315 | 316 | def cross(cp, size): 317 | _check_params(len(cp), size) 318 | 319 | crossings = 0 320 | last_sample = 0 321 | for sample in _get_samples(cp, size): 322 | if sample <= 0 < last_sample or sample >= 0 > last_sample: 323 | crossings += 1 324 | last_sample = sample 325 | 326 | return crossings 327 | 328 | 329 | def mul(cp, size, factor): 330 | _check_params(len(cp), size) 331 | clip = _get_clipfn(size) 332 | 333 | result = create_string_buffer(len(cp)) 334 | 335 | for i, sample in enumerate(_get_samples(cp, size)): 336 | sample = clip(int(sample * factor)) 337 | _put_sample(result, size, i, sample) 338 | 339 | return result.raw 340 | 341 | 342 | def tomono(cp, size, fac1, fac2): 343 | _check_params(len(cp), size) 344 | clip = _get_clipfn(size) 345 | 346 | sample_count = _sample_count(cp, size) 347 | 348 | result = create_string_buffer(len(cp) / 2) 349 | 350 | for i in range(0, sample_count, 2): 351 | l_sample = getsample(cp, size, i) 352 | r_sample = getsample(cp, size, i + 1) 353 | 354 | sample = (l_sample * fac1) + (r_sample * fac2) 355 | sample = clip(sample) 356 | 357 | _put_sample(result, size, i / 2, sample) 358 | 359 | return result.raw 360 | 361 | 362 | def tostereo(cp, size, fac1, fac2): 363 | _check_params(len(cp), size) 364 | 365 | sample_count = _sample_count(cp, size) 366 | 367 | result = create_string_buffer(len(cp) * 2) 368 | clip = _get_clipfn(size) 369 | 370 | for i in range(sample_count): 371 | sample = _get_sample(cp, size, i) 372 | 373 | l_sample = clip(sample * fac1) 374 | r_sample = clip(sample * fac2) 375 | 376 | _put_sample(result, size, i * 2, l_sample) 377 | _put_sample(result, size, i * 2 + 1, r_sample) 378 | 379 | return result.raw 380 | 381 | 382 | def add(cp1, cp2, size): 383 | _check_params(len(cp1), size) 384 | 385 | if len(cp1) != len(cp2): 386 | raise error("Lengths should be the same") 387 | 388 | clip = _get_clipfn(size) 389 | sample_count = _sample_count(cp1, size) 390 | result = create_string_buffer(len(cp1)) 391 | 392 | for i in range(int(sample_count)): 393 | sample1 = getsample(cp1, size, i) 394 | sample2 = getsample(cp2, size, i) 395 | 396 | sample = clip(sample1 + sample2) 397 | 398 | _put_sample(result, size, i, sample) 399 | 400 | return result.raw 401 | 402 | 403 | def bias(cp, size, bias): 404 | _check_params(len(cp), size) 405 | 406 | result = create_string_buffer(len(cp)) 407 | 408 | for i, sample in enumerate(_get_samples(cp, size)): 409 | sample = _overflow(sample + bias, size) 410 | _put_sample(result, size, i, sample) 411 | 412 | return result.raw 413 | 414 | 415 | def reverse(cp, size): 416 | _check_params(len(cp), size) 417 | sample_count = _sample_count(cp, size) 418 | 419 | result = create_string_buffer(len(cp)) 420 | for i, sample in enumerate(_get_samples(cp, size)): 421 | _put_sample(result, size, sample_count - i - 1, sample) 422 | 423 | return result.raw 424 | 425 | 426 | def lin2lin(cp, size, size2): 427 | _check_params(len(cp), size) 428 | _check_size(size2) 429 | 430 | if size == size2: 431 | return cp 432 | 433 | new_len = (len(cp) / size) * size2 434 | result = create_string_buffer(int(new_len)) 435 | 436 | for i in range(int(_sample_count(cp, size))): 437 | sample = _get_sample(cp, size, i) 438 | if size < size2: 439 | sample = sample << (4 * size2 / size) 440 | elif size > size2: 441 | sample = sample >> (4 * size / size2) 442 | 443 | sample = _overflow(sample, size2) 444 | 445 | _put_sample(result, size2, i, sample) 446 | 447 | return result.raw 448 | 449 | 450 | def ratecv(cp, size, nchannels, inrate, outrate, state, weightA=1, weightB=0): 451 | _check_params(len(cp), size) 452 | if nchannels < 1: 453 | raise error("# of channels should be >= 1") 454 | 455 | bytes_per_frame = size * nchannels 456 | frame_count = len(cp) / bytes_per_frame 457 | 458 | if bytes_per_frame / nchannels != size: 459 | raise OverflowError("width * nchannels too big for a C int") 460 | 461 | if weightA < 1 or weightB < 0: 462 | raise error("weightA should be >= 1, weightB should be >= 0") 463 | 464 | if len(cp) % bytes_per_frame != 0: 465 | raise error("not a whole number of frames") 466 | 467 | if inrate <= 0 or outrate <= 0: 468 | raise error("sampling rate not > 0") 469 | 470 | d = gcd(inrate, outrate) 471 | inrate /= d 472 | outrate /= d 473 | 474 | prev_i = [0] * nchannels 475 | cur_i = [0] * nchannels 476 | 477 | if state is None: 478 | d = -outrate 479 | else: 480 | d, samps = state 481 | 482 | if len(samps) != nchannels: 483 | raise error("illegal state argument") 484 | 485 | prev_i, cur_i = zip(*samps) 486 | prev_i, cur_i = list(prev_i), list(cur_i) 487 | 488 | q = frame_count / inrate 489 | ceiling = (q + 1) * outrate 490 | nbytes = ceiling * bytes_per_frame 491 | 492 | result = create_string_buffer(int(nbytes)) 493 | 494 | samples = _get_samples(cp, size) 495 | out_i = 0 496 | while True: 497 | while d < 0: 498 | if frame_count == 0: 499 | samps = zip(prev_i, cur_i) 500 | retval = result.raw 501 | 502 | # slice off extra bytes 503 | trim_index = (out_i * bytes_per_frame) - len(retval) 504 | retval = memoryview(retval)[:trim_index] 505 | 506 | return (retval, (d, tuple(samps))) 507 | 508 | for chan in range(nchannels): 509 | prev_i[chan] = cur_i[chan] 510 | cur_i[chan] = next(samples) 511 | 512 | cur_i[chan] = ( 513 | (weightA * cur_i[chan] + weightB * prev_i[chan]) 514 | / (weightA + weightB) 515 | ) 516 | 517 | frame_count -= 1 518 | d += outrate 519 | 520 | while d >= 0: 521 | for chan in range(nchannels): 522 | cur_o = ( 523 | (prev_i[chan] * d + cur_i[chan] * (outrate - d)) 524 | / outrate 525 | ) 526 | _put_sample(result, size, out_i, int(_overflow(cur_o, size))) 527 | out_i += 1 528 | d -= inrate 529 | 530 | 531 | def lin2ulaw(cp, size): 532 | raise NotImplementedError() 533 | 534 | 535 | def ulaw2lin(cp, size): 536 | raise NotImplementedError() 537 | 538 | 539 | def lin2alaw(cp, size): 540 | raise NotImplementedError() 541 | 542 | 543 | def alaw2lin(cp, size): 544 | raise NotImplementedError() 545 | 546 | 547 | def lin2adpcm(cp, size, state): 548 | raise NotImplementedError() 549 | 550 | 551 | def adpcm2lin(cp, size, state): 552 | raise NotImplementedError() 553 | -------------------------------------------------------------------------------- /game/saves/navigation.json: -------------------------------------------------------------------------------- 1 | {"name": "Animalese", "version": "1.0", "location": {"callable": {"change_playback_speed": ["game/speak.rpy", 100], "build_sentence": ["game/speak.rpy", 33], "replace_numbers": ["game/speak.rpy", 74], "replace_swear_words": ["game/speak.rpy", 59], "replace_parentheses": ["game/speak.rpy", 66]}, "screen": {"load": ["game/default renpy scripts/screens.rpyc", 597], "help": ["game/default renpy scripts/screens.rpyc", 976], "say": ["game/default renpy scripts/screens.rpyc", 98], "notify": ["game/default renpy scripts/screens.rpyc", 1260], "keyboard_help": ["game/default renpy scripts/screens.rpyc", 1005], "gamepad_help": ["game/default renpy scripts/screens.rpyc", 1075], "preferences": ["game/default renpy scripts/screens.rpyc", 719], "confirm": ["game/default renpy scripts/screens.rpyc", 1141], "mouse_help": ["game/default renpy scripts/screens.rpyc", 1052], "input": ["game/default renpy scripts/screens.rpyc", 174], "save": ["game/default renpy scripts/screens.rpyc", 590], "skip_indicator": ["game/default renpy scripts/screens.rpyc", 1204], "file_slots": ["game/default renpy scripts/screens.rpyc", 604], "choice": ["game/default renpy scripts/screens.rpyc", 207], "game_menu": ["game/default renpy scripts/screens.rpyc", 420], "main_menu": ["game/default renpy scripts/screens.rpyc", 355], "nvl": ["game/default renpy scripts/screens.rpyc", 1299], "quick_menu": ["game/default renpy scripts/screens.rpyc", 1421], "about": ["game/default renpy scripts/screens.rpyc", 546], "nvl_dialogue": ["game/default renpy scripts/screens.rpyc", 1331], "navigation": ["game/default renpy scripts/screens.rpyc", 292], "history": ["game/default renpy scripts/screens.rpyc", 886]}, "define": {"gui.accent_color": ["game/default renpy scripts/gui.rpyc", 26], "gui.interface_text_size": ["game/default renpy scripts/gui.rpyc", 73], "build.name": ["game/options.rpy", 40], "gui.bar_tile": ["game/default renpy scripts/gui.rpyc", 314], "gui.nvl_thought_xpos": ["game/default renpy scripts/gui.rpyc", 392], "gui.slot_button_text_idle_color": ["game/default renpy scripts/gui.rpyc", 229], "config.history_length": ["game/default renpy scripts/gui.rpyc", 338], "config.after_load_transition": ["game/options.rpy", 86], "gui.page_spacing": ["game/default renpy scripts/gui.rpyc", 270], "gui.page_button_borders": ["game/default renpy scripts/gui.rpyc", 187], "gui.idle_color": ["game/default renpy scripts/gui.rpyc", 29], "config.window": ["game/options.rpy", 108], "gui.slider_tile": ["game/default renpy scripts/gui.rpyc", 316], "gui.main_menu_text_xalign": ["game/default renpy scripts/gui.rpyc", 276], "gui.nvl_button_xalign": ["game/default renpy scripts/gui.rpyc", 399], "gui.nvl_text_ypos": ["game/default renpy scripts/gui.rpyc", 386], "gui.frame_borders": ["game/default renpy scripts/gui.rpyc", 285], "gui.nvl_list_length": ["game/default renpy scripts/gui.rpyc", 367], "gui.slot_button_borders": ["game/default renpy scripts/gui.rpyc", 226], "gui.scrollbar_borders": ["game/default renpy scripts/gui.rpyc", 320], "config.enter_transition": ["game/options.rpy", 75], "gui.pref_spacing": ["game/default renpy scripts/gui.rpyc", 264], "gui.dialogue_text_xalign": ["game/default renpy scripts/gui.rpyc", 139], "gui.nvl_text_xpos": ["game/default renpy scripts/gui.rpyc", 385], "config.window_icon": ["game/options.rpy", 152], "gui.muted_color": ["game/default renpy scripts/gui.rpyc", 47], "gui.dialogue_ypos": ["game/default renpy scripts/gui.rpyc", 132], "config.has_sound": ["game/options.rpy", 48], "gui.button_text_font": ["game/default renpy scripts/gui.rpyc", 159], "gui.nvl_name_ypos": ["game/default renpy scripts/gui.rpyc", 380], "gui.game_menu_background": ["game/default renpy scripts/gui.rpyc", 89], "gui.choice_button_text_hover_color": ["game/default renpy scripts/gui.rpyc", 213], "gui.nvl_button_xpos": ["game/default renpy scripts/gui.rpyc", 398], "gui.name_xalign": ["game/default renpy scripts/gui.rpyc", 112], "gui.namebox_borders": ["game/default renpy scripts/gui.rpyc", 121], "gui.frame_tile": ["game/default renpy scripts/gui.rpyc", 297], "gui.nvl_text_xalign": ["game/default renpy scripts/gui.rpyc", 388], "gui.vbar_borders": ["game/default renpy scripts/gui.rpyc", 324], "config.end_game_transition": ["game/options.rpy", 91], "gui.slot_button_text_size": ["game/default renpy scripts/gui.rpyc", 227], "gui.dialogue_xpos": ["game/default renpy scripts/gui.rpyc", 131], "gui.namebox_height": ["game/default renpy scripts/gui.rpyc", 117], "config.version": ["game/options.rpy", 26], "gui.history_text_width": ["game/default renpy scripts/gui.rpyc", 354], "gui.radio_button_borders": ["game/default renpy scripts/gui.rpyc", 181], "gui.button_text_size": ["game/default renpy scripts/gui.rpyc", 162], "config.window_hide_transition": ["game/options.rpy", 114], "gui.about": ["game/options.rpy", 32], "gui.vslider_borders": ["game/default renpy scripts/gui.rpyc", 326], "gui.navigation_spacing": ["game/default renpy scripts/gui.rpyc", 261], "gui.choice_button_borders": ["game/default renpy scripts/gui.rpyc", 208], "config.intra_transition": ["game/options.rpy", 81], "gui.slot_button_width": ["game/default renpy scripts/gui.rpyc", 224], "gui.choice_button_text_xalign": ["game/default renpy scripts/gui.rpyc", 211], "gui.show_name": ["game/options.rpy", 21], "gui.slot_button_text_selected_hover_color": ["game/default renpy scripts/gui.rpyc", 231], "gui.title_text_size": ["game/default renpy scripts/gui.rpyc", 82], "gui.slot_button_text_selected_idle_color": ["game/default renpy scripts/gui.rpyc", 230], "e2": ["game/script.rpy", 24], "gui.button_text_idle_color": ["game/default renpy scripts/gui.rpyc", 165], "gui.notify_frame_borders": ["game/default renpy scripts/gui.rpyc", 294], "gui.navigation_xpos": ["game/default renpy scripts/gui.rpyc", 249], "gui.slot_button_height": ["game/default renpy scripts/gui.rpyc", 225], "gui.history_text_ypos": ["game/default renpy scripts/gui.rpyc", 353], "config.nvl_list_length": ["game/default renpy scripts/screens.rpyc", 1352], "gui.notify_text_size": ["game/default renpy scripts/gui.rpyc", 79], "config.has_voice": ["game/options.rpy", 50], "gui.selected_color": ["game/default renpy scripts/gui.rpyc", 40], "gui.history_text_xpos": ["game/default renpy scripts/gui.rpyc", 352], "gui.skip_frame_borders": ["game/default renpy scripts/gui.rpyc", 291], "gui.confirm_button_text_xalign": ["game/default renpy scripts/gui.rpyc", 185], "gui.text_font": ["game/default renpy scripts/gui.rpyc", 58], "gui.history_name_xpos": ["game/default renpy scripts/gui.rpyc", 346], "gui.main_menu_background": ["game/default renpy scripts/gui.rpyc", 88], "gui.button_width": ["game/default renpy scripts/gui.rpyc", 148], "gui.button_text_selected_color": ["game/default renpy scripts/gui.rpyc", 167], "gui.nvl_thought_ypos": ["game/default renpy scripts/gui.rpyc", 393], "config.save_directory": ["game/options.rpy", 145], "gui.skip_ypos": ["game/default renpy scripts/gui.rpyc", 252], "gui.namebox_tile": ["game/default renpy scripts/gui.rpyc", 125], "gui.nvl_text_width": ["game/default renpy scripts/gui.rpyc", 387], "gui.hover_color": ["game/default renpy scripts/gui.rpyc", 36], "gui.interface_text_color": ["game/default renpy scripts/gui.rpyc", 52], "config.thumbnail_width": ["game/default renpy scripts/gui.rpyc", 234], "gui.idle_small_color": ["game/default renpy scripts/gui.rpyc", 33], "config.exit_transition": ["game/options.rpy", 76], "gui.button_text_xalign": ["game/default renpy scripts/gui.rpyc", 172], "gui.name_xpos": ["game/default renpy scripts/gui.rpyc", 107], "gui.name_text_size": ["game/default renpy scripts/gui.rpyc", 70], "gui.history_text_xalign": ["game/default renpy scripts/gui.rpyc", 355], "gui.file_slot_rows": ["game/default renpy scripts/gui.rpyc", 239], "gui.button_text_insensitive_color": ["game/default renpy scripts/gui.rpyc", 168], "gui.hover_muted_color": ["game/default renpy scripts/gui.rpyc", 48], "gui.scrollbar_size": ["game/default renpy scripts/gui.rpyc", 310], "gui.quick_button_text_selected_color": ["game/default renpy scripts/gui.rpyc", 192], "gui.nvl_thought_width": ["game/default renpy scripts/gui.rpyc", 394], "gui.history_height": ["game/default renpy scripts/gui.rpyc", 342], "gui.text_size": ["game/default renpy scripts/gui.rpyc", 67], "gui.unscrollable": ["game/default renpy scripts/gui.rpyc", 330], "gui.choice_button_text_font": ["game/default renpy scripts/gui.rpyc", 209], "gui.slot_spacing": ["game/default renpy scripts/gui.rpyc", 273], "gui.quick_button_text_idle_color": ["game/default renpy scripts/gui.rpyc", 191], "config.window_show_transition": ["game/options.rpy", 113], "config.narrator_menu": ["game/default renpy scripts/screens.rpyc", 217], "gui.nvl_height": ["game/default renpy scripts/gui.rpyc", 371], "gui.choice_button_height": ["game/default renpy scripts/gui.rpyc", 206], "gui.nvl_spacing": ["game/default renpy scripts/gui.rpyc", 375], "quick_menu": ["game/default renpy scripts/screens.rpyc", 271], "gui.insensitive_color": ["game/default renpy scripts/gui.rpyc", 43], "gui.bar_borders": ["game/default renpy scripts/gui.rpyc", 319], "gui.dialogue_width": ["game/default renpy scripts/gui.rpyc", 135], "gui.scrollbar_tile": ["game/default renpy scripts/gui.rpyc", 315], "gui.quick_button_text_size": ["game/default renpy scripts/gui.rpyc", 190], "config.has_music": ["game/options.rpy", 49], "gui.textbox_height": ["game/default renpy scripts/gui.rpyc", 98], "gui.file_slot_cols": ["game/default renpy scripts/gui.rpyc", 238], "gui.text_color": ["game/default renpy scripts/gui.rpyc", 51], "gui.history_name_xalign": ["game/default renpy scripts/gui.rpyc", 349], "config.name": ["game/options.rpy", 15], "gui.button_text_hover_color": ["game/default renpy scripts/gui.rpyc", 166], "gui.textbox_yalign": ["game/default renpy scripts/gui.rpyc", 102], "gui.nvl_name_width": ["game/default renpy scripts/gui.rpyc", 381], "gui.choice_button_text_idle_color": ["game/default renpy scripts/gui.rpyc", 212], "gui.button_borders": ["game/default renpy scripts/gui.rpyc", 152], "gui.button_tile": ["game/default renpy scripts/gui.rpyc", 156], "gui.choice_button_tile": ["game/default renpy scripts/gui.rpyc", 207], "gui.history_name_width": ["game/default renpy scripts/gui.rpyc", 348], "gui.language": ["game/default renpy scripts/gui.rpyc", 407], "gui.notify_ypos": ["game/default renpy scripts/gui.rpyc", 255], "gui.nvl_name_xalign": ["game/default renpy scripts/gui.rpyc", 382], "gui.label_text_size": ["game/default renpy scripts/gui.rpyc", 76], "gui.nvl_thought_xalign": ["game/default renpy scripts/gui.rpyc", 395], "gui.namebox_width": ["game/default renpy scripts/gui.rpyc", 116], "gui.choice_button_text_insensitive_color": ["game/default renpy scripts/gui.rpyc", 214], "gui.slider_borders": ["game/default renpy scripts/gui.rpyc", 321], "gui.history_allow_tags": ["game/default renpy scripts/screens.rpyc", 926], "gui.name_text_font": ["game/default renpy scripts/gui.rpyc", 61], "gui.name_ypos": ["game/default renpy scripts/gui.rpyc", 108], "gui.nvl_borders": ["game/default renpy scripts/gui.rpyc", 363], "gui.pref_button_spacing": ["game/default renpy scripts/gui.rpyc", 267], "config.thumbnail_height": ["game/default renpy scripts/gui.rpyc", 235], "gui.bar_size": ["game/default renpy scripts/gui.rpyc", 309], "gui.choice_button_width": ["game/default renpy scripts/gui.rpyc", 205], "gui.interface_text_font": ["game/default renpy scripts/gui.rpyc", 64], "e": ["game/script.rpy", 23], "gui.history_name_ypos": ["game/default renpy scripts/gui.rpyc", 347], "gui.slot_button_text_xalign": ["game/default renpy scripts/gui.rpyc", 228], "gui.nvl_name_xpos": ["game/default renpy scripts/gui.rpyc", 379], "gui.confirm_frame_borders": ["game/default renpy scripts/gui.rpyc", 288], "gui.slider_size": ["game/default renpy scripts/gui.rpyc", 311], "gui.button_height": ["game/default renpy scripts/gui.rpyc", 149], "gui.check_button_borders": ["game/default renpy scripts/gui.rpyc", 183], "gui.choice_spacing": ["game/default renpy scripts/gui.rpyc", 258], "gui.quick_button_borders": ["game/default renpy scripts/gui.rpyc", 189], "gui.choice_button_text_size": ["game/default renpy scripts/gui.rpyc", 210], "gui.vscrollbar_borders": ["game/default renpy scripts/gui.rpyc", 325]}, "transform": {"delayed_blink": ["game/default renpy scripts/screens.rpyc", 1222], "notify_appear": ["game/default renpy scripts/screens.rpyc", 1271]}, "label": {"start": ["game/script.rpy", 27]}}, "error": false, "size": [1280, 720], "build": {"documentation_patterns": ["*.html", "*.txt"], "directory_name": "Animalese-1.0", "display_name": "Animalese", "script_version": true, "destination": "Animalese-1.0-dists", "renpy": false, "allow_integrated_gpu": true, "include_update": false, "base_patterns": [["*.py", null], ["*.sh", null], ["*.app/", null], ["*.dll", null], ["*.manifest", null], ["lib/", null], ["renpy/", null], ["update/", null], ["common/", null], ["update/", null], ["icon.ico", null], ["icon.icns", null], ["project.json", null], ["log.txt", null], ["errors.txt", null], ["traceback.txt", null], ["image_cache.txt", null], ["text_overflow.txt", null], ["dialogue.txt", null], ["dialogue.tab", null], ["profile_screen.txt", null], ["files.txt", null], ["tmp/", null], ["game/saves/", null], ["game/bytecode.rpyb", null], ["archived/", null], ["launcherinfo.py", null], ["android.txt", null], [".android.json", ["android"]], ["android-*.png", ["android"]], ["android-*.jpg", ["android"]], ["ouya_icon.png", null], ["ios-presplash.*", ["ios"]], ["ios-launchimage.png", null], ["ios-icon.png", null], ["web-presplash.png", ["web"]], ["web-presplash.jpg", ["web"]], ["**~", null], ["**.bak", null], ["**/.**", null], ["**/#**", null], ["**/thumbs.db", null], [".*", null], ["**", ["all"]]], "version": "1.0", "archives": [["archive", ["all"]]], "xbit_patterns": ["**.sh", "**/*.so.*", "**/*.so", "**/*.dylib", "lib/**/python", "lib/**/pythonw", "lib/**/zsync", "lib/**/zsyncmake", "**.app/Contents/MacOS/*", "**.app/Contents/MacOS/lib/**/python", "**.app/Contents/MacOS/lib/**/pythonw", "**.app/Contents/MacOS/lib/**/zsync", "**.app/Contents/MacOS/lib/**/zsyncmake"], "exclude_empty_directories": true, "renpy_patterns": [["renpy/common/_compat/**", null], ["renpy/common/_roundrect/**", null], ["renpy/common/_outline/**", null], ["renpy/common/_theme**", null], ["**~", null], ["**/#*", null], ["**/.*", null], ["**.old", null], ["**.new", null], ["**.rpa", null], ["**/*.pyc", null], ["renpy.py", ["all"]], ["renpy/", ["all"]], ["renpy/**.py", ["renpy"]], ["renpy/**.pyx", ["renpy"]], ["renpy/**.pyd", ["renpy"]], ["renpy/**.pxi", ["renpy"]], ["renpy/common/", ["all"]], ["renpy/common/_compat/**", ["renpy"]], ["renpy/common/**.rpy", ["renpy"]], ["renpy/common/**.rpym", ["renpy"]], ["renpy/common/_compat/**", ["renpy"]], ["renpy/common/**", ["all"]], ["renpy/**", ["all"]], ["lib/*/renpy", null], ["lib/*/renpy.exe", null], ["lib/windows-i686/**", ["windows"]], ["lib/linux-*/**", ["linux"]], ["lib/darwin-x86_64/**", ["mac"]], ["/lib/**", ["windows", "linux", "mac"]], ["renpy.sh", ["linux", "mac"]]], "packages": [{"dlc": false, "hidden": false, "description": "PC: Windows and Linux", "formats": ["zip"], "file_lists": ["windows", "linux", "renpy", "all"], "update": true, "name": "pc"}, {"dlc": false, "hidden": false, "description": "Linux x86/x86_64", "formats": ["tar.bz2"], "file_lists": ["linux", "renpy", "all"], "update": true, "name": "linux"}, {"dlc": false, "hidden": false, "description": "Macintosh x86_64", "formats": ["app-zip", "app-dmg"], "file_lists": ["mac", "renpy", "all"], "update": true, "name": "mac"}, {"dlc": false, "hidden": false, "description": "Windows x86", "formats": ["zip"], "file_lists": ["windows", "renpy", "all"], "update": true, "name": "win"}, {"dlc": false, "hidden": false, "description": "Windows, Mac, Linux for Markets", "formats": ["zip"], "file_lists": ["windows", "linux", "mac", "renpy", "all"], "update": true, "name": "market"}, {"dlc": false, "hidden": true, "description": "steam", "formats": ["zip"], "file_lists": ["windows", "linux", "mac", "renpy", "all"], "update": true, "name": "steam"}, {"dlc": true, "hidden": true, "description": "android", "formats": ["directory"], "file_lists": ["android", "all"], "update": false, "name": "android"}, {"dlc": true, "hidden": true, "description": "ios", "formats": ["directory"], "file_lists": ["ios", "all"], "update": false, "name": "ios"}, {"dlc": true, "hidden": false, "description": "web", "formats": ["zip"], "file_lists": ["web", "all"], "update": false, "name": "web"}], "executable_name": "Animalese"}} -------------------------------------------------------------------------------- /game/default renpy scripts/gui.rpy: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## Initialization 3 | ################################################################################ 4 | 5 | ## The init offset statement causes the initialization statements in this file 6 | ## to run before init statements in any other file. 7 | init offset = -2 8 | 9 | ## Calling gui.init resets the styles to sensible default values, and sets the 10 | ## width and height of the game. 11 | init python: 12 | gui.init(1280, 720) 13 | 14 | 15 | 16 | ################################################################################ 17 | ## GUI Configuration Variables 18 | ################################################################################ 19 | 20 | 21 | ## Colors ###################################################################### 22 | ## 23 | ## The colors of text in the interface. 24 | 25 | ## An accent color used throughout the interface to label and highlight text. 26 | define gui.accent_color = '#cc0066' 27 | 28 | ## The color used for a text button when it is neither selected nor hovered. 29 | define gui.idle_color = '#aaaaaa' 30 | 31 | ## The small color is used for small text, which needs to be brighter/darker to 32 | ## achieve the same effect. 33 | define gui.idle_small_color = '#888888' 34 | 35 | ## The color that is used for buttons and bars that are hovered. 36 | define gui.hover_color = '#cc0066' 37 | 38 | ## The color used for a text button when it is selected but not focused. A 39 | ## button is selected if it is the current screen or preference value. 40 | define gui.selected_color = '#555555' 41 | 42 | ## The color used for a text button when it cannot be selected. 43 | define gui.insensitive_color = '#aaaaaa7f' 44 | 45 | ## Colors used for the portions of bars that are not filled in. These are not 46 | ## used directly, but are used when re-generating bar image files. 47 | define gui.muted_color = '#e066a3' 48 | define gui.hover_muted_color = '#ea99c1' 49 | 50 | ## The colors used for dialogue and menu choice text. 51 | define gui.text_color = '#404040' 52 | define gui.interface_text_color = '#404040' 53 | 54 | 55 | ## Fonts and Font Sizes ######################################################## 56 | 57 | ## The font used for in-game text. 58 | define gui.text_font = "DejaVuSans.ttf" 59 | 60 | ## The font used for character names. 61 | define gui.name_text_font = "DejaVuSans.ttf" 62 | 63 | ## The font used for out-of-game text. 64 | define gui.interface_text_font = "DejaVuSans.ttf" 65 | 66 | ## The size of normal dialogue text. 67 | define gui.text_size = 22 68 | 69 | ## The size of character names. 70 | define gui.name_text_size = 30 71 | 72 | ## The size of text in the game's user interface. 73 | define gui.interface_text_size = 22 74 | 75 | ## The size of labels in the game's user interface. 76 | define gui.label_text_size = 24 77 | 78 | ## The size of text on the notify screen. 79 | define gui.notify_text_size = 16 80 | 81 | ## The size of the game's title. 82 | define gui.title_text_size = 50 83 | 84 | 85 | ## Main and Game Menus ######################################################### 86 | 87 | ## The images used for the main and game menus. 88 | define gui.main_menu_background = "gui/main_menu.png" 89 | define gui.game_menu_background = "gui/game_menu.png" 90 | 91 | 92 | ## Dialogue #################################################################### 93 | ## 94 | ## These variables control how dialogue is displayed on the screen one line at a 95 | ## time. 96 | 97 | ## The height of the textbox containing dialogue. 98 | define gui.textbox_height = 185 99 | 100 | ## The placement of the textbox vertically on the screen. 0.0 is the top, 0.5 is 101 | ## center, and 1.0 is the bottom. 102 | define gui.textbox_yalign = 1.0 103 | 104 | 105 | ## The placement of the speaking character's name, relative to the textbox. 106 | ## These can be a whole number of pixels from the left or top, or 0.5 to center. 107 | define gui.name_xpos = 240 108 | define gui.name_ypos = 0 109 | 110 | ## The horizontal alignment of the character's name. This can be 0.0 for left- 111 | ## aligned, 0.5 for centered, and 1.0 for right-aligned. 112 | define gui.name_xalign = 0.0 113 | 114 | ## The width, height, and borders of the box containing the character's name, or 115 | ## None to automatically size it. 116 | define gui.namebox_width = None 117 | define gui.namebox_height = None 118 | 119 | ## The borders of the box containing the character's name, in left, top, right, 120 | ## bottom order. 121 | define gui.namebox_borders = Borders(5, 5, 5, 5) 122 | 123 | ## If True, the background of the namebox will be tiled, if False, the 124 | ## background of the namebox will be scaled. 125 | define gui.namebox_tile = False 126 | 127 | 128 | ## The placement of dialogue relative to the textbox. These can be a whole 129 | ## number of pixels relative to the left or top side of the textbox, or 0.5 to 130 | ## center. 131 | define gui.dialogue_xpos = 268 132 | define gui.dialogue_ypos = 50 133 | 134 | ## The maximum width of dialogue text, in pixels. 135 | define gui.dialogue_width = 744 136 | 137 | ## The horizontal alignment of the dialogue text. This can be 0.0 for left- 138 | ## aligned, 0.5 for centered, and 1.0 for right-aligned. 139 | define gui.dialogue_text_xalign = 0.0 140 | 141 | 142 | ## Buttons ##################################################################### 143 | ## 144 | ## These variables, along with the image files in gui/button, control aspects of 145 | ## how buttons are displayed. 146 | 147 | ## The width and height of a button, in pixels. If None, Ren'Py computes a size. 148 | define gui.button_width = None 149 | define gui.button_height = None 150 | 151 | ## The borders on each side of the button, in left, top, right, bottom order. 152 | define gui.button_borders = Borders(4, 4, 4, 4) 153 | 154 | ## If True, the background image will be tiled. If False, the background image 155 | ## will be linearly scaled. 156 | define gui.button_tile = False 157 | 158 | ## The font used by the button. 159 | define gui.button_text_font = gui.interface_text_font 160 | 161 | ## The size of the text used by the button. 162 | define gui.button_text_size = gui.interface_text_size 163 | 164 | ## The color of button text in various states. 165 | define gui.button_text_idle_color = gui.idle_color 166 | define gui.button_text_hover_color = gui.hover_color 167 | define gui.button_text_selected_color = gui.selected_color 168 | define gui.button_text_insensitive_color = gui.insensitive_color 169 | 170 | ## The horizontal alignment of the button text. (0.0 is left, 0.5 is center, 1.0 171 | ## is right). 172 | define gui.button_text_xalign = 0.0 173 | 174 | 175 | ## These variables override settings for different kinds of buttons. Please see 176 | ## the gui documentation for the kinds of buttons available, and what each is 177 | ## used for. 178 | ## 179 | ## These customizations are used by the default interface: 180 | 181 | define gui.radio_button_borders = Borders(18, 4, 4, 4) 182 | 183 | define gui.check_button_borders = Borders(18, 4, 4, 4) 184 | 185 | define gui.confirm_button_text_xalign = 0.5 186 | 187 | define gui.page_button_borders = Borders(10, 4, 10, 4) 188 | 189 | define gui.quick_button_borders = Borders(10, 4, 10, 0) 190 | define gui.quick_button_text_size = 14 191 | define gui.quick_button_text_idle_color = gui.idle_small_color 192 | define gui.quick_button_text_selected_color = gui.accent_color 193 | 194 | ## You can also add your own customizations, by adding properly-named variables. 195 | ## For example, you can uncomment the following line to set the width of a 196 | ## navigation button. 197 | 198 | # define gui.navigation_button_width = 250 199 | 200 | 201 | ## Choice Buttons ############################################################## 202 | ## 203 | ## Choice buttons are used in the in-game menus. 204 | 205 | define gui.choice_button_width = 790 206 | define gui.choice_button_height = None 207 | define gui.choice_button_tile = False 208 | define gui.choice_button_borders = Borders(100, 5, 100, 5) 209 | define gui.choice_button_text_font = gui.text_font 210 | define gui.choice_button_text_size = gui.text_size 211 | define gui.choice_button_text_xalign = 0.5 212 | define gui.choice_button_text_idle_color = "#cccccc" 213 | define gui.choice_button_text_hover_color = "#ffffff" 214 | define gui.choice_button_text_insensitive_color = "#444444" 215 | 216 | 217 | ## File Slot Buttons ########################################################### 218 | ## 219 | ## A file slot button is a special kind of button. It contains a thumbnail 220 | ## image, and text describing the contents of the save slot. A save slot uses 221 | ## image files in gui/button, like the other kinds of buttons. 222 | 223 | ## The save slot button. 224 | define gui.slot_button_width = 276 225 | define gui.slot_button_height = 206 226 | define gui.slot_button_borders = Borders(10, 10, 10, 10) 227 | define gui.slot_button_text_size = 14 228 | define gui.slot_button_text_xalign = 0.5 229 | define gui.slot_button_text_idle_color = gui.idle_small_color 230 | define gui.slot_button_text_selected_idle_color = gui.selected_color 231 | define gui.slot_button_text_selected_hover_color = gui.hover_color 232 | 233 | ## The width and height of thumbnails used by the save slots. 234 | define config.thumbnail_width = 256 235 | define config.thumbnail_height = 144 236 | 237 | ## The number of columns and rows in the grid of save slots. 238 | define gui.file_slot_cols = 3 239 | define gui.file_slot_rows = 2 240 | 241 | 242 | ## Positioning and Spacing ##################################################### 243 | ## 244 | ## These variables control the positioning and spacing of various user interface 245 | ## elements. 246 | 247 | ## The position of the left side of the navigation buttons, relative to the left 248 | ## side of the screen. 249 | define gui.navigation_xpos = 40 250 | 251 | ## The vertical position of the skip indicator. 252 | define gui.skip_ypos = 10 253 | 254 | ## The vertical position of the notify screen. 255 | define gui.notify_ypos = 45 256 | 257 | ## The spacing between menu choices. 258 | define gui.choice_spacing = 22 259 | 260 | ## Buttons in the navigation section of the main and game menus. 261 | define gui.navigation_spacing = 4 262 | 263 | ## Controls the amount of spacing between preferences. 264 | define gui.pref_spacing = 10 265 | 266 | ## Controls the amount of spacing between preference buttons. 267 | define gui.pref_button_spacing = 0 268 | 269 | ## The spacing between file page buttons. 270 | define gui.page_spacing = 0 271 | 272 | ## The spacing between file slots. 273 | define gui.slot_spacing = 10 274 | 275 | ## The position of the main menu text. 276 | define gui.main_menu_text_xalign = 1.0 277 | 278 | 279 | ## Frames ###################################################################### 280 | ## 281 | ## These variables control the look of frames that can contain user interface 282 | ## components when an overlay or window is not present. 283 | 284 | ## Generic frames. 285 | define gui.frame_borders = Borders(4, 4, 4, 4) 286 | 287 | ## The frame that is used as part of the confirm screen. 288 | define gui.confirm_frame_borders = Borders(40, 40, 40, 40) 289 | 290 | ## The frame that is used as part of the skip screen. 291 | define gui.skip_frame_borders = Borders(16, 5, 50, 5) 292 | 293 | ## The frame that is used as part of the notify screen. 294 | define gui.notify_frame_borders = Borders(16, 5, 40, 5) 295 | 296 | ## Should frame backgrounds be tiled? 297 | define gui.frame_tile = False 298 | 299 | 300 | ## Bars, Scrollbars, and Sliders ############################################### 301 | ## 302 | ## These control the look and size of bars, scrollbars, and sliders. 303 | ## 304 | ## The default GUI only uses sliders and vertical scrollbars. All of the other 305 | ## bars are only used in creator-written screens. 306 | 307 | ## The height of horizontal bars, scrollbars, and sliders. The width of vertical 308 | ## bars, scrollbars, and sliders. 309 | define gui.bar_size = 25 310 | define gui.scrollbar_size = 12 311 | define gui.slider_size = 25 312 | 313 | ## True if bar images should be tiled. False if they should be linearly scaled. 314 | define gui.bar_tile = False 315 | define gui.scrollbar_tile = False 316 | define gui.slider_tile = False 317 | 318 | ## Horizontal borders. 319 | define gui.bar_borders = Borders(4, 4, 4, 4) 320 | define gui.scrollbar_borders = Borders(4, 4, 4, 4) 321 | define gui.slider_borders = Borders(4, 4, 4, 4) 322 | 323 | ## Vertical borders. 324 | define gui.vbar_borders = Borders(4, 4, 4, 4) 325 | define gui.vscrollbar_borders = Borders(4, 4, 4, 4) 326 | define gui.vslider_borders = Borders(4, 4, 4, 4) 327 | 328 | ## What to do with unscrollable scrollbars in the gui. "hide" hides them, while 329 | ## None shows them. 330 | define gui.unscrollable = "hide" 331 | 332 | 333 | ## History ##################################################################### 334 | ## 335 | ## The history screen displays dialogue that the player has already dismissed. 336 | 337 | ## The number of blocks of dialogue history Ren'Py will keep. 338 | define config.history_length = 250 339 | 340 | ## The height of a history screen entry, or None to make the height variable at 341 | ## the cost of performance. 342 | define gui.history_height = 140 343 | 344 | ## The position, width, and alignment of the label giving the name of the 345 | ## speaking character. 346 | define gui.history_name_xpos = 155 347 | define gui.history_name_ypos = 0 348 | define gui.history_name_width = 155 349 | define gui.history_name_xalign = 1.0 350 | 351 | ## The position, width, and alignment of the dialogue text. 352 | define gui.history_text_xpos = 170 353 | define gui.history_text_ypos = 2 354 | define gui.history_text_width = 740 355 | define gui.history_text_xalign = 0.0 356 | 357 | 358 | ## NVL-Mode #################################################################### 359 | ## 360 | ## The NVL-mode screen displays the dialogue spoken by NVL-mode characters. 361 | 362 | ## The borders of the background of the NVL-mode background window. 363 | define gui.nvl_borders = Borders(0, 10, 0, 20) 364 | 365 | ## The maximum number of NVL-mode entries Ren'Py will display. When more entries 366 | ## than this are to be show, the oldest entry will be removed. 367 | define gui.nvl_list_length = 6 368 | 369 | ## The height of an NVL-mode entry. Set this to None to have the entries 370 | ## dynamically adjust height. 371 | define gui.nvl_height = 115 372 | 373 | ## The spacing between NVL-mode entries when gui.nvl_height is None, and between 374 | ## NVL-mode entries and an NVL-mode menu. 375 | define gui.nvl_spacing = 10 376 | 377 | ## The position, width, and alignment of the label giving the name of the 378 | ## speaking character. 379 | define gui.nvl_name_xpos = 430 380 | define gui.nvl_name_ypos = 0 381 | define gui.nvl_name_width = 150 382 | define gui.nvl_name_xalign = 1.0 383 | 384 | ## The position, width, and alignment of the dialogue text. 385 | define gui.nvl_text_xpos = 450 386 | define gui.nvl_text_ypos = 8 387 | define gui.nvl_text_width = 590 388 | define gui.nvl_text_xalign = 0.0 389 | 390 | ## The position, width, and alignment of nvl_thought text (the text said by the 391 | ## nvl_narrator character.) 392 | define gui.nvl_thought_xpos = 240 393 | define gui.nvl_thought_ypos = 0 394 | define gui.nvl_thought_width = 780 395 | define gui.nvl_thought_xalign = 0.0 396 | 397 | ## The position of nvl menu_buttons. 398 | define gui.nvl_button_xpos = 450 399 | define gui.nvl_button_xalign = 0.0 400 | 401 | ## Localization ################################################################ 402 | 403 | ## This controls where a line break is permitted. The default is suitable 404 | ## for most languages. A list of available values can be found at https:// 405 | ## www.renpy.org/doc/html/style_properties.html#style-property-language 406 | 407 | define gui.language = "unicode" 408 | 409 | 410 | ################################################################################ 411 | ## Mobile devices 412 | ################################################################################ 413 | 414 | init python: 415 | 416 | ## This increases the size of the quick buttons to make them easier to touch 417 | ## on tablets and phones. 418 | if renpy.variant("touch"): 419 | 420 | gui.quick_button_borders = Borders(40, 14, 40, 0) 421 | 422 | ## This changes the size and spacing of various GUI elements to ensure they 423 | ## are easily visible on phones. 424 | if renpy.variant("small"): 425 | 426 | ## Font sizes. 427 | gui.text_size = 30 428 | gui.name_text_size = 36 429 | gui.notify_text_size = 25 430 | gui.interface_text_size = 30 431 | gui.button_text_size = 30 432 | gui.label_text_size = 34 433 | 434 | ## Adjust the location of the textbox. 435 | gui.textbox_height = 240 436 | gui.name_xpos = 80 437 | gui.text_xpos = 90 438 | gui.text_width = 1100 439 | 440 | ## Change the size and spacing of various things. 441 | gui.slider_size = 36 442 | 443 | gui.choice_button_width = 1240 444 | 445 | gui.navigation_spacing = 20 446 | gui.pref_button_spacing = 10 447 | 448 | gui.history_height = 190 449 | gui.history_text_width = 690 450 | 451 | gui.quick_button_text_size = 20 452 | 453 | ## File button layout. 454 | gui.file_slot_cols = 2 455 | gui.file_slot_rows = 2 456 | 457 | ## NVL-mode. 458 | gui.nvl_height = 170 459 | 460 | gui.nvl_name_width = 305 461 | gui.nvl_name_xpos = 325 462 | 463 | gui.nvl_text_width = 915 464 | gui.nvl_text_xpos = 345 465 | gui.nvl_text_ypos = 5 466 | 467 | gui.nvl_thought_width = 1240 468 | gui.nvl_thought_xpos = 20 469 | 470 | gui.nvl_button_width = 1240 471 | gui.nvl_button_xpos = 20 472 | 473 | 474 | 475 | -------------------------------------------------------------------------------- /game/pydub/pywave.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import builtins 3 | import struct 4 | import sys 5 | 6 | 7 | __all__ = ["open", "Error", "Wave_read", "Wave_write"] 8 | 9 | class Error(Exception): 10 | pass 11 | 12 | WAVE_FORMAT_PCM = 0x0001 13 | WAVE_FORMAT_EXTENSIBLE = 0xFFFE 14 | # Derived from uuid.UUID("00000001-0000-0010-8000-00aa00389b71").bytes_le 15 | KSDATAFORMAT_SUBTYPE_PCM = b'\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x008\x9bq' 16 | 17 | _array_fmts = None, 'b', 'h', None, 'i' 18 | 19 | _wave_params = namedtuple('_wave_params', 20 | 'nchannels sampwidth framerate nframes comptype compname') 21 | 22 | 23 | def _byteswap(data, width): 24 | swapped_data = bytearray(len(data)) 25 | 26 | for i in range(0, len(data), width): 27 | for j in range(width): 28 | swapped_data[i + width - 1 - j] = data[i + j] 29 | 30 | return bytes(swapped_data) 31 | 32 | 33 | class _Chunk: 34 | def __init__(self, file, align=True, bigendian=True, inclheader=False): 35 | self.closed = False 36 | self.align = align # whether to align to word (2-byte) boundaries 37 | if bigendian: 38 | strflag = '>' 39 | else: 40 | strflag = '<' 41 | self.file = file 42 | self.chunkname = file.read(4) 43 | if len(self.chunkname) < 4: 44 | raise EOFError 45 | try: 46 | self.chunksize = struct.unpack_from(strflag+'L', file.read(4))[0] 47 | except struct.error: 48 | raise EOFError from None 49 | if inclheader: 50 | self.chunksize = self.chunksize - 8 # subtract header 51 | self.size_read = 0 52 | try: 53 | self.offset = self.file.tell() 54 | except (AttributeError, OSError): 55 | self.seekable = False 56 | else: 57 | self.seekable = True 58 | 59 | def getname(self): 60 | """Return the name (ID) of the current chunk.""" 61 | return self.chunkname 62 | 63 | def close(self): 64 | if not self.closed: 65 | try: 66 | self.skip() 67 | finally: 68 | self.closed = True 69 | 70 | def seek(self, pos, whence=0): 71 | """Seek to specified position into the chunk. 72 | Default position is 0 (start of chunk). 73 | If the file is not seekable, this will result in an error. 74 | """ 75 | 76 | if self.closed: 77 | raise ValueError("I/O operation on closed file") 78 | if not self.seekable: 79 | raise OSError("cannot seek") 80 | if whence == 1: 81 | pos = pos + self.size_read 82 | elif whence == 2: 83 | pos = pos + self.chunksize 84 | if pos < 0 or pos > self.chunksize: 85 | raise RuntimeError 86 | self.file.seek(self.offset + pos, 0) 87 | self.size_read = pos 88 | 89 | def tell(self): 90 | if self.closed: 91 | raise ValueError("I/O operation on closed file") 92 | return self.size_read 93 | 94 | def read(self, size=-1): 95 | """Read at most size bytes from the chunk. 96 | If size is omitted or negative, read until the end 97 | of the chunk. 98 | """ 99 | 100 | if self.closed: 101 | raise ValueError("I/O operation on closed file") 102 | if self.size_read >= self.chunksize: 103 | return b'' 104 | if size < 0: 105 | size = self.chunksize - self.size_read 106 | if size > self.chunksize - self.size_read: 107 | size = self.chunksize - self.size_read 108 | data = self.file.read(size) 109 | self.size_read = self.size_read + len(data) 110 | if self.size_read == self.chunksize and \ 111 | self.align and \ 112 | (self.chunksize & 1): 113 | dummy = self.file.read(1) 114 | self.size_read = self.size_read + len(dummy) 115 | return data 116 | 117 | def skip(self): 118 | """Skip the rest of the chunk. 119 | If you are not interested in the contents of the chunk, 120 | this method should be called so that the file points to 121 | the start of the next chunk. 122 | """ 123 | 124 | if self.closed: 125 | raise ValueError("I/O operation on closed file") 126 | if self.seekable: 127 | try: 128 | n = self.chunksize - self.size_read 129 | # maybe fix alignment 130 | if self.align and (self.chunksize & 1): 131 | n = n + 1 132 | self.file.seek(n, 1) 133 | self.size_read = self.size_read + n 134 | return 135 | except OSError: 136 | pass 137 | while self.size_read < self.chunksize: 138 | n = min(8192, self.chunksize - self.size_read) 139 | dummy = self.read(n) 140 | if not dummy: 141 | raise EOFError 142 | 143 | 144 | class Wave_read: 145 | """Variables used in this class: 146 | 147 | These variables are available to the user though appropriate 148 | methods of this class: 149 | _file -- the open file with methods read(), close(), and seek() 150 | set through the __init__() method 151 | _nchannels -- the number of audio channels 152 | available through the getnchannels() method 153 | _nframes -- the number of audio frames 154 | available through the getnframes() method 155 | _sampwidth -- the number of bytes per audio sample 156 | available through the getsampwidth() method 157 | _framerate -- the sampling frequency 158 | available through the getframerate() method 159 | _comptype -- the AIFF-C compression type ('NONE' if AIFF) 160 | available through the getcomptype() method 161 | _compname -- the human-readable AIFF-C compression type 162 | available through the getcomptype() method 163 | _soundpos -- the position in the audio stream 164 | available through the tell() method, set through the 165 | setpos() method 166 | 167 | These variables are used internally only: 168 | _fmt_chunk_read -- 1 iff the FMT chunk has been read 169 | _data_seek_needed -- 1 iff positioned correctly in audio 170 | file for readframes() 171 | _data_chunk -- instantiation of a chunk class for the DATA chunk 172 | _framesize -- size of one frame in the file 173 | """ 174 | 175 | def initfp(self, file): 176 | self._convert = None 177 | self._soundpos = 0 178 | self._file = _Chunk(file, bigendian = 0) 179 | if self._file.getname() != b'RIFF': 180 | raise Error('file does not start with RIFF id') 181 | if self._file.read(4) != b'WAVE': 182 | raise Error('not a WAVE file') 183 | self._fmt_chunk_read = 0 184 | self._data_chunk = None 185 | while 1: 186 | self._data_seek_needed = 1 187 | try: 188 | chunk = _Chunk(self._file, bigendian = 0) 189 | except EOFError: 190 | break 191 | chunkname = chunk.getname() 192 | if chunkname == b'fmt ': 193 | self._read_fmt_chunk(chunk) 194 | self._fmt_chunk_read = 1 195 | elif chunkname == b'data': 196 | if not self._fmt_chunk_read: 197 | raise Error('data chunk before fmt chunk') 198 | self._data_chunk = chunk 199 | self._nframes = chunk.chunksize // self._framesize 200 | self._data_seek_needed = 0 201 | break 202 | chunk.skip() 203 | if not self._fmt_chunk_read or not self._data_chunk: 204 | raise Error('fmt chunk and/or data chunk missing') 205 | 206 | def __init__(self, f): 207 | self._i_opened_the_file = None 208 | if isinstance(f, str): 209 | f = builtins.open(f, 'rb') 210 | self._i_opened_the_file = f 211 | # else, assume it is an open file object already 212 | try: 213 | self.initfp(f) 214 | except: 215 | if self._i_opened_the_file: 216 | f.close() 217 | raise 218 | 219 | def __del__(self): 220 | self.close() 221 | 222 | def __enter__(self): 223 | return self 224 | 225 | def __exit__(self, *args): 226 | self.close() 227 | 228 | # 229 | # User visible methods. 230 | # 231 | def getfp(self): 232 | return self._file 233 | 234 | def rewind(self): 235 | self._data_seek_needed = 1 236 | self._soundpos = 0 237 | 238 | def close(self): 239 | self._file = None 240 | file = self._i_opened_the_file 241 | if file: 242 | self._i_opened_the_file = None 243 | file.close() 244 | 245 | def tell(self): 246 | return self._soundpos 247 | 248 | def getnchannels(self): 249 | return self._nchannels 250 | 251 | def getnframes(self): 252 | return self._nframes 253 | 254 | def getsampwidth(self): 255 | return self._sampwidth 256 | 257 | def getframerate(self): 258 | return self._framerate 259 | 260 | def getcomptype(self): 261 | return self._comptype 262 | 263 | def getcompname(self): 264 | return self._compname 265 | 266 | def getparams(self): 267 | return _wave_params(self.getnchannels(), self.getsampwidth(), 268 | self.getframerate(), self.getnframes(), 269 | self.getcomptype(), self.getcompname()) 270 | 271 | def getmarkers(self): 272 | import warnings 273 | warnings._deprecated("Wave_read.getmarkers", remove=(3, 15)) 274 | return None 275 | 276 | def getmark(self, id): 277 | import warnings 278 | warnings._deprecated("Wave_read.getmark", remove=(3, 15)) 279 | raise Error('no marks') 280 | 281 | def setpos(self, pos): 282 | if pos < 0 or pos > self._nframes: 283 | raise Error('position not in range') 284 | self._soundpos = pos 285 | self._data_seek_needed = 1 286 | 287 | def readframes(self, nframes): 288 | if self._data_seek_needed: 289 | self._data_chunk.seek(0, 0) 290 | pos = self._soundpos * self._framesize 291 | if pos: 292 | self._data_chunk.seek(pos, 0) 293 | self._data_seek_needed = 0 294 | if nframes == 0: 295 | return b'' 296 | data = self._data_chunk.read(nframes * self._framesize) 297 | if self._sampwidth != 1 and sys.byteorder == 'big': 298 | data = _byteswap(data, self._sampwidth) 299 | if self._convert and data: 300 | data = self._convert(data) 301 | self._soundpos = self._soundpos + len(data) // (self._nchannels * self._sampwidth) 302 | return data 303 | 304 | # 305 | # Internal methods. 306 | # 307 | 308 | def _read_fmt_chunk(self, chunk): 309 | try: 310 | wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from(' 4: 423 | raise Error('bad sample width') 424 | self._sampwidth = sampwidth 425 | 426 | def getsampwidth(self): 427 | if not self._sampwidth: 428 | raise Error('sample width not set') 429 | return self._sampwidth 430 | 431 | def setframerate(self, framerate): 432 | if self._datawritten: 433 | raise Error('cannot change parameters after starting to write') 434 | if framerate <= 0: 435 | raise Error('bad frame rate') 436 | self._framerate = int(round(framerate)) 437 | 438 | def getframerate(self): 439 | if not self._framerate: 440 | raise Error('frame rate not set') 441 | return self._framerate 442 | 443 | def setnframes(self, nframes): 444 | if self._datawritten: 445 | raise Error('cannot change parameters after starting to write') 446 | self._nframes = nframes 447 | 448 | def getnframes(self): 449 | return self._nframeswritten 450 | 451 | def setcomptype(self, comptype, compname): 452 | if self._datawritten: 453 | raise Error('cannot change parameters after starting to write') 454 | if comptype not in ('NONE',): 455 | raise Error('unsupported compression type') 456 | self._comptype = comptype 457 | self._compname = compname 458 | 459 | def getcomptype(self): 460 | return self._comptype 461 | 462 | def getcompname(self): 463 | return self._compname 464 | 465 | def setparams(self, params): 466 | nchannels, sampwidth, framerate, nframes, comptype, compname = params 467 | if self._datawritten: 468 | raise Error('cannot change parameters after starting to write') 469 | self.setnchannels(nchannels) 470 | self.setsampwidth(sampwidth) 471 | self.setframerate(framerate) 472 | self.setnframes(nframes) 473 | self.setcomptype(comptype, compname) 474 | 475 | def getparams(self): 476 | if not self._nchannels or not self._sampwidth or not self._framerate: 477 | raise Error('not all parameters set') 478 | return _wave_params(self._nchannels, self._sampwidth, self._framerate, 479 | self._nframes, self._comptype, self._compname) 480 | 481 | def setmark(self, id, pos, name): 482 | import warnings 483 | warnings._deprecated("Wave_write.setmark", remove=(3, 15)) 484 | raise Error('setmark() not supported') 485 | 486 | def getmark(self, id): 487 | import warnings 488 | warnings._deprecated("Wave_write.getmark", remove=(3, 15)) 489 | raise Error('no marks') 490 | 491 | def getmarkers(self): 492 | import warnings 493 | warnings._deprecated("Wave_write.getmarkers", remove=(3, 15)) 494 | return None 495 | 496 | def tell(self): 497 | return self._nframeswritten 498 | 499 | def writeframesraw(self, data): 500 | if not isinstance(data, (bytes, bytearray)): 501 | data = memoryview(data).cast('B') 502 | self._ensure_header_written(len(data)) 503 | nframes = len(data) // (self._sampwidth * self._nchannels) 504 | if self._convert: 505 | data = self._convert(data) 506 | if self._sampwidth != 1 and sys.byteorder == 'big': 507 | data = _byteswap(data, self._sampwidth) 508 | self._file.write(data) 509 | self._datawritten += len(data) 510 | self._nframeswritten = self._nframeswritten + nframes 511 | 512 | def writeframes(self, data): 513 | self.writeframesraw(data) 514 | if self._datalength != self._datawritten: 515 | self._patchheader() 516 | 517 | def close(self): 518 | try: 519 | if self._file: 520 | self._ensure_header_written(0) 521 | if self._datalength != self._datawritten: 522 | self._patchheader() 523 | self._file.flush() 524 | finally: 525 | self._file = None 526 | file = self._i_opened_the_file 527 | if file: 528 | self._i_opened_the_file = None 529 | file.close() 530 | 531 | # 532 | # Internal methods. 533 | # 534 | 535 | def _ensure_header_written(self, datasize): 536 | if not self._headerwritten: 537 | if not self._nchannels: 538 | raise Error('# channels not specified') 539 | if not self._sampwidth: 540 | raise Error('sample width not specified') 541 | if not self._framerate: 542 | raise Error('sampling rate not specified') 543 | self._write_header(datasize) 544 | 545 | def _write_header(self, initlength): 546 | assert not self._headerwritten 547 | self._file.write(b'RIFF') 548 | if not self._nframes: 549 | self._nframes = initlength // (self._nchannels * self._sampwidth) 550 | self._datalength = self._nframes * self._nchannels * self._sampwidth 551 | try: 552 | self._form_length_pos = self._file.tell() 553 | except (AttributeError, OSError): 554 | self._form_length_pos = None 555 | self._file.write(struct.pack('" 798 | new "" 799 | 800 | # renpy/common/_layout/classic_load_save.rpym:170 801 | old "a" 802 | new "a" 803 | 804 | # renpy/common/_layout/classic_load_save.rpym:179 805 | old "q" 806 | new "q" 807 | 808 | # renpy/common/00iap.rpy:217 809 | old "Contacting App Store\nPlease Wait..." 810 | new "Contacting App Store\nPlease Wait..." 811 | 812 | # renpy/common/00updater.rpy:375 813 | old "The Ren'Py Updater is not supported on mobile devices." 814 | new "The Ren'Py Updater is not supported on mobile devices." 815 | 816 | # renpy/common/00updater.rpy:494 817 | old "An error is being simulated." 818 | new "An error is being simulated." 819 | 820 | # renpy/common/00updater.rpy:678 821 | old "Either this project does not support updating, or the update status file was deleted." 822 | new "Either this project does not support updating, or the update status file was deleted." 823 | 824 | # renpy/common/00updater.rpy:692 825 | old "This account does not have permission to perform an update." 826 | new "This account does not have permission to perform an update." 827 | 828 | # renpy/common/00updater.rpy:695 829 | old "This account does not have permission to write the update log." 830 | new "This account does not have permission to write the update log." 831 | 832 | # renpy/common/00updater.rpy:722 833 | old "Could not verify update signature." 834 | new "Could not verify update signature." 835 | 836 | # renpy/common/00updater.rpy:997 837 | old "The update file was not downloaded." 838 | new "The update file was not downloaded." 839 | 840 | # renpy/common/00updater.rpy:1015 841 | old "The update file does not have the correct digest - it may have been corrupted." 842 | new "The update file does not have the correct digest - it may have been corrupted." 843 | 844 | # renpy/common/00updater.rpy:1071 845 | old "While unpacking {}, unknown type {}." 846 | new "While unpacking {}, unknown type {}." 847 | 848 | # renpy/common/00updater.rpy:1439 849 | old "Updater" 850 | new "Updater" 851 | 852 | # renpy/common/00updater.rpy:1446 853 | old "An error has occured:" 854 | new "An error has occured:" 855 | 856 | # renpy/common/00updater.rpy:1448 857 | old "Checking for updates." 858 | new "Checking for updates." 859 | 860 | # renpy/common/00updater.rpy:1450 861 | old "This program is up to date." 862 | new "This program is up to date." 863 | 864 | # renpy/common/00updater.rpy:1452 865 | old "[u.version] is available. Do you want to install it?" 866 | new "[u.version] is available. Do you want to install it?" 867 | 868 | # renpy/common/00updater.rpy:1454 869 | old "Preparing to download the updates." 870 | new "Preparing to download the updates." 871 | 872 | # renpy/common/00updater.rpy:1456 873 | old "Downloading the updates." 874 | new "Downloading the updates." 875 | 876 | # renpy/common/00updater.rpy:1458 877 | old "Unpacking the updates." 878 | new "Unpacking the updates." 879 | 880 | # renpy/common/00updater.rpy:1460 881 | old "Finishing up." 882 | new "Finishing up." 883 | 884 | # renpy/common/00updater.rpy:1462 885 | old "The updates have been installed. The program will restart." 886 | new "The updates have been installed. The program will restart." 887 | 888 | # renpy/common/00updater.rpy:1464 889 | old "The updates have been installed." 890 | new "The updates have been installed." 891 | 892 | # renpy/common/00updater.rpy:1466 893 | old "The updates were cancelled." 894 | new "The updates were cancelled." 895 | 896 | # renpy/common/00updater.rpy:1481 897 | old "Proceed" 898 | new "Proceed" 899 | 900 | # renpy/common/00compat.rpy:288 901 | old "Fullscreen" 902 | new "Fullscreen" 903 | 904 | # renpy/common/00gallery.rpy:592 905 | old "Image [index] of [count] locked." 906 | new "Image [index] of [count] locked." 907 | 908 | # renpy/common/00gallery.rpy:612 909 | old "prev" 910 | new "prev" 911 | 912 | # renpy/common/00gallery.rpy:613 913 | old "next" 914 | new "next" 915 | 916 | # renpy/common/00gallery.rpy:614 917 | old "slideshow" 918 | new "slideshow" 919 | 920 | # renpy/common/00gallery.rpy:615 921 | old "return" 922 | new "return" 923 | 924 | # renpy/common/00gltest.rpy:70 925 | old "Renderer" 926 | new "Renderer" 927 | 928 | # renpy/common/00gltest.rpy:74 929 | old "Automatically Choose" 930 | new "Automatically Choose" 931 | 932 | # renpy/common/00gltest.rpy:79 933 | old "Force Angle/DirectX Renderer" 934 | new "Force Angle/DirectX Renderer" 935 | 936 | # renpy/common/00gltest.rpy:83 937 | old "Force OpenGL Renderer" 938 | new "Force OpenGL Renderer" 939 | 940 | # renpy/common/00gltest.rpy:87 941 | old "Force Software Renderer" 942 | new "Force Software Renderer" 943 | 944 | # renpy/common/00gltest.rpy:93 945 | old "NPOT" 946 | new "NPOT" 947 | 948 | # renpy/common/00gltest.rpy:97 949 | old "Enable" 950 | new "Enable" 951 | 952 | # renpy/common/00gltest.rpy:101 953 | old "Disable" 954 | new "Disable" 955 | 956 | # renpy/common/00gltest.rpy:108 957 | old "Gamepad" 958 | new "Gamepad" 959 | 960 | # renpy/common/00gltest.rpy:122 961 | old "Calibrate" 962 | new "Calibrate" 963 | 964 | # renpy/common/00gltest.rpy:131 965 | old "Powersave" 966 | new "Powersave" 967 | 968 | # renpy/common/00gltest.rpy:145 969 | old "Framerate" 970 | new "Framerate" 971 | 972 | # renpy/common/00gltest.rpy:149 973 | old "Screen" 974 | new "Screen" 975 | 976 | # renpy/common/00gltest.rpy:153 977 | old "60" 978 | new "60" 979 | 980 | # renpy/common/00gltest.rpy:157 981 | old "30" 982 | new "30" 983 | 984 | # renpy/common/00gltest.rpy:163 985 | old "Tearing" 986 | new "Tearing" 987 | 988 | # renpy/common/00gltest.rpy:179 989 | old "Changes will take effect the next time this program is run." 990 | new "Changes will take effect the next time this program is run." 991 | 992 | # renpy/common/00gltest.rpy:186 993 | old "Quit" 994 | new "Quit" 995 | 996 | # renpy/common/00gltest.rpy:213 997 | old "Performance Warning" 998 | new "Performance Warning" 999 | 1000 | # renpy/common/00gltest.rpy:218 1001 | old "This computer is using software rendering." 1002 | new "This computer is using software rendering." 1003 | 1004 | # renpy/common/00gltest.rpy:220 1005 | old "This computer is not using shaders." 1006 | new "This computer is not using shaders." 1007 | 1008 | # renpy/common/00gltest.rpy:222 1009 | old "This computer is displaying graphics slowly." 1010 | new "This computer is displaying graphics slowly." 1011 | 1012 | # renpy/common/00gltest.rpy:224 1013 | old "This computer has a problem displaying graphics: [problem]." 1014 | new "This computer has a problem displaying graphics: [problem]." 1015 | 1016 | # renpy/common/00gltest.rpy:229 1017 | old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem." 1018 | new "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem." 1019 | 1020 | # renpy/common/00gltest.rpy:231 1021 | old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display." 1022 | new "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display." 1023 | 1024 | # renpy/common/00gltest.rpy:236 1025 | old "Update DirectX" 1026 | new "Update DirectX" 1027 | 1028 | # renpy/common/00gltest.rpy:242 1029 | old "Continue, Show this warning again" 1030 | new "Continue, Show this warning again" 1031 | 1032 | # renpy/common/00gltest.rpy:246 1033 | old "Continue, Don't show warning again" 1034 | new "Continue, Don't show warning again" 1035 | 1036 | # renpy/common/00gltest.rpy:264 1037 | old "Updating DirectX." 1038 | new "Updating DirectX." 1039 | 1040 | # renpy/common/00gltest.rpy:268 1041 | old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX." 1042 | new "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX." 1043 | 1044 | # renpy/common/00gltest.rpy:272 1045 | old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box." 1046 | new "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box." 1047 | 1048 | # renpy/common/00gltest.rpy:276 1049 | old "When setup finishes, please click below to restart this program." 1050 | new "When setup finishes, please click below to restart this program." 1051 | 1052 | # renpy/common/00gltest.rpy:278 1053 | old "Restart" 1054 | new "Restart" 1055 | 1056 | # renpy/common/00gamepad.rpy:32 1057 | old "Select Gamepad to Calibrate" 1058 | new "Select Gamepad to Calibrate" 1059 | 1060 | # renpy/common/00gamepad.rpy:35 1061 | old "No Gamepads Available" 1062 | new "No Gamepads Available" 1063 | 1064 | # renpy/common/00gamepad.rpy:54 1065 | old "Calibrating [name] ([i]/[total])" 1066 | new "Calibrating [name] ([i]/[total])" 1067 | 1068 | # renpy/common/00gamepad.rpy:58 1069 | old "Press or move the [control!r] [kind]." 1070 | new "Press or move the [control!r] [kind]." 1071 | 1072 | # renpy/common/00gamepad.rpy:66 1073 | old "Skip (A)" 1074 | new "Skip (A)" 1075 | 1076 | # renpy/common/00gamepad.rpy:69 1077 | old "Back (B)" 1078 | new "Back (B)" 1079 | 1080 | # renpy/common/_errorhandling.rpym:538 1081 | old "Open" 1082 | new "Open" 1083 | 1084 | # renpy/common/_errorhandling.rpym:540 1085 | old "Opens the traceback.txt file in a text editor." 1086 | new "Opens the traceback.txt file in a text editor." 1087 | 1088 | # renpy/common/_errorhandling.rpym:542 1089 | old "Copy BBCode" 1090 | new "Copy BBCode" 1091 | 1092 | # renpy/common/_errorhandling.rpym:544 1093 | old "Copies the traceback.txt file to the clipboard as BBcode for forums like https://lemmasoft.renai.us/." 1094 | new "Copies the traceback.txt file to the clipboard as BBcode for forums like https://lemmasoft.renai.us/." 1095 | 1096 | # renpy/common/_errorhandling.rpym:546 1097 | old "Copy Markdown" 1098 | new "Copy Markdown" 1099 | 1100 | # renpy/common/_errorhandling.rpym:548 1101 | old "Copies the traceback.txt file to the clipboard as Markdown for Discord." 1102 | new "Copies the traceback.txt file to the clipboard as Markdown for Discord." 1103 | 1104 | # renpy/common/_errorhandling.rpym:577 1105 | old "An exception has occurred." 1106 | new "An exception has occurred." 1107 | 1108 | # renpy/common/_errorhandling.rpym:597 1109 | old "Rollback" 1110 | new "Rollback" 1111 | 1112 | # renpy/common/_errorhandling.rpym:599 1113 | old "Attempts a roll back to a prior time, allowing you to save or choose a different choice." 1114 | new "Attempts a roll back to a prior time, allowing you to save or choose a different choice." 1115 | 1116 | # renpy/common/_errorhandling.rpym:602 1117 | old "Ignore" 1118 | new "Ignore" 1119 | 1120 | # renpy/common/_errorhandling.rpym:606 1121 | old "Ignores the exception, allowing you to continue." 1122 | new "Ignores the exception, allowing you to continue." 1123 | 1124 | # renpy/common/_errorhandling.rpym:608 1125 | old "Ignores the exception, allowing you to continue. This often leads to additional errors." 1126 | new "Ignores the exception, allowing you to continue. This often leads to additional errors." 1127 | 1128 | # renpy/common/_errorhandling.rpym:612 1129 | old "Reload" 1130 | new "Reload" 1131 | 1132 | # renpy/common/_errorhandling.rpym:614 1133 | old "Reloads the game from disk, saving and restoring game state if possible." 1134 | new "Reloads the game from disk, saving and restoring game state if possible." 1135 | 1136 | # renpy/common/_errorhandling.rpym:617 1137 | old "Console" 1138 | new "Console" 1139 | 1140 | # renpy/common/_errorhandling.rpym:619 1141 | old "Opens a console to allow debugging the problem." 1142 | new "Opens a console to allow debugging the problem." 1143 | 1144 | # renpy/common/_errorhandling.rpym:629 1145 | old "Quits the game." 1146 | new "Quits the game." 1147 | 1148 | # renpy/common/_errorhandling.rpym:653 1149 | old "Parsing the script failed." 1150 | new "Parsing the script failed." 1151 | 1152 | # renpy/common/_errorhandling.rpym:679 1153 | old "Opens the errors.txt file in a text editor." 1154 | new "Opens the errors.txt file in a text editor." 1155 | 1156 | # renpy/common/_errorhandling.rpym:683 1157 | old "Copies the errors.txt file to the clipboard as BBcode for forums like https://lemmasoft.renai.us/." 1158 | new "Copies the errors.txt file to the clipboard as BBcode for forums like https://lemmasoft.renai.us/." 1159 | 1160 | # renpy/common/_errorhandling.rpym:687 1161 | old "Copies the errors.txt file to the clipboard as Markdown for Discord." 1162 | new "Copies the errors.txt file to the clipboard as Markdown for Discord." 1163 | 1164 | # renpy/common/00console.rpy:273 1165 | old "Press to exit console. Type help for help.\n" 1166 | new "Press to exit console. Type help for help.\n" 1167 | 1168 | # renpy/common/00console.rpy:277 1169 | old "Ren'Py script enabled." 1170 | new "Ren'Py script enabled." 1171 | 1172 | # renpy/common/00console.rpy:279 1173 | old "Ren'Py script disabled." 1174 | new "Ren'Py script disabled." 1175 | 1176 | # renpy/common/00console.rpy:526 1177 | old "help: show this help" 1178 | new "help: show this help" 1179 | 1180 | # renpy/common/00console.rpy:531 1181 | old "commands:\n" 1182 | new "commands:\n" 1183 | 1184 | # renpy/common/00console.rpy:541 1185 | old " : run the statement\n" 1186 | new " : run the statement\n" 1187 | 1188 | # renpy/common/00console.rpy:543 1189 | old " : run the expression or statement" 1190 | new " : run the expression or statement" 1191 | 1192 | # renpy/common/00console.rpy:551 1193 | old "clear: clear the console history" 1194 | new "clear: clear the console history" 1195 | 1196 | # renpy/common/00console.rpy:555 1197 | old "exit: exit the console" 1198 | new "exit: exit the console" 1199 | 1200 | # renpy/common/00console.rpy:563 1201 | old "load : loads the game from slot" 1202 | new "load : loads the game from slot" 1203 | 1204 | # renpy/common/00console.rpy:576 1205 | old "save : saves the game in slot" 1206 | new "save : saves the game in slot" 1207 | 1208 | # renpy/common/00console.rpy:587 1209 | old "reload: reloads the game, refreshing the scripts" 1210 | new "reload: reloads the game, refreshing the scripts" 1211 | 1212 | # renpy/common/00console.rpy:595 1213 | old "watch : watch a python expression" 1214 | new "watch : watch a python expression" 1215 | 1216 | # renpy/common/00console.rpy:621 1217 | old "unwatch : stop watching an expression" 1218 | new "unwatch : stop watching an expression" 1219 | 1220 | # renpy/common/00console.rpy:652 1221 | old "unwatchall: stop watching all expressions" 1222 | new "unwatchall: stop watching all expressions" 1223 | 1224 | # renpy/common/00console.rpy:669 1225 | old "jump