├── .gitignore ├── License ├── README.md ├── __jamo.py ├── audio_loader_for_gui.py ├── audio_player_for_gui.py ├── data └── KoreanSyllableData │ ├── U+11xx.json │ └── U+31xx.json ├── pyanimalese_cli.py ├── pyanimalese_gui.py ├── requirements.txt └── sources ├── 01.padata ├── 02.padata ├── 03.padata ├── 04.padata ├── 05.padata ├── 06.padata ├── 07.padata ├── 08.padata ├── 09.padata ├── 10.padata ├── 11.padata ├── 12.padata ├── 13.padata ├── 14.padata ├── 15.padata ├── 16.padata ├── 17.padata ├── 18.padata ├── 19.padata ├── 20.padata └── high ├── 01.padata ├── 02.padata ├── 03.padata ├── 04.padata ├── 05.padata ├── 06.padata ├── 07.padata ├── 08.padata ├── 09.padata ├── 10.padata ├── 11.padata ├── 12.padata ├── 13.padata ├── 14.padata ├── 15.padata ├── 16.padata ├── 17.padata ├── 18.padata ├── 19.padata └── 20.padata /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .idea/ -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ju Hwijung 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyAnimalese에 대하여 2 | 동물의 숲 NPC 목소리로 문장을 읽어주는 프로그램입니다. 3 | 4 | ## 지원 언어 5 | - 한국어 6 | 7 | ## 시연영상 8 | - [링크(YouTube)](https://www.youtube.com/watch?v=MsUTd79QnuI) 9 | 10 | ## 원리 11 | 1. 한글로 문자열을 입력 받는다. 12 | 2. 문자열을 순회하면서 자모를 분리해서 초성만 얻어낸다. 13 | 3. 미리 녹음해둔 해당 초성의 발음파일(e.g. 'ㄱ'은 '그' 처럼 어중간하게 발음함)을 가져온다. 14 | 4. 피치를 높인다. 이 때, 랜덤으로 피치 값을 조절한다. 15 | 5. 하나로 합쳐서 재생(저장)한다. 16 | 17 | ## 실행하기 18 | - 방법1: pyanimalese_cli.py를 직접 실행합니다. 이때, sources 폴더가 필요하며 아래의 디펜던시 패키지를 설치해야합니다. 19 | - 방법2: 릴리즈 버전을 다운로드하여 GUI로 사용합니다. [바로가기](https://github.com/hwi-middle/PyAnimalese/releases) 20 | 21 | 주의: 두 방법 모두 ffmpeg이 설치되어있어야합니다. 22 | 23 | ## 디펜던시 24 | - [Pydub](https://github.com/jiaaro/pydub) 25 | - [Jamo](https://github.com/JDongian/python-jamo) 26 | - [PyAudio](https://people.csail.mit.edu/hubert/pyaudio/) 27 | 28 | ## 디펜던시 패키지 설치 (Windows 기준) 29 | ```pip install -r requirements.txt``` 30 | 31 | ```pipwin install pyaudio``` 32 | 33 | 주의: PyAudio는 pipwin으로 별도로 설치해야합니다. 34 | 35 | -------------------------------------------------------------------------------- /__jamo.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Syllable and jamo analysis for Korean. Default internal exchange form is 3 | Hangul characters, not codepoints. Jamo exchange form is U+11xx characters, 4 | not U+3xxx Hangul Compatibility Jamo (HCJ) characters or codepoints. 5 | 6 | For more information, see: 7 | http://python-jamo.readthedocs.org/ko/latest/ 8 | """ 9 | 10 | import sys 11 | import os 12 | from sys import stderr 13 | from itertools import chain 14 | import json 15 | import re 16 | 17 | 18 | _ROOT = '\\'.join(sys.executable.split('\\')[0:-1]) + '\\data' 19 | 20 | _JAMO_OFFSET = 44032 21 | _JAMO_LEAD_OFFSET = 0x10ff 22 | _JAMO_VOWEL_OFFSET = 0x1160 23 | _JAMO_TAIL_OFFSET = 0x11a7 24 | 25 | with open(os.path.join(_ROOT, 'KoreanSyllableData', "U+11xx.json"), 'r') as namedata: 26 | _JAMO_TO_NAME = json.load(namedata) 27 | _JAMO_REVERSE_LOOKUP = {name: char for char, name in _JAMO_TO_NAME.items()} 28 | with open(os.path.join(_ROOT, 'KoreanSyllableData', "U+31xx.json"), 'r') as namedata: 29 | _HCJ_TO_NAME = json.load(namedata) 30 | _HCJ_REVERSE_LOOKUP = {name: char for char, name in _HCJ_TO_NAME.items()} 31 | 32 | JAMO_LEADS = [chr(_) for _ in range(0x1100, 0x115F)] 33 | JAMO_LEADS_MODERN = [chr(_) for _ in range(0x1100, 0x1113)] 34 | JAMO_VOWELS = [chr(_) for _ in range(0x1161, 0x11A8)] 35 | JAMO_VOWELS_MODERN = [chr(_) for _ in range(0x1161, 0x1176)] 36 | JAMO_TAILS = [chr(_) for _ in range(0x11A8, 0x1200)] 37 | JAMO_TAILS_MODERN = [chr(_) for _ in range(0x11A8, 0x11C3)] 38 | 39 | 40 | class InvalidJamoError(Exception): 41 | """jamo is a U+11xx codepoint.""" 42 | def __init__(self, message, jamo): 43 | super(InvalidJamoError, self).__init__(message) 44 | self.jamo = hex(ord(jamo)) 45 | print("Could not parse jamo: U+{code}".format(code=self.jamo[2:]), 46 | file=stderr) 47 | 48 | 49 | def _hangul_char_to_jamo(syllable): 50 | """Return a 3-tuple of lead, vowel, and tail jamo characters. 51 | Note: Non-Hangul characters are echoed back. 52 | """ 53 | if is_hangul_char(syllable): 54 | rem = ord(syllable) - _JAMO_OFFSET 55 | tail = rem % 28 56 | vowel = 1 + ((rem - tail) % 588) // 28 57 | lead = 1 + rem // 588 58 | if tail: 59 | return (chr(lead + _JAMO_LEAD_OFFSET), 60 | chr(vowel + _JAMO_VOWEL_OFFSET), 61 | chr(tail + _JAMO_TAIL_OFFSET)) 62 | else: 63 | return (chr(lead + _JAMO_LEAD_OFFSET), 64 | chr(vowel + _JAMO_VOWEL_OFFSET)) 65 | else: 66 | return syllable 67 | 68 | 69 | def _jamo_to_hangul_char(lead, vowel, tail=0): 70 | """Return the Hangul character for the given jamo characters. 71 | """ 72 | lead = ord(lead) - _JAMO_LEAD_OFFSET 73 | vowel = ord(vowel) - _JAMO_VOWEL_OFFSET 74 | tail = ord(tail) - _JAMO_TAIL_OFFSET if tail else 0 75 | return chr(tail + (vowel - 1) * 28 + (lead - 1) * 588 + _JAMO_OFFSET) 76 | 77 | 78 | def _jamo_char_to_hcj(char): 79 | if is_jamo(char): 80 | hcj_name = re.sub("(?<=HANGUL )(\w+)", 81 | "LETTER", 82 | _get_unicode_name(char)) 83 | if hcj_name in _HCJ_REVERSE_LOOKUP.keys(): 84 | return _HCJ_REVERSE_LOOKUP[hcj_name] 85 | return char 86 | 87 | 88 | def _get_unicode_name(char): 89 | """Fetch the unicode name for jamo characters. 90 | """ 91 | if char not in _JAMO_TO_NAME.keys() and char not in _HCJ_TO_NAME.keys(): 92 | raise InvalidJamoError("Not jamo or nameless jamo character", char) 93 | else: 94 | if is_hcj(char): 95 | return _HCJ_TO_NAME[char] 96 | return _JAMO_TO_NAME[char] 97 | 98 | 99 | def is_jamo(character): 100 | """Test if a single character is a jamo character. 101 | Valid jamo includes all modern and archaic jamo, as well as all HCJ. 102 | Non-assigned code points are invalid. 103 | """ 104 | code = ord(character) 105 | return 0x1100 <= code <= 0x11FF or\ 106 | 0xA960 <= code <= 0xA97C or\ 107 | 0xD7B0 <= code <= 0xD7C6 or 0xD7CB <= code <= 0xD7FB or\ 108 | is_hcj(character) 109 | 110 | 111 | def is_jamo_modern(character): 112 | """Test if a single character is a modern jamo character. 113 | Modern jamo includes all U+11xx jamo in addition to HCJ in modern usage, 114 | as defined in Unicode 7.0. 115 | WARNING: U+1160 is NOT considered a modern jamo character, but it is listed 116 | under 'Medial Vowels' in the Unicode 7.0 spec. 117 | """ 118 | code = ord(character) 119 | return 0x1100 <= code <= 0x1112 or\ 120 | 0x1161 <= code <= 0x1175 or\ 121 | 0x11A8 <= code <= 0x11C2 or\ 122 | is_hcj_modern(character) 123 | 124 | 125 | def is_hcj(character): 126 | """Test if a single character is a HCJ character. 127 | HCJ is defined as the U+313x to U+318x block, sans two non-assigned code 128 | points. 129 | """ 130 | return 0x3131 <= ord(character) <= 0x318E and ord(character) != 0x3164 131 | 132 | 133 | def is_hcj_modern(character): 134 | """Test if a single character is a modern HCJ character. 135 | Modern HCJ is defined as HCJ that corresponds to a U+11xx jamo character 136 | in modern usage. 137 | """ 138 | code = ord(character) 139 | return 0x3131 <= code <= 0x314E or\ 140 | 0x314F <= code <= 0x3163 141 | 142 | 143 | def is_hangul_char(character): 144 | """Test if a single character is in the U+AC00 to U+D7A3 code block, 145 | excluding unassigned codes. 146 | """ 147 | return 0xAC00 <= ord(character) <= 0xD7A3 148 | 149 | 150 | def get_jamo_class(jamo): 151 | """Determine if a jamo character is a lead, vowel, or tail. 152 | Integers and U+11xx characters are valid arguments. HCJ consonants are not 153 | valid here. 154 | 155 | get_jamo_class should return the class ["lead" | "vowel" | "tail"] of a 156 | given character or integer. 157 | 158 | Note: jamo class directly corresponds to the Unicode 7.0 specification, 159 | thus includes filler characters as having a class. 160 | """ 161 | # TODO: Perhaps raise a separate error for U+3xxx jamo. 162 | if jamo in JAMO_LEADS or jamo == chr(0x115F): 163 | return "lead" 164 | if jamo in JAMO_VOWELS or jamo == chr(0x1160) or\ 165 | 0x314F <= ord(jamo) <= 0x3163: 166 | return "vowel" 167 | if jamo in JAMO_TAILS: 168 | return "tail" 169 | else: 170 | raise InvalidJamoError("Invalid or classless jamo argument.", jamo) 171 | 172 | 173 | def jamo_to_hcj(data): 174 | """Convert jamo to HCJ. 175 | Arguments may be iterables or single characters. 176 | 177 | jamo_to_hcj should convert every jamo character into HCJ in a given input, 178 | if possible. Anything else is unchanged. 179 | 180 | jamo_to_hcj is the generator version of j2hcj, the string version. Passing 181 | a character to jamo_to_hcj will still return a generator. 182 | """ 183 | return (_jamo_char_to_hcj(_) for _ in data) 184 | 185 | 186 | def j2hcj(jamo): 187 | """Convert jamo into HCJ. 188 | Arguments may be iterables or single characters. 189 | 190 | j2hcj should convert every jamo character into HCJ in a given input, if 191 | possible. Anything else is unchanged. 192 | 193 | j2hcj is the string version of jamo_to_hcj, the generator version. 194 | """ 195 | return ''.join(jamo_to_hcj(jamo)) 196 | 197 | 198 | def hcj_to_jamo(hcj_char, position="vowel"): 199 | """Convert a HCJ character to a jamo character. 200 | Arguments may be single characters along with the desired jamo class 201 | (lead, vowel, tail). Non-mappable input will raise an InvalidJamoError. 202 | """ 203 | if position == "lead": 204 | jamo_class = "CHOSEONG" 205 | elif position == "vowel": 206 | jamo_class = "JUNGSEONG" 207 | elif position == "tail": 208 | jamo_class = "JONGSEONG" 209 | else: 210 | raise InvalidJamoError("No mapping from input to jamo.", hcj_char) 211 | jamo_name = re.sub("(?<=HANGUL )(\w+)", 212 | jamo_class, 213 | _get_unicode_name(hcj_char)) 214 | # TODO: add tests that test non entries. 215 | if jamo_name in _JAMO_REVERSE_LOOKUP.keys(): 216 | return _JAMO_REVERSE_LOOKUP[jamo_name] 217 | return hcj_char 218 | 219 | 220 | def hcj2j(hcj_char, position="vowel"): 221 | """Convert a HCJ character to a jamo character. 222 | Identical to hcj_to_jamo. 223 | """ 224 | return hcj_to_jamo(hcj_char, position) 225 | 226 | 227 | def hangul_to_jamo(hangul_string): 228 | """Convert a string of Hangul to jamo. 229 | Arguments may be iterables of characters. 230 | 231 | hangul_to_jamo should split every Hangul character into U+11xx jamo 232 | characters for any given string. Non-hangul characters are not changed. 233 | 234 | hangul_to_jamo is the generator version of h2j, the string version. 235 | """ 236 | 237 | return (_ for _ in 238 | chain.from_iterable(_hangul_char_to_jamo(_) for _ in 239 | hangul_string)) 240 | 241 | 242 | def h2j(hangul_string): 243 | """Convert a string of Hangul to jamo. 244 | Arguments may be iterables of characters. 245 | 246 | h2j should split every Hangul character into U+11xx jamo for any given 247 | string. Non-hangul characters are not touched. 248 | 249 | h2j is the string version of hangul_to_jamo, the generator version. 250 | """ 251 | 252 | return ''.join(hangul_to_jamo(hangul_string)) 253 | 254 | 255 | def jamo_to_hangul(lead, vowel, tail=''): 256 | """Return the Hangul character for the given jamo input. 257 | Integers corresponding to U+11xx jamo codepoints, U+11xx jamo characters, 258 | or HCJ are valid inputs. 259 | 260 | Outputs a one-character Hangul string. 261 | 262 | This function is identical to j2h. 263 | """ 264 | # Internally, we convert everything to a jamo char, 265 | # then pass it to _jamo_to_hangul_char 266 | lead = hcj_to_jamo(lead, "lead") 267 | vowel = hcj_to_jamo(vowel, "vowel") 268 | if not tail or ord(tail) == 0: 269 | tail = None 270 | elif is_hcj(tail): 271 | tail = hcj_to_jamo(tail, "tail") 272 | if (is_jamo(lead) and get_jamo_class(lead) == "lead") and\ 273 | (is_jamo(vowel) and get_jamo_class(vowel) == "vowel") and\ 274 | ((not tail) or (is_jamo(tail) and get_jamo_class(tail) == "tail")): 275 | result = _jamo_to_hangul_char(lead, vowel, tail) 276 | if is_hangul_char(result): 277 | return result 278 | raise InvalidJamoError("Could not synthesize characters to Hangul.", 279 | '\x00') 280 | 281 | 282 | def j2h(lead, vowel, tail=0): 283 | """Arguments may be integers corresponding to the U+11xx codepoints, the 284 | actual U+11xx jamo characters, or HCJ. 285 | 286 | Outputs a one-character Hangul string. 287 | 288 | This function is defined solely for naming conisistency with 289 | jamo_to_hangul. 290 | """ 291 | 292 | return jamo_to_hangul(lead, vowel, tail) 293 | 294 | 295 | def synth_hangul(string): 296 | """Convert jamo characters in a string into hcj as much as possible.""" 297 | raise NotImplementedError 298 | return ''.join([''.join(''.join(jamo_to_hcj(_)) for _ in string)]) 299 | -------------------------------------------------------------------------------- /audio_loader_for_gui.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtCore import * 2 | from pydub import AudioSegment 3 | 4 | 5 | class WorkerSignals(QObject): 6 | result = pyqtSignal(object, object) # create a signal that gets an object as argument 7 | 8 | 9 | class myloader(QRunnable): 10 | def __init__(self, path, char): 11 | super().__init__() 12 | self.char = char 13 | self.path = path 14 | self.signals = WorkerSignals() 15 | 16 | @pyqtSlot() 17 | def run(self): 18 | data = AudioSegment.from_mp3(self.path) 19 | self.signals.result.emit(data, self.char) 20 | -------------------------------------------------------------------------------- /audio_player_for_gui.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtCore import QRunnable, pyqtSlot 2 | from pydub.playback import play 3 | 4 | 5 | class myplayer(QRunnable): 6 | def __init__(self, sound): 7 | super().__init__() 8 | self.sound = sound 9 | 10 | @pyqtSlot() 11 | def run(self): 12 | print('시작') 13 | play(self.sound) 14 | print('끝') 15 | -------------------------------------------------------------------------------- /data/KoreanSyllableData/U+11xx.json: -------------------------------------------------------------------------------- 1 | { 2 | "\u1100": "HANGUL CHOSEONG KIYEOK", 3 | "\u1101": "HANGUL CHOSEONG SSANGKIYEOK", 4 | "\u1102": "HANGUL CHOSEONG NIEUN", 5 | "\u1103": "HANGUL CHOSEONG TIKEUT", 6 | "\u1104": "HANGUL CHOSEONG SSANGTIKEUT", 7 | "\u1105": "HANGUL CHOSEONG RIEUL", 8 | "\u1106": "HANGUL CHOSEONG MIEUM", 9 | "\u1107": "HANGUL CHOSEONG PIEUP", 10 | "\u1108": "HANGUL CHOSEONG SSANGPIEUP", 11 | "\u1109": "HANGUL CHOSEONG SIOS", 12 | "\u110a": "HANGUL CHOSEONG SSANGSIOS", 13 | "\u110b": "HANGUL CHOSEONG IEUNG", 14 | "\u110c": "HANGUL CHOSEONG CIEUC", 15 | "\u110d": "HANGUL CHOSEONG SSANGCIEUC", 16 | "\u110e": "HANGUL CHOSEONG CHIEUCH", 17 | "\u110f": "HANGUL CHOSEONG KHIEUKH", 18 | "\u1110": "HANGUL CHOSEONG THIEUTH", 19 | "\u1111": "HANGUL CHOSEONG PHIEUPH", 20 | "\u1112": "HANGUL CHOSEONG HIEUH", 21 | "\u1113": "HANGUL CHOSEONG NIEUN-KIYEOK", 22 | "\u1114": "HANGUL CHOSEONG SSANGNIEUN", 23 | "\u1115": "HANGUL CHOSEONG NIEUN-TIKEUT", 24 | "\u1116": "HANGUL CHOSEONG NIEUN-PIEUP", 25 | "\u1117": "HANGUL CHOSEONG TIKEUT-KIYEOK", 26 | "\u1118": "HANGUL CHOSEONG RIEUL-NIEUN", 27 | "\u1119": "HANGUL CHOSEONG SSANGRIEUL", 28 | "\u111a": "HANGUL CHOSEONG RIEUL-HIEUH", 29 | "\u111b": "HANGUL CHOSEONG KAPYEOUNRIEUL", 30 | "\u111c": "HANGUL CHOSEONG MIEUM-PIEUP", 31 | "\u111d": "HANGUL CHOSEONG KAPYEOUNMIEUM", 32 | "\u111e": "HANGUL CHOSEONG PIEUP-KIYEOK", 33 | "\u111f": "HANGUL CHOSEONG PIEUP-NIEUN", 34 | "\u1120": "HANGUL CHOSEONG PIEUP-TIKEUT", 35 | "\u1121": "HANGUL CHOSEONG PIEUP-SIOS", 36 | "\u1122": "HANGUL CHOSEONG PIEUP-SIOS-KIYEOK", 37 | "\u1123": "HANGUL CHOSEONG PIEUP-SIOS-TIKEUT", 38 | "\u1124": "HANGUL CHOSEONG PIEUP-SIOS-PIEUP", 39 | "\u1125": "HANGUL CHOSEONG PIEUP-SSANGSIOS", 40 | "\u1126": "HANGUL CHOSEONG PIEUP-SIOS-CIEUC", 41 | "\u1127": "HANGUL CHOSEONG PIEUP-CIEUC", 42 | "\u1128": "HANGUL CHOSEONG PIEUP-CHIEUCH", 43 | "\u1129": "HANGUL CHOSEONG PIEUP-THIEUTH", 44 | "\u112a": "HANGUL CHOSEONG PIEUP-PHIEUPH", 45 | "\u112b": "HANGUL CHOSEONG KAPYEOUNPIEUP", 46 | "\u112c": "HANGUL CHOSEONG KAPYEOUNSSANGPIEUP", 47 | "\u112d": "HANGUL CHOSEONG SIOS-KIYEOK", 48 | "\u112e": "HANGUL CHOSEONG SIOS-NIEUN", 49 | "\u112f": "HANGUL CHOSEONG SIOS-TIKEUT", 50 | "\u1130": "HANGUL CHOSEONG SIOS-RIEUL", 51 | "\u1131": "HANGUL CHOSEONG SIOS-MIEUM", 52 | "\u1132": "HANGUL CHOSEONG SIOS-PIEUP", 53 | "\u1133": "HANGUL CHOSEONG SIOS-PIEUP-KIYEOK", 54 | "\u1134": "HANGUL CHOSEONG SIOS-SSANGSIOS", 55 | "\u1135": "HANGUL CHOSEONG SIOS-IEUNG", 56 | "\u1136": "HANGUL CHOSEONG SIOS-CIEUC", 57 | "\u1137": "HANGUL CHOSEONG SIOS-CHIEUCH", 58 | "\u1138": "HANGUL CHOSEONG SIOS-KHIEUKH", 59 | "\u1139": "HANGUL CHOSEONG SIOS-THIEUTH", 60 | "\u113a": "HANGUL CHOSEONG SIOS-PHIEUPH", 61 | "\u113b": "HANGUL CHOSEONG SIOS-HIEUH", 62 | "\u113c": "HANGUL CHOSEONG CHITUEUMSIOS", 63 | "\u113d": "HANGUL CHOSEONG CHITUEUMSSANGSIOS", 64 | "\u113e": "HANGUL CHOSEONG CEONGCHIEUMSIOS", 65 | "\u113f": "HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS", 66 | "\u1140": "HANGUL CHOSEONG PANSIOS", 67 | "\u1141": "HANGUL CHOSEONG IEUNG-KIYEOK", 68 | "\u1142": "HANGUL CHOSEONG IEUNG-TIKEUT", 69 | "\u1143": "HANGUL CHOSEONG IEUNG-MIEUM", 70 | "\u1144": "HANGUL CHOSEONG IEUNG-PIEUP", 71 | "\u1145": "HANGUL CHOSEONG IEUNG-SIOS", 72 | "\u1146": "HANGUL CHOSEONG IEUNG-PANSIOS", 73 | "\u1147": "HANGUL CHOSEONG SSANGIEUNG", 74 | "\u1148": "HANGUL CHOSEONG IEUNG-CIEUC", 75 | "\u1149": "HANGUL CHOSEONG IEUNG-CHIEUCH", 76 | "\u114a": "HANGUL CHOSEONG IEUNG-THIEUTH", 77 | "\u114b": "HANGUL CHOSEONG IEUNG-PHIEUPH", 78 | "\u114c": "HANGUL CHOSEONG YESIEUNG", 79 | "\u114d": "HANGUL CHOSEONG CIEUC-IEUNG", 80 | "\u114e": "HANGUL CHOSEONG CHITUEUMCIEUC", 81 | "\u114f": "HANGUL CHOSEONG CHITUEUMSSANGCIEUC", 82 | "\u1150": "HANGUL CHOSEONG CEONGCHIEUMCIEUC", 83 | "\u1151": "HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC", 84 | "\u1152": "HANGUL CHOSEONG CHIEUCH-KHIEUKH", 85 | "\u1153": "HANGUL CHOSEONG CHIEUCH-HIEUH", 86 | "\u1154": "HANGUL CHOSEONG CHITUEUMCHIEUCH", 87 | "\u1155": "HANGUL CHOSEONG CEONGCHIEUMCHIEUCH", 88 | "\u1156": "HANGUL CHOSEONG PHIEUPH-PIEUP", 89 | "\u1157": "HANGUL CHOSEONG KAPYEOUNPHIEUPH", 90 | "\u1158": "HANGUL CHOSEONG SSANGHIEUH", 91 | "\u1159": "HANGUL CHOSEONG YEORINHIEUH", 92 | "\u115a": "HANGUL CHOSEONG KIYEOK-TIKEUT", 93 | "\u115b": "HANGUL CHOSEONG NIEUN-SIOS", 94 | "\u115c": "HANGUL CHOSEONG NIEUN-CIEUC", 95 | "\u115d": "HANGUL CHOSEONG NIEUN-HIEUH", 96 | "\u115e": "HANGUL CHOSEONG TIKEUT-RIEUL", 97 | "\u115f": "HANGUL CHOSEONG FILLER", 98 | "\u1160": "HANGUL JUNGSEONG FILLER", 99 | "\u1161": "HANGUL JUNGSEONG A", 100 | "\u1162": "HANGUL JUNGSEONG AE", 101 | "\u1163": "HANGUL JUNGSEONG YA", 102 | "\u1164": "HANGUL JUNGSEONG YAE", 103 | "\u1165": "HANGUL JUNGSEONG EO", 104 | "\u1166": "HANGUL JUNGSEONG E", 105 | "\u1167": "HANGUL JUNGSEONG YEO", 106 | "\u1168": "HANGUL JUNGSEONG YE", 107 | "\u1169": "HANGUL JUNGSEONG O", 108 | "\u116a": "HANGUL JUNGSEONG WA", 109 | "\u116b": "HANGUL JUNGSEONG WAE", 110 | "\u116c": "HANGUL JUNGSEONG OE", 111 | "\u116d": "HANGUL JUNGSEONG YO", 112 | "\u116e": "HANGUL JUNGSEONG U", 113 | "\u116f": "HANGUL JUNGSEONG WEO", 114 | "\u1170": "HANGUL JUNGSEONG WE", 115 | "\u1171": "HANGUL JUNGSEONG WI", 116 | "\u1172": "HANGUL JUNGSEONG YU", 117 | "\u1173": "HANGUL JUNGSEONG EU", 118 | "\u1174": "HANGUL JUNGSEONG YI", 119 | "\u1175": "HANGUL JUNGSEONG I", 120 | "\u1176": "HANGUL JUNGSEONG A-O", 121 | "\u1177": "HANGUL JUNGSEONG A-U", 122 | "\u1178": "HANGUL JUNGSEONG YA-O", 123 | "\u1179": "HANGUL JUNGSEONG YA-YO", 124 | "\u117a": "HANGUL JUNGSEONG EO-O", 125 | "\u117b": "HANGUL JUNGSEONG EO-U", 126 | "\u117c": "HANGUL JUNGSEONG EO-EU", 127 | "\u117d": "HANGUL JUNGSEONG YEO-O", 128 | "\u117e": "HANGUL JUNGSEONG YEO-U", 129 | "\u117f": "HANGUL JUNGSEONG O-EO", 130 | "\u1180": "HANGUL JUNGSEONG O-E", 131 | "\u1181": "HANGUL JUNGSEONG O-YE", 132 | "\u1182": "HANGUL JUNGSEONG O-O", 133 | "\u1183": "HANGUL JUNGSEONG O-U", 134 | "\u1184": "HANGUL JUNGSEONG YO-YA", 135 | "\u1185": "HANGUL JUNGSEONG YO-YAE", 136 | "\u1186": "HANGUL JUNGSEONG YO-YEO", 137 | "\u1187": "HANGUL JUNGSEONG YO-O", 138 | "\u1188": "HANGUL JUNGSEONG YO-I", 139 | "\u1189": "HANGUL JUNGSEONG U-A", 140 | "\u118a": "HANGUL JUNGSEONG U-AE", 141 | "\u118b": "HANGUL JUNGSEONG U-EO-EU", 142 | "\u118c": "HANGUL JUNGSEONG U-YE", 143 | "\u118d": "HANGUL JUNGSEONG U-U", 144 | "\u118e": "HANGUL JUNGSEONG YU-A", 145 | "\u118f": "HANGUL JUNGSEONG YU-EO", 146 | "\u1190": "HANGUL JUNGSEONG YU-E", 147 | "\u1191": "HANGUL JUNGSEONG YU-YEO", 148 | "\u1192": "HANGUL JUNGSEONG YU-YE", 149 | "\u1193": "HANGUL JUNGSEONG YU-U", 150 | "\u1194": "HANGUL JUNGSEONG YU-I", 151 | "\u1195": "HANGUL JUNGSEONG EU-U", 152 | "\u1196": "HANGUL JUNGSEONG EU-EU", 153 | "\u1197": "HANGUL JUNGSEONG YI-U", 154 | "\u1198": "HANGUL JUNGSEONG I-A", 155 | "\u1199": "HANGUL JUNGSEONG I-YA", 156 | "\u119a": "HANGUL JUNGSEONG I-O", 157 | "\u119b": "HANGUL JUNGSEONG I-U", 158 | "\u119c": "HANGUL JUNGSEONG I-EU", 159 | "\u119d": "HANGUL JUNGSEONG I-ARAEA", 160 | "\u119e": "HANGUL JUNGSEONG ARAEA", 161 | "\u119f": "HANGUL JUNGSEONG ARAEA-EO", 162 | "\u11a0": "HANGUL JUNGSEONG ARAEA-U", 163 | "\u11a1": "HANGUL JUNGSEONG ARAEA-I", 164 | "\u11a2": "HANGUL JUNGSEONG SSANGARAEA", 165 | "\u11a3": "HANGUL JUNGSEONG A-EU", 166 | "\u11a4": "HANGUL JUNGSEONG YA-U", 167 | "\u11a5": "HANGUL JUNGSEONG YEO-YA", 168 | "\u11a6": "HANGUL JUNGSEONG O-YA", 169 | "\u11a7": "HANGUL JUNGSEONG O-YAE", 170 | "\u11a8": "HANGUL JONGSEONG KIYEOK", 171 | "\u11a9": "HANGUL JONGSEONG SSANGKIYEOK", 172 | "\u11aa": "HANGUL JONGSEONG KIYEOK-SIOS", 173 | "\u11ab": "HANGUL JONGSEONG NIEUN", 174 | "\u11ac": "HANGUL JONGSEONG NIEUN-CIEUC", 175 | "\u11ad": "HANGUL JONGSEONG NIEUN-HIEUH", 176 | "\u11ae": "HANGUL JONGSEONG TIKEUT", 177 | "\u11af": "HANGUL JONGSEONG RIEUL", 178 | "\u11b0": "HANGUL JONGSEONG RIEUL-KIYEOK", 179 | "\u11b1": "HANGUL JONGSEONG RIEUL-MIEUM", 180 | "\u11b2": "HANGUL JONGSEONG RIEUL-PIEUP", 181 | "\u11b3": "HANGUL JONGSEONG RIEUL-SIOS", 182 | "\u11b4": "HANGUL JONGSEONG RIEUL-THIEUTH", 183 | "\u11b5": "HANGUL JONGSEONG RIEUL-PHIEUPH", 184 | "\u11b6": "HANGUL JONGSEONG RIEUL-HIEUH", 185 | "\u11b7": "HANGUL JONGSEONG MIEUM", 186 | "\u11b8": "HANGUL JONGSEONG PIEUP", 187 | "\u11b9": "HANGUL JONGSEONG PIEUP-SIOS", 188 | "\u11ba": "HANGUL JONGSEONG SIOS", 189 | "\u11bb": "HANGUL JONGSEONG SSANGSIOS", 190 | "\u11bc": "HANGUL JONGSEONG IEUNG", 191 | "\u11bd": "HANGUL JONGSEONG CIEUC", 192 | "\u11be": "HANGUL JONGSEONG CHIEUCH", 193 | "\u11bf": "HANGUL JONGSEONG KHIEUKH", 194 | "\u11c0": "HANGUL JONGSEONG THIEUTH", 195 | "\u11c1": "HANGUL JONGSEONG PHIEUPH", 196 | "\u11c2": "HANGUL JONGSEONG HIEUH", 197 | "\u11c3": "HANGUL JONGSEONG KIYEOK-RIEUL", 198 | "\u11c4": "HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK", 199 | "\u11c5": "HANGUL JONGSEONG NIEUN-KIYEOK", 200 | "\u11c6": "HANGUL JONGSEONG NIEUN-TIKEUT", 201 | "\u11c7": "HANGUL JONGSEONG NIEUN-SIOS", 202 | "\u11c8": "HANGUL JONGSEONG NIEUN-PANSIOS", 203 | "\u11c9": "HANGUL JONGSEONG NIEUN-THIEUTH", 204 | "\u11ca": "HANGUL JONGSEONG TIKEUT-KIYEOK", 205 | "\u11cb": "HANGUL JONGSEONG TIKEUT-RIEUL", 206 | "\u11cc": "HANGUL JONGSEONG RIEUL-KIYEOK-SIOS", 207 | "\u11cd": "HANGUL JONGSEONG RIEUL-NIEUN", 208 | "\u11ce": "HANGUL JONGSEONG RIEUL-TIKEUT", 209 | "\u11cf": "HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH", 210 | "\u11d0": "HANGUL JONGSEONG SSANGRIEUL", 211 | "\u11d1": "HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK", 212 | "\u11d2": "HANGUL JONGSEONG RIEUL-MIEUM-SIOS", 213 | "\u11d3": "HANGUL JONGSEONG RIEUL-PIEUP-SIOS", 214 | "\u11d4": "HANGUL JONGSEONG RIEUL-PIEUP-HIEUH", 215 | "\u11d5": "HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP", 216 | "\u11d6": "HANGUL JONGSEONG RIEUL-SSANGSIOS", 217 | "\u11d7": "HANGUL JONGSEONG RIEUL-PANSIOS", 218 | "\u11d8": "HANGUL JONGSEONG RIEUL-KHIEUKH", 219 | "\u11d9": "HANGUL JONGSEONG RIEUL-YEORINHIEUH", 220 | "\u11da": "HANGUL JONGSEONG MIEUM-KIYEOK", 221 | "\u11db": "HANGUL JONGSEONG MIEUM-RIEUL", 222 | "\u11dc": "HANGUL JONGSEONG MIEUM-PIEUP", 223 | "\u11dd": "HANGUL JONGSEONG MIEUM-SIOS", 224 | "\u11de": "HANGUL JONGSEONG MIEUM-SSANGSIOS", 225 | "\u11df": "HANGUL JONGSEONG MIEUM-PANSIOS", 226 | "\u11e0": "HANGUL JONGSEONG MIEUM-CHIEUCH", 227 | "\u11e1": "HANGUL JONGSEONG MIEUM-HIEUH", 228 | "\u11e2": "HANGUL JONGSEONG KAPYEOUNMIEUM", 229 | "\u11e3": "HANGUL JONGSEONG PIEUP-RIEUL", 230 | "\u11e4": "HANGUL JONGSEONG PIEUP-PHIEUPH", 231 | "\u11e5": "HANGUL JONGSEONG PIEUP-HIEUH", 232 | "\u11e6": "HANGUL JONGSEONG KAPYEOUNPIEUP", 233 | "\u11e7": "HANGUL JONGSEONG SIOS-KIYEOK", 234 | "\u11e8": "HANGUL JONGSEONG SIOS-TIKEUT", 235 | "\u11e9": "HANGUL JONGSEONG SIOS-RIEUL", 236 | "\u11ea": "HANGUL JONGSEONG SIOS-PIEUP", 237 | "\u11eb": "HANGUL JONGSEONG PANSIOS", 238 | "\u11ec": "HANGUL JONGSEONG IEUNG-KIYEOK", 239 | "\u11ed": "HANGUL JONGSEONG IEUNG-SSANGKIYEOK", 240 | "\u11ee": "HANGUL JONGSEONG SSANGIEUNG", 241 | "\u11ef": "HANGUL JONGSEONG IEUNG-KHIEUKH", 242 | "\u11f0": "HANGUL JONGSEONG YESIEUNG", 243 | "\u11f1": "HANGUL JONGSEONG YESIEUNG-SIOS", 244 | "\u11f2": "HANGUL JONGSEONG YESIEUNG-PANSIOS", 245 | "\u11f3": "HANGUL JONGSEONG PHIEUPH-PIEUP", 246 | "\u11f4": "HANGUL JONGSEONG KAPYEOUNPHIEUPH", 247 | "\u11f5": "HANGUL JONGSEONG HIEUH-NIEUN", 248 | "\u11f6": "HANGUL JONGSEONG HIEUH-RIEUL", 249 | "\u11f7": "HANGUL JONGSEONG HIEUH-MIEUM", 250 | "\u11f8": "HANGUL JONGSEONG HIEUH-PIEUP", 251 | "\u11f9": "HANGUL JONGSEONG YEORINHIEUH", 252 | "\u11fa": "HANGUL JONGSEONG KIYEOK-NIEUN", 253 | "\u11fb": "HANGUL JONGSEONG KIYEOK-PIEUP", 254 | "\u11fc": "HANGUL JONGSEONG KIYEOK-CHIEUCH", 255 | "\u11fd": "HANGUL JONGSEONG KIYEOK-KHIEUKH", 256 | "\u11fe": "HANGUL JONGSEONG KIYEOK-HIEUH", 257 | "\u11ff": "HANGUL JONGSEONG SSANGNIEUN" 258 | } -------------------------------------------------------------------------------- /data/KoreanSyllableData/U+31xx.json: -------------------------------------------------------------------------------- 1 | { 2 | "\u3131": "HANGUL LETTER KIYEOK", 3 | "\u3132": "HANGUL LETTER SSANGKIYEOK", 4 | "\u3133": "HANGUL LETTER KIYEOK-SIOS", 5 | "\u3134": "HANGUL LETTER NIEUN", 6 | "\u3135": "HANGUL LETTER NIEUN-CIEUC", 7 | "\u3136": "HANGUL LETTER NIEUN-HIEUH", 8 | "\u3137": "HANGUL LETTER TIKEUT", 9 | "\u3138": "HANGUL LETTER SSANGTIKEUT", 10 | "\u3139": "HANGUL LETTER RIEUL", 11 | "\u313a": "HANGUL LETTER RIEUL-KIYEOK", 12 | "\u313b": "HANGUL LETTER RIEUL-MIEUM", 13 | "\u313c": "HANGUL LETTER RIEUL-PIEUP", 14 | "\u313d": "HANGUL LETTER RIEUL-SIOS", 15 | "\u313e": "HANGUL LETTER RIEUL-THIEUTH", 16 | "\u313f": "HANGUL LETTER RIEUL-PHIEUPH", 17 | "\u3140": "HANGUL LETTER RIEUL-HIEUH", 18 | "\u3141": "HANGUL LETTER MIEUM", 19 | "\u3142": "HANGUL LETTER PIEUP", 20 | "\u3143": "HANGUL LETTER SSANGPIEUP", 21 | "\u3144": "HANGUL LETTER PIEUP-SIOS", 22 | "\u3145": "HANGUL LETTER SIOS", 23 | "\u3146": "HANGUL LETTER SSANGSIOS", 24 | "\u3147": "HANGUL LETTER IEUNG", 25 | "\u3148": "HANGUL LETTER CIEUC", 26 | "\u3149": "HANGUL LETTER SSANGCIEUC", 27 | "\u314a": "HANGUL LETTER CHIEUCH", 28 | "\u314b": "HANGUL LETTER KHIEUKH", 29 | "\u314c": "HANGUL LETTER THIEUTH", 30 | "\u314d": "HANGUL LETTER PHIEUPH", 31 | "\u314e": "HANGUL LETTER HIEUH", 32 | "\u314f": "HANGUL LETTER A", 33 | "\u3150": "HANGUL LETTER AE", 34 | "\u3151": "HANGUL LETTER YA", 35 | "\u3152": "HANGUL LETTER YAE", 36 | "\u3153": "HANGUL LETTER EO", 37 | "\u3154": "HANGUL LETTER E", 38 | "\u3155": "HANGUL LETTER YEO", 39 | "\u3156": "HANGUL LETTER YE", 40 | "\u3157": "HANGUL LETTER O", 41 | "\u3158": "HANGUL LETTER WA", 42 | "\u3159": "HANGUL LETTER WAE", 43 | "\u315a": "HANGUL LETTER OE", 44 | "\u315b": "HANGUL LETTER YO", 45 | "\u315c": "HANGUL LETTER U", 46 | "\u315d": "HANGUL LETTER WEO", 47 | "\u315e": "HANGUL LETTER WE", 48 | "\u315f": "HANGUL LETTER WI", 49 | "\u3160": "HANGUL LETTER YU", 50 | "\u3161": "HANGUL LETTER EU", 51 | "\u3162": "HANGUL LETTER YI", 52 | "\u3163": "HANGUL LETTER I", 53 | "\u3164": "HANGUL FILLER", 54 | "\u3165": "HANGUL LETTER SSANGNIEUN", 55 | "\u3166": "HANGUL LETTER NIEUN-TIKEUT", 56 | "\u3167": "HANGUL LETTER NIEUN-SIOS", 57 | "\u3168": "HANGUL LETTER NIEUN-PANSIOS", 58 | "\u3169": "HANGUL LETTER RIEUL-KIYEOK-SIOS", 59 | "\u316a": "HANGUL LETTER RIEUL-TIKEUT", 60 | "\u316b": "HANGUL LETTER RIEUL-PIEUP-SIOS", 61 | "\u316c": "HANGUL LETTER RIEUL-PANSIOS", 62 | "\u316d": "HANGUL LETTER RIEUL-YEORINHIEUH", 63 | "\u316e": "HANGUL LETTER MIEUM-PIEUP", 64 | "\u316f": "HANGUL LETTER MIEUM-SIOS", 65 | "\u3170": "HANGUL LETTER MIEUM-PANSIOS", 66 | "\u3171": "HANGUL LETTER KAPYEOUNMIEUM", 67 | "\u3172": "HANGUL LETTER PIEUP-KIYEOK", 68 | "\u3173": "HANGUL LETTER PIEUP-TIKEUT", 69 | "\u3174": "HANGUL LETTER PIEUP-SIOS-KIYEOK", 70 | "\u3175": "HANGUL LETTER PIEUP-SIOS-TIKEUT", 71 | "\u3176": "HANGUL LETTER PIEUP-CIEUC", 72 | "\u3177": "HANGUL LETTER PIEUP-THIEUTH", 73 | "\u3178": "HANGUL LETTER KAPYEOUNPIEUP", 74 | "\u3179": "HANGUL LETTER KAPYEOUNSSANGPIEUP", 75 | "\u317a": "HANGUL LETTER SIOS-KIYEOK", 76 | "\u317b": "HANGUL LETTER SIOS-NIEUN", 77 | "\u317c": "HANGUL LETTER SIOS-TIKEUT", 78 | "\u317d": "HANGUL LETTER SIOS-PIEUP", 79 | "\u317e": "HANGUL LETTER SIOS-CIEUC", 80 | "\u317f": "HANGUL LETTER PANSIOS", 81 | "\u3180": "HANGUL LETTER SSANGIEUNG", 82 | "\u3181": "HANGUL LETTER YESIEUNG", 83 | "\u3182": "HANGUL LETTER YESIEUNG-SIOS", 84 | "\u3183": "HANGUL LETTER YESIEUNG-PANSIOS", 85 | "\u3184": "HANGUL LETTER KAPYEOUNPHIEUPH", 86 | "\u3185": "HANGUL LETTER SSANGHIEUH", 87 | "\u3186": "HANGUL LETTER YEORINHIEUH", 88 | "\u3187": "HANGUL LETTER YO-YA", 89 | "\u3188": "HANGUL LETTER YO-YAE", 90 | "\u3189": "HANGUL LETTER YO-I", 91 | "\u318a": "HANGUL LETTER YU-YEO", 92 | "\u318b": "HANGUL LETTER YU-YE", 93 | "\u318c": "HANGUL LETTER YU-I", 94 | "\u318d": "HANGUL LETTER ARAEA", 95 | "\u318e": "HANGUL LETTER ARAEAE" 96 | } -------------------------------------------------------------------------------- /pyanimalese_cli.py: -------------------------------------------------------------------------------- 1 | import random 2 | from pydub import AudioSegment 3 | from pydub.playback import play 4 | from jamo import h2j, j2hcj 5 | 6 | char_list = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ', ' '] 7 | 8 | char_sounds = {} 9 | char_sounds_high = {} 10 | 11 | for idx, item in enumerate(char_list): 12 | str_idx = str(idx + 1).zfill(2) 13 | char_sounds[item] = AudioSegment.from_mp3(f'./sources/{str_idx}.padata') 14 | char_sounds_high[item] = AudioSegment.from_mp3(f'./sources/high/{str_idx}.padata') 15 | 16 | while True: 17 | source = input('원본 문자열 입력: ') 18 | 19 | if source == "종료": 20 | break 21 | 22 | result_sound = None 23 | result_sound_high = None 24 | print('생성중...') 25 | for ch in source: 26 | jamo_ch = j2hcj(h2j(ch)) 27 | if jamo_ch[0] not in char_list: 28 | print(f'지원되지 않는 문자를 건너뛰었습니다: {jamo_ch}') 29 | else: 30 | char_sound = char_sounds[jamo_ch[0]] 31 | char_sound_high = char_sounds_high[jamo_ch[0]] 32 | 33 | octaves = 2 * random.uniform(0.96, 1.15) 34 | new_sample_rate = int(char_sound.frame_rate * (2.0 ** octaves)) 35 | 36 | pitch_char_sound = char_sound._spawn(char_sound.raw_data, overrides={'frame_rate': new_sample_rate}) 37 | result_sound = pitch_char_sound if result_sound is None else result_sound + pitch_char_sound 38 | 39 | pitch_char_sound_high = char_sound_high._spawn(char_sound_high.raw_data, 40 | overrides={'frame_rate': new_sample_rate}) 41 | result_sound_high = pitch_char_sound_high if result_sound_high is None else result_sound_high + pitch_char_sound_high 42 | 43 | print("재생중: " + source + "(일반)") 44 | play(result_sound) 45 | 46 | print("재생중: " + source + "(고음)") 47 | play(result_sound_high) 48 | 49 | print('종료되었습니다.') 50 | -------------------------------------------------------------------------------- /pyanimalese_gui.py: -------------------------------------------------------------------------------- 1 | # Form implementation generated from reading ui file 'PyAnimalese.ui' 2 | # 3 | # Created by: PyQt6 UI code generator 6.3.0 4 | # 5 | # WARNING: Any manual changes made to this file will be lost when pyuic6 is 6 | # run again. Do not edit this file unless you know what you are doing. 7 | import os.path 8 | import traceback 9 | from PyQt6 import QtCore, QtGui, QtWidgets 10 | from PyQt6.QtCore import QThreadPool 11 | import random 12 | from pydub import AudioSegment 13 | from pydub.playback import play 14 | from audio_player_for_gui import myplayer 15 | 16 | from audio_loader_for_gui import myloader 17 | 18 | try: 19 | from jamo import h2j, j2hcj 20 | except: 21 | from __jamo import h2j, j2hcj 22 | 23 | is_debug = False 24 | else: 25 | is_debug = True 26 | 27 | 28 | class Ui_MainWindow(object): 29 | def setupUi(self, MainWindow): 30 | MainWindow.setObjectName("MainWindow") 31 | MainWindow.resize(700, 400) 32 | MainWindow.setMinimumSize(QtCore.QSize(700, 400)) 33 | MainWindow.setMaximumSize(QtCore.QSize(700, 400)) 34 | MainWindow.setAutoFillBackground(False) 35 | self.centralwidget = QtWidgets.QWidget(MainWindow) 36 | self.centralwidget.setObjectName("centralwidget") 37 | self.help_label = QtWidgets.QLabel(self.centralwidget) 38 | self.help_label.setGeometry(QtCore.QRect(20, 20, 331, 41)) 39 | self.help_label.setObjectName("help_label") 40 | self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget) 41 | self.horizontalLayoutWidget.setGeometry(QtCore.QRect(20, 60, 531, 31)) 42 | self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") 43 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget) 44 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 45 | self.horizontalLayout.setObjectName("horizontalLayout") 46 | self.source_text = QtWidgets.QLineEdit(self.horizontalLayoutWidget) 47 | self.source_text.setObjectName("source_text") 48 | self.horizontalLayout.addWidget(self.source_text) 49 | self.convert_btn = QtWidgets.QPushButton(self.horizontalLayoutWidget) 50 | self.convert_btn.setObjectName("convert_btn") 51 | self.horizontalLayout.addWidget(self.convert_btn) 52 | self.progress_label = QtWidgets.QLabel(self.centralwidget) 53 | self.progress_label.setGeometry(QtCore.QRect(20, 120, 531, 41)) 54 | self.progress_label.setObjectName("progress_label") 55 | self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.centralwidget) 56 | self.horizontalLayoutWidget_2.setGeometry(QtCore.QRect(20, 280, 451, 51)) 57 | self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2") 58 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_2) 59 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) 60 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 61 | self.play_or_save_label = QtWidgets.QLabel(self.horizontalLayoutWidget_2) 62 | self.play_or_save_label.setObjectName("play_or_save_label") 63 | self.horizontalLayout_2.addWidget(self.play_or_save_label) 64 | self.play_btn = QtWidgets.QPushButton(self.horizontalLayoutWidget_2) 65 | self.play_btn.setObjectName("play_btn") 66 | self.horizontalLayout_2.addWidget(self.play_btn) 67 | self.save_btn = QtWidgets.QPushButton(self.horizontalLayoutWidget_2) 68 | self.save_btn.setObjectName("save_btn") 69 | self.horizontalLayout_2.addWidget(self.save_btn) 70 | # self.horizontalLayoutWidget_3 = QtWidgets.QWidget(self.centralwidget) 71 | # self.horizontalLayoutWidget_3.setGeometry(QtCore.QRect(20, 310, 451, 41)) 72 | # self.horizontalLayoutWidget_3.setObjectName("horizontalLayoutWidget_3") 73 | # self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_3) 74 | # self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0) 75 | # self.horizontalLayout_3.setObjectName("horizontalLayout_3") 76 | # self.set_path_btn = QtWidgets.QPushButton(self.horizontalLayoutWidget_3) 77 | # self.set_path_btn.setObjectName("set_path_btn") 78 | # self.horizontalLayout_3.addWidget(self.set_path_btn) 79 | # self.github_btn = QtWidgets.QPushButton(self.horizontalLayoutWidget_3) 80 | # self.github_btn.setObjectName("github_btn") 81 | # self.horizontalLayout_3.addWidget(self.github_btn) 82 | self.contact_label = QtWidgets.QLabel(self.centralwidget) 83 | self.contact_label.setGeometry(QtCore.QRect(20, 360, 341, 41)) 84 | self.contact_label.setObjectName("contact_label") 85 | self.progress_bar = QtWidgets.QProgressBar(self.centralwidget) 86 | self.progress_bar.setGeometry(QtCore.QRect(20, 100, 531, 23)) 87 | self.progress_bar.setProperty("value", 0) 88 | self.progress_bar.setObjectName("progress_bar") 89 | self.line = QtWidgets.QFrame(self.centralwidget) 90 | self.line.setGeometry(QtCore.QRect(20, 250, 531, 20)) 91 | self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) 92 | self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) 93 | self.line.setObjectName("line") 94 | MainWindow.setCentralWidget(self.centralwidget) 95 | 96 | self.connect_events() 97 | 98 | self.retranslateUi(MainWindow) 99 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 100 | 101 | def retranslateUi(self, MainWindow): 102 | _translate = QtCore.QCoreApplication.translate 103 | MainWindow.setWindowTitle(_translate("MainWindow", f"PyAnimalese {self.version}")) 104 | self.help_label.setText(_translate("MainWindow", "동물의 숲 NPC 목소리로 읽고 싶은 문장을 입력하세요.")) 105 | self.convert_btn.setText(_translate("MainWindow", "변환")) 106 | self.progress_label.setText(_translate("MainWindow", "대기중...")) 107 | self.play_or_save_label.setText(_translate("MainWindow", "생성된 음성을...")) 108 | self.play_btn.setText(_translate("MainWindow", "재생하기")) 109 | self.save_btn.setText(_translate("MainWindow", "저장하기")) 110 | # self.set_path_btn.setText(_translate("MainWindow", "저장경로 설정하기")) 111 | # self.github_btn.setText(_translate("MainWindow", "GitHub Repo 확인하기")) 112 | self.contact_label.setText(_translate("MainWindow", "개발자: 주휘중 (contact@jbstudio.xyz)")) 113 | 114 | # My codes below 115 | def __init__(self): 116 | self.version = "1.0.0" 117 | self.threadpool = QThreadPool() 118 | self.root_dir = '\\'.join(sys.executable.split('\\')[0:-1]) 119 | self.is_processing = False 120 | self.result_sound = None 121 | self.source_string = "" 122 | self.char_list = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ', ' '] 123 | 124 | self.char_sounds = {} 125 | # self.char_sounds_high = {} 126 | self.loading_audio_files = False 127 | self.loaded_audio_num = 0 128 | 129 | def connect_events(self): 130 | self.convert_btn.clicked.connect(self.convert_to_animalese) 131 | self.play_btn.clicked.connect(self.play_sound) 132 | self.save_btn.clicked.connect(lambda: self.save_sound(self.source_string)) 133 | 134 | def initialize_audio_files(self): 135 | if self.loading_audio_files: 136 | return 137 | 138 | self.loading_audio_files = True 139 | self.progress_label.setText(f"데이터 파일을 불러오고 있어요. 검은색 창이 나와도 놀라지 마세요! ({self.loaded_audio_num}/{len(self.char_list)})") 140 | QtWidgets.QApplication.processEvents() 141 | 142 | for idx, item in enumerate(self.char_list): 143 | str_idx = str(idx + 1).zfill(2) 144 | if is_debug: 145 | try: 146 | my_loader = myloader(f'./sources/{str_idx}.padata', item) 147 | my_loader.signals.result.connect(self.finished_single_audio_file) 148 | self.threadpool.start(my_loader) 149 | except Exception as e: 150 | print(e) 151 | 152 | # self.char_sounds[item] = AudioSegment.from_mp3(f'{self.root_dir}\\data\\sources\\{str_idx}.padata') 153 | # self.char_sounds_high[item] = f'./sources/high/{str_idx}.padata' 154 | else: 155 | my_loader = myloader(f'{self.root_dir}\\data\\sources\\{str_idx}.padata', item) 156 | my_loader.signals.result.connect(self.finished_single_audio_file) 157 | self.threadpool.start(my_loader) 158 | # self.char_sounds[item] = AudioSegment.from_mp3(f'{self.root_dir}\\data\\sources\\{str_idx}.padata') 159 | 160 | def finished_single_audio_file(self, sound, char): 161 | self.char_sounds[char] = sound 162 | 163 | self.loaded_audio_num += 1 164 | self.progress_bar.setMinimum(0) 165 | self.progress_bar.setMaximum(len(self.char_list)) 166 | self.progress_bar.value = self.loaded_audio_num 167 | print( self.loaded_audio_num) 168 | self.progress_label.setText(f"데이터 파일을 불러오고 있어요. 검은색 창이 나와도 놀라지 마세요! ({self.loaded_audio_num}/{len(self.char_list)})") 169 | QtWidgets.QApplication.processEvents() 170 | 171 | if len(self.char_sounds) == len(self.char_list): 172 | print('완료') 173 | self.loading_audio_files = False 174 | self.progress_label.setText("로드 완료") 175 | QtWidgets.QApplication.processEvents() 176 | 177 | def convert_to_animalese(self): 178 | if self.is_processing: 179 | return 180 | 181 | if self.loading_audio_files: 182 | return 183 | 184 | self.source_string = self.source_text.text() 185 | self.result_sound = None 186 | # print(self.source_string) 187 | self.is_processing = True 188 | self.progress_label.setText("변환중...") 189 | self.progress_bar.setMinimum(0) 190 | self.progress_bar.setMaximum(len(self.source_string)) 191 | QtWidgets.QApplication.processEvents() 192 | 193 | completed_char_num = 0 194 | skipped_char_num = 0 195 | for ch in self.source_string: 196 | jamo_ch = j2hcj(h2j(ch)) 197 | # print(jamo_ch) 198 | if jamo_ch[0] not in self.char_list: 199 | skipped_char_num += 1 200 | else: 201 | char_sound = self.char_sounds[jamo_ch[0]] 202 | 203 | octaves = 2 * random.uniform(0.96, 1.15) 204 | new_sample_rate = int(char_sound.frame_rate * (2.0 ** octaves)) 205 | 206 | pitch_char_sound = char_sound._spawn(char_sound.raw_data, overrides={'frame_rate': new_sample_rate}) 207 | self.result_sound = pitch_char_sound if self.result_sound is None else self.result_sound + pitch_char_sound 208 | 209 | completed_char_num += 1 210 | self.progress_bar.setValue(completed_char_num) 211 | 212 | self.is_processing = False 213 | self.progress_label.setText("변환완료") 214 | QtWidgets.QApplication.processEvents() 215 | 216 | self.play_sound() 217 | 218 | def play_sound(self): 219 | if self.result_sound is None: 220 | return 221 | 222 | my_player = myplayer(self.result_sound) 223 | self.threadpool.start(my_player) 224 | 225 | def save_sound(self, filename): 226 | if self.result_sound is None: 227 | return 228 | 229 | try: 230 | os.makedirs('result', exist_ok=True) 231 | self.result_sound.export(f'{self.root_dir}\\result\\{self.source_string}.mp3', format='mp3') 232 | except Exception as e: 233 | traceback.print_exc() 234 | 235 | 236 | if __name__ == "__main__": 237 | import sys 238 | 239 | app = QtWidgets.QApplication(sys.argv) 240 | MainWindow = QtWidgets.QMainWindow() 241 | ui = Ui_MainWindow() 242 | ui.setupUi(MainWindow) 243 | MainWindow.show() 244 | ui.initialize_audio_files() 245 | sys.exit(app.exec()) 246 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/requirements.txt -------------------------------------------------------------------------------- /sources/01.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/01.padata -------------------------------------------------------------------------------- /sources/02.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/02.padata -------------------------------------------------------------------------------- /sources/03.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/03.padata -------------------------------------------------------------------------------- /sources/04.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/04.padata -------------------------------------------------------------------------------- /sources/05.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/05.padata -------------------------------------------------------------------------------- /sources/06.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/06.padata -------------------------------------------------------------------------------- /sources/07.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/07.padata -------------------------------------------------------------------------------- /sources/08.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/08.padata -------------------------------------------------------------------------------- /sources/09.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/09.padata -------------------------------------------------------------------------------- /sources/10.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/10.padata -------------------------------------------------------------------------------- /sources/11.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/11.padata -------------------------------------------------------------------------------- /sources/12.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/12.padata -------------------------------------------------------------------------------- /sources/13.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/13.padata -------------------------------------------------------------------------------- /sources/14.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/14.padata -------------------------------------------------------------------------------- /sources/15.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/15.padata -------------------------------------------------------------------------------- /sources/16.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/16.padata -------------------------------------------------------------------------------- /sources/17.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/17.padata -------------------------------------------------------------------------------- /sources/18.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/18.padata -------------------------------------------------------------------------------- /sources/19.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/19.padata -------------------------------------------------------------------------------- /sources/20.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/20.padata -------------------------------------------------------------------------------- /sources/high/01.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/01.padata -------------------------------------------------------------------------------- /sources/high/02.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/02.padata -------------------------------------------------------------------------------- /sources/high/03.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/03.padata -------------------------------------------------------------------------------- /sources/high/04.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/04.padata -------------------------------------------------------------------------------- /sources/high/05.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/05.padata -------------------------------------------------------------------------------- /sources/high/06.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/06.padata -------------------------------------------------------------------------------- /sources/high/07.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/07.padata -------------------------------------------------------------------------------- /sources/high/08.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/08.padata -------------------------------------------------------------------------------- /sources/high/09.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/09.padata -------------------------------------------------------------------------------- /sources/high/10.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/10.padata -------------------------------------------------------------------------------- /sources/high/11.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/11.padata -------------------------------------------------------------------------------- /sources/high/12.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/12.padata -------------------------------------------------------------------------------- /sources/high/13.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/13.padata -------------------------------------------------------------------------------- /sources/high/14.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/14.padata -------------------------------------------------------------------------------- /sources/high/15.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/15.padata -------------------------------------------------------------------------------- /sources/high/16.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/16.padata -------------------------------------------------------------------------------- /sources/high/17.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/17.padata -------------------------------------------------------------------------------- /sources/high/18.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/18.padata -------------------------------------------------------------------------------- /sources/high/19.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/19.padata -------------------------------------------------------------------------------- /sources/high/20.padata: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hwi-middle/PyAnimalese/bbe29f5668791f3c678b4bdb72e4aa64b58b3e43/sources/high/20.padata --------------------------------------------------------------------------------