mirror of
https://github.com/correl/turntable.git
synced 2024-12-27 11:09:53 +00:00
Initial code commit
This commit is contained in:
parent
67a0e82ccf
commit
0b87836eb2
10 changed files with 1004 additions and 0 deletions
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
.idea
|
||||
*.log
|
||||
tmp/
|
||||
|
||||
*.py[cod]
|
||||
*.egg
|
||||
build
|
||||
htmlcov
|
588
poetry.lock
generated
Normal file
588
poetry.lock
generated
Normal file
|
@ -0,0 +1,588 @@
|
|||
[[package]]
|
||||
category = "dev"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
name = "appdirs"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "The uncompromising code formatter."
|
||||
name = "black"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "20.8b1"
|
||||
|
||||
[package.dependencies]
|
||||
appdirs = "*"
|
||||
click = ">=7.1.2"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
pathspec = ">=0.6,<1"
|
||||
regex = ">=2020.1.8"
|
||||
toml = ">=0.10.1"
|
||||
typed-ast = ">=1.4.0"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
name = "certifi"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.6.20"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Universal encoding detector for Python 2 and 3"
|
||||
name = "chardet"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.0.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Composable command line interface toolkit"
|
||||
name = "click"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "7.1.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Composable style cycles"
|
||||
name = "cycler"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.10.0"
|
||||
|
||||
[package.dependencies]
|
||||
six = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
name = "idna"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.10"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A fast implementation of the Cassowary constraint solver"
|
||||
name = "kiwisolver"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "1.2.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python plotting package"
|
||||
name = "matplotlib"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "3.1.1"
|
||||
|
||||
[package.dependencies]
|
||||
cycler = ">=0.10"
|
||||
kiwisolver = ">=1.0.1"
|
||||
numpy = ">=1.11"
|
||||
pyparsing = ">=2.0.1,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6"
|
||||
python-dateutil = ">=2.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Optional static typing for Python"
|
||||
name = "mypy"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "0.782"
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=0.4.3,<0.5.0"
|
||||
typed-ast = ">=1.4.0,<1.5.0"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
name = "mypy-extensions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.4.3"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "MySQL driver written in Python"
|
||||
name = "mysql-connector-python"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "8.0.17"
|
||||
|
||||
[package.dependencies]
|
||||
protobuf = ">=3.0.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "NumPy is the fundamental package for array computing with Python."
|
||||
name = "numpy"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "1.17.2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
name = "pathspec"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "0.8.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Protocol Buffers"
|
||||
name = "protobuf"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.13.0"
|
||||
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
six = ">=1.9"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||
name = "psycopg2"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
||||
version = "2.8.3"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "ALSA bindings"
|
||||
name = "pyalsaaudio"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.9.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Bindings for PortAudio v19, the cross-platform audio input/output stream library."
|
||||
name = "pyaudio"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.2.11"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Dejavu: Audio Fingerprinting in Python"
|
||||
name = "PyDejavu"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.1.3"
|
||||
|
||||
[package.dependencies]
|
||||
PyAudio = "0.2.11"
|
||||
matplotlib = "3.1.1"
|
||||
mysql-connector-python = "8.0.17"
|
||||
numpy = "1.17.2"
|
||||
psycopg2 = "2.8.3"
|
||||
pydub = "0.23.1"
|
||||
scipy = "1.3.1"
|
||||
|
||||
[package.source]
|
||||
reference = "e56a4a221ad204654a191d217f92aebf3f058b62"
|
||||
type = "git"
|
||||
url = "https://github.com/worldveil/dejavu.git"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Manipulate audio with an simple and easy high level interface"
|
||||
name = "pydub"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.23.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python parsing module"
|
||||
name = "pyparsing"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "2.4.7"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
name = "python-dateutil"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
version = "2.8.1"
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
name = "regex"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.7.14"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python HTTP for Humans."
|
||||
name = "requests"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.24.0"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
chardet = ">=3.0.2,<4"
|
||||
idna = ">=2.5,<3"
|
||||
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
|
||||
|
||||
[package.extras]
|
||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "SciPy: Scientific Library for Python"
|
||||
name = "scipy"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "1.3.1"
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.13.3"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
name = "six"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "1.15.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
name = "toml"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.10.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
name = "typed-ast"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||
name = "typing-extensions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.7.4.3"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
name = "urllib3"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
version = "1.25.10"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "284dea422084579d1f99320aaa7c816165b0d7e2aca709c84a0036dee4255a4d"
|
||||
lock-version = "1.0"
|
||||
python-versions = "^3.8"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
]
|
||||
black = [
|
||||
{file = "black-20.8b1-py3-none-any.whl", hash = "sha256:70b62ef1527c950db59062cda342ea224d772abdf6adc58b86a45421bab20a6b"},
|
||||
{file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
|
||||
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
|
||||
]
|
||||
chardet = [
|
||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
||||
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
|
||||
]
|
||||
cycler = [
|
||||
{file = "cycler-0.10.0-py2.py3-none-any.whl", hash = "sha256:1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d"},
|
||||
{file = "cycler-0.10.0.tar.gz", hash = "sha256:cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
|
||||
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
|
||||
]
|
||||
kiwisolver = [
|
||||
{file = "kiwisolver-1.2.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:443c2320520eda0a5b930b2725b26f6175ca4453c61f739fef7a5847bd262f74"},
|
||||
{file = "kiwisolver-1.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:efcf3397ae1e3c3a4a0a0636542bcad5adad3b1dd3e8e629d0b6e201347176c8"},
|
||||
{file = "kiwisolver-1.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fccefc0d36a38c57b7bd233a9b485e2f1eb71903ca7ad7adacad6c28a56d62d2"},
|
||||
{file = "kiwisolver-1.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:be046da49fbc3aa9491cc7296db7e8d27bcf0c3d5d1a40259c10471b014e4e0c"},
|
||||
{file = "kiwisolver-1.2.0-cp36-none-win32.whl", hash = "sha256:60a78858580761fe611d22127868f3dc9f98871e6fdf0a15cc4203ed9ba6179b"},
|
||||
{file = "kiwisolver-1.2.0-cp36-none-win_amd64.whl", hash = "sha256:556da0a5f60f6486ec4969abbc1dd83cf9b5c2deadc8288508e55c0f5f87d29c"},
|
||||
{file = "kiwisolver-1.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7cc095a4661bdd8a5742aaf7c10ea9fac142d76ff1770a0f84394038126d8fc7"},
|
||||
{file = "kiwisolver-1.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c955791d80e464da3b471ab41eb65cf5a40c15ce9b001fdc5bbc241170de58ec"},
|
||||
{file = "kiwisolver-1.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:603162139684ee56bcd57acc74035fceed7dd8d732f38c0959c8bd157f913fec"},
|
||||
{file = "kiwisolver-1.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:63f55f490b958b6299e4e5bdac66ac988c3d11b7fafa522800359075d4fa56d1"},
|
||||
{file = "kiwisolver-1.2.0-cp37-none-win32.whl", hash = "sha256:03662cbd3e6729f341a97dd2690b271e51a67a68322affab12a5b011344b973c"},
|
||||
{file = "kiwisolver-1.2.0-cp37-none-win_amd64.whl", hash = "sha256:4eadb361baf3069f278b055e3bb53fa189cea2fd02cb2c353b7a99ebb4477ef1"},
|
||||
{file = "kiwisolver-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c31bc3c8e903d60a1ea31a754c72559398d91b5929fcb329b1c3a3d3f6e72113"},
|
||||
{file = "kiwisolver-1.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d52b989dc23cdaa92582ceb4af8d5bcc94d74b2c3e64cd6785558ec6a879793e"},
|
||||
{file = "kiwisolver-1.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e586b28354d7b6584d8973656a7954b1c69c93f708c0c07b77884f91640b7657"},
|
||||
{file = "kiwisolver-1.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:38d05c9ecb24eee1246391820ed7137ac42a50209c203c908154782fced90e44"},
|
||||
{file = "kiwisolver-1.2.0-cp38-none-win32.whl", hash = "sha256:d069ef4b20b1e6b19f790d00097a5d5d2c50871b66d10075dab78938dc2ee2cf"},
|
||||
{file = "kiwisolver-1.2.0-cp38-none-win_amd64.whl", hash = "sha256:18d749f3e56c0480dccd1714230da0f328e6e4accf188dd4e6884bdd06bf02dd"},
|
||||
{file = "kiwisolver-1.2.0.tar.gz", hash = "sha256:247800260cd38160c362d211dcaf4ed0f7816afb5efe56544748b21d6ad6d17f"},
|
||||
]
|
||||
matplotlib = [
|
||||
{file = "matplotlib-3.1.1-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:796edbd1182cbffa7e1e7a97f1e141f875a8501ba8dd834269ae3cd45a8c976f"},
|
||||
{file = "matplotlib-3.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bab9d848dbf1517bc58d1f486772e99919b19efef5dd8596d4b26f9f5ee08b6b"},
|
||||
{file = "matplotlib-3.1.1-cp36-cp36m-win32.whl", hash = "sha256:934e6243df7165aad097572abf5b6003c77c9b6c480c3c4de6f2ef1b5fdd4ec0"},
|
||||
{file = "matplotlib-3.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:c1fe1e6cdaa53f11f088b7470c2056c0df7d80ee4858dadf6cbe433fcba4323b"},
|
||||
{file = "matplotlib-3.1.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:ec6bd0a6a58df3628ff269978f4a4b924a0d371ad8ce1f8e2b635b99e482877a"},
|
||||
{file = "matplotlib-3.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:31a30d03f39528c79f3a592857be62a08595dec4ac034978ecd0f814fa0eec2d"},
|
||||
{file = "matplotlib-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:e5b8aeca9276a3a988caebe9f08366ed519fff98f77c6df5b64d7603d0e42e36"},
|
||||
{file = "matplotlib-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4442ce720907f67a79d45de9ada47be81ce17e6c2f448b3c64765af93f6829c9"},
|
||||
{file = "matplotlib-3.1.1.tar.gz", hash = "sha256:1febd22afe1489b13c6749ea059d392c03261b2950d1d45c17e3aed812080c93"},
|
||||
]
|
||||
mypy = [
|
||||
{file = "mypy-0.782-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:2c6cde8aa3426c1682d35190b59b71f661237d74b053822ea3d748e2c9578a7c"},
|
||||
{file = "mypy-0.782-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9c7a9a7ceb2871ba4bac1cf7217a7dd9ccd44c27c2950edbc6dc08530f32ad4e"},
|
||||
{file = "mypy-0.782-cp35-cp35m-win_amd64.whl", hash = "sha256:c05b9e4fb1d8a41d41dec8786c94f3b95d3c5f528298d769eb8e73d293abc48d"},
|
||||
{file = "mypy-0.782-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:6731603dfe0ce4352c555c6284c6db0dc935b685e9ce2e4cf220abe1e14386fd"},
|
||||
{file = "mypy-0.782-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f05644db6779387ccdb468cc47a44b4356fc2ffa9287135d05b70a98dc83b89a"},
|
||||
{file = "mypy-0.782-cp36-cp36m-win_amd64.whl", hash = "sha256:b7fbfabdbcc78c4f6fc4712544b9b0d6bf171069c6e0e3cb82440dd10ced3406"},
|
||||
{file = "mypy-0.782-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:3fdda71c067d3ddfb21da4b80e2686b71e9e5c72cca65fa216d207a358827f86"},
|
||||
{file = "mypy-0.782-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7df6eddb6054d21ca4d3c6249cae5578cb4602951fd2b6ee2f5510ffb098707"},
|
||||
{file = "mypy-0.782-cp37-cp37m-win_amd64.whl", hash = "sha256:a4a2cbcfc4cbf45cd126f531dedda8485671545b43107ded25ce952aac6fb308"},
|
||||
{file = "mypy-0.782-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6bb93479caa6619d21d6e7160c552c1193f6952f0668cdda2f851156e85186fc"},
|
||||
{file = "mypy-0.782-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:81c7908b94239c4010e16642c9102bfc958ab14e36048fa77d0be3289dda76ea"},
|
||||
{file = "mypy-0.782-cp38-cp38-win_amd64.whl", hash = "sha256:5dd13ff1f2a97f94540fd37a49e5d255950ebcdf446fb597463a40d0df3fac8b"},
|
||||
{file = "mypy-0.782-py3-none-any.whl", hash = "sha256:e0b61738ab504e656d1fe4ff0c0601387a5489ca122d55390ade31f9ca0e252d"},
|
||||
{file = "mypy-0.782.tar.gz", hash = "sha256:eff7d4a85e9eea55afa34888dfeaccde99e7520b51f867ac28a48492c0b1130c"},
|
||||
]
|
||||
mypy-extensions = [
|
||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
mysql-connector-python = [
|
||||
{file = "mysql-connector-python-8.0.17.tar.gz", hash = "sha256:6cc0cda651be46f2319f4f4cd4be5eed715597dc9210b51066f598e1a4a9d76d"},
|
||||
{file = "mysql_connector_python-8.0.17-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:07ca349395ea6c9b4eb8acb588293dbf5a2abb356ad6b272cc0cab8a90551271"},
|
||||
{file = "mysql_connector_python-8.0.17-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:8181994e343154feb12baa39659fcdfd83fce956a24ee29f89bc535215caf1ce"},
|
||||
{file = "mysql_connector_python-8.0.17-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9fb1b849b87d56b05472c19da786788422fdc38ccdc09b7c5dfc5749371cdfd9"},
|
||||
{file = "mysql_connector_python-8.0.17-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:a2bb7797de49e0a642ee15c6714744530e78f17cf62678efe66b584509e22cb6"},
|
||||
{file = "mysql_connector_python-8.0.17-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:555af640b649ba2a52c2e1e8b2af69aad3a10c9dae03e9746f8e02551e563546"},
|
||||
{file = "mysql_connector_python-8.0.17-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:b7cb9ac85d6b0cb526b56cc1caa3334e73594ff4b0c9a9d17a4f70631ca465e0"},
|
||||
{file = "mysql_connector_python-8.0.17-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:5b7ce1e4a829421ea59b262bce16d2d3255ad25de67062edc7d6e722f67d8788"},
|
||||
{file = "mysql_connector_python-8.0.17-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6dd1d01b4baa4b5a4d1c0175c9785c48d60d5d71d0af7ecf97550f3dca2b0991"},
|
||||
{file = "mysql_connector_python-8.0.17-cp35-cp35m-win_amd64.whl", hash = "sha256:1939eac9a19b66bd24d3747839eb546e34ba74e8473dae0ada0867b0018abe9e"},
|
||||
{file = "mysql_connector_python-8.0.17-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:66e0f779f5c628364a7895e31fb11bc473e32d841eb215c2a548fcd4087d81e5"},
|
||||
{file = "mysql_connector_python-8.0.17-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:d68e4d8808bf14d777b2e53a3233abbd450c33cf6801e24d714000ed782aee2f"},
|
||||
{file = "mysql_connector_python-8.0.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2acc28a677917f507ea9789206e575519cf311b7631ceee1e1ef03047e2d1c98"},
|
||||
{file = "mysql_connector_python-8.0.17-cp36-cp36m-win_amd64.whl", hash = "sha256:a00201d5e63ad88656139baf9e6d9e5073a7ecb6cd89dfc64788832b61a51186"},
|
||||
{file = "mysql_connector_python-8.0.17-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:d8c2f022256cbaaaf2260c5d95879f8d81db22cc215e5c6b68fa7521ed4a309c"},
|
||||
{file = "mysql_connector_python-8.0.17-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c13835fa713b888e78487bbc180e25d682a2bd628ecb41e0af2508a600e0e0d3"},
|
||||
{file = "mysql_connector_python-8.0.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ad3692e629a5937db85fc97fc9803cc9bec33ae59fb0ef6871ac2c274744b33b"},
|
||||
{file = "mysql_connector_python-8.0.17-cp37-cp37m-win_amd64.whl", hash = "sha256:11bc8de94b4b3aaaba0c839954c82cb6d0cc6204d13df6ee07d4d8a8f297ce1f"},
|
||||
{file = "mysql_connector_python-8.0.17-py2.py3-none-any.whl", hash = "sha256:88ab8262d35e4239726593d69c072c9e31944c0a35550aa0cb46a80f6b32b1b5"},
|
||||
]
|
||||
numpy = [
|
||||
{file = "numpy-1.17.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:3d0b0989dd2d066db006158de7220802899a1e5c8cf622abe2d0bd158fd01c2c"},
|
||||
{file = "numpy-1.17.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7bd355ad7496f4ce1d235e9814ec81ee3d28308d591c067ce92e49f745ba2c2f"},
|
||||
{file = "numpy-1.17.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7d077f2976b8f3de08a0dcf5d72083f4af5411e8fddacd662aae27baa2601196"},
|
||||
{file = "numpy-1.17.2-cp35-cp35m-win32.whl", hash = "sha256:05dbfe72684cc14b92568de1bc1f41e5f62b00f714afc9adee42f6311738091f"},
|
||||
{file = "numpy-1.17.2-cp35-cp35m-win_amd64.whl", hash = "sha256:f4a4f6aba148858a5a5d546a99280f71f5ee6ec8182a7d195af1a914195b21a2"},
|
||||
{file = "numpy-1.17.2-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:ee8e9d7cad5fe6dde50ede0d2e978d81eafeaa6233fb0b8719f60214cf226578"},
|
||||
{file = "numpy-1.17.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:438a3f0e7b681642898fd7993d38e2bf140a2d1eafaf3e89bb626db7f50db355"},
|
||||
{file = "numpy-1.17.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b458de8624c9f6034af492372eb2fee41a8e605f03f4732f43fc099e227858b2"},
|
||||
{file = "numpy-1.17.2-cp36-cp36m-win32.whl", hash = "sha256:0d82cb7271a577529d07bbb05cb58675f2deb09772175fab96dc8de025d8ac05"},
|
||||
{file = "numpy-1.17.2-cp36-cp36m-win_amd64.whl", hash = "sha256:12322df2e21f033a60c80319c25011194cd2a21294cc66fee0908aeae2c27832"},
|
||||
{file = "numpy-1.17.2-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:e70fc8ff03a961f13363c2c95ef8285e0cf6a720f8271836f852cc0fa64e97c8"},
|
||||
{file = "numpy-1.17.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a4092682778dc48093e8bda8d26ee8360153e2047826f95a3f5eae09f0ae3abf"},
|
||||
{file = "numpy-1.17.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:10132aa1fef99adc85a905d82e8497a580f83739837d7cbd234649f2e9b9dc58"},
|
||||
{file = "numpy-1.17.2-cp37-cp37m-win32.whl", hash = "sha256:16f19b3aa775dddc9814e02a46b8e6ae6a54ed8cf143962b4e53f0471dbd7b16"},
|
||||
{file = "numpy-1.17.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5fd214f482ab53f2cea57414c5fb3e58895b17df6e6f5bca5be6a0bb6aea23bb"},
|
||||
{file = "numpy-1.17.2.zip", hash = "sha256:73615d3edc84dd7c4aeb212fa3748fb83217e00d201875a47327f55363cef2df"},
|
||||
]
|
||||
pathspec = [
|
||||
{file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"},
|
||||
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
|
||||
]
|
||||
protobuf = [
|
||||
{file = "protobuf-3.13.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9c2e63c1743cba12737169c447374fab3dfeb18111a460a8c1a000e35836b18c"},
|
||||
{file = "protobuf-3.13.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1e834076dfef9e585815757a2c7e4560c7ccc5962b9d09f831214c693a91b463"},
|
||||
{file = "protobuf-3.13.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:df3932e1834a64b46ebc262e951cd82c3cf0fa936a154f0a42231140d8237060"},
|
||||
{file = "protobuf-3.13.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8c35bcbed1c0d29b127c886790e9d37e845ffc2725cc1db4bd06d70f4e8359f4"},
|
||||
{file = "protobuf-3.13.0-cp35-cp35m-win32.whl", hash = "sha256:339c3a003e3c797bc84499fa32e0aac83c768e67b3de4a5d7a5a9aa3b0da634c"},
|
||||
{file = "protobuf-3.13.0-cp35-cp35m-win_amd64.whl", hash = "sha256:361acd76f0ad38c6e38f14d08775514fbd241316cce08deb2ce914c7dfa1184a"},
|
||||
{file = "protobuf-3.13.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9edfdc679a3669988ec55a989ff62449f670dfa7018df6ad7f04e8dbacb10630"},
|
||||
{file = "protobuf-3.13.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5db9d3e12b6ede5e601b8d8684a7f9d90581882925c96acf8495957b4f1b204b"},
|
||||
{file = "protobuf-3.13.0-cp36-cp36m-win32.whl", hash = "sha256:c8abd7605185836f6f11f97b21200f8a864f9cb078a193fe3c9e235711d3ff1e"},
|
||||
{file = "protobuf-3.13.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4d1174c9ed303070ad59553f435846a2f877598f59f9afc1b89757bdf846f2a7"},
|
||||
{file = "protobuf-3.13.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0bba42f439bf45c0f600c3c5993666fcb88e8441d011fad80a11df6f324eef33"},
|
||||
{file = "protobuf-3.13.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c0c5ab9c4b1eac0a9b838f1e46038c3175a95b0f2d944385884af72876bd6bc7"},
|
||||
{file = "protobuf-3.13.0-cp37-cp37m-win32.whl", hash = "sha256:f68eb9d03c7d84bd01c790948320b768de8559761897763731294e3bc316decb"},
|
||||
{file = "protobuf-3.13.0-cp37-cp37m-win_amd64.whl", hash = "sha256:91c2d897da84c62816e2f473ece60ebfeab024a16c1751aaf31100127ccd93ec"},
|
||||
{file = "protobuf-3.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3dee442884a18c16d023e52e32dd34a8930a889e511af493f6dc7d4d9bf12e4f"},
|
||||
{file = "protobuf-3.13.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e7662437ca1e0c51b93cadb988f9b353fa6b8013c0385d63a70c8a77d84da5f9"},
|
||||
{file = "protobuf-3.13.0-py2.py3-none-any.whl", hash = "sha256:d69697acac76d9f250ab745b46c725edf3e98ac24763990b24d58c16c642947a"},
|
||||
{file = "protobuf-3.13.0.tar.gz", hash = "sha256:6a82e0c8bb2bf58f606040cc5814e07715b2094caeba281e2e7d0b0e2e397db5"},
|
||||
]
|
||||
psycopg2 = [
|
||||
{file = "psycopg2-2.8.3-cp27-cp27m-win32.whl", hash = "sha256:2315e7f104681d498ccf6fd70b0dba5bce65d60ac92171492bfe228e21dcc242"},
|
||||
{file = "psycopg2-2.8.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4b5417dcd2999db0f5a891d54717cfaee33acc64f4772c4bc574d4ff95ed9d80"},
|
||||
{file = "psycopg2-2.8.3-cp34-cp34m-win32.whl", hash = "sha256:b1b8e41da09a0c3ef0b3d4bb72da0dde2abebe583c1e8462973233fd5ad0235f"},
|
||||
{file = "psycopg2-2.8.3-cp34-cp34m-win_amd64.whl", hash = "sha256:640113ddc943522aaf71294e3f2d24013b0edd659b7820621492c9ebd3a2fb0b"},
|
||||
{file = "psycopg2-2.8.3-cp35-cp35m-win32.whl", hash = "sha256:128d0fa910ada0157bba1cb74a9c5f92bb8a1dca77cf91a31eb274d1f889e001"},
|
||||
{file = "psycopg2-2.8.3-cp35-cp35m-win_amd64.whl", hash = "sha256:f0e6b697a975d9d3ccd04135316c947dd82d841067c7800ccf622a8717e98df1"},
|
||||
{file = "psycopg2-2.8.3-cp36-cp36m-win32.whl", hash = "sha256:8dceca81409898c870e011c71179454962dec152a1a6b86a347f4be74b16d864"},
|
||||
{file = "psycopg2-2.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:d3a27550a8185e53b244ad7e79e307594b92fede8617d80200a8cce1fba2c60f"},
|
||||
{file = "psycopg2-2.8.3-cp37-cp37m-win32.whl", hash = "sha256:227fd46cf9b7255f07687e5bde454d7d67ae39ca77e170097cdef8ebfc30c323"},
|
||||
{file = "psycopg2-2.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:cb407fccc12fc29dc331f2b934913405fa49b9b75af4f3a72d0f50f57ad2ca23"},
|
||||
{file = "psycopg2-2.8.3.tar.gz", hash = "sha256:897a6e838319b4bf648a574afb6cabcb17d0488f8c7195100d48d872419f4457"},
|
||||
]
|
||||
pyalsaaudio = [
|
||||
{file = "pyalsaaudio-0.9.0.tar.gz", hash = "sha256:3ca069c736c8ad2a3047b5033468d983a2480f94fad4feb0169c056060e01e69"},
|
||||
]
|
||||
pyaudio = [
|
||||
{file = "PyAudio-0.2.11-cp27-cp27m-win32.whl", hash = "sha256:f78d543a98b730e64621ebf7f3e2868a79ade0a373882ef51c0293455ffa8e6e"},
|
||||
{file = "PyAudio-0.2.11-cp27-cp27m-win_amd64.whl", hash = "sha256:259bb9c1363be895b4f9a97e320a6017dd06bc540728c1a04eb4a7b6fe75035b"},
|
||||
{file = "PyAudio-0.2.11-cp34-cp34m-win32.whl", hash = "sha256:0d92f6a294565260a282f7c9a0b0d309fc8cc988b5ee5b50645634ab9e2da7f7"},
|
||||
{file = "PyAudio-0.2.11-cp34-cp34m-win_amd64.whl", hash = "sha256:589bfad2c615dd4b5d3757e763019c42ab82f06fba5cae64ec02fd7f5ae407ed"},
|
||||
{file = "PyAudio-0.2.11-cp35-cp35m-win32.whl", hash = "sha256:8f89075b4844ea94dde0c951c2937581c989fabd4df09bfd3f075035f50955df"},
|
||||
{file = "PyAudio-0.2.11-cp35-cp35m-win_amd64.whl", hash = "sha256:cf1543ba50bd44ac0d0ab5c035bb9c3127eb76047ff12235149d9adf86f532b6"},
|
||||
{file = "PyAudio-0.2.11-cp36-cp36m-win32.whl", hash = "sha256:51b558d1b28c68437b53218279110db44f69f3f5dd3d81859f569a4a96962bdc"},
|
||||
{file = "PyAudio-0.2.11-cp36-cp36m-win_amd64.whl", hash = "sha256:2a19bdb8ec1445b4f3e4b7b109e0e4cec1fd1f1ce588592aeb6db0b58d4fb3b0"},
|
||||
{file = "PyAudio-0.2.11.tar.gz", hash = "sha256:93bfde30e0b64e63a46f2fd77e85c41fd51182a4a3413d9edfaf9ffaa26efb74"},
|
||||
]
|
||||
PyDejavu = []
|
||||
pydub = [
|
||||
{file = "pydub-0.23.1-py2.py3-none-any.whl", hash = "sha256:d29901a486fb421c5d7b0f3d5d3a60527179204d8ffb20e74e1ae81c17e81b46"},
|
||||
{file = "pydub-0.23.1.tar.gz", hash = "sha256:c362fa02da1eebd1d08bd47aa9b0102582dff7ca2269dbe9e043d228a0c1ea93"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
|
||||
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
|
||||
]
|
||||
regex = [
|
||||
{file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"},
|
||||
{file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"},
|
||||
{file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"},
|
||||
{file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"},
|
||||
{file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"},
|
||||
{file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
|
||||
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
|
||||
]
|
||||
scipy = [
|
||||
{file = "scipy-1.3.1-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:3ae3692616975d3c10aca6d574d6b4ff95568768d4525f76222fb60f142075b9"},
|
||||
{file = "scipy-1.3.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7ccfa44a08226825126c4ef0027aa46a38c928a10f0a8a8483c80dd9f9a0ad44"},
|
||||
{file = "scipy-1.3.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbc0611699e420774e945f6a4e2830f7ca2b3ee3483fca1aa659100049487dd5"},
|
||||
{file = "scipy-1.3.1-cp35-cp35m-win32.whl", hash = "sha256:435d19f80b4dcf67dc090cc04fde2c5c8a70b3372e64f6a9c58c5b806abfa5a8"},
|
||||
{file = "scipy-1.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:243b04730d7223d2b844bda9500310eecc9eda0cba9ceaf0cde1839f8287dfa8"},
|
||||
{file = "scipy-1.3.1-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:46a5e55850cfe02332998b3aef481d33f1efee1960fe6cfee0202c7dd6fc21ab"},
|
||||
{file = "scipy-1.3.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:dd3b52e00f93fd1c86f2d78243dfb0d02743c94dd1d34ffea10055438e63b99d"},
|
||||
{file = "scipy-1.3.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:75b513c462e58eeca82b22fc00f0d1875a37b12913eee9d979233349fce5c8b2"},
|
||||
{file = "scipy-1.3.1-cp36-cp36m-win32.whl", hash = "sha256:396eb4cdad421f846a1498299474f0a3752921229388f91f60dc3eda55a00488"},
|
||||
{file = "scipy-1.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:a81da2fe32f4eab8b60d56ad43e44d93d392da228a77e229e59b51508a00299c"},
|
||||
{file = "scipy-1.3.1-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0baa64bf42592032f6f6445a07144e355ca876b177f47ad8d0612901c9375bef"},
|
||||
{file = "scipy-1.3.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:d02d813ec9958ed63b390ded463163685af6025cb2e9a226ec2c477df90c6957"},
|
||||
{file = "scipy-1.3.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89dd6a6d329e3f693d1204d5562dd63af0fd7a17854ced17f9cbc37d5b853c8d"},
|
||||
{file = "scipy-1.3.1-cp37-cp37m-win32.whl", hash = "sha256:ac37eb652248e2d7cbbfd89619dce5ecfd27d657e714ed049d82f19b162e8d45"},
|
||||
{file = "scipy-1.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a9d606d11eb2eec7ef893eb825017fbb6eef1e1d0b98a5b7fc11446ebeb2b9b1"},
|
||||
{file = "scipy-1.3.1.tar.gz", hash = "sha256:2643cfb46d97b7797d1dbdb6f3c23fe3402904e3c90e6facfe6a9b98d808c1b5"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
||||
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"},
|
||||
{file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
|
||||
]
|
||||
typed-ast = [
|
||||
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
|
||||
{file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"},
|
||||
{file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"},
|
||||
{file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"},
|
||||
{file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"},
|
||||
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"},
|
||||
{file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"},
|
||||
{file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"},
|
||||
{file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"},
|
||||
{file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"},
|
||||
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"},
|
||||
{file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"},
|
||||
{file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"},
|
||||
{file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"},
|
||||
{file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"},
|
||||
{file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"},
|
||||
{file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
|
||||
{file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
|
||||
{file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
|
||||
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
|
||||
]
|
23
pyproject.toml
Normal file
23
pyproject.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[tool.poetry]
|
||||
name = "turntable"
|
||||
version = "0.1.0"
|
||||
description = "Turntable audio monitoring"
|
||||
authors = ["Correl Roush <correl@gmail.com>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
pyalsaaudio = "^0.9.0"
|
||||
pydejavu = {git = "https://github.com/worldveil/dejavu.git"}
|
||||
requests = "^2.24.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
black = "^20.8b1"
|
||||
mypy = "^0.782"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
turntable = "turntable.cli:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
turntable/__init__.py
Normal file
0
turntable/__init__.py
Normal file
62
turntable/audio.py
Normal file
62
turntable/audio.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
from collections import deque
|
||||
import logging
|
||||
import math
|
||||
from multiprocessing import Process, Queue
|
||||
from multiprocessing.connection import Connection
|
||||
from typing import Deque, List, Tuple, Union
|
||||
|
||||
import alsaaudio # type: ignore
|
||||
|
||||
from turntable.models import PCM
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Listener(Process):
|
||||
def __init__(
|
||||
self,
|
||||
pcm_in: "Queue[PCM]",
|
||||
device: str,
|
||||
sample_length: int = 30,
|
||||
framerate: int = 44100,
|
||||
channels: int = 2,
|
||||
period_size: int = 1024,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
logger.info("Initializing Listener")
|
||||
self.pcm_in = pcm_in
|
||||
self.framerate = framerate
|
||||
self.channels = channels
|
||||
self.capture = alsaaudio.PCM(
|
||||
device=device,
|
||||
type=alsaaudio.PCM_CAPTURE,
|
||||
format=alsaaudio.PCM_FORMAT_S16_LE,
|
||||
periodsize=period_size,
|
||||
rate=framerate,
|
||||
channels=channels,
|
||||
)
|
||||
available_channels: List[int] = self.capture.getchannels()
|
||||
available_rates: Union[int, Tuple[int, int]] = self.capture.getrates()
|
||||
if channels not in available_channels:
|
||||
raise ValueError(f"Unsupported channel count: {channels}")
|
||||
if isinstance(available_rates, int):
|
||||
framerate = available_rates
|
||||
elif framerate not in range(*available_rates):
|
||||
raise ValueError(f"Unsupported framerate: {framerate}")
|
||||
logger.info(
|
||||
"Listener started on '%s' [rate=%d, channels=%d, periodsize=%d]",
|
||||
device,
|
||||
framerate,
|
||||
channels,
|
||||
period_size,
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
while True:
|
||||
length, data = self.capture.read()
|
||||
if length > 0:
|
||||
self.pcm_in.put(PCM(self.framerate, self.channels, data))
|
||||
else:
|
||||
logger.warning(
|
||||
"Sampler error (length={}, bytes={})".format(length, len(data))
|
||||
)
|
79
turntable/cli.py
Normal file
79
turntable/cli.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import argparse
|
||||
import importlib.metadata
|
||||
import json
|
||||
import logging
|
||||
from multiprocessing import Queue
|
||||
import os
|
||||
from typing import Any, Dict
|
||||
|
||||
from dejavu import Dejavu # type: ignore
|
||||
|
||||
from turntable.audio import Listener
|
||||
from turntable.icecast import Icecast
|
||||
from turntable.models import PCM
|
||||
from turntable.turntable import (
|
||||
Event,
|
||||
NewMetadata,
|
||||
StartedPlaying,
|
||||
StoppedPlaying,
|
||||
Turntable,
|
||||
)
|
||||
|
||||
VERSION = importlib.metadata.version("turntable")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
print(f"Turntable {VERSION}")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--config", default=os.path.expanduser("~/.config/turntable.json")
|
||||
)
|
||||
args = parser.parse_args()
|
||||
with open(args.config, "r") as config_file:
|
||||
config: Dict[str, Any] = json.load(config_file)
|
||||
|
||||
pcm_in: "Queue[PCM]" = Queue()
|
||||
events: "Queue[Event]" = Queue()
|
||||
|
||||
audio_config = config.get("audio", dict())
|
||||
listener = Listener(
|
||||
pcm_in,
|
||||
audio_config.get("device", "default"),
|
||||
framerate=audio_config.get("framerate", 44100),
|
||||
channels=audio_config.get("channels", 2),
|
||||
period_size=audio_config.get("period_size", 4096),
|
||||
)
|
||||
|
||||
dejavu = Dejavu(config.get("dejavu", dict()))
|
||||
|
||||
player = Turntable(listener.framerate, listener.channels, dejavu, pcm_in, events)
|
||||
|
||||
icecast_config = config.get("icecast", dict())
|
||||
icecast = Icecast(
|
||||
host=icecast_config.get("host", "localhost"),
|
||||
port=icecast_config.get("port", 8000),
|
||||
mountpoint=icecast_config.get("mountpoint", "stream.mp3"),
|
||||
user=icecast_config.get("admin_user", "admin"),
|
||||
password=icecast_config.get("admin_password", "hackme"),
|
||||
)
|
||||
|
||||
processes = [listener, player]
|
||||
for process in processes:
|
||||
process.daemon = True
|
||||
process.start()
|
||||
try:
|
||||
icecast.set_title("<Idle>")
|
||||
while event := events.get():
|
||||
logging.info("Event: %s", event)
|
||||
if isinstance(event, StartedPlaying):
|
||||
icecast.set_title("<Record starting...>")
|
||||
elif isinstance(event, StoppedPlaying):
|
||||
icecast.set_title("<Idle>")
|
||||
elif isinstance(event, NewMetadata):
|
||||
icecast.set_title(event.title)
|
||||
except KeyboardInterrupt:
|
||||
for process in processes:
|
||||
if process.is_alive():
|
||||
process.terminate()
|
28
turntable/icecast.py
Normal file
28
turntable/icecast.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Icecast:
|
||||
def __init__(self, host: str, port: int, mountpoint: str, user: str, password: str):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.mountpoint = mountpoint
|
||||
self.credentials = (user, password)
|
||||
|
||||
def set_title(self, title: str):
|
||||
try:
|
||||
requests.get(
|
||||
f"http://{self.host}:{self.port}/admin/metadata",
|
||||
params={
|
||||
"mount": os.path.join("/", self.mountpoint),
|
||||
"mode": "updinfo",
|
||||
"song": title,
|
||||
},
|
||||
auth=self.credentials,
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
logger.warning("Failed to update icecast metadata: %s", e)
|
49
turntable/models.py
Normal file
49
turntable/models.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
from collections import deque
|
||||
from dataclasses import dataclass
|
||||
from typing import Deque, Iterable, Optional, Union
|
||||
|
||||
|
||||
class PCM:
|
||||
"""16-bit raw PCM audio."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
framerate: int,
|
||||
channels: int,
|
||||
data: bytes = b"",
|
||||
maxlen: Optional[int] = None,
|
||||
):
|
||||
self.framerate = framerate
|
||||
self.channels = channels
|
||||
self._data: Deque[int] = deque(data, maxlen)
|
||||
|
||||
@property
|
||||
def raw(self):
|
||||
return bytes(self._data)
|
||||
|
||||
@property
|
||||
def framesize(self):
|
||||
# Two bytes for each channel
|
||||
return self.channels * 2
|
||||
|
||||
def __getitem__(self, key: Union[int, slice]) -> "PCM":
|
||||
"""Address raw data by frame."""
|
||||
if isinstance(key, int):
|
||||
start = key * self.framesize
|
||||
stop = start + self.framesize
|
||||
return PCM(self.framerate, self.channels, self.raw[start:stop])
|
||||
else:
|
||||
start = key.start * self.framesize if key.start is not None else None
|
||||
stop = key.stop * self.framesize if key.stop is not None else None
|
||||
step = key.step * self.framesize if key.step is not None else None
|
||||
return PCM(self.framerate, self.channels, self.raw[start:stop:step])
|
||||
|
||||
def __iter__(self) -> "Iterable[PCM]":
|
||||
"""Iterate over raw data by frame."""
|
||||
for i in range(0, len(self._data), self.framesize):
|
||||
yield PCM(self.framerate, self.channels, self.raw[i : i + self.framesize])
|
||||
|
||||
def append(self, other: "PCM") -> None:
|
||||
if other.framerate != self.framerate or other.channels != self.channels:
|
||||
raise ValueError("Cannot append incompatible PCM audio")
|
||||
self._data.extend(other._data)
|
166
turntable/turntable.py
Normal file
166
turntable/turntable.py
Normal file
|
@ -0,0 +1,166 @@
|
|||
import audioop
|
||||
from dataclasses import dataclass
|
||||
import enum
|
||||
import logging
|
||||
from multiprocessing import Process, Queue
|
||||
from multiprocessing.connection import Connection
|
||||
import struct
|
||||
import time
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple
|
||||
import wave
|
||||
|
||||
from dejavu import Dejavu # type: ignore
|
||||
from dejavu.base_classes.base_recognizer import BaseRecognizer # type: ignore
|
||||
import dejavu.config.settings # type: ignore
|
||||
|
||||
|
||||
from turntable.models import PCM
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
FINGERPRINT_IDENTIFY_SECONDS = 5
|
||||
FINGERPRINT_STORE_SECONDS = 30
|
||||
SAMPLE_SECONDS = 30
|
||||
SILENCE_THRESHOLD = 100
|
||||
STOP_DELAY = 5
|
||||
|
||||
|
||||
class State(enum.Enum):
|
||||
idle = "idle"
|
||||
playing = "playing"
|
||||
silent = "silent"
|
||||
|
||||
|
||||
class Event:
|
||||
@property
|
||||
def type(self) -> str:
|
||||
return self.__class__.__name__
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.type}>"
|
||||
|
||||
|
||||
class StartedPlaying(Event):
|
||||
...
|
||||
|
||||
|
||||
class StoppedPlaying(Event):
|
||||
...
|
||||
|
||||
|
||||
@dataclass
|
||||
class NewMetadata(Event):
|
||||
title: str
|
||||
|
||||
|
||||
class PCMRecognizer(BaseRecognizer):
|
||||
def pcm_to_channel_data(self, pcm: PCM) -> List[List[int]]:
|
||||
def to_ints(data: bytes) -> List[int]:
|
||||
return list(struct.unpack("{}h".format(len(data) // 2), data))
|
||||
|
||||
stream = to_ints(pcm.raw)
|
||||
return [stream[channel :: pcm.channels] for channel in range(pcm.channels)]
|
||||
|
||||
def recognize(self, pcm: PCM) -> Dict[str, Any]:
|
||||
data = self.pcm_to_channel_data(pcm)
|
||||
t = time.time()
|
||||
matches, fingerprint_time, query_time, align_time = self._recognize(*data)
|
||||
t = time.time() - t
|
||||
return {
|
||||
dejavu.config.settings.TOTAL_TIME: t,
|
||||
dejavu.config.settings.FINGERPRINT_TIME: fingerprint_time,
|
||||
dejavu.config.settings.QUERY_TIME: query_time,
|
||||
dejavu.config.settings.ALIGN_TIME: align_time,
|
||||
dejavu.config.settings.RESULTS: matches,
|
||||
}
|
||||
|
||||
|
||||
class Turntable(Process):
|
||||
def __init__(
|
||||
self,
|
||||
framerate: int,
|
||||
channels: int,
|
||||
dejavu: Dejavu,
|
||||
pcm_in: "Queue[PCM]",
|
||||
events_out: "Queue[Event]",
|
||||
) -> None:
|
||||
super().__init__()
|
||||
maxlen = channels * 2 * framerate * SAMPLE_SECONDS
|
||||
self.buffer = PCM(framerate=framerate, channels=channels, maxlen=maxlen)
|
||||
self.recognizer = PCMRecognizer(dejavu)
|
||||
self.pcm_in = pcm_in
|
||||
self.events_out = events_out
|
||||
self.state: State = State.idle
|
||||
self.identified = False
|
||||
self.captured = False
|
||||
self.last_update: float = time.time()
|
||||
|
||||
def run(self) -> None:
|
||||
logger.info("Initializing Turntable")
|
||||
while fragment := self.pcm_in.get():
|
||||
self.buffer.append(fragment)
|
||||
maximum = audioop.max(fragment.raw, 2)
|
||||
self.update_audiolevel(maximum)
|
||||
|
||||
def update_audiolevel(self, level: int):
|
||||
newstate = self.state
|
||||
now = time.time()
|
||||
if self.state == State.idle:
|
||||
# Transition to playing if there's sufficient audio.
|
||||
if level > SILENCE_THRESHOLD:
|
||||
self.transition(State.playing, now)
|
||||
elif self.state == State.playing:
|
||||
# Transition to silent when the audio drops out.
|
||||
if level <= SILENCE_THRESHOLD:
|
||||
self.transition(State.silent, now)
|
||||
elif (
|
||||
now - self.last_update >= FINGERPRINT_IDENTIFY_SECONDS
|
||||
and self.identified == False
|
||||
):
|
||||
sample = self.buffer[
|
||||
0 : self.buffer.framerate * FINGERPRINT_IDENTIFY_SECONDS
|
||||
]
|
||||
identification = self.recognizer.recognize(sample)
|
||||
logger.debug("Dejavu results: %s", identification)
|
||||
if results := identification[dejavu.config.settings.RESULTS]:
|
||||
self.events_out.put(
|
||||
NewMetadata(
|
||||
results[0][dejavu.config.settings.SONG_NAME].decode("utf-8")
|
||||
)
|
||||
)
|
||||
self.identified = True
|
||||
elif (
|
||||
now - self.last_update >= FINGERPRINT_STORE_SECONDS
|
||||
and self.captured == False
|
||||
):
|
||||
sample = self.buffer[
|
||||
0 : self.buffer.framerate * FINGERPRINT_STORE_SECONDS
|
||||
]
|
||||
with wave.open("/tmp/fingerprint.wav", "wb") as wavfile:
|
||||
wavfile.setsampwidth(2)
|
||||
wavfile.setnchannels(sample.channels)
|
||||
wavfile.setframerate(sample.framerate)
|
||||
wavfile.writeframesraw(sample.raw)
|
||||
logger.info("Captured waveform for fingerprinting")
|
||||
self.captured = True
|
||||
|
||||
elif self.state == State.silent:
|
||||
# Transition back to playing if audio returns within STOP_DELAY
|
||||
# seconds, otherwise transition to idle.
|
||||
if level > SILENCE_THRESHOLD:
|
||||
self.transition(State.playing, now)
|
||||
elif now - self.last_update >= STOP_DELAY:
|
||||
self.transition(State.idle, now)
|
||||
|
||||
def transition(self, to_state: State, updated_at: float):
|
||||
self.state = to_state
|
||||
self.last_update = updated_at
|
||||
logger.debug("State: %s", self.state)
|
||||
|
||||
if to_state == State.idle:
|
||||
self.events_out.put(StoppedPlaying())
|
||||
self.identified = False
|
||||
self.captured = False
|
||||
elif to_state == State.playing:
|
||||
self.events_out.put(StartedPlaying())
|
Loading…
Reference in a new issue