name: PyTaiko on: push: branches: ["main"] pull_request: branches: ["main"] permissions: contents: write pull-requests: write issues: write repository-projects: write jobs: build: strategy: matrix: os: [ubuntu-22.04, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Check-out repository uses: actions/checkout@v4 - name: Install Audio Dependencies (macOS) if: runner.os == 'macOS' run: | brew update brew install portaudio libsndfile libsamplerate pkg-config - name: Set up MSYS2 (Windows) if: runner.os == 'Windows' uses: msys2/setup-msys2@v2 with: update: true install: >- base-devel mingw-w64-x86_64-gcc mingw-w64-x86_64-portaudio mingw-w64-x86_64-libsndfile mingw-w64-x86_64-libsamplerate mingw-w64-x86_64-flac mingw-w64-x86_64-libvorbis mingw-w64-x86_64-libogg mingw-w64-x86_64-opus mingw-w64-x86_64-mpg123 mingw-w64-x86_64-lame mingw-w64-x86_64-speex mingw-w64-x86_64-cmake mingw-w64-x86_64-pkg-config # Build PortAudio from source with ASIO support (Windows only) - name: Build PortAudio with ASIO support (Windows) if: runner.os == 'Windows' shell: msys2 {0} run: | # Download PortAudio source curl -L http://files.portaudio.com/archives/pa_stable_v190700_20210406.tgz -o portaudio.tgz tar -xzf portaudio.tgz cd portaudio # Configure with ASIO and other Windows audio APIs mkdir build && cd build cmake .. \ -G "MSYS Makefiles" \ -DCMAKE_BUILD_TYPE=Release \ -DPA_USE_ASIO=ON \ -DPA_USE_DS=ON \ -DPA_USE_WMME=ON \ -DPA_USE_WASAPI=ON \ -DPA_BUILD_SHARED=ON \ -DPA_BUILD_STATIC=ON \ -DCMAKE_INSTALL_PREFIX=/mingw64 # Build and install (this will fail if ASIO SDK is missing, but continue anyway) make -j$(nproc) || echo "Build failed, likely due to missing ASIO SDK - continuing with system PortAudio" make install 2>/dev/null || echo "Install failed - using system PortAudio" # Verify what we have echo "=== PortAudio library verification ===" find /mingw64 -name "*portaudio*" -type f | head -10 pkg-config --exists portaudio && echo "PortAudio pkg-config found" || echo "No PortAudio pkg-config" - name: Verify ASIO support (Windows) if: runner.os == 'Windows' shell: msys2 {0} run: | # Check if ASIO symbols are present in PortAudio echo "=== Checking for ASIO support in PortAudio ===" # Look for ASIO in the installed library find /mingw64 -name "*portaudio*" -exec nm {} \; 2>/dev/null | grep -i asio && echo "ASIO symbols found!" || echo "No ASIO symbols found - will use DirectSound/WASAPI fallback" # Check what audio APIs are available pkg-config --cflags --libs portaudio 2>/dev/null || echo "Using manual linking flags" - name: Build static audio library (Windows) if: runner.os == 'Windows' shell: msys2 {0} working-directory: libs/audio run: | # Clean previous builds make clean 2>/dev/null || echo "No previous build to clean" # Build with PortAudio support # Add ASIO flag but don't fail if not available export CFLAGS="$CFLAGS -DPA_USE_ASIO=1" export PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH" # Try building with pkg-config first, then fallback to manual flags if pkg-config --exists portaudio; then echo "Building with pkg-config PortAudio support" make all PORTAUDIO_CFLAGS="$(pkg-config --cflags portaudio)" PORTAUDIO_LIBS="$(pkg-config --libs portaudio)" else echo "Building with manual PortAudio linking" make all PORTAUDIO_LIBS="-lportaudio -lole32 -luuid -lwinmm -ldsound -lwsock32 -lsetupapi" fi # Verify the build make verify 2>/dev/null || echo "Verification step not available" # Show final library info echo "=== Final library verification ===" ls -la *.dll *.a 2>/dev/null || echo "No libraries found" # Check for ASIO symbols in our library if [ -f libaudio.dll ]; then echo "=== Checking our library for ASIO symbols ===" nm libaudio.dll | grep -i asio && echo "Our library has ASIO support!" || echo "Our library uses non-ASIO audio APIs" - name: Copy static DLL (Windows) if: runner.os == 'Windows' run: | mkdir -p build/lib cp libs/audio/libaudio.dll build/lib/ # No need to copy other DLLs since everything is statically linked! echo "Static build complete - single DLL created" ls -la build/lib/ shell: bash # For Unix systems, also try static builds - name: Install static development libraries (Ubuntu) if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libportaudio2 \ portaudio19-dev \ libsndfile1-dev \ libsamplerate0-dev \ libflac-dev \ libvorbis-dev \ libogg-dev \ ccache - name: Build static audio library (Unix) if: runner.os != 'Windows' run: | cd libs/audio make clean make static || make all # Fallback to regular build if static fails make verify shell: bash - name: Install static audio library (Unix) if: runner.os != 'Windows' run: | cd libs/audio sudo make install shell: bash - name: Install uv uses: astral-sh/setup-uv@v4 - name: Setup Python run: uv python install - name: Install Dependencies run: | uv sync - name: Install Nuitka run: | uv add nuitka - name: Build Executable run: | uv run nuitka --lto=yes --mode=app --noinclude-setuptools-mode=nofollow --noinclude-IPython-mode=nofollow --assume-yes-for-downloads PyTaiko.py - name: Create Release Directory run: | mkdir -p release cp -r Graphics Sounds Videos Songs config.toml shader model release/ # Copy the compiled audio library and dependencies to release if [ "${{ runner.os }}" == "Windows" ]; then # Copy all DLLs from libs/audio (includes our library and dependencies) cp libs/audio/*.dll release/ 2>/dev/null || echo "No DLLs found in libs/audio/" # Also try from build/lib as backup cp build/lib/*.dll release/ 2>/dev/null || echo "No DLLs found in build/lib/" # List what we copied echo "DLLs in release directory:" ls -la release/*.dll 2>/dev/null || echo "No DLLs found in release/" elif [ "${{ runner.os }}" == "macOS" ]; then cp libs/audio/libaudio.dylib release/ 2>/dev/null || true else cp libs/audio/libaudio.so release/ 2>/dev/null || true fi # Copy executable based on OS if [ "${{ runner.os }}" == "Windows" ]; then cp *.exe release/ 2>/dev/null || echo "No .exe files found" elif [ "${{ runner.os }}" == "macOS" ]; then cp -r *.app release/ 2>/dev/null || echo "No .app bundles found" else cp *.bin release/ 2>/dev/null || echo "No .bin files found" fi echo "Final release directory contents:" ls -la release/ shell: bash - name: Create Zip Archive run: | cd release if [ "${{ runner.os }}" == "Windows" ]; then 7z a ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip * else zip -r ../PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip * fi shell: bash - name: Upload Artifacts uses: actions/upload-artifact@v4 with: name: PyTaiko-${{ runner.os }}-${{ runner.arch }} path: release/ - name: Upload Release uses: softprops/action-gh-release@v2 if: github.ref == 'refs/heads/main' && github.event_name == 'push' with: files: PyTaiko-${{ runner.os }}-${{ runner.arch }}.zip name: "PyTaiko [Rolling Release]" tag_name: "latest" make_latest: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}