diff --git a/.github/actions/supercollider/action.yml b/.github/actions/supercollider/action.yml index 30b52faae..39ac7a182 100644 --- a/.github/actions/supercollider/action.yml +++ b/.github/actions/supercollider/action.yml @@ -16,7 +16,6 @@ runs: run: | git clone --quiet --recursive --branch ${{ inputs.branch }} ${{ inputs.origin }} /tmp/supercollider cd /tmp/supercollider - mkdir build echo "SC_COMMIT_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV if [ "$RUNNER_OS" == "Linux" ]; then echo "SC_ORIGIN_MD5=$(echo ${{inputs.origin}} | md5sum | head -c 7)" >> $GITHUB_ENV @@ -27,110 +26,127 @@ runs: exit 1 fi shell: bash - - name: Cache SuperCollider - id: cache + - name: Cache current date + id: current-date + run: echo "stamp=$(date '+%Y-%m-%d')" >> $GITHUB_OUTPUT + shell: bash + - name: '[Linux] Cache ccache' + if: runner.os == 'Linux' + uses: actions/cache@v3 + with: + path: ~/.ccache + key: ccache-${{ runner.os }}-${{ steps.current-date.outputs.stamp }} + restore-keys: ccache-${{ runner.os }}- + - name: '[macOS] Cache ccache' + if: runner.os == 'macOS' + uses: actions/cache@v3 + with: + path: ~/Library/Caches/ccache + key: ccache-${{ runner.os }}-${{ steps.current-date.outputs.stamp }} + restore-keys: ccache-${{ runner.os }}- + - name: '[macOS] Cache Homebrew' + id: cache-homebrew + if: runner.os == 'macOS' uses: actions/cache@v3 with: - path: /tmp/supercollider/build - key: ${{ runner.os }}-supercollider-${{ env.SC_ORIGIN_MD5 }}-${{ env.SC_COMMIT_SHA }} - restore-keys: | - ${{ runner.os }}-supercollider- - - name: Validate cache - run: echo "Cached? ${{ steps.cache.outputs.cache-hit }}" + path: ~/Library/Caches/Homebrew/downloads + key: homebrew-${{ runner.os }}-${{ steps.current-date.outputs.stamp }} + restore-keys: homebrew-${{ runner.os }}- + - name: '[macOS] Cleanup Homebrew' + if: runner.os == 'macOS' && !steps.cache-homebrew.outputs.cache-hit + run: rm -rf $(brew --cache) shell: bash - - name: Install SuperCollider Deps + - name: '[Linux] Install dependencies' + if: runner.os == 'Linux' run: | - echo "Installing SuperCollider deps..." - if [ "$RUNNER_OS" == "Linux" ]; then - export DEBIAN_FRONTEND=noninteractive - sudo apt-get update --yes - sudo apt-get install --yes \ - alsa-oss \ - alsa-utils \ - build-essential \ - cmake \ - jackd2 \ - libasound2-dev \ - libavahi-client-dev \ - libfftw3-dev \ - libicu-dev \ - libjack-jackd2-dev \ - libreadline6-dev \ - libsndfile1-dev \ - libudev-dev \ - libxt-dev \ - pkg-config - elif [ "$RUNNER_OS" == "macOS" ]; then - brew install \ - cmake \ - fftw \ - git \ - jack \ - libsndfile \ - portaudio \ - qt5 \ - readline - echo "Update ld cache" - sudo update_dyld_shared_cache - else - echo "$RUNNER_OS not supported" - exit 1 - fi + sudo apt-get update + sudo apt-get install --yes \ + build-essential \ + ccache \ + cmake \ + emacs \ + jackd2 \ + libasound2-dev \ + libavahi-client-dev \ + libfftw3-dev \ + libicu-dev \ + libjack-jackd2-dev \ + libreadline6-dev \ + libsndfile1-dev \ + libudev-dev \ + libxt-dev \ + pkg-config shell: bash - - name: Prep SuperCollider build - if: steps.cache.outputs.cache-hit != 'true' + - name: '[macOS] Install dependencies' + if: runner.os == 'macOS' run: | - echo "[Cache Miss] Configuring SuperCollider..." - if [ "$RUNNER_OS" == "Linux" ]; then - cmake \ - --debug-output \ - -DCMAKE_build_TYPE=Release \ - -DSC_EL=OFF \ - -DSC_IDE=OFF \ - -DSC_QT=OFF \ - -DSUPERNOVA=ON \ - /tmp/supercollider - elif [ "$RUNNER_OS" == "macOS" ]; then - cmake \ - -DCMAKE_PREFIX_PATH=`brew --prefix qt5` \ - -DSUPERNOVA=ON \ - -G Xcode \ - /tmp/supercollider - else - echo "$RUNNER_OS not supported" - exit 1 - fi + brew install \ + ccache \ + fftw \ + jack \ + portaudio \ + qt5 \ + readline + echo "/usr/local/opt/ccache/libexec" >> $GITHUB_PATH shell: bash - working-directory: /tmp/supercollider/build - - name: Build SuperCollider - if: steps.cache.outputs.cache-hit != 'true' + - name: '[Linux] Configure' + if: runner.os == 'Linux' run: | - echo "[Cache Miss] Building SuperCollider..." - if [ "$RUNNER_OS" == "Linux" ]; then - make - elif [ "$RUNNER_OS" == "macOS" ]; then - cmake --build . --target install --config RelWithDebInfo - else - echo "$RUNNER_OS not supported" - exit 1 - fi + mkdir /tmp/supercollider/build + cd /tmp/supercollider/build + cmake \ + -DSC_ED=OFF \ + -DSC_EL=OFF \ + -DSC_IDE=OFF \ + -DSC_VIM=OFF \ + -DSC_QT=OFF \ + -DSUPERNOVA=ON \ + .. shell: bash - working-directory: /tmp/supercollider/build - - name: Install SuperCollider + - name: '[macOS] Configure' + if: runner.os == 'macOS' run: | - echo "Installing SuperCollider..." - if [ "$RUNNER_OS" == "Linux" ]; then - sudo make install/fast - mkdir -p /home/runner/.local/share/SuperCollider/synthdefs - elif [ "$RUNNER_OS" == "macOS" ]; then - echo "PATH=/tmp/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS:/tmp/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/:$PATH" >> $GITHUB_ENV - mkdir -p "/Users/runner/Library/Application Support/SuperCollider/synthdefs" - else - echo "$RUNNER_OS not supported" - exit 1 - fi + mkdir /tmp/supercollider/build + cd /tmp/supercollider/build + cmake \ + -DCMAKE_PREFIX_PATH=`brew --prefix qt5` \ + -DRULE_LAUNCH_COMPILE=ccache \ + -DSC_ED=OFF \ + -DSC_EL=OFF \ + -DSC_IDE=ON \ + -DSC_QT=ON \ + -DSC_VIM=OFF \ + -DSUPERNOVA=ON \ + -G Xcode \ + .. + shell: bash + - name: '[Linux] Build' + if: runner.os == 'Linux' + run: | + cd /tmp/supercollider/build + make -j2 + shell: bash + - name: '[macOS] Build' + if: runner.os == 'macOS' + run: cmake --build /tmp/supercollider/build --config Release --target install + shell: bash + - name: '[Linux] Install' + if: runner.os == 'Linux' + run: | + cd /tmp/supercollider/build + sudo make install -j2 + mkdir -p /home/runner/.local/share/SuperCollider/synthdefs + shell: bash + - name: '[macOS] Install' + if: runner.os == 'macOS' + run: | + echo "/tmp/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/MacOS" >> $GITHUB_PATH + echo "/tmp/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources" >> $GITHUB_PATH + mkdir -p "/Users/runner/Library/Application Support/SuperCollider/synthdefs" + shell: bash + - name: Debug ccache + run: ccache --show-stats --show-config shell: bash - working-directory: /tmp/supercollider/build - name: Setup Jack run: | echo "Setting up Jack..." @@ -159,4 +175,3 @@ runs: sleep 5 killall supernova shell: bash - diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2735e1e03..dd6e401ff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,18 +107,6 @@ jobs: timeout-minutes: 45 steps: - uses: actions/checkout@v3 - - name: Setup cache timestamp - id: current-date - run: | - echo "::set-output name=stamp::$(date '+%Y-%m-%d')" - echo "::set-output name=week::$(date '+%V')" - - name: Cache Homebrew - uses: actions/cache@v3 - if: ${{ matrix.os == 'macos-latest' }} - with: - path: ~/Library/Caches/Homebrew/downloads - key: ${{ runner.os }}-homebrew-${{ steps.current-date.outputs.stamp }} - restore-keys: ${{ runner.os }}-homebrew- - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: @@ -156,6 +144,8 @@ jobs: run: python -c "from supriya.realtime.shm import ServerSHM; print(ServerSHM)" - name: Install Supriya test dependencies run: pip install -e .[test] + - name: Install ffmpeg + uses: FedericoCarboni/setup-ffmpeg@v2 - name: Install additional packages shell: bash run: | @@ -164,17 +154,18 @@ jobs: sudo apt-get update --yes sudo apt-get install --yes \ espeak \ - ffmpeg \ graphviz \ lame elif [ "$RUNNER_OS" == "macOS" ]; then - brew install ffmpeg graphviz lame + brew install \ + graphviz elif [ "$RUNNER_OS" == "Windows" ]; then - choco install ffmpeg graphviz lame + choco install \ + graphviz fi - name: Run Pytest run: pytest --cov supriya - timeout-minutes: 10 + timeout-minutes: 15 - name: Check for stray processes (Non-Windows) if: ${{ matrix.os != 'windows-latest' }} run: | diff --git a/docs/source/realtime/nodes.rst b/docs/source/realtime/nodes.rst index c8e920283..8b42e076f 100644 --- a/docs/source/realtime/nodes.rst +++ b/docs/source/realtime/nodes.rst @@ -98,6 +98,19 @@ first:: >>> server.add_group(add_action="add to head") +.. note:: + + When using :term:`supernova` as your server executable, you can create + _parallel_ groups by specifying ``parallel=True`` in any call you would use + to create a group:: + + >>> server.add_group(parallel=True) + + Parallel groups will process their child nodes via multiple threads. + Because the order of node processing within a parallel group is + non-deterministic they're best suited for summing together signals rather + than processing in-place. + Creating synths ``````````````` diff --git a/setup.py b/setup.py index c9d37e222..4434c9fd5 100644 --- a/setup.py +++ b/setup.py @@ -45,4 +45,5 @@ def read_version(): packages=find_packages(include=["supriya", "supriya.*"]) + ["supriya.assets.audio", "supriya.assets.audio.birds"], version=read_version(), + package_data={"supriya": ["py.typed"]}, ) diff --git a/supriya/providers.py b/supriya/providers.py index bc9ff0d85..c2d28a22f 100644 --- a/supriya/providers.py +++ b/supriya/providers.py @@ -207,8 +207,11 @@ def add_group( *, add_action: AddActionLike = AddAction.ADD_TO_HEAD, name: Optional[str] = None, + parallel: bool = False, ) -> "GroupProxy": - return self.provider.add_group(add_action=add_action, target_node=self) + return self.provider.add_group( + add_action=add_action, target_node=self, parallel=parallel + ) def add_synth( self, @@ -268,7 +271,6 @@ class GroupProxy(NodeProxy): def as_add_request( self, add_action, target_node ) -> Union[commands.GroupNewRequest, commands.ParallelGroupNewRequest]: - request_method = commands.GroupNewRequest if self.parallel: request_method = commands.ParallelGroupNewRequest diff --git a/supriya/py.typed b/supriya/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/supriya/synthdefs/synthdefs.py b/supriya/synthdefs/synthdefs.py index 5804b33e6..ef72efc18 100644 --- a/supriya/synthdefs/synthdefs.py +++ b/supriya/synthdefs/synthdefs.py @@ -1026,7 +1026,7 @@ def compile(self): sc_file_path = directory_path / f"{self.name}.sc" sc_file_path.write_text(sc_input) command = [str(sclang_path), "-D", str(sc_file_path)] - subprocess.run(command) + subprocess.run(command, timeout=10) result = (directory_path / f"{self.name}.scsyndef").read_bytes() return bytes(result)