palace
Advanced tools
| @ECHO OFF | ||
| pushd %~dp0 | ||
| REM Command file for Sphinx documentation | ||
| if "%SPHINXBUILD%" == "" ( | ||
| set SPHINXBUILD=sphinx-build | ||
| ) | ||
| set SOURCEDIR=source | ||
| set BUILDDIR=build | ||
| if "%1" == "" goto help | ||
| %SPHINXBUILD% >NUL 2>NUL | ||
| if errorlevel 9009 ( | ||
| echo. | ||
| echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | ||
| echo.installed, then set the SPHINXBUILD environment variable to point | ||
| echo.to the full path of the 'sphinx-build' executable. Alternatively you | ||
| echo.may add the Sphinx directory to PATH. | ||
| echo. | ||
| echo.If you don't have Sphinx installed, grab it from | ||
| echo.http://sphinx-doc.org/ | ||
| exit /b 1 | ||
| ) | ||
| %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
| goto end | ||
| :help | ||
| %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
| :end | ||
| popd |
| # Minimal makefile for Sphinx documentation | ||
| # You can set these variables from the command line, | ||
| # and also from the environment for the first two. | ||
| SPHINXOPTS ?= | ||
| SPHINXBUILD ?= sphinx-build | ||
| SOURCEDIR = source | ||
| BUILDDIR = build | ||
| # Put it first so that "make" without argument is like "make help". | ||
| help: | ||
| @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
| .PHONY: help Makefile | ||
| # Catch-all target: route all unknown targets to Sphinx using the new | ||
| # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). | ||
| %: Makefile | ||
| @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
| # Configuration file for the Sphinx documentation builder. | ||
| # | ||
| # This file only contains a selection of the most common options. | ||
| # For a full list see the documentation: | ||
| # https://www.sphinx-doc.org/en/master/usage/configuration.html | ||
| # Project information | ||
| project = 'palace' | ||
| copyright = '2019, 2020 Nguyễn Gia Phong et al' | ||
| author = 'Nguyễn Gia Phong et al.' | ||
| release = '0.2.1' | ||
| # Add any Sphinx extension module names here, as strings. | ||
| # They can be extensions coming with Sphinx (named 'sphinx.ext.*') | ||
| # or your custom ones. | ||
| extensions = [ | ||
| 'sphinx.ext.autodoc', 'sphinx.ext.githubpages', 'sphinx.ext.napoleon'] | ||
| napoleon_google_docstring = False | ||
| default_role = 'py:obj' | ||
| # Add any paths that contain templates here, relative to this directory. | ||
| templates_path = ['templates'] | ||
| # List of patterns, relative to source directory, that match | ||
| # files and directories to ignore when looking for source files. | ||
| # This pattern also affects html_static_path and html_extra_path. | ||
| exclude_patterns = [] | ||
| # Options for HTML output | ||
| html_theme = 'sphinx_rtd_theme' | ||
| # Add any paths that contain custom static files (such as style sheets) | ||
| # here, relative to this directory. They are copied after the builtin | ||
| # static files, so a file named "default.css" will overwrite the builtin | ||
| # "default.css". | ||
| html_static_path = [] |
| Getting Involved | ||
| ================ | ||
| .. note:: The development of palace is carried out on GitHub_. | ||
| Since GitHub is not free software, we fully understand | ||
| if one does not want to register an account just to participate | ||
| in our development. Therefore, we also welcome patches | ||
| and bug reports sent via email. | ||
| First of all, thank you for using and contributing to palace! We welcome | ||
| all forms of contribution, and `the mo the merier`_. By saying this, we also | ||
| mean that we much prefer receiving many small and self-contained bug reports, | ||
| feature requests and patches than a giant one. There is no limit for | ||
| the number of contributions one may or should make. While it may seem | ||
| appealing to be able to dump all thoughts and feelings into one ticket, | ||
| it would be more difficult for us to keep track of the progress. | ||
| Reporting a Bug | ||
| --------------- | ||
| Before filing a bug report, please make sure that the bug has not been | ||
| already reported by searching our GitHub Issues_ tracker. | ||
| To facilitate the debugging process, a bug report should at least contain | ||
| the following information: | ||
| #. The platform, the CPython version and the compiler used to build it. | ||
| These can be obtained from :py:func:`platform.platform`, | ||
| :py:func:`platform.python_version` and :py:func:`platform.python_compiler`, | ||
| respectively. | ||
| #. The version of palace and how you installed it. | ||
| The earlier is usually provided by ``pip show palace``. | ||
| #. Detailed instructions on how to reproduce the bug, | ||
| for example a short Python script would be appreciated. | ||
| Requesting a Feature | ||
| -------------------- | ||
| Prior to filing a feature request, please make sure that the feature | ||
| has not been already reported by searching our GitHub Issues_ tracker. | ||
| Please only ask for features that you (or an incapacitated friend | ||
| you can personally talk to) require. Do not request features because | ||
| they seem like a good idea. If they are really useful, they will be | ||
| requested by someone who requires them. | ||
| Submitting a Patch | ||
| ------------------ | ||
| We accept all kinds of patches, from documentation and CI/CD setup | ||
| to bug fixes, feature implementations and tests. These are hosted on GitHub | ||
| and one may create a local repository by running:: | ||
| git clone https://github.com/McSinyx/palace | ||
| While the patch can be submitted via email, it is preferable to file | ||
| a pull request on GitHub against the ``master`` branch to allow more people | ||
| to review it, since we do not have any mail list. Either way, contributors | ||
| must have legal permission to distribute the code and it must be available | ||
| under `LGPLv3+`_. Furthermore, each contributor retains the copyrights | ||
| of their patch, to ensure that the licence can never be revoked even if | ||
| others wants to. It is advisable that the author list per legal name | ||
| under the copyright header of each source file they modify, like so:: | ||
| Copyright (C) 2038 Foo Bar | ||
| Using GitHub | ||
| ^^^^^^^^^^^^ | ||
| #. Create a fork_ of our repository on GitHub. | ||
| #. Checkout the source code and (optionally) add the ``upstream`` remote:: | ||
| git clone https://github.com/YOUR_GITHUB_USERNAME/palace | ||
| cd palace | ||
| git remote add upstream https://github.com/McSinyx/palace | ||
| #. Start working on your patch and make sure your code complies with | ||
| the `Style Guidelines`_ and passes the test suit run by tox_. | ||
| #. Add relevant tests to the patch and work on it until they all pass. | ||
| In case one is only modifying tests, perse may install palace using | ||
| ``CYTHON_TRACE=1 pip install .`` then run pytest_ directly to avoid | ||
| having to build the extension module multiple times. | ||
| #. Update the copyright notices of the files you modified. | ||
| Palace is collectively licensed under `LGPLv3+`_, | ||
| and to protect the freedom of the users, | ||
| copyright holders need to be properly documented. | ||
| #. Add_, commit_ with `a great message`_ then push_ the result. | ||
| #. Finally, `create a pull request`_. We will then review and merge it. | ||
| It is recommended to create a new branch in your fork | ||
| (``git checkout -c what-you-are-working-on``) instead of working directly | ||
| on ``master``. This way one can still sync per fork with our ``master`` branch | ||
| and ``git pull --rebase upstream master`` to avoid integration issues. | ||
| Via Email | ||
| ^^^^^^^^^ | ||
| #. Checkout the source code:: | ||
| git clone https://github.com/McSinyx/palace | ||
| cd palace | ||
| #. Work on your patch with tests and copyright notice included | ||
| as described above. | ||
| #. `git-format-patch`_ and send it to one of the maintainers | ||
| (our emails addresses are available under ``git log``). | ||
| We will then review and merge it. | ||
| In any case, thank you very much for your contributions! | ||
| Making a Release | ||
| ---------------- | ||
| While this is meant for developers doing a palace release, contributors wishing | ||
| to improve the CI/CD may find it helpful. | ||
| #. Under the local repository, checkout the ``master`` branch | ||
| and sync with the one on GitHub using ``git pull``. | ||
| #. Bump the version in ``setup.cfg`` and push to GitHub. | ||
| #. Create a source distribution by running ``setup.py sdist``. | ||
| The distribution generated by this command is now referred to as ``sdist``. | ||
| #. Using twine_, upload the ``sdist`` to PyPI via ``twine upload $sdist``. | ||
| #. On GitHub, tag a new release with the ``sdist`` attached. | ||
| In the release note, make sure to include all user-facing changes | ||
| since the previous release. This will trigger the CD services | ||
| to build the wheels and publish them to PyPI. | ||
| #. Wait for the wheel for your platform to arrive to PyPI and install it. | ||
| Play around with it for a little to make sure that everything is OK. | ||
| Style Guidelines | ||
| ---------------- | ||
| Python and Cython | ||
| ^^^^^^^^^^^^^^^^^ | ||
| Generally, palace follows :pep:`8` and :pep:`257`, | ||
| with the following preferences and exceptions: | ||
| * Hanging indentation is *always* preferred, | ||
| where continuation lines are indented by 4 spaces. | ||
| * Comments and one-line docstrings are limited to column 79 | ||
| instead of 72 like for multi-line docstrings. | ||
| * Cython extern declarations need not follow the 79-character limit. | ||
| * Break long lines before a binary operator. | ||
| * Use form feeds sparingly to break long modules | ||
| into pages of relating functions and classes. | ||
| * Prefer single-quoted strings over double-quoted strings, | ||
| unless the string contains single quote characters. | ||
| * Avoid trailing commas at all costs. | ||
| * Line breaks within comments and docstrings should not cut a phrase in half. | ||
| * Everything deserves a docstring. Palace follows numpydoc_ which support | ||
| documenting attributes as well as constants and module-level variables. | ||
| In additional to docstrings, type annotations should be employed | ||
| for all public names. | ||
| * Use numpydoc_ markups moderately to keep docstrings readable as plain text. | ||
| C++ | ||
| ^^^ | ||
| C++ codes should follow GNU style, which is best documented at Octave_. | ||
| reStructuredText | ||
| ^^^^^^^^^^^^^^^^ | ||
| In order for reStructuredText to be rendered correctly, the body of | ||
| constructs beginning with a marker (lists, hyperlink targets, comments, etc.) | ||
| must be aligned relative to the marker. For this reason, it is convenient | ||
| to set your editor indentation level to 3 spaces, since most constructs | ||
| starts with two dots and a space. However, be aware of that bullet items | ||
| require 2-space alignment and other exceptions. | ||
| Limit all lines to a maximum of 79 characters. Similar to comments | ||
| and docstrings, phrases should not be broken in the middle. | ||
| The source code of this guide itself is a good example on how line breaks | ||
| should be handled. Additionally, two spaces should also be used | ||
| after a sentence-ending period in multi-sentence paragraph, | ||
| except after the final sentence. | ||
| .. _GitHub: https://github.com/McSinyx/palace | ||
| .. _the mo the merier: | ||
| https://www.phrases.org.uk/meanings/the-more-the-merrier.html | ||
| .. _Issues: https://github.com/McSinyx/palace/issues | ||
| .. _LGPLv3+: https://www.gnu.org/licenses/lgpl-3.0.en.html | ||
| .. _fork: https://github.com/McSinyx/palace/fork | ||
| .. _tox: https://tox.readthedocs.io/en/latest/ | ||
| .. _pytest: https://docs.pytest.org/en/latest/ | ||
| .. _Add: https://git-scm.com/docs/git-add | ||
| .. _commit: https://git-scm.com/docs/git-commit | ||
| .. _a great message: https://chris.beams.io/posts/git-commit/#seven-rules | ||
| .. _push: https://git-scm.com/docs/git-push | ||
| .. _create a pull request: | ||
| https://help.github.com/articles/creating-a-pull-request | ||
| .. _git-format-patch: https://git-scm.com/docs/git-format-patch | ||
| .. _twine: https://twine.readthedocs.io/en/latest/ | ||
| .. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html | ||
| .. _Octave: https://wiki.octave.org/C%2B%2B_style_guide |
| Copying | ||
| ======= | ||
| This listing is our best-faith, hard-work effort at accurate attribution, | ||
| sources, and licenses for everything in palace. If you discover | ||
| an asset/contribution that is incorrectly attributed or licensed, | ||
| please contact us immediately. We are happy to do everything we can | ||
| to fix or remove the issue. | ||
| License | ||
| ------- | ||
| Palace is free software: you can redistribute it and/or modify it | ||
| under the terms of the `GNU Lesser General Public License`_ | ||
| as published by the Free Software Foundation, either version 3 | ||
| of the License, or (at your option) any later version. | ||
| To ensure that palace can run without any dependencies outside of the pip_ | ||
| toolchain, the wheels are bundled with dynamically linked libraries from | ||
| the build machine, which is similar to static linking: | ||
| ============== ============ | ||
| Library License | ||
| ============== ============ | ||
| Alure_ ZLib | ||
| `OpenAL Soft`_ GNU LGPLv2+ | ||
| Vorbis_ 3-clause BSD | ||
| Opus_ 3-clause BSD | ||
| libsndfile_ GNU LGPL2.1+ | ||
| ============== ============ | ||
| In addition, the following sounds are used for testing: | ||
| =============================================== ========= | ||
| Sound (located in ``tests/data``) License | ||
| =============================================== ========= | ||
| `164957__zonkmachine__white-noise.ogg`_ CC0 1.0 | ||
| `24741__tim-kahn__b23-c1-raw.aiff`_ CC BY 3.0 | ||
| `261590__kwahmah-02__little-glitch.flac`_ CC BY 3.0 | ||
| `353684__tec-studio__drip2.mp3`_ CC0 1.0 | ||
| `99642__jobro__deconvoluted-20hz-to-20khz.wav`_ CC BY 3.0 | ||
| =============================================== ========= | ||
| Credits | ||
| ------- | ||
| Palace would never have seen the light of day without the help from | ||
| the developers of Alure_ and Cython_ who promptly gave detail answers | ||
| and made quick fixes to all of our problems. | ||
| The wheels are build using cibuildwheel_, which made building extension modules | ||
| much less of a painful experience. `Travis CI`_ and AppVeyor_ kindly provides | ||
| their services free of charge for automated CI/CD. | ||
| This documentation is generated using Sphinx_, whose maintainer responses | ||
| extreamly quickly to obsolete Cython-related issues. | ||
| .. _GNU Lesser General Public License: | ||
| https://www.gnu.org/licenses/lgpl-3.0.en.html | ||
| .. _pip: https://pip.pypa.io/en/latest/ | ||
| .. _Alure: https://github.com/kcat/alure | ||
| .. _OpenAL Soft: https://kcat.strangesoft.net/openal.html | ||
| .. _Vorbis: https://xiph.org/vorbis/ | ||
| .. _Opus: https://opus-codec.org/ | ||
| .. _libsndfile: http://www.mega-nerd.com/libsndfile/ | ||
| .. _164957__zonkmachine__white-noise.ogg: https://freesound.org/s/164957/ | ||
| .. _24741__tim-kahn__b23-c1-raw.aiff: https://freesound.org/s/24741/ | ||
| .. _261590__kwahmah-02__little-glitch.flac: https://freesound.org/s/261590/ | ||
| .. _353684__tec-studio__drip2.mp3: https://freesound.org/s/353684/ | ||
| .. _99642__jobro__deconvoluted-20hz-to-20khz.wav: https://freesound.org/s/99642/ | ||
| .. _Cython: https://cython.org/ | ||
| .. _cibuildwheel: https://cibuildwheel.readthedocs.io/en/stable/ | ||
| .. _Sphinx: https://www.sphinx-doc.org/en/master/ | ||
| .. _Travis CI: https://travis-ci.com/ | ||
| .. _AppVeyor: https://www.appveyor.com/ |
| Design Principles | ||
| ================= | ||
| .. currentmodule:: palace | ||
| In this section, we will discuss a few design principles in order to write | ||
| a safe, efficient, easy-to-use and extendable 3D audio library for Python, | ||
| by wrapping existing functionalities from the C++ API alure_. | ||
| This part of the documentation assumes its reader are at least familiar with | ||
| Cython, Python and C++11. | ||
| .. _impl-idiom: | ||
| The Impl Idiom | ||
| -------------- | ||
| *Not to be confused with* `the pimpl idiom`_. | ||
| For memory-safety, whenever possible, we rely on Cython for allocation and | ||
| deallocation of C++ objects. To do this, the nullary constructor needs to be | ||
| (re-)declared in Cython, e.g. | ||
| .. code-block:: cython | ||
| cdef extern from 'foobar.h' namespace 'foobar': | ||
| cdef cppclass Foo: | ||
| Foo() | ||
| float meth(size_t crack) except + | ||
| ... | ||
| The Cython extension type can then be declared as follows | ||
| .. code-block:: cython | ||
| cdef class Bar: | ||
| cdef Foo impl | ||
| def __init__(self, *args, **kwargs): | ||
| self.impl = ... | ||
| @staticmethod | ||
| def from_baz(baz: Baz) -> Bar: | ||
| bar = Bar.__new__(Bar) | ||
| bar.impl = ... | ||
| return bar | ||
| def meth(self, crack: int) -> float: | ||
| return self.impl.meth(crack) | ||
| The Modern Python | ||
| ----------------- | ||
| One of the goal of palace is to create a Pythonic, i.e. intuitive and concise, | ||
| interface. To achieve this, we try to make use of some modern Python features, | ||
| which not only allow users to adopt palace with ease, but also make their | ||
| programs more readable and less error-prone. | ||
| .. _getter-setter: | ||
| Property Attributes | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
| A large proportion of alure API are getters/setter methods. In Python, | ||
| it is a good practice to use property_ to abstract these calls, and thus make | ||
| the interface more natural with attribute-like referencing and assignments. | ||
| Due to implementation details, Cython has to hijack the ``@property`` decorator | ||
| to make it work for read-write properties. Unfortunately, the Cython-generated | ||
| descriptors do not play very well with other builtin decorators, thus in some | ||
| cases, it is recommended to alias the call to ``property`` as follows | ||
| .. code-block:: python | ||
| getter = property | ||
| setter = lambda fset: property(fset=fset, doc=fset.__doc__) | ||
| Then ``@getter`` and ``@setter`` can be used to decorate read-only and | ||
| write-only properties, respectively, without any trouble even if other | ||
| decorators are used for the same extension type method. | ||
| Context Managers | ||
| ^^^^^^^^^^^^^^^^ | ||
| The alure API defines many objects that need manual tear-down in | ||
| a particular order. Instead of trying to be clever and perform automatic | ||
| clean-ups at garbage collection, we should put the user in control. | ||
| To quote *The Zen of Python*, | ||
| | If the implementation is hard to explain, it's a bad idea. | ||
| | If the implementation is easy to explain, it may be a good idea. | ||
| With that being said, it does not mean we do not provide any level of | ||
| abstraction. A simplified case in point would be | ||
| .. code-block:: cython | ||
| cdef class Device: | ||
| cdef alure.Device impl | ||
| def __init__(self, name: str = '') -> None: | ||
| self.impl = devmgr.open_playback(name) | ||
| def __enter__(self) -> Device: | ||
| return self | ||
| def __exit__(self, *exc) -> Optional[bool]: | ||
| self.close() | ||
| def close(self) -> None: | ||
| self.impl.close() | ||
| Now if the ``with`` statement is used, it will make sure the device | ||
| will be closed, regardless of whatever may happen within the inner block | ||
| .. code-block:: python | ||
| with Device() as dev: | ||
| ... | ||
| as it is equivalent to | ||
| .. code-block:: python | ||
| dev = Device() | ||
| try: | ||
| ... | ||
| finally: | ||
| dev.close() | ||
| Other than closure/destruction of objects, typical uses of `context managers`__ | ||
| also include saving and restoring various kinds of global state (as seen in | ||
| :py:class:`Context`), locking and unlocking resources, etc. | ||
| __ https://docs.python.org/3/reference/datamodel.html#context-managers | ||
| The Double Reference | ||
| -------------------- | ||
| While wrapping C++ interfaces, :ref:`the impl idiom <impl-idiom>` might not | ||
| be adequate, since the derived Python methods need to be callable from C++. | ||
| Luckily, Cython can handle Python objects within C++ classes just fine, | ||
| although we'll need to handle the reference count ourselves, e.g. | ||
| .. code-block:: cython | ||
| cdef cppclass CppDecoder(alure.BaseDecoder): | ||
| Decoder pyo | ||
| __init__(Decoder decoder): | ||
| this.pyo = decoder | ||
| Py_INCREF(pyo) | ||
| __dealloc__(): | ||
| Py_DECREF(pyo) | ||
| bool seek(uint64_t pos): | ||
| return pyo.seek(pos) | ||
| With this being done, we can now write the wrapper as simply as | ||
| .. code-block:: cython | ||
| cdef class BaseDecoder: | ||
| cdef shared_ptr[alure.Decoder] pimpl | ||
| def __cinit__(self, *args, **kwargs) -> None: | ||
| self.pimpl = shared_ptr[alure.Decoder](new CppDecoder(self)) | ||
| def seek(pos: int) -> bool: | ||
| ... | ||
| Because ``__cinit__`` is called by ``__new__``, any Python class derived | ||
| from ``BaseDecoder`` will be exposed to C++ as an attribute of ``CppDecoder``. | ||
| Effectively, this means the users can have the alure API calling their | ||
| inherited Python object as naturally as if palace is implemented in pure Python. | ||
| In practice, :py:class:`BaseDecoder` will also need to take into account | ||
| other guarding mechanisms like :py:class:`abc.ABC`. Due to Cython limitations, | ||
| implementation as a pure Python class and :ref:`aliasing <getter-setter>` of | ||
| ``@getter``/``@setter`` should be considered. | ||
| .. _alure: https://github.com/kcat/alure | ||
| .. _`the pimpl idiom`: https://wiki.c2.com/?PimplIdiom | ||
| .. _property: https://docs.python.org/3/library/functions.html#property |
| Overview | ||
| ======== | ||
| Pythonic Audio Library and Codecs Environment provides common higher-level API | ||
| for audio rendering using OpenAL: | ||
| * 3D positional rendering, with HRTF_ support for stereo systems | ||
| * Environmental effects: reverb, atmospheric air absorption, | ||
| sound occlusion and obstruction | ||
| * Out-of-the-box codec support: FLAC, MP3, Ogg Vorbis, Opus, WAV, AIFF, etc. | ||
| Palace wraps around the C++ interface alure_ using Cython_ for a safe and | ||
| convenient interface with type hinting, data descriptors and context managers, | ||
| following :pep:`8#naming-conventions` (``PascalCase.snake_case``). | ||
| .. toctree:: | ||
| :caption: Table of Contents | ||
| :maxdepth: 2 | ||
| installation | ||
| tutorial/index | ||
| reference/index | ||
| design | ||
| contributing | ||
| copying | ||
| .. toctree:: | ||
| :caption: Quick Navigation | ||
| :hidden: | ||
| Python Package Index <https://pypi.org/project/palace/> | ||
| Travis CI Build <https://travis-ci.com/github/McSinyx/palace> | ||
| AppVeyor Build <https://ci.appveyor.com/project/McSinyx/palace> | ||
| GitHub Repository <https://github.com/McSinyx/palace> | ||
| Matrix Chat Room <https://matrix.to/#/#palace-dev:matrix.org> | ||
| Indices and Tables | ||
| ------------------ | ||
| * :ref:`genindex` | ||
| * :ref:`search` | ||
| .. _HRTF: https://en.wikipedia.org/wiki/Head-related_transfer_function | ||
| .. _alure: https://github.com/kcat/alure | ||
| .. _Cython: https://cython.org |
| Installation | ||
| ============ | ||
| Prerequisites | ||
| ------------- | ||
| Palace requires CPython_ version 3.6 or above for runtime | ||
| and pip_ for installation. | ||
| Via PyPI | ||
| -------- | ||
| Palace can be installed from PyPI:: | ||
| pip install palace | ||
| Wheel distributions are built exclusively for amd64. Currently, only GNU/Linux | ||
| and macOS are properly supported. If you want to help packaging for Windows, | ||
| please see `GH-1`_ on our issues tracker on GitHub. | ||
| From source | ||
| ----------- | ||
| Aside from the build dependencies listed in ``pyproject.toml``, | ||
| one will additionally need compatible Python headers, alure_, | ||
| a C++14 compiler, CMake_ 2.6+ (and probably git_ for fetching the source). | ||
| Palace can then be compiled and installed by running:: | ||
| git clone https://github.com/McSinyx/palace.git | ||
| pip install palace/ | ||
| .. _CPython: https://www.python.org/ | ||
| .. _pip: https://pip.pypa.io/en/latest/ | ||
| .. _GH-1: https://github.com/McSinyx/palace/issues/1 | ||
| .. _alure: https://github.com/kcat/alure | ||
| .. _CMake: https://cmake.org/ | ||
| .. _git: https://git-scm.com/ |
| Resource Caching | ||
| ================ | ||
| .. currentmodule:: palace | ||
| Audio Buffers | ||
| ------------- | ||
| .. autoclass:: Buffer | ||
| :members: | ||
| Loading & Freeing in Batch | ||
| -------------------------- | ||
| .. autofunction:: cache | ||
| .. autofunction:: free |
| Audio Library Contexts | ||
| ====================== | ||
| .. currentmodule:: palace | ||
| Context and Auxiliary Classes | ||
| ----------------------------- | ||
| .. autoclass:: Context | ||
| :members: | ||
| .. autoclass:: Listener | ||
| :members: | ||
| .. autoclass:: MessageHandler | ||
| :members: | ||
| Using Contexts | ||
| -------------- | ||
| .. autofunction:: use_context | ||
| .. autofunction:: current_context | ||
| .. autofunction:: thread_local | ||
| Context Creation Attributes | ||
| --------------------------- | ||
| .. data:: CHANNEL_CONFIG | ||
| :type: int | ||
| Context creation key to specify the channel configuration | ||
| (either ``MONO``, ``STEREO``, ``QUAD``, ``X51``, ``X61`` or ``X71``). | ||
| .. data:: SAMPLE_TYPE | ||
| :type: int | ||
| Context creation key to specify the sample type | ||
| (either ``[UNSIGNED_]{BYTE,SHORT,INT}`` or ``FLOAT``). | ||
| .. data:: FREQUENCY | ||
| :type: int | ||
| Context creation key to specify the frequency in hertz. | ||
| .. data:: MONO_SOURCES | ||
| :type: int | ||
| Context creation key to specify the number of mono (3D) sources. | ||
| .. data:: STEREO_SOURCES | ||
| :type: int | ||
| Context creation key to specify the number of stereo sources. | ||
| .. data:: MAX_AUXILIARY_SENDS | ||
| :type: int | ||
| Context creation key to specify the maximum number of | ||
| auxiliary source sends. | ||
| .. data:: HRTF | ||
| :type: int | ||
| Context creation key to specify whether to enable HRTF | ||
| (either ``FALSE``, ``TRUE`` or ``DONT_CARE``). | ||
| .. data:: HRTF_ID | ||
| :type: int | ||
| Context creation key to specify the HRTF to be used. | ||
| .. data:: OUTPUT_LIMITER | ||
| :type: int | ||
| Context creation key to specify whether to use a gain limiter | ||
| (either ``FALSE``, ``TRUE`` or ``DONT_CARE``). | ||
| .. data:: distance_models | ||
| :type: Tuple[str, ...] | ||
| Names of available distance models. |
| Audio Streams | ||
| ============= | ||
| .. currentmodule:: palace | ||
| Builtin Decoders | ||
| ---------------- | ||
| .. autoclass:: Decoder | ||
| :members: | ||
| Decoder Interface | ||
| ----------------- | ||
| .. data:: decoder_factories | ||
| :type: DecoderNamespace | ||
| Simple object for storing decoder factories. | ||
| User-registered factories are tried one after another | ||
| if :py:exc:`RuntimeError` is raised, in lexicographical order. | ||
| Internal decoder factories are always used after registered ones. | ||
| .. autofunction:: decode | ||
| .. autoclass:: BaseDecoder | ||
| :members: | ||
| Miscellaneous | ||
| ------------- | ||
| .. data:: sample_types | ||
| :type: Tuple[str, ...] | ||
| Names of available sample types. | ||
| .. data:: channel_configs | ||
| :type: Tuple[str, ...] | ||
| Names of available channel configurations. | ||
| .. autofunction:: sample_size | ||
| .. autofunction:: sample_length |
| Audio Devices | ||
| ============= | ||
| .. currentmodule:: palace | ||
| Device-Dependent Utilities | ||
| -------------------------- | ||
| .. autoclass:: Device | ||
| :members: | ||
| Device-Independent Utilities | ||
| ---------------------------- | ||
| .. data:: device_names | ||
| :type: DeviceNames | ||
| Read-only namespace of device names by category (``basic``, ``full`` and | ||
| ``capture``), as tuples of strings whose first item being the default. | ||
| .. autofunction:: query_extension |
| Environmental Effects | ||
| ===================== | ||
| .. currentmodule:: palace | ||
| For the sake of brevity, we only document the constraints of each effect's | ||
| properties. Further details can be found at OpenAL's `Effect Extension Guide`_ | ||
| which specifies the purpose and usage of each value. | ||
| Base Effect | ||
| ----------- | ||
| .. autoclass:: BaseEffect | ||
| :members: | ||
| Chorus Effect | ||
| ------------- | ||
| .. autoclass:: ChorusEffect | ||
| :members: | ||
| Reverb Effect | ||
| ------------- | ||
| .. data:: reverb_preset_names | ||
| :type: Tuple[str, ...] | ||
| Names of predefined reverb effect presets in lexicographical order. | ||
| .. autoclass:: ReverbEffect | ||
| :members: | ||
| .. _Effect Extension Guide: | ||
| https://kcat.strangesoft.net/misc-downloads/Effects%20Extension%20Guide.pdf |
| File I/O Interface | ||
| ================== | ||
| .. currentmodule:: palace | ||
| .. autofunction:: current_fileio | ||
| .. autofunction:: use_fileio | ||
| .. autoclass:: FileIO | ||
| :members: |
| Reference | ||
| ========= | ||
| API reference is divided into the following sections: | ||
| .. toctree:: | ||
| device | ||
| context | ||
| buffer | ||
| source | ||
| effect | ||
| decoder | ||
| file-io |
| Sources & Source Groups | ||
| ======================= | ||
| .. currentmodule:: palace | ||
| Sources | ||
| ------- | ||
| .. autoclass:: Source | ||
| :members: | ||
| Source Groups | ||
| ------------- | ||
| .. autoclass:: SourceGroup | ||
| :members: |
| <h3>Quick Navigation</h3> | ||
| <ul> | ||
| <li class="toctree-l1"> | ||
| <a class="reference external" href="https://pypi.org/project/palace/"> | ||
| Python Package Index | ||
| </a> | ||
| </li> | ||
| <li class="toctree-l1"> | ||
| <a class="reference external" | ||
| href="https://travis-ci.com/github/McSinyx/palace"> | ||
| Travis CI Build | ||
| </a> | ||
| </li> | ||
| <li class="toctree-l1"> | ||
| <a class="reference external" | ||
| href="https://ci.appveyor.com/project/McSinyx/palace"> | ||
| AppVeyor Build | ||
| </a> | ||
| </li> | ||
| <li class="toctree-l1"> | ||
| <a class="reference external" href="https://github.com/McSinyx/palace"> | ||
| GitHub Repository | ||
| </a> | ||
| </li> | ||
| <li class="toctree-l1"> | ||
| <a class="reference external" | ||
| href="https://matrix.to/#/#palace-dev:matrix.org"> | ||
| Matrix Chat Room | ||
| </a> | ||
| </li> | ||
| </ul> |
| Context Creation | ||
| ================ | ||
| .. currentmodule:: palace | ||
| A context is an object that allows palace to access OpenAL, | ||
| which is essential when you work with palace. Context maintains | ||
| the audio environment and contains environment settings and components | ||
| such as sources, buffers, and effects. | ||
| Creating a Device Object | ||
| ------------------------ | ||
| To create a context, we must first create a device, | ||
| since it's a parameter of the context object. | ||
| To create an object, well, you just have to instantiate | ||
| the :py:class:`Device` class. | ||
| .. code-block:: python | ||
| from palace import Device | ||
| with Device() as dev: | ||
| # Your code goes here | ||
| This is how you declare a :py:class:`Device` object with the default device. | ||
| There can be several devices available, which can be found | ||
| in :py:data:`device_names`. | ||
| Creating a Context | ||
| ------------------ | ||
| Now that we've created a device, we can create the context: | ||
| .. code-block:: python | ||
| from palace import Device, Context | ||
| with Device() as dev, Context(dev) as ctx: | ||
| # Your code goes here |
| Adding an Effect | ||
| ================ | ||
| .. currentmodule:: palace | ||
| This section will focus on how to add effects to the audio. | ||
| There are two set of audio effects supported by palace: :py:class:`ReverbEffect` | ||
| and :py:class:`ChorusEffect`. | ||
| Reverb Effect | ||
| ------------- | ||
| Reverb happens when a sound is reflected and then decay as the sound is absorbed | ||
| by the objects in the medium. :py:class:`ReverbEffect` facilitates such effect. | ||
| Creating a reverb effect can be as simple as: | ||
| .. code-block:: python | ||
| with ReverbEffect() as effect: | ||
| source.sends[0].effect = effect | ||
| :py:attr:`Source.sends` is a collection of send path signals, each of which | ||
| contains `effects` and `filter` that describes it. Here we are only concerned | ||
| about the former. | ||
| The above code would yield a *generic* reverb effect by default. | ||
| There are several other presets that you can use, which are listed | ||
| by :py:data:`reverb_preset_names`. To use these preset, you can simply provide | ||
| the preset effect name as the first parameter for the constructor. For example, | ||
| to use `PIPE_LARGE` preset effect, you can initialize the effect like below: | ||
| .. code-block:: python | ||
| with ReverbEffect('PIPE_LARGE') as effect: | ||
| source.sends[0].effect = effect | ||
| These effects can be modified via their attributes. | ||
| .. code-block:: python | ||
| effect.gain = 0.4 | ||
| effect.diffusion = 0.65 | ||
| late_reverb_pan = 0.2, 0.1, 0.3 | ||
| The list of these attributes and their constraints can be found | ||
| in the documentation of :py:class:`ReverbEffect`. | ||
| Chorus Effect | ||
| ------------- | ||
| :py:class:`ChorusEffect` does not have preset effects like | ||
| :py:class:`ReverbEffect`, so you would have to initialize the effect attributes | ||
| on creation. | ||
| There are five parameters to initialize the effect, respectively: waveform, | ||
| phase, depth, feedback, and delay. | ||
| .. code-block:: python | ||
| with ChorusEffect('sine', 20, 0.4, 0.5, 0.008) as effect: | ||
| source.sends[0].effect = effect | ||
| For the constraints of these parameters, please refer to the documentation. |
| Tutorial | ||
| ======== | ||
| This tutorial will guide you on: | ||
| .. toctree:: | ||
| :maxdepth: 2 | ||
| context | ||
| play-audio | ||
| source | ||
| effect | ||
| .. comment these to add later | ||
| Customize decoder | ||
| Generate sounds |
| Play an Audio | ||
| ============= | ||
| .. currentmodule:: palace | ||
| Now that you know how to create a context, | ||
| let's get into the most essential use case: playing audio. | ||
| Creating a Source | ||
| ----------------- | ||
| To play an audio, you have to create a source. This source | ||
| is an imaginary sound broadcaster, whose positions and properties | ||
| can be changed to create desired effects. | ||
| .. code-block:: python | ||
| from palace import Device, Context, Source | ||
| with Device() as dev, Context(dev) as ctx: | ||
| with Source() as src: | ||
| # to be written | ||
| Just like for the case of :py:class:`Context`, :py:class:`Source` creation | ||
| requires a context, but here the context is passed implicitly. | ||
| Decode the Audio File | ||
| --------------------- | ||
| Palace has a module level function :py:func:`decode`, which decodes audio file | ||
| automatically, and this decoded file is a :py:class:`Decoder` object. This object | ||
| can be played by a simple :py:meth:`Decoder.play` method. | ||
| .. code-block:: python | ||
| from palace import Device, Context, Source, decode | ||
| filename = 'some_audio.ogg' | ||
| with Device() as dev, Context(dev) as ctx: | ||
| with Source() as src: | ||
| dec = decode(filename) | ||
| We are almost there. Now, let's look at the document for :py:meth:`Decoder.play`. | ||
| The method takes 3 parameters: ``chunk_len``, ``queue_size``, and ``source``. | ||
| The source object is optional, because if you don't have it, a new source | ||
| will be generated by default. | ||
| The audio is divided into chunks, each of which is of length ``chunk_len``. | ||
| Then ``queue_size`` is the number of these chunks that it will play. | ||
| .. TODO: I think it's better to include a diagram here. Add later | ||
| .. code-block:: python | ||
| from palace import Device, Context, Source, decode | ||
| filename = 'some_audio.ogg' | ||
| with Device() as dev, Context(dev) as ctx: | ||
| with Source() as src: | ||
| dec = decode(filename) | ||
| dec.play(12000, 4, src) | ||
| But we don't want it to play only a small part of the audio. We want it to | ||
| play all of it. How do we do that? The answer is a loop. | ||
| There is a method, :py:meth:`Context.update`, which update the context and the source. | ||
| When the source is updated, it will be filled with new chunks of data from | ||
| the decoder. | ||
| .. code-block:: python | ||
| from palace import Device, Context, Source, decode | ||
| filename = 'some_audio.ogg' | ||
| with Device() as dev, Context(dev) as ctx: | ||
| with Source() as src: | ||
| dec = decode(filename) | ||
| dec.play(12000, 4, src) | ||
| while src.playing: | ||
| ctx.update() | ||
| If you tried this code for a song, you will find that it's a bit rush. | ||
| That is because the source is renewed too fast. So, a simple solution | ||
| is to ``sleep`` for a while. | ||
| .. code-block:: python | ||
| from time import sleep | ||
| from palace import Device, Context, Source, decode | ||
| filename = 'some_audio.ogg' | ||
| with Device() as dev, Context(dev) as ctx: | ||
| with Source() as src: | ||
| dec = decode(filename) | ||
| dec.play(12000, 4, src) | ||
| while src.playing: | ||
| sleep(0.025) | ||
| ctx.update() | ||
| Congratulation! Enjoy your music before we get to the next part of this tutorial. |
| Source Manipulation | ||
| =================== | ||
| .. currentmodule:: palace | ||
| We have created a source in the last section. | ||
| As said previously, its properties can be manipulated to create wanted effects. | ||
| Moving the Source | ||
| ----------------- | ||
| Changing :py:attr:`Source.position` is one of the most noticeable, | ||
| but first, we have to enable spatialization via :py:attr:`Source.spatialize`. | ||
| .. code-block:: python | ||
| from time import sleep | ||
| from palace import Device, Context, Source, decode | ||
| with Device() as device, Context(device) as context, Source() as source: | ||
| source.spatialize = True | ||
| decoder = decode('some_audio.ogg') | ||
| decoder.play(12000, 4, source) | ||
| while source.playing: | ||
| sleep(0.025) | ||
| context.update() | ||
| Now, we can set the position of the source in this virtual 3D space. | ||
| The position is a 3-tuple indicating the coordinate of the source. | ||
| The axes are aligned according to the normal coordinate system: | ||
| - The x-axis goes from left to right | ||
| - The y-axis goes from below to above | ||
| - The z-axis goes from front to back | ||
| For example, this will set the source above the listener:: | ||
| src.position = 0, 1, 0 | ||
| .. note:: | ||
| For this too work for stereo, you have to have HRTF enabled. | ||
| You can check that via :py:attr:`Device.current_hrtf`. | ||
| You can as well use a function to move the source automatically by writing | ||
| a function that generate positions. A simple example is circular motion. | ||
| .. code-block:: python | ||
| from itertools import takewhile, count | ||
| ... | ||
| for i in takewhile(src.playing, count(step=0.025)): | ||
| source.position = sin(i), 0, cos(-i) | ||
| ... | ||
| A more well-written example of this can be found `in our repository`_. | ||
| Speed and Pitch | ||
| --------------- | ||
| Modifying :py:attr:`pitch` changes the playing speed, effectively changing | ||
| pitch. Pitch can be any positive number. | ||
| .. code-block:: python | ||
| src.pitch = 2 # high pitch | ||
| src.pitch = 0.4 # low pitch | ||
| Air Absorption Factor | ||
| --------------------- | ||
| :py:attr:`Source.air_absorption_factor` simulates atmospheric high-frequency | ||
| air absorption. Higher values simulate foggy air and lower values simulate | ||
| drier air. | ||
| .. code-block:: python | ||
| src.air_absorption_factor = 9 # very high humidity | ||
| src.air_absorption_factor = 0 # dry air (default) | ||
| .. _in our repository: | ||
| https://github.com/McSinyx/palace/blob/master/examples/palace-hrtf.py |
+3
-0
| include CMakeLists.txt | ||
| recursive-include src *.h *.pxd *.pyx | ||
| graft docs | ||
| prune docs/build | ||
| include tox.ini | ||
@@ -5,0 +8,0 @@ recursive-include tests *.py |
| Metadata-Version: 2.1 | ||
| Name: palace | ||
| Version: 0.2.1 | ||
| Version: 0.2.2 | ||
| Summary: Pythonic Audio Library and Codecs Environment | ||
@@ -77,7 +77,7 @@ Home-page: https://mcsinyx.github.io/palace | ||
| [CMake]: https://cmake.org/ | ||
| [API]: https://mcsinyx.github.io/palace/html/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/html/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/html/design.html | ||
| [API]: https://mcsinyx.github.io/palace/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/design.html | ||
| [LGPLv3+]: https://www.gnu.org/licenses/lgpl-3.0.en.html | ||
| [copying]: https://mcsinyx.github.io/palace/html/copying.html | ||
| [copying]: https://mcsinyx.github.io/palace/copying.html | ||
@@ -84,0 +84,0 @@ Keywords: openal,alure,hrtf |
@@ -9,2 +9,24 @@ CMakeLists.txt | ||
| tox.ini | ||
| docs/Makefile | ||
| docs/make.bat | ||
| docs/source/conf.py | ||
| docs/source/contributing.rst | ||
| docs/source/copying.rst | ||
| docs/source/design.rst | ||
| docs/source/index.rst | ||
| docs/source/installation.rst | ||
| docs/source/reference/buffer.rst | ||
| docs/source/reference/context.rst | ||
| docs/source/reference/decoder.rst | ||
| docs/source/reference/device.rst | ||
| docs/source/reference/effect.rst | ||
| docs/source/reference/file-io.rst | ||
| docs/source/reference/index.rst | ||
| docs/source/reference/source.rst | ||
| docs/source/templates/quicknav.html | ||
| docs/source/tutorial/context.rst | ||
| docs/source/tutorial/effect.rst | ||
| docs/source/tutorial/index.rst | ||
| docs/source/tutorial/play-audio.rst | ||
| docs/source/tutorial/source.rst | ||
| examples/palace-event.py | ||
@@ -11,0 +33,0 @@ examples/palace-hrtf.py |
+5
-5
| Metadata-Version: 2.1 | ||
| Name: palace | ||
| Version: 0.2.1 | ||
| Version: 0.2.2 | ||
| Summary: Pythonic Audio Library and Codecs Environment | ||
@@ -77,7 +77,7 @@ Home-page: https://mcsinyx.github.io/palace | ||
| [CMake]: https://cmake.org/ | ||
| [API]: https://mcsinyx.github.io/palace/html/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/html/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/html/design.html | ||
| [API]: https://mcsinyx.github.io/palace/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/design.html | ||
| [LGPLv3+]: https://www.gnu.org/licenses/lgpl-3.0.en.html | ||
| [copying]: https://mcsinyx.github.io/palace/html/copying.html | ||
| [copying]: https://mcsinyx.github.io/palace/copying.html | ||
@@ -84,0 +84,0 @@ Keywords: openal,alure,hrtf |
+1
-1
| [build-system] | ||
| requires = ['setuptools>=43', 'wheel>=0.31', 'Cython'] | ||
| build-backend = "setuptools.build_meta" | ||
| build-backend = 'setuptools.build_meta' |
+4
-4
@@ -69,6 +69,6 @@ # palace | ||
| [CMake]: https://cmake.org/ | ||
| [API]: https://mcsinyx.github.io/palace/html/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/html/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/html/design.html | ||
| [API]: https://mcsinyx.github.io/palace/reference.html | ||
| [contrib]: https://mcsinyx.github.io/palace/contributing.html | ||
| [design]: https://mcsinyx.github.io/palace/design.html | ||
| [LGPLv3+]: https://www.gnu.org/licenses/lgpl-3.0.en.html | ||
| [copying]: https://mcsinyx.github.io/palace/html/copying.html | ||
| [copying]: https://mcsinyx.github.io/palace/copying.html |
+1
-1
| [metadata] | ||
| name = palace | ||
| version = 0.2.1 | ||
| version = 0.2.2 | ||
| url = https://mcsinyx.github.io/palace | ||
@@ -5,0 +5,0 @@ author = Nguyễn Gia Phong |
+6
-4
@@ -10,10 +10,12 @@ [tox] | ||
| scipy | ||
| flake8 | ||
| pytest-cov | ||
| commands = | ||
| flake8 | ||
| pytest | ||
| commands = pytest | ||
| setenv = CYTHON_TRACE = 1 | ||
| passenv = TRAVIS | ||
| [testenv:lint] | ||
| skip_install = true | ||
| deps = flake8 | ||
| commands = flake8 | ||
| [flake8] | ||
@@ -20,0 +22,0 @@ filename = *.pxd, *.pyx, *.py |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
3348421
1.12%65
51.16%1754
1.74%