├── .clang-tidy ├── .github └── workflows │ ├── Tagged.yaml │ └── Untagged.yaml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── build └── .empty ├── fmt-11.1.1 ├── .clang-format ├── .github │ ├── dependabot.yml │ ├── issue_template.md │ ├── pull_request_template.md │ └── workflows │ │ ├── cifuzz.yml │ │ ├── doc.yml │ │ ├── lint.yml │ │ ├── linux.yml │ │ ├── macos.yml │ │ ├── scorecard.yml │ │ └── windows.yml ├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTING.md ├── ChangeLog.md ├── LICENSE ├── README.md ├── doc │ ├── ChangeLog-old.md │ ├── api.md │ ├── fmt.css │ ├── fmt.js │ ├── get-started.md │ ├── index.md │ ├── perf.svg │ ├── python-license.txt │ └── syntax.md ├── include │ └── fmt │ │ ├── args.h │ │ ├── base.h │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── os.h │ │ ├── ostream.h │ │ ├── printf.h │ │ ├── ranges.h │ │ ├── std.h │ │ └── xchar.h ├── src │ ├── fmt.cc │ ├── format.cc │ └── os.cc └── support │ ├── Android.mk │ ├── AndroidManifest.xml │ ├── C++.sublime-syntax │ ├── README │ ├── Vagrantfile │ ├── bazel │ ├── .bazelversion │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── README.md │ └── WORKSPACE.bazel │ ├── build.gradle │ ├── check-commits │ ├── cmake │ ├── FindSetEnv.cmake │ ├── JoinPaths.cmake │ ├── fmt-config.cmake.in │ └── fmt.pc.in │ ├── docopt.py │ ├── mkdocs │ ├── mkdocs.yml │ ├── printable.py │ ├── python │ └── mkdocstrings_handlers │ │ └── cxx │ │ ├── __init__.py │ │ └── templates │ │ └── README │ └── release.py ├── mingw.def ├── msvc.def ├── msvc64.def ├── src ├── AL │ ├── al.h │ ├── alc.h │ ├── alext.h │ └── efx.h ├── buffer.cpp ├── buffer.h ├── capture.cpp ├── capture.h ├── comhelpers.h ├── comptr.h ├── dsoal.cpp ├── dsoal.h ├── dsoal_global.h ├── dsoundoal.cpp ├── dsoundoal.h ├── eax.cpp ├── eax.h ├── enumerate.h ├── expected.h ├── factory.cpp ├── factory.h ├── fullduplex.cpp ├── fullduplex.h ├── guidprinter.h ├── logging.cpp ├── logging.h ├── primarybuffer.cpp ├── primarybuffer.h ├── propset.cpp ├── propset.h └── vmanager.h ├── version.cmake ├── version.h.in └── version.rc /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: '-*, 3 | bugprone-argument-comment, 4 | bugprone-assert-side-effect, 5 | bugprone-assignment-in-if-condition, 6 | bugprone-bad-signal-to-kill-thread, 7 | bugprone-bool-pointer-implicit-conversion, 8 | bugprone-casting-through-void, 9 | bugprone-chained-comparison, 10 | bugprone-compare-pointer-to-member-virtual-function, 11 | bugprone-copy-constructor-init, 12 | bugprone-crtp-constructor-accessibility, 13 | bugprone-dangling-handle, 14 | bugprone-dynamic-static-initializers, 15 | bugprone-fold-init-type, 16 | bugprone-forward-declaration-namespace, 17 | bugprone-forwarding-reference-overload, 18 | bugprone-implicit-widening-of-multiplication-result, 19 | bugprone-inaccurate-erase, 20 | bugprone-incorrect-*, 21 | bugprone-infinite-loop, 22 | bugprone-integer-division, 23 | bugprone-lambda-function-name, 24 | bugprone-macro-repeated-side-effects, 25 | bugprone-misplaced-*, 26 | bugprone-move-forwarding-reference, 27 | bugprone-multiple-*, 28 | bugprone-narrowing-conversions, 29 | bugprone-no-escape, 30 | bugprone-non-zero-enum-to-bool-conversion, 31 | bugprone-not-null-terminated-result, 32 | bugprone-optional-value-conversion, 33 | bugprone-parent-virtual-call, 34 | bugprone-pointer-arithmetic-on-polymorphic-object, 35 | bugprone-posix-return, 36 | bugprone-redundant-branch-condition, 37 | bugprone-reserved-identifier, 38 | bugprone-return-const-ref-from-parameter, 39 | bugprone-shared-ptr-array-mismatch, 40 | bugprone-signal-handler, 41 | bugprone-signed-char-misuse, 42 | bugprone-sizeof-*, 43 | bugprone-spuriously-wake-up-functions, 44 | bugprone-standalone-empty, 45 | bugprone-string-*, 46 | bugprone-stringview-nullptr, 47 | bugprone-suspicious-*, 48 | bugprone-swapped-arguments, 49 | bugprone-terminating-continue, 50 | bugprone-throw-keyword-missing, 51 | bugprone-too-small-loop-variable, 52 | bugprone-undefined-memory-manipulation, 53 | bugprone-undelegated-constructor, 54 | bugprone-unhandled-*, 55 | bugprone-unique-ptr-array-mismatch, 56 | bugprone-unsafe-functions, 57 | bugprone-unused-*, 58 | bugprone-use-after-move, 59 | bugprone-virtual-near-miss, 60 | cert-dcl50-cpp, 61 | cert-dcl58-cpp, 62 | cert-env33-c, 63 | cert-err34-c, 64 | cert-err52-cpp, 65 | cert-err60-cpp, 66 | cert-flp30-c, 67 | cert-mem57-cpp, 68 | clang-analyzer-apiModeling.*, 69 | clang-analyzer-core.*, 70 | clang-analyzer-cplusplus.*, 71 | clang-analyzer-deadcode.DeadStores, 72 | clang-analyzer-fuchsia.HandleChecker, 73 | clang-analyzer-nullability.*, 74 | clang-analyzer-optin.*, 75 | clang-analyzer-osx.*, 76 | clang-analyzer-security.FloatLoopCounter, 77 | clang-analyzer-security.PutenvStackArray, 78 | clang-analyzer-security.SetgidSetuidOrder, 79 | clang-analyzer-security.cert.env.InvalidPtr, 80 | clang-analyzer-security.insecureAPI.SecuritySyntaxChecker, 81 | clang-analyzer-security.insecureAPI.UncheckedReturn, 82 | clang-analyzer-security.insecureAPI.bcmp, 83 | clang-analyzer-security.insecureAPI.bcopy, 84 | clang-analyzer-security.insecureAPI.bzero, 85 | clang-analyzer-security.insecureAPI.decodeValueOfObjCType, 86 | clang-analyzer-security.insecureAPI.getpw, 87 | clang-analyzer-security.insecureAPI.gets, 88 | clang-analyzer-security.insecureAPI.mkstemp, 89 | clang-analyzer-security.insecureAPI.mktemp, 90 | clang-analyzer-security.insecureAPI.rand, 91 | clang-analyzer-security.insecureAPI.strcpy, 92 | clang-analyzer-security.insecureAPI.vfork, 93 | clang-analyzer-unix.*, 94 | clang-analyzer-valist.*, 95 | clang-analyzer-webkit.*, 96 | concurrency-thread-canceltype-asynchronous, 97 | cppcoreguidelines-avoid-capturing-lambda-coroutines, 98 | cppcoreguidelines-avoid-c-arrays, 99 | cppcoreguidelines-avoid-goto, 100 | cppcoreguidelines-avoid-reference-coroutine-parameters, 101 | cppcoreguidelines-c-copy-assignment-signature, 102 | cppcoreguidelines-explicit-virtual-functions, 103 | cppcoreguidelines-interfaces-global-init, 104 | cppcoreguidelines-narrowing-conversions, 105 | cppcoreguidelines-no-malloc, 106 | cppcoreguidelines-no-suspend-with-lock, 107 | cppcoreguidelines-owning-memory, 108 | cppcoreguidelines-prefer-member-initializer, 109 | cppcoreguidelines-pro-bounds-array-to-pointer-decay, 110 | cppcoreguidelines-pro-bounds-pointer-arithmetic, 111 | cppcoreguidelines-pro-type-const-cast, 112 | cppcoreguidelines-pro-type-cstyle-cast, 113 | cppcoreguidelines-pro-type-member-init, 114 | cppcoreguidelines-pro-type-static-cast-downcast, 115 | cppcoreguidelines-pro-type-union-access, 116 | cppcoreguidelines-pro-type-vararg, 117 | cppcoreguidelines-slicing, 118 | cppcoreguidelines-virtual-class-destructor, 119 | google-build-explicit-make-pair, 120 | google-default-arguments, 121 | google-explicit-constructor, 122 | hicpp-exception-baseclass, 123 | misc-confusable-identifiers, 124 | misc-coroutine-hostile-raii, 125 | misc-misleading-*, 126 | misc-non-copyable-objects, 127 | misc-throw-by-value-catch-by-reference, 128 | misc-uniqueptr-reset-release, 129 | modernize-avoid-*, 130 | modernize-concat-nested-namespaces, 131 | modernize-deprecated-*, 132 | modernize-loop-convert, 133 | modernize-macro-to-enum, 134 | modernize-make-*, 135 | modernize-pass-by-value, 136 | modernize-raw-string-literal, 137 | modernize-redundant-void-arg, 138 | modernize-replace-*, 139 | modernize-return-braced-init-list, 140 | modernize-shrink-to-fit, 141 | modernize-unary-static-assert, 142 | modernize-use-auto, 143 | modernize-use-bool-literals, 144 | modernize-use-default-member-init, 145 | modernize-use-emplace, 146 | modernize-use-equals-*, 147 | modernize-use-nodiscard, 148 | modernize-use-noexcept, 149 | modernize-use-nullptr, 150 | modernize-use-override, 151 | modernize-use-transparent-functors, 152 | modernize-use-uncaught-exceptions, 153 | modernize-use-using, 154 | performance-faster-string-find, 155 | performance-for-range-copy, 156 | performance-inefficient-*, 157 | performance-move-constructor-init, 158 | performance-noexcept-destructor, 159 | performance-noexcept-swap, 160 | performance-unnecessary-copy-initialization, 161 | portability-restrict-system-includes, 162 | portability-std-allocator-const, 163 | readability-const-return-type, 164 | readability-container-contains, 165 | readability-container-size-empty, 166 | readability-convert-member-functions-to-static, 167 | readability-delete-null-pointer, 168 | readability-duplicate-include, 169 | readability-else-after-return, 170 | readability-inconsistent-declaration-parameter-name, 171 | readability-make-member-function-const, 172 | readability-misleading-indentation, 173 | readability-misplaced-array-index, 174 | readability-redundant-*, 175 | readability-simplify-subscript-expr, 176 | readability-static-definition-in-anonymous-namespace, 177 | readability-string-compare, 178 | readability-uniqueptr-delete-release, 179 | readability-use-*' 180 | -------------------------------------------------------------------------------- /.github/workflows/Tagged.yaml: -------------------------------------------------------------------------------- 1 | name: Tagged build 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*.*.*' 7 | paths-ignore: 8 | - '.github/workflows/Untagged.yaml' 9 | workflow_dispatch: 10 | 11 | env: 12 | Configuration: Release 13 | DSOALRepo: ${{github.repository}} 14 | DSOALBranch: master 15 | OpenALSoftRepo: kcat/openal-soft 16 | OpenALSoftBranch: master 17 | GH_TOKEN: ${{github.token}} 18 | 19 | jobs: 20 | Build: 21 | name: ${{matrix.config.name}} 22 | runs-on: windows-latest 23 | strategy: 24 | matrix: 25 | config: 26 | - { 27 | name: "Win32", 28 | platform: "Win32" 29 | } 30 | - { 31 | name: "Win64", 32 | platform: "x64" 33 | } 34 | steps: 35 | 36 | - name: Clone DSOAL 37 | run: | 38 | git clone --branch ${{env.DSOALBranch}} https://github.com/${{env.DSOALRepo}}.git . 39 | git fetch --tags 40 | echo "DSOALCommitTag=$(git tag --list "*.*.*" --contains $(git rev-parse HEAD))" >> $env:GITHUB_ENV 41 | 42 | - name: Clone OpenAL Soft 43 | run: | 44 | git clone --branch ${{env.OpenALSoftBranch}} https://github.com/${{env.OpenALSoftRepo}}.git 45 | cd "openal-soft" 46 | git fetch --tags 47 | echo "OpenALSoftCommitTag=$(git describe --tags --abbrev=0 --match *.*.*)" >> $env:GITHUB_ENV 48 | cd "${{github.workspace}}" 49 | 50 | - name: Clone OpenAL Soft v${{env.OpenALSoftCommitTag}} 51 | run: | 52 | rm openal-soft -r -force 53 | git clone --branch ${{env.OpenALSoftCommitTag}} https://github.com/${{env.OpenALSoftRepo}}.git 54 | 55 | - name: Get version details 56 | run: | 57 | echo "DSOALCommitHash=$(git rev-parse HEAD)" >> $env:GITHUB_ENV 58 | echo "DSOALCommitHashShort=$(git rev-parse --short=8 HEAD)" >> $env:GITHUB_ENV 59 | echo "DSOALCommitDate=$(git show -s --date=iso-local --format=%cd)" >> $env:GITHUB_ENV 60 | echo "DSOALCommitTitle=$(git show --pretty=format:%s -s HEAD)" >> $env:GITHUB_ENV 61 | cd "openal-soft" 62 | echo "OpenALSoftCommitHash=$(git rev-parse HEAD)" >> $env:GITHUB_ENV 63 | echo "OpenALSoftCommitHashShort=$(git rev-parse --short=8 HEAD)" >> $env:GITHUB_ENV 64 | echo "OpenALSoftCommitDate=$(git show -s --date=iso-local --format=%cd)" >> $env:GITHUB_ENV 65 | echo "OpenALSoftCommitTitle=$(git show --pretty=format:%s -s HEAD)" >> $env:GITHUB_ENV 66 | cd "${{github.workspace}}" 67 | 68 | - name: Build DSOAL 69 | run: | 70 | cmake -B "${{github.workspace}}/build" -A ${{matrix.config.platform}} 71 | cmake --build "${{github.workspace}}/build" --config ${{env.Configuration}} 72 | 73 | - name: Build OpenAL Soft 74 | run: | 75 | cmake -B "${{github.workspace}}/openal-soft/build" -DCMAKE_Configuration=${{env.Configuration}} -A ${{matrix.config.platform}} -DALSOFT_BUILD_ROUTER=ON -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON "${{github.workspace}}/openal-soft" 76 | cmake --build "${{github.workspace}}/openal-soft/build" --config ${{env.Configuration}} 77 | 78 | - name: Collect binaries 79 | run: | 80 | mkdir "DSOAL" 81 | mkdir "DSOAL/Documentation" 82 | move "${{github.workspace}}/build/${{env.Configuration}}/dsound.dll" "DSOAL/dsound.dll" 83 | move "${{github.workspace}}/openal-soft/build/${{env.Configuration}}/soft_oal.dll" "DSOAL/dsoal-aldrv.dll" 84 | copy "${{github.workspace}}/openal-soft/alsoftrc.sample" "DSOAL/alsoft.ini" 85 | copy "${{github.workspace}}/README.md" "DSOAL/Documentation/DSOAL-ReadMe.txt" 86 | copy "${{github.workspace}}/LICENSE" "DSOAL/Documentation/DSOAL-License.txt" 87 | echo "${{env.DSOALRepo}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 88 | echo "${{env.DSOALBranch}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 89 | echo "${{env.DSOALCommitHash}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 90 | echo "v${{env.DSOALCommitTag}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 91 | echo "${{env.DSOALCommitTitle}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 92 | echo "${{env.DSOALCommitDate}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 93 | copy "${{github.workspace}}/openal-soft/README.md" "DSOAL/Documentation/OpenALSoft-ReadMe.txt" 94 | copy "${{github.workspace}}/openal-soft/COPYING" "DSOAL/Documentation/OpenALSoft-License.txt" 95 | copy "${{github.workspace}}/openal-soft/BSD-3Clause" "DSOAL/Documentation/OpenALSoft-License_BSD-3Clause.txt" 96 | copy "${{github.workspace}}/openal-soft/LICENSE-pffft" "DSOAL/Documentation/OpenALSoft-License_PFFFT.txt" 97 | copy "${{github.workspace}}/openal-soft/ChangeLog" "DSOAL/Documentation/OpenALSoft-ChangeLog.txt" 98 | echo "${{env.OpenALSoftRepo}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 99 | echo "${{env.OpenALSoftBranch}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 100 | echo "${{env.OpenALSoftCommitHash}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 101 | echo "v${{env.OpenALSoftCommitTag}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 102 | echo "${{env.OpenALSoftCommitTitle}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 103 | echo "${{env.OpenALSoftCommitDate}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 104 | 105 | - name: Upload artifact to GitHub actions 106 | uses: actions/upload-artifact@v4 107 | with: 108 | name: DSOAL_v${{env.DSOALCommitTag}}-${{env.DSOALCommitHashShort}}+OpenALSoft_v${{env.OpenALSoftCommitTag}}-${{env.OpenALSoftCommitHashShort}}-${{matrix.config.name}} 109 | path: DSOAL/ 110 | 111 | outputs: 112 | DSOALRepo: ${{env.DSOALRepo}} 113 | DSOALBranch: ${{env.DSOALBranch}} 114 | DSOALCommitHash: ${{env.DSOALCommitHash}} 115 | DSOALCommitHashShort: ${{env.DSOALCommitHashShort}} 116 | DSOALCommitTag: ${{env.DSOALCommitTag}} 117 | DSOALCommitTitle: ${{env.DSOALCommitTitle}} 118 | DSOALCommitDate: ${{env.DSOALCommitDate}} 119 | OpenALSoftRepo: ${{env.OpenALSoftRepo}} 120 | OpenALSoftBranch: ${{env.OpenALSoftBranch}} 121 | OpenALSoftCommitHash: ${{env.OpenALSoftCommitHash}} 122 | OpenALSoftCommitHashShort: ${{env.OpenALSoftCommitHashShort}} 123 | OpenALSoftCommitTag: ${{env.OpenALSoftCommitTag}} 124 | OpenALSoftCommitTitle: ${{env.OpenALSoftCommitTitle}} 125 | OpenALSoftCommitDate: ${{env.OpenALSoftCommitDate}} 126 | 127 | Release: 128 | needs: Build 129 | runs-on: ubuntu-latest 130 | steps: 131 | 132 | - name: Download build artifacts 133 | run: | 134 | gh run download ${{github.run_id}} --repo ${{env.DSOALRepo}} --dir Release 135 | 136 | - name: Collect binaries 137 | run: | 138 | mv "Release/DSOAL_v${{needs.Build.outputs.DSOALCommitTag}}-${{needs.Build.outputs.DSOALCommitHashShort}}+OpenALSoft_v${{needs.Build.outputs.OpenALSoftCommitTag}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}}-Win32" "Release/Win32" 139 | mv "Release/DSOAL_v${{needs.Build.outputs.DSOALCommitTag}}-${{needs.Build.outputs.DSOALCommitHashShort}}+OpenALSoft_v${{needs.Build.outputs.OpenALSoftCommitTag}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}}-Win64" "Release/Win64" 140 | mkdir "Release/DSOAL" 141 | mv "Release/Win32" "Release/DSOAL/Win32" 142 | mv "Release/Win64" "Release/DSOAL/Win64" 143 | mv "Release/DSOAL/Win32/Documentation" "Release/DSOAL/Documentation" 144 | rm -r "Release/DSOAL/Win64/Documentation" 145 | cp -R "Release/DSOAL" "Release/DSOAL+HRTF" 146 | mv "Release/DSOAL+HRTF/Win32/alsoft.ini" "Release/DSOAL+HRTF/Documentation/alsoft.ini" 147 | rm "Release/DSOAL+HRTF/Win64/alsoft.ini" 148 | curl https://raw.githubusercontent.com/${{needs.Build.outputs.OpenALSoftRepo}}/${{needs.Build.outputs.OpenALSoftBranch}}/configs/HRTF/alsoft.ini -o "Release/DSOAL+HRTF/Win32/alsoft.ini" 149 | cp "Release/DSOAL+HRTF/Win32/alsoft.ini" "Release/DSOAL+HRTF/Win64/alsoft.ini" 150 | 151 | - name: Compress artifacts 152 | run: | 153 | 7z a ./Release/DSOAL_v${{needs.Build.outputs.DSOALCommitTag}}.zip ./Release/DSOAL ./Release/DSOAL+HRTF -m0=Copy 154 | 7z a DSOAL.zip ./Release/DSOAL_v${{needs.Build.outputs.DSOALCommitTag}}.zip -m0=lzma -mx=9 155 | 156 | - name: Purge tag - ${{needs.Build.outputs.DSOALCommitTag}} 157 | run: | 158 | gh release delete ${{needs.Build.outputs.DSOALCommitTag}} --repo ${{env.DSOALRepo}} --cleanup-tag --yes || true 159 | 160 | - name: Release - ${{needs.Build.outputs.DSOALCommitTag}} 161 | run: | 162 | gh release create ${{needs.Build.outputs.DSOALCommitTag}} --repo ${{env.DSOALRepo}} --target ${{needs.Build.outputs.DSOALCommitHash}} --generate-notes --latest=true --title "DSOAL v${{needs.Build.outputs.DSOALCommitTag}} + OpenAL Soft v${{needs.Build.outputs.OpenALSoftCommitTag}}" --notes "DSOAL v${{needs.Build.outputs.DSOALCommitTag}}-${{needs.Build.outputs.DSOALCommitHashShort}} ${{needs.Build.outputs.DSOALBranch}} - ${{needs.Build.outputs.DSOALCommitTitle}} [${{needs.Build.outputs.DSOALCommitDate}}] 163 | OpenAL Soft v${{needs.Build.outputs.OpenALSoftCommitTag}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}} ${{needs.Build.outputs.OpenALSoftBranch}} - ${{needs.Build.outputs.OpenALSoftCommitTitle}} [${{needs.Build.outputs.OpenALSoftCommitDate}}] 164 | Build log: https://github.com/${{env.DSOALRepo}}/actions/runs/${{github.run_id}}" 165 | gh release upload ${{needs.Build.outputs.DSOALCommitTag}} --repo ${{env.DSOALRepo}} --clobber DSOAL.zip -------------------------------------------------------------------------------- /.github/workflows/Untagged.yaml: -------------------------------------------------------------------------------- 1 | name: Untagged build 2 | 3 | on: 4 | push: 5 | branches: 6 | - "**" 7 | tags: 8 | - "!**" 9 | paths-ignore: 10 | - '.github/workflows/Tagged.yaml' 11 | workflow_dispatch: 12 | schedule: 13 | - cron: '0 0 * * *' 14 | 15 | env: 16 | Configuration: Release 17 | DSOALRepo: ${{github.repository}} 18 | DSOALBranch: ${{github.ref_name}} 19 | OpenALSoftRepo: kcat/openal-soft 20 | OpenALSoftBranch: master 21 | GH_TOKEN: ${{github.token}} 22 | 23 | jobs: 24 | Build: 25 | name: ${{matrix.config.name}} 26 | runs-on: windows-latest 27 | strategy: 28 | matrix: 29 | config: 30 | - { 31 | name: "Win32", 32 | platform: "Win32" 33 | } 34 | - { 35 | name: "Win64", 36 | platform: "x64" 37 | } 38 | steps: 39 | 40 | - name: Clone DSOAL 41 | run: | 42 | git clone --branch ${{env.DSOALBranch}} https://github.com/${{env.DSOALRepo}}.git . 43 | 44 | - name: Clone OpenAL Soft 45 | run: | 46 | git clone --branch ${{env.OpenALSoftBranch}} https://github.com/${{env.OpenALSoftRepo}}.git 47 | 48 | - name: Get version details 49 | run: | 50 | echo "DSOALCommitHash=$(git rev-parse HEAD)" >> $env:GITHUB_ENV 51 | echo "DSOALCommitHashShort=$(git rev-parse --short=8 HEAD)" >> $env:GITHUB_ENV 52 | echo "DSOALCommitDate=$(git show -s --date=iso-local --format=%cd)" >> $env:GITHUB_ENV 53 | echo "DSOALCommitCount=$(git rev-list --count HEAD)" >> $env:GITHUB_ENV 54 | echo "DSOALCommitTitle=$(git show --pretty=format:%s -s HEAD)" >> $env:GITHUB_ENV 55 | cd "openal-soft" 56 | echo "OpenALSoftCommitHash=$(git rev-parse HEAD)" >> $env:GITHUB_ENV 57 | echo "OpenALSoftCommitHashShort=$(git rev-parse --short=8 HEAD)" >> $env:GITHUB_ENV 58 | echo "OpenALSoftCommitDate=$(git show -s --date=iso-local --format=%cd)" >> $env:GITHUB_ENV 59 | echo "OpenALSoftCommitCount=$(git rev-list --count HEAD)" >> $env:GITHUB_ENV 60 | echo "OpenALSoftCommitTitle=$(git show --pretty=format:%s -s HEAD)" >> $env:GITHUB_ENV 61 | cd "${{github.workspace}}" 62 | 63 | - name: Build DSOAL 64 | run: | 65 | cmake -B "${{github.workspace}}/build" -A ${{matrix.config.platform}} 66 | cmake --build "${{github.workspace}}/build" --config ${{env.Configuration}} 67 | 68 | - name: Build OpenAL Soft 69 | run: | 70 | cmake -B "${{github.workspace}}/openal-soft/build" -DCMAKE_Configuration=${{env.Configuration}} -A ${{matrix.config.platform}} -DALSOFT_BUILD_ROUTER=ON -DALSOFT_REQUIRE_WINMM=ON -DALSOFT_REQUIRE_DSOUND=ON -DALSOFT_REQUIRE_WASAPI=ON "${{github.workspace}}/openal-soft" 71 | cmake --build "${{github.workspace}}/openal-soft/build" --config ${{env.Configuration}} 72 | 73 | - name: Collect binaries 74 | run: | 75 | mkdir "DSOAL" 76 | mkdir "DSOAL/Documentation" 77 | move "${{github.workspace}}/build/${{env.Configuration}}/dsound.dll" "DSOAL/dsound.dll" 78 | move "${{github.workspace}}/openal-soft/build/${{env.Configuration}}/soft_oal.dll" "DSOAL/dsoal-aldrv.dll" 79 | copy "${{github.workspace}}/openal-soft/alsoftrc.sample" "DSOAL/alsoft.ini" 80 | copy "${{github.workspace}}/README.md" "DSOAL/Documentation/DSOAL-ReadMe.txt" 81 | copy "${{github.workspace}}/LICENSE" "DSOAL/Documentation/DSOAL-License.txt" 82 | echo "${{env.DSOALRepo}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 83 | echo "${{env.DSOALBranch}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 84 | echo "${{env.DSOALCommitHash}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 85 | echo "r${{env.DSOALCommitCount}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 86 | echo "${{env.DSOALCommitTitle}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 87 | echo "${{env.DSOALCommitDate}}" >> "DSOAL/Documentation/DSOAL-Version.txt" 88 | copy "${{github.workspace}}/openal-soft/README.md" "DSOAL/Documentation/OpenALSoft-ReadMe.txt" 89 | copy "${{github.workspace}}/openal-soft/COPYING" "DSOAL/Documentation/OpenALSoft-License.txt" 90 | copy "${{github.workspace}}/openal-soft/BSD-3Clause" "DSOAL/Documentation/OpenALSoft-License_BSD-3Clause.txt" 91 | copy "${{github.workspace}}/openal-soft/LICENSE-pffft" "DSOAL/Documentation/OpenALSoft-License_PFFFT.txt" 92 | copy "${{github.workspace}}/openal-soft/ChangeLog" "DSOAL/Documentation/OpenALSoft-ChangeLog.txt" 93 | echo "${{env.OpenALSoftRepo}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 94 | echo "${{env.OpenALSoftBranch}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 95 | echo "${{env.OpenALSoftCommitHash}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 96 | echo "r${{env.OpenALSoftCommitCount}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 97 | echo "${{env.OpenALSoftCommitTitle}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 98 | echo "${{env.OpenALSoftCommitDate}}" >> "DSOAL/Documentation/OpenALSoft-Version.txt" 99 | 100 | - name: Upload artifact to GitHub actions 101 | uses: actions/upload-artifact@v4 102 | with: 103 | name: DSOAL_r${{env.DSOALCommitCount}}-${{env.DSOALCommitHashShort}}+OpenALSoft_r${{env.OpenALSoftCommitCount}}-${{env.OpenALSoftCommitHashShort}}-${{matrix.config.name}} 104 | path: DSOAL/ 105 | 106 | outputs: 107 | DSOALRepo: ${{env.DSOALRepo}} 108 | DSOALBranch: ${{env.DSOALBranch}} 109 | DSOALCommitHash: ${{env.DSOALCommitHash}} 110 | DSOALCommitHashShort: ${{env.DSOALCommitHashShort}} 111 | DSOALCommitCount: ${{env.DSOALCommitCount}} 112 | DSOALCommitTitle: ${{env.DSOALCommitTitle}} 113 | DSOALCommitDate: ${{env.DSOALCommitDate}} 114 | OpenALSoftRepo: ${{env.OpenALSoftRepo}} 115 | OpenALSoftBranch: ${{env.OpenALSoftBranch}} 116 | OpenALSoftCommitHash: ${{env.OpenALSoftCommitHash}} 117 | OpenALSoftCommitHashShort: ${{env.OpenALSoftCommitHashShort}} 118 | OpenALSoftCommitCount: ${{env.OpenALSoftCommitCount}} 119 | OpenALSoftCommitTitle: ${{env.OpenALSoftCommitTitle}} 120 | OpenALSoftCommitDate: ${{env.OpenALSoftCommitDate}} 121 | 122 | Release: 123 | needs: Build 124 | runs-on: ubuntu-latest 125 | steps: 126 | 127 | - name: Download build artifacts 128 | run: | 129 | gh run download ${{github.run_id}} --repo ${{env.DSOALRepo}} --dir Release 130 | 131 | - name: Collect binaries 132 | run: | 133 | mv "Release/DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}-${{needs.Build.outputs.DSOALCommitHashShort}}+OpenALSoft_r${{needs.Build.outputs.OpenALSoftCommitCount}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}}-Win32" "Release/Win32" 134 | mv "Release/DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}-${{needs.Build.outputs.DSOALCommitHashShort}}+OpenALSoft_r${{needs.Build.outputs.OpenALSoftCommitCount}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}}-Win64" "Release/Win64" 135 | mkdir "Release/DSOAL" 136 | mv "Release/Win32" "Release/DSOAL/Win32" 137 | mv "Release/Win64" "Release/DSOAL/Win64" 138 | mv "Release/DSOAL/Win32/Documentation" "Release/DSOAL/Documentation" 139 | rm -r "Release/DSOAL/Win64/Documentation" 140 | cp -R "Release/DSOAL" "Release/DSOAL+HRTF" 141 | mv "Release/DSOAL+HRTF/Win32/alsoft.ini" "Release/DSOAL+HRTF/Documentation/alsoft.ini" 142 | rm "Release/DSOAL+HRTF/Win64/alsoft.ini" 143 | curl https://raw.githubusercontent.com/${{needs.Build.outputs.OpenALSoftRepo}}/${{needs.Build.outputs.OpenALSoftBranch}}/configs/HRTF/alsoft.ini -o "Release/DSOAL+HRTF/Win32/alsoft.ini" 144 | cp "Release/DSOAL+HRTF/Win32/alsoft.ini" "Release/DSOAL+HRTF/Win64/alsoft.ini" 145 | 146 | - name: Compress artifacts 147 | run: | 148 | 7z a ./Release/DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}.zip ./Release/DSOAL ./Release/DSOAL+HRTF -m0=Copy 149 | 7z a DSOAL.zip ./Release/DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}.zip -m0=lzma -mx=9 150 | cp DSOAL.zip DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}.zip 151 | 152 | - name: Purge tag - latest-${{needs.Build.outputs.DSOALBranch}} 153 | run: | 154 | gh release delete latest-${{needs.Build.outputs.DSOALBranch}} --repo ${{env.DSOALRepo}} --cleanup-tag --yes || true 155 | 156 | - name: Release - archive 157 | run: | 158 | gh release create archive --repo ${{env.DSOALRepo}} --target 98584ab11d231d36488bc055bdeb19b607706bc6 --latest=false --prerelease --title "DSOAL build archive" || true 159 | gh release upload archive --repo ${{env.DSOALRepo}} --clobber DSOAL_r${{needs.Build.outputs.DSOALCommitCount}}.zip 160 | 161 | - name: Release - latest-${{needs.Build.outputs.DSOALBranch}} 162 | run: | 163 | gh release create latest-${{needs.Build.outputs.DSOALBranch}} --repo ${{env.DSOALRepo}} --target ${{needs.Build.outputs.DSOALCommitHash}} --generate-notes --latest=true --prerelease --title "DSOAL r${{needs.Build.outputs.DSOALCommitCount}} + OpenAL Soft r${{needs.Build.outputs.OpenALSoftCommitCount}}" --notes "DSOAL r${{needs.Build.outputs.DSOALCommitCount}}-${{needs.Build.outputs.DSOALCommitHashShort}} ${{needs.Build.outputs.DSOALBranch}} - ${{needs.Build.outputs.DSOALCommitTitle}} [${{needs.Build.outputs.DSOALCommitDate}}] 164 | OpenAL Soft r${{needs.Build.outputs.OpenALSoftCommitCount}}-${{needs.Build.outputs.OpenALSoftCommitHashShort}} ${{needs.Build.outputs.OpenALSoftBranch}} - ${{needs.Build.outputs.OpenALSoftCommitTitle}} [${{needs.Build.outputs.OpenALSoftCommitDate}}] 165 | Build log: https://github.com/${{env.DSOALRepo}}/actions/runs/${{github.run_id}}" 166 | gh release upload latest-${{needs.Build.outputs.DSOALBranch}} --repo ${{env.DSOALRepo}} --clobber DSOAL.zip 167 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | build*/ 38 | .kdev4/ 39 | 40 | # qtcreator generated files 41 | *.pro.user* 42 | CMakeLists.txt.user* 43 | 44 | # xemacs temporary files 45 | *.flc 46 | 47 | # Vim temporary files 48 | .*.swp 49 | 50 | # Visual Studio generated files 51 | *.ib_pdb_index 52 | *.idb 53 | *.ilk 54 | *.pdb 55 | *.sln 56 | *.suo 57 | *.vcproj 58 | *vcproj.*.*.user 59 | *.ncb 60 | *.sdf 61 | *.opensdf 62 | *.vcxproj 63 | *vcxproj.* 64 | 65 | # MinGW generated files 66 | *.Debug 67 | *.Release 68 | 69 | # Python byte code 70 | *.pyc 71 | 72 | # Binaries 73 | # -------- 74 | *.dll 75 | *.exe 76 | 77 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project(dsoal LANGUAGES CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | add_subdirectory(fmt-11.1.1) 9 | 10 | include(CheckCXXCompilerFlag) 11 | include(GNUInstallDirs) 12 | 13 | set(VERSION 0.9) 14 | 15 | set(DSOAL_CPPDEFS ) 16 | set(DSOAL_CFLAGS ) 17 | set(DSOAL_LINK_FLAGS ) 18 | 19 | if(MSVC) 20 | if(CMAKE_SIZEOF_VOID_P MATCHES "8") 21 | set(DEF_FILE msvc64.def) 22 | else() 23 | set(DEF_FILE msvc.def) 24 | endif() 25 | 26 | set(DSOAL_CPPDEFS ${DSOAL_CPPDEFS} _CRT_SECURE_NO_WARNINGS NOMINMAX) 27 | 28 | check_cxx_compiler_flag(/permissive- HAVE_PERMISSIVE_SWITCH) 29 | if(HAVE_PERMISSIVE_SWITCH) 30 | set(DSOAL_CFLAGS ${DSOAL_CFLAGS} $<$:/permissive->) 31 | endif() 32 | set(DSOAL_CFLAGS ${DSOAL_CFLAGS} /W4 /w14640 /wd4065 /wd4127 /wd4268 /wd4324 /wd5030 /wd5051 33 | $<$:/EHsc>) 34 | else() 35 | set(DEF_FILE mingw.def) 36 | 37 | set(DSOAL_CFLAGS ${DSOAL_CFLAGS} -Winline -Wunused -Wall -Wextra -Wshadow -Wconversion 38 | -Wcast-align -Wpedantic 39 | $<$:-Wold-style-cast -Wnon-virtual-dtor -Woverloaded-virtual>) 40 | 41 | check_cxx_compiler_flag(-ftrivial-auto-var-init=pattern HAVE_FTRIVIAL_AUTO_VAR_INIT) 42 | if(HAVE_FTRIVIAL_AUTO_VAR_INIT) 43 | set(DSOAL_CFLAGS ${DSOAL_CFLAGS} -ftrivial-auto-var-init=pattern) 44 | endif() 45 | 46 | set(OLD_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) 47 | # Yes GCC, really don't accept command line options you don't support 48 | set(CMAKE_REQUIRED_FLAGS "${OLD_REQUIRED_FLAGS} -Werror") 49 | check_cxx_compiler_flag(-msse2 HAVE_MSSE2_SWITCH) 50 | if(HAVE_MSSE2_SWITCH) 51 | set(SSE2_SWITCH "-msse2") 52 | endif() 53 | set(CMAKE_REQUIRED_FLAGS ${OLD_REQUIRED_FLAGS}) 54 | unset(OLD_REQUIRED_FLAGS) 55 | 56 | if(CMAKE_SIZEOF_VOID_P MATCHES "4" AND SSE2_SWITCH) 57 | option(DSOAL_ENABLE_SSE2_CODEGEN "Enable SSE2 code generation instead of x87 for 32-bit targets." TRUE) 58 | if(DSOAL_ENABLE_SSE2_CODEGEN) 59 | check_cxx_compiler_flag("${SSE2_SWITCH} -mfpmath=sse" HAVE_MFPMATH_SSE_2) 60 | if(HAVE_MFPMATH_SSE_2) 61 | set(DSOAL_CFLAGS ${DSOAL_CFLAGS} ${SSE2_SWITCH} -mfpmath=sse) 62 | endif() 63 | endif() 64 | endif() 65 | 66 | set(DSOAL_LINK_FLAGS ${DSOAL_LINK_FLAGS} -static-libgcc -static-libstdc++) 67 | set(DSOAL_LINK_FLAGS ${DSOAL_LINK_FLAGS} "-Wl,--push-state,-Bstatic,-lstdc++,-lwinpthread,--pop-state") 68 | endif(MSVC) 69 | 70 | 71 | find_package(Git) 72 | option(DSOAL_UPDATE_BUILD_VERSION "Update git build version info" ON) 73 | if(DSOAL_UPDATE_BUILD_VERSION AND GIT_FOUND AND EXISTS "${dsoal_SOURCE_DIR}/.git") 74 | set(GIT_DIR "${dsoal_SOURCE_DIR}/.git") 75 | 76 | # Check if this is a submodule, if it is then find the .git directory 77 | if(NOT IS_DIRECTORY "${dsoal_SOURCE_DIR}/.git") 78 | file(READ ${GIT_DIR} submodule) 79 | string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE ${submodule}) 80 | string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE) 81 | get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) 82 | get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) 83 | endif() 84 | 85 | # Get the current working branch and its latest abbreviated commit hash 86 | add_custom_command(OUTPUT "${dsoal_BINARY_DIR}/version_witness.txt" 87 | BYPRODUCTS "${dsoal_BINARY_DIR}/version.h" 88 | COMMAND ${CMAKE_COMMAND} -D GIT_EXECUTABLE=${GIT_EXECUTABLE} -D LIB_VERSION=${VERSION} 89 | -D SRC=${dsoal_SOURCE_DIR}/version.h.in -D DST=${dsoal_BINARY_DIR}/version.h 90 | -P ${dsoal_SOURCE_DIR}/version.cmake 91 | COMMAND ${CMAKE_COMMAND} -E touch "${dsoal_BINARY_DIR}/version_witness.txt" 92 | WORKING_DIRECTORY "${dsoal_SOURCE_DIR}" 93 | MAIN_DEPENDENCY "${dsoal_SOURCE_DIR}/version.h.in" 94 | DEPENDS "${GIT_DIR}/index" "${dsoal_SOURCE_DIR}/version.cmake" 95 | VERBATIM 96 | ) 97 | 98 | add_custom_target(dsoal.build_version DEPENDS "${dsoal_BINARY_DIR}/version_witness.txt") 99 | else() 100 | set(GIT_BRANCH "UNKNOWN") 101 | set(GIT_COMMIT_HASH "unknown") 102 | configure_file( 103 | "${dsoal_SOURCE_DIR}/version.h.in" 104 | "${dsoal_BINARY_DIR}/version.h") 105 | endif() 106 | 107 | 108 | if(MINGW) 109 | set(CMAKE_RC_COMPILER_INIT windres) 110 | set(CMAKE_RC_COMPILE_OBJECT 111 | " -O coff -i -o ") 112 | endif(MINGW) 113 | enable_language(RC) 114 | 115 | set(SRC_OBJS 116 | src/AL/al.h 117 | src/AL/alc.h 118 | src/AL/alext.h 119 | src/AL/efx.h 120 | src/buffer.cpp 121 | src/buffer.h 122 | src/capture.cpp 123 | src/capture.h 124 | src/comhelpers.h 125 | src/comptr.h 126 | src/dsoal_global.h 127 | src/dsoal.cpp 128 | src/dsoal.h 129 | src/dsoundoal.cpp 130 | src/dsoundoal.h 131 | src/eax.cpp 132 | src/eax.h 133 | src/enumerate.h 134 | src/expected.h 135 | src/factory.cpp 136 | src/factory.h 137 | src/fullduplex.cpp 138 | src/fullduplex.h 139 | src/guidprinter.h 140 | src/logging.cpp 141 | src/logging.h 142 | src/primarybuffer.cpp 143 | src/primarybuffer.h 144 | src/propset.cpp 145 | src/propset.h 146 | src/vmanager.h) 147 | 148 | set(TXT_FILES 149 | LICENSE 150 | README.md) 151 | 152 | add_library(dsound SHARED ${SRC_OBJS} version.rc ${DEF_FILE} ${TXT_FILES}) 153 | set_target_properties(dsound PROPERTIES PREFIX "") 154 | target_link_libraries(dsound PRIVATE dsoal::fmt ${DSOAL_LINK_FLAGS}) 155 | target_include_directories(dsound PRIVATE ${dsoal_BINARY_DIR}) 156 | target_compile_definitions(dsound PRIVATE DSOAL_LIBRARY ${DSOAL_CPPDEFS}) 157 | target_compile_options(dsound PRIVATE ${DSOAL_CFLAGS}) 158 | if(TARGET dsoal.build_version) 159 | add_dependencies(dsound dsoal.build_version) 160 | endif() 161 | 162 | install(TARGETS dsound 163 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 164 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 165 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 166 | if(EXISTS "${dsoal_BINARY_DIR}/dsoal-aldrv.dll") 167 | install(FILES 168 | "${dsoal_BINARY_DIR}/dsoal-aldrv.dll" 169 | DESTINATION ${CMAKE_INSTALL_BINDIR}) 170 | endif() 171 | 172 | target_sources(dsound PRIVATE ${TXT_FILES}) 173 | install(FILES ${TXT_FILES} TYPE DATA) 174 | 175 | 176 | set(NEED_ANALYZE_SOURCE_FILES "") 177 | foreach(obj ${SRC_OBJS}) 178 | list(APPEND NEED_ANALYZE_SOURCE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${obj}") 179 | endforeach() 180 | set(CLANG_TIDY_EXECUTABLE "clang-tidy") 181 | if(DEFINED ENV{CLANG_TIDY_EXECUTABLE}) 182 | set(CLANG_TIDY_EXECUTABLE $ENV{CLANG_TIDY_EXECUTABLE}) 183 | endif() 184 | add_custom_target(clang-tidy-check ${CLANG_TIDY_EXECUTABLE} -format-style=file 185 | -p ${CMAKE_BINARY_DIR}/compile_commands.json ${NEED_ANALYZE_SOURCE_FILES} 186 | DEPENDS ${NEED_ANALYZE_SOURCE_FILES} ${CMAKE_BINARY_DIR}/compile_commands.json) 187 | 188 | 189 | set(CPACK_GENERATOR "ZIP") 190 | set(CPACK_PACKAGE_VENDOR "Chris Robinson") 191 | set(CPACK_PACKAGE_VERSION ${VERSION}) 192 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") 193 | set(CPACK_STRIP_FILES TRUE) 194 | set(CPACK_OUTPUT_FILE_PREFIX packages) 195 | 196 | include(CPack) 197 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSOAL 2 | 3 | This project is for a DirectSound DLL replacement. It implements the 4 | DirectSound interfaces by translating the calls to OpenAL, and fools 5 | applications into thinking there is a hardware accelerated sound device. EAX is 6 | also implemented (up to version 4) by using OpenAL's EAX extension, allowing 7 | for environmental reverb with sound obstruction and occlusion effects. 8 | 9 | Effectively, this allows DirectSound applications to enable their DirectSound3D 10 | acceleration path, and turn on EAX. The actual processing is being done by 11 | OpenAL with no hardware acceleration requirement, allowing it to work on 12 | systems where audio acceleration is not otherwise available. 13 | 14 | Or more succinctly: it enables DirectSound3D surround sound and EAX for systems 15 | without the requisite hardware. 16 | 17 | 18 | ## Source Code 19 | 20 | To build the source, you will need [CMake](https://cmake.org/) 2.6 or newer. 21 | You can either use the CMake GUI, specifying the directories for the source and 22 | where the build files should go, or using one of the command-line programs, for 23 | example by first making sure to be in an empty directory where the build files 24 | will go (such as the provided build/ sub-directory) and running cmake with the 25 | path to the source. 26 | 27 | Once successfully built, it should have created dsound.dll. 28 | 29 | 30 | ## Usage 31 | 32 | Once built, copy dsound.dll to the same location as the desired application's 33 | executable. You must also provide an OpenAL DLL in the same location, named as 34 | dsoal-aldrv.dll, or else the DLL will fail to work. Some applications may need 35 | to be configured to use DirectSound3D acceleration and EAX, but it otherwise 36 | goes to work the next time the application is run. 37 | 38 | Source releases and Windows binaries for OpenAL Soft are 39 | available at its [homepage](https://openal-soft.org/). 40 | Instructions are also provided there. 41 | 42 | ### Environment Variables 43 | The following environment variables can be set: 44 | - `DSOAL_LOGLEVEL`: 45 | - Values: Integer, range `0-3` 46 | - Description: Set the verbosity of DSOAL logging. Level 3 enables logging of API traces. By default, a log level of `1` is used to report errors only. 47 | - `DSOAL_LOGFILE`: 48 | - Values: String 49 | - Description: Path to a file that will be created/overwritten by DSOAL on each execution. All logging will be redirected to that file. If unset, logging it written to the process's `stderr` output. 50 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 4 | GEN: "Visual Studio 17 2022" 5 | ARCH: Win32 6 | CFG: Release 7 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 8 | GEN: "Visual Studio 17 2022" 9 | ARCH: x64 10 | CFG: Release 11 | 12 | after_build: 13 | - 7z a ..\dsoal.zip "%APPVEYOR_BUILD_FOLDER%\build\%CFG%\dsound.dll" "%APPVEYOR_BUILD_FOLDER%\README.md" "%APPVEYOR_BUILD_FOLDER%\LICENSE" 14 | 15 | artifacts: 16 | - path: dsoal.zip 17 | 18 | build_script: 19 | - cmd: | 20 | cd build 21 | cmake -G"%GEN%" -A %ARCH% .. 22 | cmake --build . --config %CFG% --clean-first 23 | -------------------------------------------------------------------------------- /build/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThreeDeeJay/dsoal/7840f9e7b9691e8b3fddfe293f5344e8afcea640/build/.empty -------------------------------------------------------------------------------- /fmt-11.1.1/.clang-format: -------------------------------------------------------------------------------- 1 | # Run manually to reformat a file: 2 | # clang-format -i --style=file 3 | Language: Cpp 4 | BasedOnStyle: Google 5 | IndentPPDirectives: AfterHash 6 | IndentCaseLabels: false 7 | AlwaysBreakTemplateDeclarations: false 8 | DerivePointerAlignment: false 9 | AllowShortCaseLabelsOnASingleLine: true 10 | AlignConsecutiveShortCaseStatements: 11 | Enabled: true 12 | AcrossEmptyLines: true 13 | AcrossComments: true 14 | AlignCaseColons: false -------------------------------------------------------------------------------- /fmt-11.1.1/.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" # Necessary to update action hashes. 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | # Allow up to 3 opened pull requests for github-actions versions. 8 | open-pull-requests-limit: 3 9 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/cifuzz.yml: -------------------------------------------------------------------------------- 1 | name: CIFuzz 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | Fuzzing: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Build fuzzers 12 | id: build 13 | uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@92182553173581f871130c71c71b17f003d47b0a 14 | with: 15 | oss-fuzz-project-name: 'fmt' 16 | dry-run: false 17 | language: c++ 18 | 19 | - name: Run fuzzers 20 | uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@92182553173581f871130c71c71b17f003d47b0a 21 | with: 22 | oss-fuzz-project-name: 'fmt' 23 | fuzz-seconds: 300 24 | dry-run: false 25 | language: c++ 26 | 27 | - name: Upload crash 28 | uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 29 | if: failure() && steps.build.outcome == 'success' 30 | with: 31 | name: artifacts 32 | path: ./out/artifacts 33 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/doc.yml: -------------------------------------------------------------------------------- 1 | name: doc 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | # Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken. 11 | runs-on: ubuntu-20.04 12 | 13 | steps: 14 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 15 | 16 | - name: Add Ubuntu mirrors 17 | run: | 18 | # Github Actions caching proxy is at times unreliable 19 | # see https://github.com/actions/runner-images/issues/7048 20 | printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt 21 | curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt 22 | sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list 23 | 24 | - name: Create build environment 25 | run: | 26 | sudo apt update 27 | sudo apt install doxygen 28 | pip install mkdocs-material==9.5.25 mkdocstrings==0.25.1 mike==2.1.1 29 | cmake -E make_directory ${{runner.workspace}}/build 30 | # Workaround https://github.com/actions/checkout/issues/13: 31 | git config --global user.name "$(git --no-pager log --format=format:'%an' -n 1)" 32 | git config --global user.email "$(git --no-pager log --format=format:'%ae' -n 1)" 33 | 34 | - name: Build 35 | working-directory: ${{runner.workspace}}/build 36 | run: $GITHUB_WORKSPACE/support/mkdocs deploy dev 37 | 38 | - name: Deploy 39 | env: 40 | KEY: "${{secrets.KEY}}" 41 | if: env.KEY != '' && github.ref == 'refs/heads/master' 42 | working-directory: ${{runner.workspace}}/fmt/build/fmt.dev 43 | run: git push https://$KEY@github.com/fmtlib/fmt.dev.git 44 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - '**.h' 7 | - '**.cc' 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | format_code: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 17 | 18 | - name: Install clang-format 19 | run: | 20 | wget https://apt.llvm.org/llvm.sh 21 | sudo bash ./llvm.sh 17 22 | sudo apt install clang-format-17 23 | 24 | - name: Run clang-format 25 | run: | 26 | find include src -name '*.h' -o -name '*.cc' | \ 27 | xargs clang-format-17 -i -style=file -fallback-style=none 28 | git diff --exit-code 29 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: linux 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-20.04 11 | strategy: 12 | matrix: 13 | cxx: [g++-4.9, g++-10, clang++-9] 14 | build_type: [Debug, Release] 15 | std: [11] 16 | shared: [""] 17 | include: 18 | - cxx: g++-4.9 19 | install: sudo apt install g++-4.9 20 | - cxx: g++-8 21 | build_type: Debug 22 | std: 14 23 | install: sudo apt install g++-8 24 | - cxx: g++-8 25 | build_type: Debug 26 | std: 17 27 | install: sudo apt install g++-8 28 | - cxx: g++-9 29 | build_type: Debug 30 | std: 17 31 | - cxx: g++-10 32 | build_type: Debug 33 | std: 17 34 | - cxx: g++-11 35 | build_type: Debug 36 | std: 20 37 | install: sudo apt install g++-11 38 | - cxx: clang++-8 39 | build_type: Debug 40 | std: 17 41 | cxxflags: -stdlib=libc++ 42 | install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev 43 | - cxx: clang++-9 44 | install: sudo apt install clang-9 45 | - cxx: clang++-9 46 | build_type: Debug 47 | fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON 48 | std: 17 49 | install: sudo apt install clang-9 50 | - cxx: clang++-11 51 | build_type: Debug 52 | std: 20 53 | - cxx: clang++-11 54 | build_type: Debug 55 | std: 20 56 | cxxflags: -stdlib=libc++ 57 | install: sudo apt install libc++-11-dev libc++abi-11-dev 58 | - cxx: g++-13 59 | build_type: Release 60 | std: 23 61 | install: sudo apt install g++-13 62 | shared: -DBUILD_SHARED_LIBS=ON 63 | 64 | steps: 65 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 66 | 67 | - name: Set timezone 68 | run: sudo timedatectl set-timezone 'Asia/Yekaterinburg' 69 | 70 | - name: Add repositories for older GCC 71 | run: | 72 | # Below repo provides GCC 4.9. 73 | sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial main' 74 | sudo apt-add-repository 'deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe' 75 | if: ${{ matrix.cxx == 'g++-4.9' }} 76 | 77 | - name: Add repositories for newer GCC 78 | run: | 79 | sudo apt-add-repository ppa:ubuntu-toolchain-r/test 80 | if: ${{ matrix.cxx == 'g++-11' || matrix.cxx == 'g++-13' }} 81 | 82 | - name: Add Ubuntu mirrors 83 | run: | 84 | # Github Actions caching proxy is at times unreliable 85 | # see https://github.com/actions/runner-images/issues/7048 86 | printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt 87 | curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt 88 | sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list 89 | 90 | - name: Create Build Environment 91 | run: | 92 | sudo apt update 93 | ${{matrix.install}} 94 | sudo apt install locales-all 95 | cmake -E make_directory ${{runner.workspace}}/build 96 | 97 | - name: Configure 98 | working-directory: ${{runner.workspace}}/build 99 | env: 100 | CXX: ${{matrix.cxx}} 101 | CXXFLAGS: ${{matrix.cxxflags}} 102 | run: | 103 | cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \ 104 | -DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \ 105 | -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ 106 | -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE 107 | 108 | - name: Build 109 | working-directory: ${{runner.workspace}}/build 110 | run: | 111 | threads=`nproc` 112 | cmake --build . --config ${{matrix.build_type}} --parallel $threads 113 | 114 | - name: Test 115 | working-directory: ${{runner.workspace}}/build 116 | run: ctest -C ${{matrix.build_type}} 117 | env: 118 | CTEST_OUTPUT_ON_FAILURE: True 119 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macos 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | strategy: 11 | matrix: 12 | os: [macos-13, macos-14] 13 | build_type: [Debug, Release] 14 | std: [11, 17, 20] 15 | shared: [""] 16 | exclude: 17 | - { os: macos-13, std: 11 } 18 | - { os: macos-13, std: 17 } 19 | include: 20 | - os: macos-14 21 | std: 23 22 | build_type: Release 23 | shared: -DBUILD_SHARED_LIBS=ON 24 | 25 | runs-on: '${{ matrix.os }}' 26 | 27 | steps: 28 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 29 | 30 | - name: Set timezone 31 | run: sudo systemsetup -settimezone 'Asia/Yekaterinburg' 32 | 33 | - name: Select Xcode 14.3 (macOS 13) 34 | run: sudo xcode-select -s "/Applications/Xcode_14.3.app" 35 | if: ${{ matrix.os == 'macos-13' }} 36 | 37 | - name: Create Build Environment 38 | run: cmake -E make_directory ${{runner.workspace}}/build 39 | 40 | - name: Configure 41 | working-directory: ${{runner.workspace}}/build 42 | run: | 43 | cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \ 44 | -DCMAKE_CXX_STANDARD=${{matrix.std}} \ 45 | -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ 46 | -DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE 47 | 48 | - name: Build 49 | working-directory: ${{runner.workspace}}/build 50 | run: | 51 | threads=`sysctl -n hw.logicalcpu` 52 | cmake --build . --config ${{matrix.build_type}} --parallel $threads 53 | 54 | - name: Test 55 | working-directory: ${{runner.workspace}}/build 56 | run: ctest -C ${{matrix.build_type}} 57 | env: 58 | CTEST_OUTPUT_ON_FAILURE: True 59 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '26 14 * * 5' 14 | push: 15 | branches: [ "master" ] 16 | 17 | # Declare default permissions as read only. 18 | permissions: read-all 19 | 20 | jobs: 21 | analysis: 22 | name: Scorecard analysis 23 | runs-on: ubuntu-latest 24 | permissions: 25 | # Needed to upload the results to code-scanning dashboard. 26 | security-events: write 27 | # Needed to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | 30 | steps: 31 | - name: "Checkout code" 32 | uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 33 | with: 34 | persist-credentials: false 35 | 36 | - name: "Run analysis" 37 | uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 38 | with: 39 | results_file: results.sarif 40 | results_format: sarif 41 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 42 | # - you want to enable the Branch-Protection check on a *public* repository, or 43 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 44 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 45 | 46 | # Public repositories: 47 | # - Publish results to OpenSSF REST API for easy access by consumers 48 | # - Allows the repository to include the Scorecard badge. 49 | # - See https://github.com/ossf/scorecard-action#publishing-results. 50 | publish_results: true 51 | 52 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 53 | # format to the repository Actions tab. 54 | - name: "Upload artifact" 55 | uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 56 | with: 57 | name: SARIF file 58 | path: results.sarif 59 | retention-days: 5 60 | 61 | # Upload the results to GitHub's code scanning dashboard. 62 | - name: "Upload to code-scanning" 63 | uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0 64 | with: 65 | sarif_file: results.sarif 66 | -------------------------------------------------------------------------------- /fmt-11.1.1/.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: windows 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | build: 10 | runs-on: ${{matrix.os}} 11 | strategy: 12 | matrix: 13 | # windows-2019 has MSVC 2019 installed; 14 | # windows-2022 has MSVC 2022 installed: 15 | # https://github.com/actions/virtual-environments. 16 | os: [windows-2019] 17 | platform: [Win32, x64] 18 | toolset: [v141, v142] 19 | standard: [14, 17, 20] 20 | shared: ["", -DBUILD_SHARED_LIBS=ON] 21 | build_type: [Debug, Release] 22 | exclude: 23 | - { toolset: v141, standard: 20 } 24 | - { toolset: v142, standard: 14 } 25 | - { platform: Win32, toolset: v141 } 26 | - { platform: Win32, standard: 14 } 27 | - { platform: Win32, standard: 20 } 28 | - { platform: x64, toolset: v141, shared: -DBUILD_SHARED_LIBS=ON } 29 | - { platform: x64, standard: 14, shared: -DBUILD_SHARED_LIBS=ON } 30 | - { platform: x64, standard: 20, shared: -DBUILD_SHARED_LIBS=ON } 31 | include: 32 | - os: windows-2022 33 | platform: x64 34 | toolset: v143 35 | build_type: Debug 36 | standard: 20 37 | 38 | steps: 39 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 40 | 41 | - name: Set timezone 42 | run: tzutil /s "Ekaterinburg Standard Time" 43 | 44 | - name: Create Build Environment 45 | run: cmake -E make_directory ${{runner.workspace}}/build 46 | 47 | - name: Configure 48 | # Use a bash shell for $GITHUB_WORKSPACE. 49 | shell: bash 50 | working-directory: ${{runner.workspace}}/build 51 | run: | 52 | cmake -A ${{matrix.platform}} -T ${{matrix.toolset}} \ 53 | -DCMAKE_CXX_STANDARD=${{matrix.standard}} \ 54 | ${{matrix.shared}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ 55 | $GITHUB_WORKSPACE 56 | 57 | - name: Build 58 | working-directory: ${{runner.workspace}}/build 59 | run: | 60 | $threads = (Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors 61 | cmake --build . --config ${{matrix.build_type}} --parallel $threads 62 | 63 | - name: Test 64 | working-directory: ${{runner.workspace}}/build 65 | run: ctest -C ${{matrix.build_type}} -V 66 | env: 67 | CTEST_OUTPUT_ON_FAILURE: True 68 | 69 | mingw: 70 | runs-on: windows-latest 71 | defaults: 72 | run: 73 | shell: msys2 {0} 74 | strategy: 75 | matrix: 76 | sys: [ mingw64, ucrt64 ] 77 | steps: 78 | - name: Set timezone 79 | run: tzutil /s "Ekaterinburg Standard Time" 80 | shell: cmd 81 | - uses: msys2/setup-msys2@c52d1fa9c7492275e60fe763540fb601f5f232a1 # v2.25.0 82 | with: 83 | release: false 84 | msystem: ${{matrix.sys}} 85 | pacboy: cc:p cmake:p ninja:p lld:p 86 | - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 87 | - name: Configure 88 | run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug 89 | env: { LDFLAGS: -fuse-ld=lld } 90 | - name: Build 91 | run: cmake --build ../build 92 | - name: Test 93 | run: ctest -j `nproc` --test-dir ../build 94 | env: 95 | CTEST_OUTPUT_ON_FAILURE: True 96 | -------------------------------------------------------------------------------- /fmt-11.1.1/.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.so* 3 | *.xcodeproj 4 | *~ 5 | .vscode/ 6 | /CMakeScripts 7 | /Testing 8 | /_CPack_Packages 9 | /install_manifest.txt 10 | CMakeCache.txt 11 | CMakeFiles 12 | CPack*.cmake 13 | CTestTestfile.cmake 14 | FMT.build 15 | Makefile 16 | bin/ 17 | build/ 18 | cmake_install.cmake 19 | fmt-*.cmake 20 | fmt.pc 21 | -------------------------------------------------------------------------------- /fmt-11.1.1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8...3.28) 2 | 3 | # [CR] Heavily modified for OpenAL Soft to avoid clashes if used as a sub- 4 | # project with other uses of fmt. 5 | 6 | # Fallback for using newer policies on CMake <3.12. 7 | if (${CMAKE_VERSION} VERSION_LESS 3.12) 8 | cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) 9 | endif () 10 | 11 | # Joins arguments and places the results in ${result_var}. 12 | function(join result_var) 13 | set(result "") 14 | foreach (arg ${ARGN}) 15 | set(result "${result}${arg}") 16 | endforeach () 17 | set(${result_var} "${result}" PARENT_SCOPE) 18 | endfunction() 19 | 20 | include(CMakeParseArguments) 21 | 22 | project(DSOAL_FMT CXX) 23 | 24 | # Get version from base.h 25 | file(READ include/fmt/base.h base_h) 26 | if (NOT base_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") 27 | message(FATAL_ERROR "Cannot get FMT_VERSION from base.h.") 28 | endif () 29 | # Use math to skip leading zeros if any. 30 | math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1}) 31 | math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2}) 32 | math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3}) 33 | join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}. 34 | ${CPACK_PACKAGE_VERSION_PATCH}) 35 | message(STATUS "{fmt} version: ${FMT_VERSION}") 36 | 37 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 38 | 39 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 40 | "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") 41 | 42 | include(CheckCXXCompilerFlag) 43 | include(JoinPaths) 44 | 45 | function(add_headers VAR) 46 | set(headers ${${VAR}}) 47 | foreach (header ${ARGN}) 48 | set(headers ${headers} include/fmt/${header}) 49 | endforeach() 50 | set(${VAR} ${headers} PARENT_SCOPE) 51 | endfunction() 52 | 53 | set(DSOAL_FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.") 54 | 55 | # Define the fmt library, its includes and the needed defines. 56 | add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h 57 | format-inl.h os.h ostream.h printf.h ranges.h std.h 58 | xchar.h) 59 | set(FMT_SOURCES src/format.cc src/os.cc) 60 | 61 | add_library(dsoal.fmt OBJECT ${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md) 62 | add_library(dsoal::fmt ALIAS dsoal.fmt) 63 | 64 | if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) 65 | target_compile_features(dsoal.fmt PUBLIC cxx_std_11) 66 | else () 67 | message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler") 68 | endif () 69 | 70 | target_include_directories(dsoal.fmt PUBLIC 71 | $) 72 | 73 | set_target_properties(dsoal.fmt PROPERTIES 74 | VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR} 75 | DEBUG_POSTFIX "${DSOAL_FMT_DEBUG_POSTFIX}" 76 | POSITION_INDEPENDENT_CODE TRUE 77 | C_VISIBILITY_PRESET hidden 78 | CXX_VISIBILITY_PRESET hidden 79 | EXCLUDE_FROM_ALL TRUE) 80 | 81 | if (MSVC) 82 | # Unicode support requires compiling with /utf-8. 83 | target_compile_options(dsoal.fmt PUBLIC $<$:/utf-8>) 84 | endif () 85 | -------------------------------------------------------------------------------- /fmt-11.1.1/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to {fmt} 2 | ===================== 3 | 4 | By submitting a pull request or a patch, you represent that you have the right 5 | to license your contribution to the {fmt} project owners and the community, 6 | agree that your contributions are licensed under the {fmt} license, and agree 7 | to future changes to the licensing. 8 | 9 | All C++ code must adhere to [Google C++ Style Guide]( 10 | https://google.github.io/styleguide/cppguide.html) with the following 11 | exceptions: 12 | 13 | * Exceptions are permitted 14 | * snake_case should be used instead of UpperCamelCase for function and type 15 | names 16 | 17 | All documentation must adhere to the [Google Developer Documentation Style 18 | Guide](https://developers.google.com/style). 19 | 20 | Thanks for contributing! 21 | -------------------------------------------------------------------------------- /fmt-11.1.1/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | --- Optional exception to the license --- 23 | 24 | As an exception, if, as a result of your compiling your source code, portions 25 | of this Software are embedded into a machine-executable object form of such 26 | source code, you may redistribute such embedded portions in such object form 27 | without including the above copyright and permission notices. 28 | -------------------------------------------------------------------------------- /fmt-11.1.1/doc/fmt.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --md-primary-fg-color: #0050D0; 3 | } 4 | 5 | .md-grid { 6 | max-width: 960px; 7 | } 8 | 9 | @media (min-width: 400px) { 10 | .md-tabs { 11 | display: block; 12 | } 13 | } 14 | 15 | .docblock { 16 | border-left: .05rem solid var(--md-primary-fg-color); 17 | } 18 | 19 | .docblock-desc { 20 | margin-left: 1em; 21 | } 22 | 23 | pre > code.decl { 24 | white-space: pre-wrap; 25 | } 26 | 27 | 28 | code.decl > div { 29 | text-indent: -2ch; /* Negative indent to counteract the indent on the first line */ 30 | padding-left: 2ch; /* Add padding to the left to create an indent */ 31 | } 32 | 33 | .features-container { 34 | display: flex; 35 | flex-wrap: wrap; 36 | gap: 20px; 37 | justify-content: center; /* Center the items horizontally */ 38 | } 39 | 40 | .feature { 41 | flex: 1 1 calc(50% - 20px); /* Two columns with space between */ 42 | max-width: 600px; /* Set the maximum width for the feature boxes */ 43 | box-sizing: border-box; 44 | padding: 10px; 45 | overflow: hidden; /* Hide overflow content */ 46 | text-overflow: ellipsis; /* Handle text overflow */ 47 | white-space: normal; /* Allow text wrapping */ 48 | } 49 | 50 | .feature h2 { 51 | margin-top: 0px; 52 | font-weight: bold; 53 | } 54 | 55 | @media (max-width: 768px) { 56 | .feature { 57 | flex: 1 1 100%; /* Stack columns on smaller screens */ 58 | max-width: 100%; /* Allow full width on smaller screens */ 59 | white-space: normal; /* Allow text wrapping on smaller screens */ 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /fmt-11.1.1/doc/fmt.js: -------------------------------------------------------------------------------- 1 | document$.subscribe(() => { 2 | hljs.highlightAll(), 3 | { language: 'c++' } 4 | }) 5 | -------------------------------------------------------------------------------- /fmt-11.1.1/doc/get-started.md: -------------------------------------------------------------------------------- 1 | # Get Started 2 | 3 | Compile and run {fmt} examples online with [Compiler Explorer]( 4 | https://godbolt.org/z/P7h6cd6o3). 5 | 6 | {fmt} is compatible with any build system. The next section describes its usage 7 | with CMake, while the [Build Systems](#build-systems) section covers the rest. 8 | 9 | ## CMake 10 | 11 | {fmt} provides two CMake targets: `fmt::fmt` for the compiled library and 12 | `fmt::fmt-header-only` for the header-only library. It is recommended to use 13 | the compiled library for improved build times. 14 | 15 | There are three primary ways to use {fmt} with CMake: 16 | 17 | * **FetchContent**: Starting from CMake 3.11, you can use [`FetchContent`]( 18 | https://cmake.org/cmake/help/v3.30/module/FetchContent.html) to automatically 19 | download {fmt} as a dependency at configure time: 20 | 21 | include(FetchContent) 22 | 23 | FetchContent_Declare( 24 | fmt 25 | GIT_REPOSITORY https://github.com/fmtlib/fmt 26 | GIT_TAG e69e5f977d458f2650bb346dadf2ad30c5320281) # 10.2.1 27 | FetchContent_MakeAvailable(fmt) 28 | 29 | target_link_libraries( fmt::fmt) 30 | 31 | * **Installed**: You can find and use an [installed](#installation) version of 32 | {fmt} in your `CMakeLists.txt` file as follows: 33 | 34 | find_package(fmt) 35 | target_link_libraries( fmt::fmt) 36 | 37 | * **Embedded**: You can add the {fmt} source tree to your project and include it 38 | in your `CMakeLists.txt` file: 39 | 40 | add_subdirectory(fmt) 41 | target_link_libraries( fmt::fmt) 42 | 43 | ## Installation 44 | 45 | ### Debian/Ubuntu 46 | 47 | To install {fmt} on Debian, Ubuntu, or any other Debian-based Linux 48 | distribution, use the following command: 49 | 50 | apt install libfmt-dev 51 | 52 | ### Homebrew 53 | 54 | Install {fmt} on macOS using [Homebrew](https://brew.sh/): 55 | 56 | brew install fmt 57 | 58 | ### Conda 59 | 60 | Install {fmt} on Linux, macOS, and Windows with [Conda]( 61 | https://docs.conda.io/en/latest/), using its [conda-forge package]( 62 | https://github.com/conda-forge/fmt-feedstock): 63 | 64 | conda install -c conda-forge fmt 65 | 66 | ### vcpkg 67 | 68 | Download and install {fmt} using the vcpkg package manager: 69 | 70 | git clone https://github.com/Microsoft/vcpkg.git 71 | cd vcpkg 72 | ./bootstrap-vcpkg.sh 73 | ./vcpkg integrate install 74 | ./vcpkg install fmt 75 | 76 | 80 | 81 | ## Building from Source 82 | 83 | CMake works by generating native makefiles or project files that can be 84 | used in the compiler environment of your choice. The typical workflow 85 | starts with: 86 | 87 | mkdir build # Create a directory to hold the build output. 88 | cd build 89 | cmake .. # Generate native build scripts. 90 | 91 | run in the `fmt` repository. 92 | 93 | If you are on a Unix-like system, you should now see a Makefile in the 94 | current directory. Now you can build the library by running `make`. 95 | 96 | Once the library has been built you can invoke `make test` to run the tests. 97 | 98 | You can control generation of the make `test` target with the `FMT_TEST` 99 | CMake option. This can be useful if you include fmt as a subdirectory in 100 | your project but don't want to add fmt's tests to your `test` target. 101 | 102 | To build a shared library set the `BUILD_SHARED_LIBS` CMake variable to `TRUE`: 103 | 104 | cmake -DBUILD_SHARED_LIBS=TRUE .. 105 | 106 | To build a static library with position-independent code (e.g. for 107 | linking it into another shared library such as a Python extension), set the 108 | `CMAKE_POSITION_INDEPENDENT_CODE` CMake variable to `TRUE`: 109 | 110 | cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE .. 111 | 112 | After building the library you can install it on a Unix-like system by 113 | running `sudo make install`. 114 | 115 | ### Building the Docs 116 | 117 | To build the documentation you need the following software installed on 118 | your system: 119 | 120 | - [Python](https://www.python.org/) 121 | - [Doxygen](http://www.stack.nl/~dimitri/doxygen/) 122 | - [MkDocs](https://www.mkdocs.org/) with `mkdocs-material`, `mkdocstrings`, 123 | `pymdown-extensions` and `mike` 124 | 125 | First generate makefiles or project files using CMake as described in 126 | the previous section. Then compile the `doc` target/project, for example: 127 | 128 | make doc 129 | 130 | This will generate the HTML documentation in `doc/html`. 131 | 132 | ## Build Systems 133 | 134 | ### build2 135 | 136 | You can use [build2](https://build2.org), a dependency manager and a build 137 | system, to use {fmt}. 138 | 139 | Currently this package is available in these package repositories: 140 | 141 | - for released and published versions. 142 | - for unreleased or custom versions. 143 | 144 | **Usage:** 145 | 146 | - `build2` package name: `fmt` 147 | - Library target name: `lib{fmt}` 148 | 149 | To make your `build2` project depend on `fmt`: 150 | 151 | - Add one of the repositories to your configurations, or in your 152 | `repositories.manifest`, if not already there: 153 | 154 | : 155 | role: prerequisite 156 | location: https://pkg.cppget.org/1/stable 157 | 158 | - Add this package as a dependency to your `manifest` file (example 159 | for version 10): 160 | 161 | depends: fmt ~10.0.0 162 | 163 | - Import the target and use it as a prerequisite to your own target 164 | using `fmt` in the appropriate `buildfile`: 165 | 166 | import fmt = fmt%lib{fmt} 167 | lib{mylib} : cxx{**} ... $fmt 168 | 169 | Then build your project as usual with `b` or `bdep update`. 170 | 171 | ### Meson 172 | 173 | [Meson WrapDB](https://mesonbuild.com/Wrapdb-projects.html) includes an `fmt` 174 | package. 175 | 176 | **Usage:** 177 | 178 | - Install the `fmt` subproject from the WrapDB by running: 179 | 180 | meson wrap install fmt 181 | 182 | from the root of your project. 183 | 184 | - In your project's `meson.build` file, add an entry for the new subproject: 185 | 186 | fmt = subproject('fmt') 187 | fmt_dep = fmt.get_variable('fmt_dep') 188 | 189 | - Include the new dependency object to link with fmt: 190 | 191 | my_build_target = executable( 192 | 'name', 'src/main.cc', dependencies: [fmt_dep]) 193 | 194 | **Options:** 195 | 196 | If desired, {fmt} can be built as a static library, or as a header-only library. 197 | 198 | For a static build, use the following subproject definition: 199 | 200 | fmt = subproject('fmt', default_options: 'default_library=static') 201 | fmt_dep = fmt.get_variable('fmt_dep') 202 | 203 | For the header-only version, use: 204 | 205 | fmt = subproject('fmt') 206 | fmt_dep = fmt.get_variable('fmt_header_only_dep') 207 | 208 | ### Android NDK 209 | 210 | {fmt} provides [Android.mk file]( 211 | https://github.com/fmtlib/fmt/blob/master/support/Android.mk) that can be used 212 | to build the library with [Android NDK]( 213 | https://developer.android.com/tools/sdk/ndk/index.html). 214 | 215 | ### Other 216 | 217 | To use the {fmt} library with any other build system, add 218 | `include/fmt/base.h`, `include/fmt/format.h`, `include/fmt/format-inl.h`, 219 | `src/format.cc` and optionally other headers from a [release archive]( 220 | https://github.com/fmtlib/fmt/releases) or the [git repository]( 221 | https://github.com/fmtlib/fmt) to your project, add `include` to include 222 | directories and make sure `src/format.cc` is compiled and linked with your code. 223 | -------------------------------------------------------------------------------- /fmt-11.1.1/doc/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide: 3 | - navigation 4 | - toc 5 | --- 6 | 7 | # A modern formatting library 8 | 9 |
10 | 11 |
12 |

Safety

13 |

14 | Inspired by Python's formatting facility, {fmt} provides a safe replacement 15 | for the printf family of functions. Errors in format strings, 16 | which are a common source of vulnerabilities in C, are reported at 17 | compile time. For example: 18 | 19 |

fmt::format("{:d}", "I am not a number");
21 | 22 | will give a compile-time error because d is not a valid 23 | format specifier for strings. APIs like 24 | fmt::format prevent buffer overflow errors via 25 | automatic memory management. 26 |

27 | → Learn more 28 |
29 | 30 |
31 |

Extensibility

32 |

33 | Formatting of most standard types, including all containers, dates, 34 | and times is supported out-of-the-box. For example: 35 | 36 |

fmt::print("{}", std::vector{1, 2, 3});
38 | 39 | prints the vector in a JSON-like format: 40 | 41 |
[1, 2, 3]
42 | 43 | You can make your own types formattable and even make compile-time 44 | checks work for them. 45 |

46 | → Learn more 47 |
48 | 49 |
50 |

Performance

51 |

52 | {fmt} can be anywhere from tens of percent to 20-30 times faster than 53 | iostreams and sprintf, especially for numeric formatting. 54 | 55 | 56 | 57 | 58 | 59 | The library minimizes dynamic memory allocations and can optionally 60 | compile format strings to optimal code. 61 |

62 |
63 | 64 |
65 |

Unicode support

66 |

67 | {fmt} provides portable Unicode support on major operating systems 68 | with UTF-8 and char strings. For example: 69 | 70 |

fmt::print("Слава Україні!");
72 | 73 | will be printed correctly on Linux, macOS, and even Windows console, 74 | irrespective of the codepages. 75 |

76 |

77 | The default is locale-independent, but you can opt into localized 78 | formatting and {fmt} makes it work with Unicode, addressing issues in the 79 | standard libary. 80 |

81 |
82 | 83 |
84 |

Fast compilation

85 |

86 | The library makes extensive use of type erasure to achieve fast 87 | compilation. fmt/base.h provides a subset of the API with 88 | minimal include dependencies and enough functionality to replace 89 | all uses of *printf. 90 |

91 |

92 | Code using {fmt} is usually several times faster to compile than the 93 | equivalent iostreams code, and while printf compiles faster 94 | still, the gap is narrowing. 95 |

96 | 98 | → Learn more 99 |
100 | 101 |
102 |

Small binary footprint

103 |

104 | Type erasure is also used to prevent template bloat, resulting in compact 105 | per-call binary code. For example, a call to fmt::print with 106 | a single argument is just a few 107 | instructions, comparable to printf despite adding 108 | runtime safety, and much smaller than the equivalent iostreams code. 109 |

110 |

111 | The library itself has small binary footprint and some components such as 112 | floating-point formatting can be disabled to make it even smaller for 113 | resource-constrained devices. 114 |

115 |
116 | 117 |
118 |

Portability

119 |

120 | {fmt} has a small self-contained codebase with the core consisting of 121 | just three headers and no external dependencies. 122 |

123 |

124 | The library is highly portable and requires only a minimal subset of 125 | C++11 features which are available in GCC 4.9, Clang 3.4, MSVC 19.10 126 | (2017) and later. Newer compiler and standard library features are used 127 | if available, and enable additional functionality. 128 |

129 |

130 | Where possible, the output of formatting functions is consistent across 131 | platforms. 132 |

133 |

134 |
135 | 136 |
137 |

Open source

138 |

139 | {fmt} is in the top hundred open-source C++ libraries on GitHub and has 140 | hundreds of 141 | all-time contributors. 142 |

143 |

144 | The library is distributed under a permissive MIT 145 | license and is 146 | relied upon by many open-source projects, including Blender, PyTorch, 147 | Apple's FoundationDB, Windows Terminal, MongoDB, and others. 148 |

149 |
150 | 151 |
152 | -------------------------------------------------------------------------------- /fmt-11.1.1/doc/perf.svg: -------------------------------------------------------------------------------- 1 | double to string02505007501,0001,2501,500ostringstreamostrstreamsprintfdoubleconvfmtTime (ns), smaller is better -------------------------------------------------------------------------------- /fmt-11.1.1/include/fmt/args.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - dynamic argument lists 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_ARGS_H_ 9 | #define FMT_ARGS_H_ 10 | 11 | #ifndef FMT_MODULE 12 | # include // std::reference_wrapper 13 | # include // std::unique_ptr 14 | # include 15 | #endif 16 | 17 | #include "format.h" // std_string_view 18 | 19 | FMT_BEGIN_NAMESPACE 20 | namespace detail { 21 | 22 | template struct is_reference_wrapper : std::false_type {}; 23 | template 24 | struct is_reference_wrapper> : std::true_type {}; 25 | 26 | template auto unwrap(const T& v) -> const T& { return v; } 27 | template 28 | auto unwrap(const std::reference_wrapper& v) -> const T& { 29 | return static_cast(v); 30 | } 31 | 32 | // node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC 33 | // 2022 (v17.10.0). 34 | // 35 | // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for 36 | // templates it doesn't complain about inability to deduce single translation 37 | // unit for placing vtable. So node is made a fake template. 38 | template struct node { 39 | virtual ~node() = default; 40 | std::unique_ptr> next; 41 | }; 42 | 43 | class dynamic_arg_list { 44 | template struct typed_node : node<> { 45 | T value; 46 | 47 | template 48 | FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} 49 | 50 | template 51 | FMT_CONSTEXPR typed_node(const basic_string_view& arg) 52 | : value(arg.data(), arg.size()) {} 53 | }; 54 | 55 | std::unique_ptr> head_; 56 | 57 | public: 58 | template auto push(const Arg& arg) -> const T& { 59 | auto new_node = std::unique_ptr>(new typed_node(arg)); 60 | auto& value = new_node->value; 61 | new_node->next = std::move(head_); 62 | head_ = std::move(new_node); 63 | return value; 64 | } 65 | }; 66 | } // namespace detail 67 | 68 | /** 69 | * A dynamic list of formatting arguments with storage. 70 | * 71 | * It can be implicitly converted into `fmt::basic_format_args` for passing 72 | * into type-erased formatting functions such as `fmt::vformat`. 73 | */ 74 | template class dynamic_format_arg_store { 75 | private: 76 | using char_type = typename Context::char_type; 77 | 78 | template struct need_copy { 79 | static constexpr detail::type mapped_type = 80 | detail::mapped_type_constant::value; 81 | 82 | enum { 83 | value = !(detail::is_reference_wrapper::value || 84 | std::is_same>::value || 85 | std::is_same>::value || 86 | (mapped_type != detail::type::cstring_type && 87 | mapped_type != detail::type::string_type && 88 | mapped_type != detail::type::custom_type)) 89 | }; 90 | }; 91 | 92 | template 93 | using stored_t = conditional_t< 94 | std::is_convertible>::value && 95 | !detail::is_reference_wrapper::value, 96 | std::basic_string, T>; 97 | 98 | // Storage of basic_format_arg must be contiguous. 99 | std::vector> data_; 100 | std::vector> named_info_; 101 | 102 | // Storage of arguments not fitting into basic_format_arg must grow 103 | // without relocation because items in data_ refer to it. 104 | detail::dynamic_arg_list dynamic_args_; 105 | 106 | friend class basic_format_args; 107 | 108 | auto data() const -> const basic_format_arg* { 109 | return named_info_.empty() ? data_.data() : data_.data() + 1; 110 | } 111 | 112 | template void emplace_arg(const T& arg) { 113 | data_.emplace_back(arg); 114 | } 115 | 116 | template 117 | void emplace_arg(const detail::named_arg& arg) { 118 | if (named_info_.empty()) 119 | data_.insert(data_.begin(), basic_format_arg(nullptr, 0)); 120 | data_.emplace_back(detail::unwrap(arg.value)); 121 | auto pop_one = [](std::vector>* data) { 122 | data->pop_back(); 123 | }; 124 | std::unique_ptr>, decltype(pop_one)> 125 | guard{&data_, pop_one}; 126 | named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); 127 | data_[0] = {named_info_.data(), named_info_.size()}; 128 | guard.release(); 129 | } 130 | 131 | public: 132 | constexpr dynamic_format_arg_store() = default; 133 | 134 | operator basic_format_args() const { 135 | return basic_format_args(data(), static_cast(data_.size()), 136 | !named_info_.empty()); 137 | } 138 | 139 | /** 140 | * Adds an argument into the dynamic store for later passing to a formatting 141 | * function. 142 | * 143 | * Note that custom types and string types (but not string views) are copied 144 | * into the store dynamically allocating memory if necessary. 145 | * 146 | * **Example**: 147 | * 148 | * fmt::dynamic_format_arg_store store; 149 | * store.push_back(42); 150 | * store.push_back("abc"); 151 | * store.push_back(1.5f); 152 | * std::string result = fmt::vformat("{} and {} and {}", store); 153 | */ 154 | template void push_back(const T& arg) { 155 | if (detail::const_check(need_copy::value)) 156 | emplace_arg(dynamic_args_.push>(arg)); 157 | else 158 | emplace_arg(detail::unwrap(arg)); 159 | } 160 | 161 | /** 162 | * Adds a reference to the argument into the dynamic store for later passing 163 | * to a formatting function. 164 | * 165 | * **Example**: 166 | * 167 | * fmt::dynamic_format_arg_store store; 168 | * char band[] = "Rolling Stones"; 169 | * store.push_back(std::cref(band)); 170 | * band[9] = 'c'; // Changing str affects the output. 171 | * std::string result = fmt::vformat("{}", store); 172 | * // result == "Rolling Scones" 173 | */ 174 | template void push_back(std::reference_wrapper arg) { 175 | static_assert( 176 | need_copy::value, 177 | "objects of built-in types and string views are always copied"); 178 | emplace_arg(arg.get()); 179 | } 180 | 181 | /** 182 | * Adds named argument into the dynamic store for later passing to a 183 | * formatting function. `std::reference_wrapper` is supported to avoid 184 | * copying of the argument. The name is always copied into the store. 185 | */ 186 | template 187 | void push_back(const detail::named_arg& arg) { 188 | const char_type* arg_name = 189 | dynamic_args_.push>(arg.name).c_str(); 190 | if (detail::const_check(need_copy::value)) { 191 | emplace_arg( 192 | fmt::arg(arg_name, dynamic_args_.push>(arg.value))); 193 | } else { 194 | emplace_arg(fmt::arg(arg_name, arg.value)); 195 | } 196 | } 197 | 198 | /// Erase all elements from the store. 199 | void clear() { 200 | data_.clear(); 201 | named_info_.clear(); 202 | dynamic_args_ = {}; 203 | } 204 | 205 | /// Reserves space to store at least `new_cap` arguments including 206 | /// `new_cap_named` named arguments. 207 | void reserve(size_t new_cap, size_t new_cap_named) { 208 | FMT_ASSERT(new_cap >= new_cap_named, 209 | "set of arguments includes set of named arguments"); 210 | data_.reserve(new_cap); 211 | named_info_.reserve(new_cap_named); 212 | } 213 | 214 | /// Returns the number of elements in the store. 215 | size_t size() const noexcept { return data_.size(); } 216 | }; 217 | 218 | FMT_END_NAMESPACE 219 | 220 | #endif // FMT_ARGS_H_ 221 | -------------------------------------------------------------------------------- /fmt-11.1.1/include/fmt/core.h: -------------------------------------------------------------------------------- 1 | // This file is only provided for compatibility and may be removed in future 2 | // versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h 3 | // otherwise. 4 | 5 | #include "format.h" 6 | -------------------------------------------------------------------------------- /fmt-11.1.1/include/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #ifndef FMT_MODULE 12 | # include // std::filebuf 13 | #endif 14 | 15 | #ifdef _WIN32 16 | # ifdef __GLIBCXX__ 17 | # include 18 | # include 19 | # endif 20 | # include 21 | #endif 22 | 23 | #include "chrono.h" // formatbuf 24 | 25 | #ifdef _MSVC_STL_UPDATE 26 | # define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE 27 | #elif defined(_MSC_VER) && _MSC_VER < 1912 // VS 15.5 28 | # define FMT_MSVC_STL_UPDATE _MSVC_LANG 29 | #else 30 | # define FMT_MSVC_STL_UPDATE 0 31 | #endif 32 | 33 | FMT_BEGIN_NAMESPACE 34 | namespace detail { 35 | 36 | // Generate a unique explicit instantion in every translation unit using a tag 37 | // type in an anonymous namespace. 38 | namespace { 39 | struct file_access_tag {}; 40 | } // namespace 41 | template 42 | class file_access { 43 | friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } 44 | }; 45 | 46 | #if FMT_MSVC_STL_UPDATE 47 | template class file_access; 49 | auto get_file(std::filebuf&) -> FILE*; 50 | #endif 51 | 52 | // Write the content of buf to os. 53 | // It is a separate function rather than a part of vprint to simplify testing. 54 | template 55 | void write_buffer(std::basic_ostream& os, buffer& buf) { 56 | const Char* buf_data = buf.data(); 57 | using unsigned_streamsize = make_unsigned_t; 58 | unsigned_streamsize size = buf.size(); 59 | unsigned_streamsize max_size = to_unsigned(max_value()); 60 | do { 61 | unsigned_streamsize n = size <= max_size ? size : max_size; 62 | os.write(buf_data, static_cast(n)); 63 | buf_data += n; 64 | size -= n; 65 | } while (size != 0); 66 | } 67 | 68 | template struct streamed_view { 69 | const T& value; 70 | }; 71 | } // namespace detail 72 | 73 | // Formats an object of type T that has an overloaded ostream operator<<. 74 | template 75 | struct basic_ostream_formatter : formatter, Char> { 76 | void set_debug_format() = delete; 77 | 78 | template 79 | auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { 80 | auto buffer = basic_memory_buffer(); 81 | auto&& formatbuf = detail::formatbuf>(buffer); 82 | auto&& output = std::basic_ostream(&formatbuf); 83 | output.imbue(std::locale::classic()); // The default is always unlocalized. 84 | output << value; 85 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 86 | return formatter, Char>::format( 87 | {buffer.data(), buffer.size()}, ctx); 88 | } 89 | }; 90 | 91 | using ostream_formatter = basic_ostream_formatter; 92 | 93 | template 94 | struct formatter, Char> 95 | : basic_ostream_formatter { 96 | template 97 | auto format(detail::streamed_view view, Context& ctx) const 98 | -> decltype(ctx.out()) { 99 | return basic_ostream_formatter::format(view.value, ctx); 100 | } 101 | }; 102 | 103 | /** 104 | * Returns a view that formats `value` via an ostream `operator<<`. 105 | * 106 | * **Example**: 107 | * 108 | * fmt::print("Current thread id: {}\n", 109 | * fmt::streamed(std::this_thread::get_id())); 110 | */ 111 | template 112 | constexpr auto streamed(const T& value) -> detail::streamed_view { 113 | return {value}; 114 | } 115 | 116 | inline void vprint(std::ostream& os, string_view fmt, format_args args) { 117 | auto buffer = memory_buffer(); 118 | detail::vformat_to(buffer, fmt, args); 119 | FILE* f = nullptr; 120 | #if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI 121 | if (auto* buf = dynamic_cast(os.rdbuf())) 122 | f = detail::get_file(*buf); 123 | #elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI 124 | auto* rdbuf = os.rdbuf(); 125 | if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) 126 | f = sfbuf->file(); 127 | else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) 128 | f = fbuf->file(); 129 | #endif 130 | #ifdef _WIN32 131 | if (f) { 132 | int fd = _fileno(f); 133 | if (_isatty(fd)) { 134 | os.flush(); 135 | if (detail::write_console(fd, {buffer.data(), buffer.size()})) return; 136 | } 137 | } 138 | #endif 139 | detail::ignore_unused(f); 140 | detail::write_buffer(os, buffer); 141 | } 142 | 143 | /** 144 | * Prints formatted data to the stream `os`. 145 | * 146 | * **Example**: 147 | * 148 | * fmt::print(cerr, "Don't {}!", "panic"); 149 | */ 150 | FMT_EXPORT template 151 | void print(std::ostream& os, format_string fmt, T&&... args) { 152 | fmt::vargs vargs = {{args...}}; 153 | if (detail::use_utf8) return vprint(os, fmt.str, vargs); 154 | auto buffer = memory_buffer(); 155 | detail::vformat_to(buffer, fmt.str, vargs); 156 | detail::write_buffer(os, buffer); 157 | } 158 | 159 | FMT_EXPORT template 160 | void println(std::ostream& os, format_string fmt, T&&... args) { 161 | fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); 162 | } 163 | 164 | FMT_END_NAMESPACE 165 | 166 | #endif // FMT_OSTREAM_H_ 167 | -------------------------------------------------------------------------------- /fmt-11.1.1/src/fmt.cc: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | #ifdef _MSVC_LANG 4 | # define FMT_CPLUSPLUS _MSVC_LANG 5 | #else 6 | # define FMT_CPLUSPLUS __cplusplus 7 | #endif 8 | 9 | // Put all implementation-provided headers into the global module fragment 10 | // to prevent attachment to this module. 11 | #ifndef FMT_IMPORT_STD 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | # include 19 | # include 20 | # include 21 | # include 22 | # include 23 | # include 24 | # if FMT_CPLUSPLUS > 202002L 25 | # include 26 | # endif 27 | # include 28 | # include 29 | # include 30 | # include 31 | # include 32 | # include 33 | # include 34 | # include 35 | # include 36 | # include 37 | # include 38 | # include 39 | # include 40 | # include 41 | # include 42 | # include 43 | # include 44 | # include 45 | # include 46 | # include 47 | #else 48 | # include 49 | # include 50 | # include 51 | # include 52 | #endif 53 | #include 54 | #include 55 | #include 56 | 57 | #if __has_include() 58 | # include 59 | #endif 60 | #if defined(_MSC_VER) || defined(__MINGW32__) 61 | # include 62 | #endif 63 | #if defined __APPLE__ || defined(__FreeBSD__) 64 | # include 65 | #endif 66 | #if __has_include() 67 | # include 68 | #endif 69 | #if (__has_include() || defined(__APPLE__) || \ 70 | defined(__linux__)) && \ 71 | (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) 72 | # include 73 | # include 74 | # include 75 | # ifndef _WIN32 76 | # include 77 | # else 78 | # include 79 | # endif 80 | #endif 81 | #ifdef _WIN32 82 | # if defined(__GLIBCXX__) 83 | # include 84 | # include 85 | # endif 86 | # define WIN32_LEAN_AND_MEAN 87 | # include 88 | #endif 89 | 90 | export module fmt; 91 | 92 | #ifdef FMT_IMPORT_STD 93 | import std; 94 | #endif 95 | 96 | #define FMT_EXPORT export 97 | #define FMT_BEGIN_EXPORT export { 98 | #define FMT_END_EXPORT } 99 | 100 | // If you define FMT_ATTACH_TO_GLOBAL_MODULE 101 | // - all declarations are detached from module 'fmt' 102 | // - the module behaves like a traditional static library, too 103 | // - all library symbols are mangled traditionally 104 | // - you can mix TUs with either importing or #including the {fmt} API 105 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 106 | extern "C++" { 107 | #endif 108 | 109 | #ifndef FMT_OS 110 | # define FMT_OS 1 111 | #endif 112 | 113 | // All library-provided declarations and definitions must be in the module 114 | // purview to be exported. 115 | #include "fmt/args.h" 116 | #include "fmt/chrono.h" 117 | #include "fmt/color.h" 118 | #include "fmt/compile.h" 119 | #include "fmt/format.h" 120 | #if FMT_OS 121 | # include "fmt/os.h" 122 | #endif 123 | #include "fmt/ostream.h" 124 | #include "fmt/printf.h" 125 | #include "fmt/ranges.h" 126 | #include "fmt/std.h" 127 | #include "fmt/xchar.h" 128 | 129 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 130 | } 131 | #endif 132 | 133 | // gcc doesn't yet implement private module fragments 134 | #if !FMT_GCC_VERSION 135 | module :private; 136 | #endif 137 | 138 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 139 | extern "C++" { 140 | #endif 141 | 142 | #if FMT_HAS_INCLUDE("format.cc") 143 | # include "format.cc" 144 | #endif 145 | #if FMT_OS && FMT_HAS_INCLUDE("os.cc") 146 | # include "os.cc" 147 | #endif 148 | 149 | #ifdef FMT_ATTACH_TO_GLOBAL_MODULE 150 | } 151 | #endif 152 | -------------------------------------------------------------------------------- /fmt-11.1.1/src/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | namespace detail { 12 | 13 | template FMT_API auto dragonbox::to_decimal(float x) noexcept 14 | -> dragonbox::decimal_fp; 15 | template FMT_API auto dragonbox::to_decimal(double x) noexcept 16 | -> dragonbox::decimal_fp; 17 | 18 | #if FMT_USE_LOCALE 19 | // DEPRECATED! locale_ref in the detail namespace 20 | template FMT_API locale_ref::locale_ref(const std::locale& loc); 21 | template FMT_API auto locale_ref::get() const -> std::locale; 22 | #endif 23 | 24 | // Explicit instantiations for char. 25 | 26 | template FMT_API auto thousands_sep_impl(locale_ref) 27 | -> thousands_sep_result; 28 | template FMT_API auto decimal_point_impl(locale_ref) -> char; 29 | 30 | // DEPRECATED! 31 | template FMT_API void buffer::append(const char*, const char*); 32 | 33 | // DEPRECATED! 34 | template FMT_API void vformat_to(buffer&, string_view, 35 | typename vformat_args<>::type, locale_ref); 36 | 37 | // Explicit instantiations for wchar_t. 38 | 39 | template FMT_API auto thousands_sep_impl(locale_ref) 40 | -> thousands_sep_result; 41 | template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; 42 | 43 | template FMT_API void buffer::append(const wchar_t*, const wchar_t*); 44 | 45 | } // namespace detail 46 | FMT_END_NAMESPACE 47 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_MODULE := fmt_static 5 | LOCAL_MODULE_FILENAME := libfmt 6 | 7 | LOCAL_SRC_FILES := ../src/format.cc 8 | 9 | LOCAL_C_INCLUDES := $(LOCAL_PATH) 10 | LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) 11 | 12 | LOCAL_CFLAGS += -std=c++11 -fexceptions 13 | 14 | include $(BUILD_STATIC_LIBRARY) 15 | 16 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/README: -------------------------------------------------------------------------------- 1 | This directory contains build support files such as 2 | 3 | * CMake modules 4 | * Build scripts 5 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # A vagrant config for testing against gcc-4.8. 5 | Vagrant.configure("2") do |config| 6 | config.vm.box = "bento/ubuntu-22.04-arm64" 7 | 8 | config.vm.provider "vmware_desktop" do |vb| 9 | vb.memory = "4096" 10 | end 11 | 12 | config.vm.provision "shell", inline: <<-SHELL 13 | apt-get update 14 | apt-get install -y g++ make wget git 15 | wget -q https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-x86_64.tar.gz 16 | tar xzf cmake-3.26.0-Linux-x86_64.tar.gz 17 | ln -s `pwd`/cmake-3.26.0-Linux-x86_64/bin/cmake /usr/local/bin 18 | SHELL 19 | end 20 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/bazel/.bazelversion: -------------------------------------------------------------------------------- 1 | 7.1.2 2 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/bazel/BUILD.bazel: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "fmt", 3 | srcs = [ 4 | #"src/fmt.cc", # No C++ module support, yet in Bazel (https://github.com/bazelbuild/bazel/pull/19940) 5 | "src/format.cc", 6 | "src/os.cc", 7 | ], 8 | hdrs = glob([ 9 | "include/fmt/*.h", 10 | ]), 11 | copts = select({ 12 | "@platforms//os:windows": ["-utf-8"], 13 | "//conditions:default": [], 14 | }), 15 | includes = [ 16 | "include", 17 | ], 18 | strip_include_prefix = "include", 19 | visibility = ["//visibility:public"], 20 | ) 21 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/bazel/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "fmt", 3 | compatibility_level = 10, 4 | ) 5 | 6 | bazel_dep(name = "platforms", version = "0.0.10") 7 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/bazel/README.md: -------------------------------------------------------------------------------- 1 | # Bazel support 2 | 3 | To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, 4 | `MODULE.bazel`, `WORKSPACE.bazel`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. 5 | This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}). 6 | 7 | ## Using {fmt} as a dependency 8 | 9 | ### Using Bzlmod 10 | 11 | The [Bazel Central Registry](https://github.com/bazelbuild/bazel-central-registry/tree/main/modules/fmt) provides support for {fmt}. 12 | 13 | For instance, to use {fmt} add to your `MODULE.bazel` file: 14 | 15 | ``` 16 | bazel_dep(name = "fmt", version = "10.2.1") 17 | ``` 18 | 19 | ### Live at head 20 | 21 | For a live-at-head approach, you can copy the contents of this repository and move the Bazel-related build files to the root folder of this project as described above and make use of `local_path_override`, e.g.: 22 | 23 | ``` 24 | local_path_override( 25 | module_name = "fmt", 26 | path = "../third_party/fmt", 27 | ) 28 | ``` 29 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/bazel/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # WORKSPACE marker file needed by Bazel 2 | 3 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/build.gradle: -------------------------------------------------------------------------------- 1 | import java.nio.file.Paths 2 | 3 | // General gradle arguments for root project 4 | buildscript { 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | // 11 | // https://developer.android.com/studio/releases/gradle-plugin#updating-gradle 12 | // 13 | // Notice that 4.0.0 here is the version of [Android Gradle Plugin] 14 | // According to URL above you will need Gradle 6.1 or higher 15 | // 16 | classpath "com.android.tools.build:gradle:4.1.1" 17 | } 18 | } 19 | repositories { 20 | google() 21 | jcenter() 22 | } 23 | 24 | // Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir 25 | def rootDir = Paths.get(project.buildDir.getParent()).getParent() 26 | println("rootDir: ${rootDir}") 27 | 28 | // Output: Shared library (.so) for Android 29 | apply plugin: "com.android.library" 30 | android { 31 | compileSdkVersion 25 // Android 7.0 32 | 33 | // Target ABI 34 | // - This option controls target platform of module 35 | // - The platform might be limited by compiler's support 36 | // some can work with Clang(default), but some can work only with GCC... 37 | // if bad, both toolchains might not support it 38 | splits { 39 | abi { 40 | enable true 41 | // Specify platforms for Application 42 | reset() 43 | include "arm64-v8a", "armeabi-v7a", "x86_64" 44 | } 45 | } 46 | ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit 47 | 48 | defaultConfig { 49 | minSdkVersion 21 // Android 5.0+ 50 | targetSdkVersion 25 // Follow Compile SDK 51 | versionCode 34 // Follow release count 52 | versionName "7.1.2" // Follow Official version 53 | 54 | externalNativeBuild { 55 | cmake { 56 | arguments "-DANDROID_STL=c++_shared" // Specify Android STL 57 | arguments "-DBUILD_SHARED_LIBS=true" // Build shared object 58 | arguments "-DFMT_TEST=false" // Skip test 59 | arguments "-DFMT_DOC=false" // Skip document 60 | cppFlags "-std=c++17" 61 | targets "fmt" 62 | } 63 | } 64 | println(externalNativeBuild.cmake.cppFlags) 65 | println(externalNativeBuild.cmake.arguments) 66 | } 67 | 68 | // External Native build 69 | // - Use existing CMakeList.txt 70 | // - Give path to CMake. This gradle file should be 71 | // neighbor of the top level cmake 72 | externalNativeBuild { 73 | cmake { 74 | version "3.10.0+" 75 | path "${rootDir}/CMakeLists.txt" 76 | // buildStagingDirectory "./build" // Custom path for cmake output 77 | } 78 | } 79 | 80 | sourceSets{ 81 | // Android Manifest for Gradle 82 | main { 83 | manifest.srcFile "AndroidManifest.xml" 84 | } 85 | } 86 | 87 | // https://developer.android.com/studio/build/native-dependencies#build_system_configuration 88 | buildFeatures { 89 | prefab true 90 | prefabPublishing true 91 | } 92 | prefab { 93 | fmt { 94 | headers "${rootDir}/include" 95 | } 96 | } 97 | } 98 | 99 | assemble.doLast 100 | { 101 | // Instead of `ninja install`, Gradle will deploy the files. 102 | // We are doing this since FMT is dependent to the ANDROID_STL after build 103 | copy { 104 | from "build/intermediates/cmake" 105 | into "${rootDir}/libs" 106 | } 107 | // Copy debug binaries 108 | copy { 109 | from "${rootDir}/libs/debug/obj" 110 | into "${rootDir}/libs/debug" 111 | } 112 | // Copy Release binaries 113 | copy { 114 | from "${rootDir}/libs/release/obj" 115 | into "${rootDir}/libs/release" 116 | } 117 | // Remove empty directory 118 | delete "${rootDir}/libs/debug/obj" 119 | delete "${rootDir}/libs/release/obj" 120 | 121 | // Copy AAR files. Notice that the aar is named after the folder of this script. 122 | copy { 123 | from "build/outputs/aar/support-release.aar" 124 | into "${rootDir}/libs" 125 | rename "support-release.aar", "fmt-release.aar" 126 | } 127 | copy { 128 | from "build/outputs/aar/support-debug.aar" 129 | into "${rootDir}/libs" 130 | rename "support-debug.aar", "fmt-debug.aar" 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/check-commits: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Compile source on a range of commits 4 | 5 | Usage: 6 | check-commits 7 | """ 8 | 9 | import docopt, os, sys, tempfile 10 | from subprocess import check_call, check_output, run 11 | 12 | args = docopt.docopt(__doc__) 13 | start = args.get('') 14 | source = args.get('') 15 | 16 | cwd = os.getcwd() 17 | 18 | with tempfile.TemporaryDirectory() as work_dir: 19 | check_call(['git', 'clone', 'https://github.com/fmtlib/fmt.git'], 20 | cwd=work_dir) 21 | repo_dir = os.path.join(work_dir, 'fmt') 22 | commits = check_output( 23 | ['git', 'rev-list', f'{start}..HEAD', '--abbrev-commit', 24 | '--', 'include', 'src'], 25 | text=True, cwd=repo_dir).rstrip().split('\n') 26 | commits.reverse() 27 | print('Time\tCommit') 28 | for commit in commits: 29 | check_call(['git', '-c', 'advice.detachedHead=false', 'checkout', commit], 30 | cwd=repo_dir) 31 | returncode = run( 32 | ['c++', '-std=c++11', '-O3', '-DNDEBUG', '-I', 'include', 33 | 'src/format.cc', os.path.join(cwd, source)], cwd=repo_dir).returncode 34 | if returncode != 0: 35 | continue 36 | times = [] 37 | for i in range(5): 38 | output = check_output([os.path.join(repo_dir, 'a.out')], text=True) 39 | times.append(float(output)) 40 | message = check_output(['git', 'log', '-1', '--pretty=format:%s', commit], 41 | cwd=repo_dir, text=True) 42 | print(f'{min(times)}\t{commit} {message[:40]}') 43 | sys.stdout.flush() 44 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/cmake/FindSetEnv.cmake: -------------------------------------------------------------------------------- 1 | # A CMake script to find SetEnv.cmd. 2 | 3 | find_program(WINSDK_SETENV NAMES SetEnv.cmd 4 | PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]/bin") 5 | if (WINSDK_SETENV AND PRINT_PATH) 6 | execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${WINSDK_SETENV}") 7 | endif () 8 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/cmake/JoinPaths.cmake: -------------------------------------------------------------------------------- 1 | # This module provides function for joining paths 2 | # known from from most languages 3 | # 4 | # Original license: 5 | # SPDX-License-Identifier: (MIT OR CC0-1.0) 6 | # Explicit permission given to distribute this module under 7 | # the terms of the project as described in /LICENSE.rst. 8 | # Copyright 2020 Jan Tojnar 9 | # https://github.com/jtojnar/cmake-snips 10 | # 11 | # Modelled after Python’s os.path.join 12 | # https://docs.python.org/3.7/library/os.path.html#os.path.join 13 | # Windows not supported 14 | function(join_paths joined_path first_path_segment) 15 | set(temp_path "${first_path_segment}") 16 | foreach(current_segment IN LISTS ARGN) 17 | if(NOT ("${current_segment}" STREQUAL "")) 18 | if(IS_ABSOLUTE "${current_segment}") 19 | set(temp_path "${current_segment}") 20 | else() 21 | set(temp_path "${temp_path}/${current_segment}") 22 | endif() 23 | endif() 24 | endforeach() 25 | set(${joined_path} "${temp_path}" PARENT_SCOPE) 26 | endfunction() 27 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/cmake/fmt-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | if (NOT TARGET fmt::fmt) 4 | include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake) 5 | endif () 6 | 7 | check_required_components(fmt) 8 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/cmake/fmt.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=@libdir_for_pc_file@ 4 | includedir=@includedir_for_pc_file@ 5 | 6 | Name: fmt 7 | Description: A modern formatting library 8 | Version: @FMT_VERSION@ 9 | Libs: -L${libdir} -l@FMT_LIB_NAME@ 10 | Cflags: -I${includedir} 11 | 12 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/mkdocs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # A script to invoke mkdocs with the correct environment. 3 | # Additionally supports deploying via mike: 4 | # ./mkdocs deploy [mike-deploy-options] 5 | 6 | import errno, os, shutil, sys 7 | from subprocess import call 8 | 9 | support_dir = os.path.dirname(os.path.normpath(__file__)) 10 | build_dir = os.path.join(os.path.dirname(support_dir), 'build') 11 | 12 | # Set PYTHONPATH for the mkdocstrings handler. 13 | env = os.environ.copy() 14 | path = env.get('PYTHONPATH') 15 | env['PYTHONPATH'] = \ 16 | (path + ':' if path else '') + os.path.join(support_dir, 'python') 17 | 18 | redirect_page = \ 19 | ''' 20 | 21 | 22 | 23 | Redirecting 24 | 27 | 32 | 33 | 34 | Redirecting to api... 35 | 36 | 37 | ''' 38 | 39 | config_path = os.path.join(support_dir, 'mkdocs.yml') 40 | args = sys.argv[1:] 41 | if len(args) > 0: 42 | command = args[0] 43 | if command == 'deploy': 44 | git_url = 'https://github.com/' if 'CI' in os.environ else 'git@github.com:' 45 | site_repo = git_url + 'fmtlib/fmt.dev.git' 46 | 47 | site_dir = os.path.join(build_dir, 'fmt.dev') 48 | try: 49 | shutil.rmtree(site_dir) 50 | except OSError as e: 51 | if e.errno == errno.ENOENT: 52 | pass 53 | ret = call(['git', 'clone', '--depth=1', site_repo, site_dir]) 54 | if ret != 0: 55 | sys.exit(ret) 56 | 57 | # Copy the config to the build dir because the site is built relative to it. 58 | config_build_path = os.path.join(build_dir, 'mkdocs.yml') 59 | shutil.copyfile(config_path, config_build_path) 60 | 61 | version = args[1] 62 | ret = call(['mike'] + args + ['--config-file', config_build_path, 63 | '--branch', 'master'], cwd=site_dir, env=env) 64 | if ret != 0 or version == 'dev': 65 | sys.exit(ret) 66 | redirect_page_path = os.path.join(site_dir, version, 'api.html') 67 | with open(redirect_page_path, "w") as file: 68 | file.write(redirect_page) 69 | ret = call(['git', 'add', redirect_page_path], cwd=site_dir) 70 | if ret != 0: 71 | sys.exit(ret) 72 | ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir) 73 | sys.exit(ret) 74 | elif not command.startswith('-'): 75 | args += ['-f', config_path] 76 | sys.exit(call(['mkdocs'] + args, env=env)) 77 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: '{fmt}' 2 | 3 | docs_dir: ../doc 4 | 5 | repo_url: https://github.com/fmtlib/fmt 6 | 7 | theme: 8 | name: material 9 | features: 10 | - navigation.tabs 11 | - navigation.top 12 | - toc.integrate 13 | 14 | extra_javascript: 15 | - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js 16 | - fmt.js 17 | 18 | extra_css: 19 | - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css 20 | - fmt.css 21 | 22 | markdown_extensions: 23 | - pymdownx.highlight: 24 | # Use JavaScript syntax highlighter instead of Pygments because it 25 | # automatically applies to code blocks extracted through Doxygen. 26 | use_pygments: false 27 | anchor_linenums: true 28 | line_spans: __span 29 | pygments_lang_class: true 30 | - pymdownx.inlinehilite 31 | - pymdownx.snippets 32 | 33 | plugins: 34 | - search 35 | - mkdocstrings: 36 | default_handler: cxx 37 | nav: 38 | - Home: index.md 39 | - Get Started: get-started.md 40 | - API: api.md 41 | - Syntax: syntax.md 42 | 43 | exclude_docs: ChangeLog-old.md 44 | 45 | extra: 46 | version: 47 | provider: mike 48 | generator: false 49 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/printable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This script is based on 4 | # https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py 5 | # distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT. 6 | 7 | # This script uses the following Unicode tables: 8 | # - UnicodeData.txt 9 | 10 | 11 | from collections import namedtuple 12 | import csv 13 | import os 14 | import subprocess 15 | 16 | NUM_CODEPOINTS=0x110000 17 | 18 | def to_ranges(iter): 19 | current = None 20 | for i in iter: 21 | if current is None or i != current[1] or i in (0x10000, 0x20000): 22 | if current is not None: 23 | yield tuple(current) 24 | current = [i, i + 1] 25 | else: 26 | current[1] += 1 27 | if current is not None: 28 | yield tuple(current) 29 | 30 | def get_escaped(codepoints): 31 | for c in codepoints: 32 | if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): 33 | yield c.value 34 | 35 | def get_file(f): 36 | try: 37 | return open(os.path.basename(f)) 38 | except FileNotFoundError: 39 | subprocess.run(["curl", "-O", f], check=True) 40 | return open(os.path.basename(f)) 41 | 42 | Codepoint = namedtuple('Codepoint', 'value class_') 43 | 44 | def get_codepoints(f): 45 | r = csv.reader(f, delimiter=";") 46 | prev_codepoint = 0 47 | class_first = None 48 | for row in r: 49 | codepoint = int(row[0], 16) 50 | name = row[1] 51 | class_ = row[2] 52 | 53 | if class_first is not None: 54 | if not name.endswith("Last>"): 55 | raise ValueError("Missing Last after First") 56 | 57 | for c in range(prev_codepoint + 1, codepoint): 58 | yield Codepoint(c, class_first) 59 | 60 | class_first = None 61 | if name.endswith("First>"): 62 | class_first = class_ 63 | 64 | yield Codepoint(codepoint, class_) 65 | prev_codepoint = codepoint 66 | 67 | if class_first is not None: 68 | raise ValueError("Missing Last after First") 69 | 70 | for c in range(prev_codepoint + 1, NUM_CODEPOINTS): 71 | yield Codepoint(c, None) 72 | 73 | def compress_singletons(singletons): 74 | uppers = [] # (upper, # items in lowers) 75 | lowers = [] 76 | 77 | for i in singletons: 78 | upper = i >> 8 79 | lower = i & 0xff 80 | if len(uppers) == 0 or uppers[-1][0] != upper: 81 | uppers.append((upper, 1)) 82 | else: 83 | upper, count = uppers[-1] 84 | uppers[-1] = upper, count + 1 85 | lowers.append(lower) 86 | 87 | return uppers, lowers 88 | 89 | def compress_normal(normal): 90 | # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f 91 | # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff 92 | compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] 93 | 94 | prev_start = 0 95 | for start, count in normal: 96 | truelen = start - prev_start 97 | falselen = count 98 | prev_start = start + count 99 | 100 | assert truelen < 0x8000 and falselen < 0x8000 101 | entry = [] 102 | if truelen > 0x7f: 103 | entry.append(0x80 | (truelen >> 8)) 104 | entry.append(truelen & 0xff) 105 | else: 106 | entry.append(truelen & 0x7f) 107 | if falselen > 0x7f: 108 | entry.append(0x80 | (falselen >> 8)) 109 | entry.append(falselen & 0xff) 110 | else: 111 | entry.append(falselen & 0x7f) 112 | 113 | compressed.append(entry) 114 | 115 | return compressed 116 | 117 | def print_singletons(uppers, lowers, uppersname, lowersname): 118 | print(" static constexpr singleton {}[] = {{".format(uppersname)) 119 | for u, c in uppers: 120 | print(" {{{:#04x}, {}}},".format(u, c)) 121 | print(" };") 122 | print(" static constexpr unsigned char {}[] = {{".format(lowersname)) 123 | for i in range(0, len(lowers), 8): 124 | print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) 125 | print(" };") 126 | 127 | def print_normal(normal, normalname): 128 | print(" static constexpr unsigned char {}[] = {{".format(normalname)) 129 | for v in normal: 130 | print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) 131 | print(" };") 132 | 133 | def main(): 134 | file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") 135 | 136 | codepoints = get_codepoints(file) 137 | 138 | CUTOFF=0x10000 139 | singletons0 = [] 140 | singletons1 = [] 141 | normal0 = [] 142 | normal1 = [] 143 | extra = [] 144 | 145 | for a, b in to_ranges(get_escaped(codepoints)): 146 | if a > 2 * CUTOFF: 147 | extra.append((a, b - a)) 148 | elif a == b - 1: 149 | if a & CUTOFF: 150 | singletons1.append(a & ~CUTOFF) 151 | else: 152 | singletons0.append(a) 153 | elif a == b - 2: 154 | if a & CUTOFF: 155 | singletons1.append(a & ~CUTOFF) 156 | singletons1.append((a + 1) & ~CUTOFF) 157 | else: 158 | singletons0.append(a) 159 | singletons0.append(a + 1) 160 | else: 161 | if a >= 2 * CUTOFF: 162 | extra.append((a, b - a)) 163 | elif a & CUTOFF: 164 | normal1.append((a & ~CUTOFF, b - a)) 165 | else: 166 | normal0.append((a, b - a)) 167 | 168 | singletons0u, singletons0l = compress_singletons(singletons0) 169 | singletons1u, singletons1l = compress_singletons(singletons1) 170 | normal0 = compress_normal(normal0) 171 | normal1 = compress_normal(normal1) 172 | 173 | print("""\ 174 | FMT_FUNC auto is_printable(uint32_t cp) -> bool {\ 175 | """) 176 | print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower') 177 | print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower') 178 | print_normal(normal0, 'normal0') 179 | print_normal(normal1, 'normal1') 180 | print("""\ 181 | auto lower = static_cast(cp); 182 | if (cp < 0x10000) { 183 | return is_printable(lower, singletons0, 184 | sizeof(singletons0) / sizeof(*singletons0), 185 | singletons0_lower, normal0, sizeof(normal0)); 186 | } 187 | if (cp < 0x20000) { 188 | return is_printable(lower, singletons1, 189 | sizeof(singletons1) / sizeof(*singletons1), 190 | singletons1_lower, normal1, sizeof(normal1)); 191 | }\ 192 | """) 193 | for a, b in extra: 194 | print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b)) 195 | print("""\ 196 | return cp < 0x{:x}; 197 | }}\ 198 | """.format(NUM_CODEPOINTS)) 199 | 200 | if __name__ == '__main__': 201 | main() 202 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/python/mkdocstrings_handlers/cxx/templates/README: -------------------------------------------------------------------------------- 1 | mkdocsstrings requires a handler to have a templates directory. 2 | -------------------------------------------------------------------------------- /fmt-11.1.1/support/release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """Make a release. 4 | 5 | Usage: 6 | release.py [] 7 | 8 | For the release command $FMT_TOKEN should contain a GitHub personal access token 9 | obtained from https://github.com/settings/tokens. 10 | """ 11 | 12 | from __future__ import print_function 13 | import datetime, docopt, errno, fileinput, json, os 14 | import re, shutil, sys 15 | from subprocess import check_call 16 | import urllib.request 17 | 18 | 19 | class Git: 20 | def __init__(self, dir): 21 | self.dir = dir 22 | 23 | def call(self, method, args, **kwargs): 24 | return check_call(['git', method] + list(args), **kwargs) 25 | 26 | def add(self, *args): 27 | return self.call('add', args, cwd=self.dir) 28 | 29 | def checkout(self, *args): 30 | return self.call('checkout', args, cwd=self.dir) 31 | 32 | def clean(self, *args): 33 | return self.call('clean', args, cwd=self.dir) 34 | 35 | def clone(self, *args): 36 | return self.call('clone', list(args) + [self.dir]) 37 | 38 | def commit(self, *args): 39 | return self.call('commit', args, cwd=self.dir) 40 | 41 | def pull(self, *args): 42 | return self.call('pull', args, cwd=self.dir) 43 | 44 | def push(self, *args): 45 | return self.call('push', args, cwd=self.dir) 46 | 47 | def reset(self, *args): 48 | return self.call('reset', args, cwd=self.dir) 49 | 50 | def update(self, *args): 51 | clone = not os.path.exists(self.dir) 52 | if clone: 53 | self.clone(*args) 54 | return clone 55 | 56 | 57 | def clean_checkout(repo, branch): 58 | repo.clean('-f', '-d') 59 | repo.reset('--hard') 60 | repo.checkout(branch) 61 | 62 | 63 | class Runner: 64 | def __init__(self, cwd): 65 | self.cwd = cwd 66 | 67 | def __call__(self, *args, **kwargs): 68 | kwargs['cwd'] = kwargs.get('cwd', self.cwd) 69 | check_call(args, **kwargs) 70 | 71 | 72 | def create_build_env(): 73 | """Create a build environment.""" 74 | class Env: 75 | pass 76 | env = Env() 77 | env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 78 | env.build_dir = 'build' 79 | env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt')) 80 | return env 81 | 82 | 83 | if __name__ == '__main__': 84 | args = docopt.docopt(__doc__) 85 | env = create_build_env() 86 | fmt_repo = env.fmt_repo 87 | 88 | branch = args.get('') 89 | if branch is None: 90 | branch = 'master' 91 | if not fmt_repo.update('-b', branch, 'git@github.com:fmtlib/fmt'): 92 | clean_checkout(fmt_repo, branch) 93 | 94 | # Update the date in the changelog and extract the version and the first 95 | # section content. 96 | changelog = 'ChangeLog.md' 97 | changelog_path = os.path.join(fmt_repo.dir, changelog) 98 | is_first_section = True 99 | first_section = [] 100 | for i, line in enumerate(fileinput.input(changelog_path, inplace=True)): 101 | if i == 0: 102 | version = re.match(r'# (.*) - TBD', line).group(1) 103 | line = '# {} - {}\n'.format( 104 | version, datetime.date.today().isoformat()) 105 | elif not is_first_section: 106 | pass 107 | elif line.startswith('#'): 108 | is_first_section = False 109 | else: 110 | first_section.append(line) 111 | sys.stdout.write(line) 112 | if first_section[0] == '\n': 113 | first_section.pop(0) 114 | 115 | ns_version = None 116 | base_h_path = os.path.join(fmt_repo.dir, 'include', 'fmt', 'base.h') 117 | for line in fileinput.input(base_h_path): 118 | m = re.match(r'\s*inline namespace v(.*) .*', line) 119 | if m: 120 | ns_version = m.group(1) 121 | break 122 | major_version = version.split('.')[0] 123 | if not ns_version or ns_version != major_version: 124 | raise Exception(f'Version mismatch {ns_version} != {major_version}') 125 | 126 | # Workaround GitHub-flavored Markdown treating newlines as
. 127 | changes = '' 128 | code_block = False 129 | stripped = False 130 | for line in first_section: 131 | if re.match(r'^\s*```', line): 132 | code_block = not code_block 133 | changes += line 134 | stripped = False 135 | continue 136 | if code_block: 137 | changes += line 138 | continue 139 | if line == '\n' or re.match(r'^\s*\|.*', line): 140 | if stripped: 141 | changes += '\n' 142 | stripped = False 143 | changes += line 144 | continue 145 | if stripped: 146 | line = ' ' + line.lstrip() 147 | changes += line.rstrip() 148 | stripped = True 149 | 150 | fmt_repo.checkout('-B', 'release') 151 | fmt_repo.add(changelog) 152 | fmt_repo.commit('-m', 'Update version') 153 | 154 | # Build the docs and package. 155 | run = Runner(fmt_repo.dir) 156 | run('cmake', '.') 157 | run('make', 'doc', 'package_source') 158 | 159 | # Create a release on GitHub. 160 | fmt_repo.push('origin', 'release') 161 | auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')} 162 | req = urllib.request.Request( 163 | 'https://api.github.com/repos/fmtlib/fmt/releases', 164 | data=json.dumps({'tag_name': version, 165 | 'target_commitish': 'release', 166 | 'body': changes, 'draft': True}).encode('utf-8'), 167 | headers=auth_headers, method='POST') 168 | with urllib.request.urlopen(req) as response: 169 | if response.status != 201: 170 | raise Exception(f'Failed to create a release ' + 171 | '{response.status} {response.reason}') 172 | response_data = json.loads(response.read().decode('utf-8')) 173 | id = response_data['id'] 174 | 175 | # Upload the package. 176 | uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases' 177 | package = 'fmt-{}.zip'.format(version) 178 | req = urllib.request.Request( 179 | f'{uploads_url}/{id}/assets?name={package}', 180 | headers={'Content-Type': 'application/zip'} | auth_headers, 181 | data=open('build/fmt/' + package, 'rb').read(), method='POST') 182 | with urllib.request.urlopen(req) as response: 183 | if response.status != 201: 184 | raise Exception(f'Failed to upload an asset ' 185 | '{response.status} {response.reason}') 186 | 187 | short_version = '.'.join(version.split('.')[:-1]) 188 | check_call(['./mkdocs', 'deploy', short_version]) 189 | -------------------------------------------------------------------------------- /mingw.def: -------------------------------------------------------------------------------- 1 | LIBRARY DSOUND.dll 2 | 3 | EXPORTS 4 | DirectSoundCreate = DSOAL_DirectSoundCreate@12 @1 5 | DirectSoundEnumerateA = DSOAL_DirectSoundEnumerateA@8 @2 6 | DirectSoundEnumerateW = DSOAL_DirectSoundEnumerateW@8 @3 7 | DllCanUnloadNow = DSOAL_DllCanUnloadNow@0 PRIVATE 8 | DllGetClassObject = DSOAL_DllGetClassObject@12 PRIVATE 9 | DirectSoundCaptureCreate = DSOAL_DirectSoundCaptureCreate@12 @6 10 | DirectSoundCaptureEnumerateA = DSOAL_DirectSoundCaptureEnumerateA@8 @7 11 | DirectSoundCaptureEnumerateW = DSOAL_DirectSoundCaptureEnumerateW@8 @8 12 | GetDeviceID = DSOAL_GetDeviceID@8 @9 13 | DirectSoundFullDuplexCreate = DSOAL_DirectSoundFullDuplexCreate@40 @10 14 | DirectSoundCreate8 = DSOAL_DirectSoundCreate8@12 @11 15 | DirectSoundCaptureCreate8 = DSOAL_DirectSoundCaptureCreate8@12 @12 16 | -------------------------------------------------------------------------------- /msvc.def: -------------------------------------------------------------------------------- 1 | LIBRARY DSOUND.dll 2 | 3 | EXPORTS 4 | DirectSoundCreate = _DSOAL_DirectSoundCreate@12 @1 5 | DirectSoundEnumerateA = _DSOAL_DirectSoundEnumerateA@8 @2 6 | DirectSoundEnumerateW = _DSOAL_DirectSoundEnumerateW@8 @3 7 | DllCanUnloadNow = _DSOAL_DllCanUnloadNow@0 PRIVATE 8 | DllGetClassObject = _DSOAL_DllGetClassObject@12 PRIVATE 9 | DirectSoundCaptureCreate = _DSOAL_DirectSoundCaptureCreate@12 @6 10 | DirectSoundCaptureEnumerateA = _DSOAL_DirectSoundCaptureEnumerateA@8 @7 11 | DirectSoundCaptureEnumerateW = _DSOAL_DirectSoundCaptureEnumerateW@8 @8 12 | GetDeviceID = _DSOAL_GetDeviceID@8 @9 13 | DirectSoundFullDuplexCreate = _DSOAL_DirectSoundFullDuplexCreate@40 @10 14 | DirectSoundCreate8 = _DSOAL_DirectSoundCreate8@12 @11 15 | DirectSoundCaptureCreate8 = _DSOAL_DirectSoundCaptureCreate8@12 @12 16 | -------------------------------------------------------------------------------- /msvc64.def: -------------------------------------------------------------------------------- 1 | LIBRARY DSOUND.dll 2 | 3 | EXPORTS 4 | DirectSoundCreate = DSOAL_DirectSoundCreate @1 5 | DirectSoundEnumerateA = DSOAL_DirectSoundEnumerateA @2 6 | DirectSoundEnumerateW = DSOAL_DirectSoundEnumerateW @3 7 | DllCanUnloadNow = DSOAL_DllCanUnloadNow PRIVATE 8 | DllGetClassObject = DSOAL_DllGetClassObject PRIVATE 9 | DirectSoundCaptureCreate = DSOAL_DirectSoundCaptureCreate @6 10 | DirectSoundCaptureEnumerateA = DSOAL_DirectSoundCaptureEnumerateA @7 11 | DirectSoundCaptureEnumerateW = DSOAL_DirectSoundCaptureEnumerateW @8 12 | GetDeviceID = DSOAL_GetDeviceID @9 13 | DirectSoundFullDuplexCreate = DSOAL_DirectSoundFullDuplexCreate @10 14 | DirectSoundCreate8 = DSOAL_DirectSoundCreate8 @11 15 | DirectSoundCaptureCreate8 = DSOAL_DirectSoundCaptureCreate8 @12 16 | -------------------------------------------------------------------------------- /src/capture.h: -------------------------------------------------------------------------------- 1 | #ifndef CAPTURE_H 2 | #define CAPTURE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "comptr.h" 11 | 12 | 13 | class DSCapture final : IDirectSoundCapture { 14 | explicit DSCapture(bool is8); 15 | ~DSCapture(); 16 | 17 | class Unknown final : IUnknown { 18 | DSCapture *impl_from_base() noexcept 19 | { 20 | #ifdef __GNUC__ 21 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 22 | #endif 23 | return CONTAINING_RECORD(this, DSCapture, mUnknownIface); 24 | #ifdef __GNUC__ 25 | _Pragma("GCC diagnostic pop") 26 | #endif 27 | } 28 | 29 | public: 30 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 31 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 32 | ULONG STDMETHODCALLTYPE Release() noexcept override; 33 | 34 | template 35 | T as() noexcept { return static_cast(this); } 36 | }; 37 | Unknown mUnknownIface; 38 | 39 | std::atomic mTotalRef{1u}, mDsRef{1u}, mUnkRef{0u}; 40 | 41 | std::mutex mMutex; 42 | std::string mDeviceName; 43 | bool mIs8{}; 44 | 45 | public: 46 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) noexcept override; 47 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 48 | ULONG STDMETHODCALLTYPE Release() noexcept override; 49 | HRESULT STDMETHODCALLTYPE CreateCaptureBuffer(const DSCBUFFERDESC *dscBufferDesc, 50 | IDirectSoundCaptureBuffer **dsCaptureBuffer, IUnknown *outer) noexcept override; 51 | HRESULT STDMETHODCALLTYPE GetCaps(DSCCAPS *dscCaps) noexcept override; 52 | HRESULT STDMETHODCALLTYPE Initialize(const GUID *guid) noexcept override; 53 | 54 | void finalize() noexcept 55 | { 56 | if(mTotalRef.fetch_sub(1u, std::memory_order_relaxed) == 1) [[unlikely]] 57 | delete this; 58 | } 59 | 60 | [[nodiscard]] 61 | auto getLockGuard() { return std::lock_guard{mMutex}; } 62 | 63 | [[nodiscard]] 64 | auto getUniqueLock() { return std::unique_lock{mMutex}; } 65 | 66 | [[nodiscard]] 67 | auto getName() const noexcept -> const std::string& { return mDeviceName; } 68 | 69 | template [[nodiscard]] 70 | T as() noexcept { return static_cast(this); } 71 | 72 | static ComPtr Create(bool is8); 73 | }; 74 | 75 | #endif // CAPTURE_H 76 | -------------------------------------------------------------------------------- /src/comhelpers.h: -------------------------------------------------------------------------------- 1 | #ifndef COMHELPERS_H 2 | #define COMHELPERS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class PropVariant { 12 | PROPVARIANT mProp{}; 13 | 14 | public: 15 | PropVariant() { PropVariantInit(&mProp); } 16 | PropVariant(const PropVariant &rhs) : PropVariant{} { PropVariantCopy(&mProp, &rhs.mProp); } 17 | ~PropVariant() { clear(); } 18 | 19 | auto operator=(const PropVariant &rhs) -> PropVariant& 20 | { 21 | if(this != &rhs) 22 | PropVariantCopy(&mProp, &rhs.mProp); 23 | return *this; 24 | } 25 | 26 | void clear() { PropVariantClear(&mProp); } 27 | 28 | auto get() noexcept -> PROPVARIANT* { return &mProp; } 29 | 30 | /* NOLINTBEGIN(cppcoreguidelines-pro-type-union-access) */ 31 | [[nodiscard]] 32 | auto type() const noexcept -> VARTYPE { return mProp.vt; } 33 | 34 | template [[nodiscard]] 35 | auto value() const -> T 36 | { 37 | if constexpr(std::is_same_v) 38 | { 39 | assert(mProp.vt == VT_UI4 || mProp.vt == VT_UINT); 40 | return mProp.uintVal; 41 | } 42 | else if constexpr(std::is_same_v) 43 | { 44 | assert(mProp.vt == VT_UI4 || mProp.vt == VT_UINT); 45 | return mProp.ulVal; 46 | } 47 | else if constexpr(std::is_same_v || std::is_same_v 48 | || std::is_same_v || std::is_same_v) 49 | { 50 | assert(mProp.vt == VT_LPWSTR); 51 | return mProp.pwszVal; 52 | } 53 | } 54 | /* NOLINTEND(cppcoreguidelines-pro-type-union-access) */ 55 | }; 56 | 57 | struct ComWrapper { 58 | HRESULT mStatus{}; 59 | 60 | ComWrapper() : mStatus{CoInitialize(nullptr)} { } 61 | ComWrapper(ComWrapper&& rhs) : mStatus{std::exchange(rhs.mStatus, E_FAIL)} { } 62 | ComWrapper(const ComWrapper&) = delete; 63 | ~ComWrapper() { if(SUCCEEDED(mStatus)) CoUninitialize(); } 64 | 65 | ComWrapper& operator=(ComWrapper&& rhs) 66 | { 67 | if(SUCCEEDED(mStatus)) 68 | CoUninitialize(); 69 | mStatus = std::exchange(rhs.mStatus, E_FAIL); 70 | return *this; 71 | } 72 | ComWrapper& operator=(const ComWrapper&) = delete; 73 | 74 | void uninit() 75 | { 76 | if(SUCCEEDED(mStatus)) 77 | CoUninitialize(); 78 | mStatus = E_FAIL; 79 | } 80 | }; 81 | 82 | #endif // COMHELPERS_H 83 | -------------------------------------------------------------------------------- /src/comptr.h: -------------------------------------------------------------------------------- 1 | #ifndef COMPTR_H 2 | #define COMPTR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | struct ComPtr { 10 | using element_type = T; 11 | 12 | ComPtr() noexcept = default; 13 | ComPtr(const ComPtr &rhs) noexcept(noexcept(mPtr->AddRef())) : mPtr{rhs.mPtr} 14 | { if(mPtr) mPtr->AddRef(); } 15 | ComPtr(ComPtr&& rhs) noexcept : mPtr{rhs.mPtr} { rhs.mPtr = nullptr; } 16 | ComPtr(std::nullptr_t) noexcept { } /* NOLINT(google-explicit-constructor) */ 17 | explicit ComPtr(T *ptr) noexcept : mPtr{ptr} { } 18 | ~ComPtr() { if(mPtr) mPtr->Release(); } 19 | 20 | /* NOLINTNEXTLINE(bugprone-unhandled-self-assignment) Yes it is. */ 21 | ComPtr& operator=(const ComPtr &rhs) 22 | noexcept(noexcept(rhs.mPtr->AddRef()) && noexcept(mPtr->Release())) 23 | { 24 | if constexpr(noexcept(rhs.mPtr->AddRef()) && noexcept(mPtr->Release())) 25 | { 26 | if(rhs.mPtr) rhs.mPtr->AddRef(); 27 | if(mPtr) mPtr->Release(); 28 | mPtr = rhs.mPtr; 29 | return *this; 30 | } 31 | else 32 | { 33 | ComPtr tmp{rhs}; 34 | if(mPtr) mPtr->Release(); 35 | mPtr = tmp.release(); 36 | return *this; 37 | } 38 | } 39 | ComPtr& operator=(ComPtr&& rhs) noexcept(noexcept(mPtr->Release())) 40 | { 41 | if(&rhs != this) 42 | { 43 | if(mPtr) mPtr->Release(); 44 | mPtr = std::exchange(rhs.mPtr, nullptr); 45 | } 46 | return *this; 47 | } 48 | 49 | void reset(T *ptr=nullptr) noexcept(noexcept(mPtr->Release())) 50 | { 51 | if(mPtr) mPtr->Release(); 52 | mPtr = ptr; 53 | } 54 | 55 | explicit operator bool() const noexcept { return mPtr != nullptr; } 56 | 57 | T& operator*() const noexcept { return *mPtr; } 58 | T* operator->() const noexcept { return mPtr; } 59 | T* get() const noexcept { return mPtr; } 60 | 61 | T* release() noexcept { return std::exchange(mPtr, nullptr); } 62 | 63 | void swap(ComPtr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); } 64 | void swap(ComPtr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); } 65 | 66 | private: 67 | T *mPtr{nullptr}; 68 | }; 69 | 70 | 71 | namespace ds { 72 | 73 | template 74 | class out_ptr_t { 75 | static_assert(!std::is_same_v); 76 | 77 | SP &mRes; 78 | std::variant mPtr{}; 79 | 80 | public: 81 | explicit out_ptr_t(SP &res) : mRes{res} { } 82 | ~out_ptr_t() 83 | { 84 | auto set_res = [this](auto &ptr) 85 | { mRes.reset(static_cast(ptr)); }; 86 | std::visit(set_res, mPtr); 87 | } 88 | out_ptr_t(const out_ptr_t&) = delete; 89 | 90 | out_ptr_t& operator=(const out_ptr_t&) = delete; 91 | 92 | operator PT*() && noexcept /* NOLINT(google-explicit-constructor) */ 93 | { return &std::get(mPtr); } 94 | 95 | operator void**() && noexcept /* NOLINT(google-explicit-constructor) */ 96 | { return &mPtr.template emplace(); } 97 | }; 98 | 99 | template 100 | auto out_ptr(SP &res) 101 | { 102 | using ptype = typename SP::element_type*; 103 | return out_ptr_t{res}; 104 | } 105 | 106 | } // namespace ds 107 | 108 | #endif // COMPTR_H 109 | -------------------------------------------------------------------------------- /src/dsoal_global.h: -------------------------------------------------------------------------------- 1 | #ifndef DSOAL_GLOBAL_H 2 | #define DSOAL_GLOBAL_H 3 | 4 | #if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 5 | # define Q_DECL_EXPORT __declspec(dllexport) 6 | # define Q_DECL_IMPORT __declspec(dllimport) 7 | #else 8 | # define Q_DECL_EXPORT __attribute__((visibility("default"))) 9 | # define Q_DECL_IMPORT __attribute__((visibility("default"))) 10 | #endif 11 | 12 | #if defined(DSOAL_LIBRARY) 13 | # define DSOAL_EXPORT Q_DECL_EXPORT 14 | #else 15 | # define DSOAL_EXPORT Q_DECL_IMPORT 16 | #endif 17 | 18 | #endif // DSOAL_GLOBAL_H 19 | -------------------------------------------------------------------------------- /src/dsoundoal.h: -------------------------------------------------------------------------------- 1 | #ifndef DSOUNDOAL_H 2 | #define DSOUNDOAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "AL/alc.h" 18 | #include "comptr.h" 19 | #include "expected.h" 20 | #include "primarybuffer.h" 21 | 22 | 23 | class Buffer; 24 | struct BufferSubList; 25 | 26 | enum Extensions : uint8_t { 27 | EXT_EAX, 28 | EXT_EFX, 29 | EXT_FLOAT32, 30 | EXT_MCFORMATS, 31 | EXT_STATIC_BUFFER, 32 | SOFT_SOURCE_PANNING, 33 | 34 | ExtensionCount 35 | }; 36 | 37 | struct SharedDevice { 38 | static std::mutex sDeviceListMutex; 39 | static std::vector sDeviceList; 40 | 41 | explicit SharedDevice(const GUID &id) : mId{id} { } 42 | SharedDevice(const SharedDevice&) = delete; 43 | ~SharedDevice(); 44 | 45 | SharedDevice& operator=(const SharedDevice&) = delete; 46 | 47 | void dispose() noexcept; 48 | 49 | ULONG AddRef() noexcept { return mRef.fetch_add(1u, std::memory_order_relaxed)+1; } 50 | ULONG Release() noexcept 51 | { 52 | const auto ret = mRef.fetch_sub(1u, std::memory_order_relaxed)-1; 53 | if(ret == 0) dispose(); 54 | return ret; 55 | } 56 | 57 | DWORD mMaxHwSources{}; 58 | DWORD mMaxSwSources{}; 59 | std::atomic mCurrentHwSources; 60 | std::atomic mCurrentSwSources; 61 | 62 | std::bitset mExtensions; 63 | DWORD mRefresh{100u}; 64 | 65 | const GUID mId; 66 | DWORD mSpeakerConfig{}; 67 | 68 | ALCdevice *mDevice{}; 69 | ALCcontext *mContext{}; 70 | 71 | std::atomic mRef{1u}; 72 | 73 | [[nodiscard]] 74 | auto getCurrentHwCount() const noexcept -> DWORD 75 | { return mCurrentHwSources.load(std::memory_order_relaxed); } 76 | 77 | [[nodiscard]] 78 | auto getCurrentSwCount() const noexcept -> DWORD 79 | { return mCurrentSwSources.load(std::memory_order_relaxed); } 80 | 81 | /* Increment mCurrentHwSources up to mMaxHwSources. Returns false is the 82 | * current is already at max, or true if it was successfully incremented. 83 | */ 84 | bool incHwSources() noexcept 85 | { 86 | DWORD cur{mCurrentHwSources.load(std::memory_order_relaxed)}; 87 | do { 88 | if(cur == mMaxHwSources) 89 | return false; 90 | } while(!mCurrentHwSources.compare_exchange_weak(cur, cur+1, std::memory_order_relaxed)); 91 | return true; 92 | } 93 | 94 | /* Increment mCurrentSwSources up to mMaxSwSources. */ 95 | bool incSwSources() noexcept 96 | { 97 | DWORD cur{mCurrentSwSources.load(std::memory_order_relaxed)}; 98 | do { 99 | if(cur == mMaxSwSources) 100 | return false; 101 | } while(!mCurrentSwSources.compare_exchange_weak(cur, cur+1, std::memory_order_relaxed)); 102 | return true; 103 | } 104 | 105 | void decHwSources() noexcept { mCurrentHwSources.fetch_sub(1u, std::memory_order_relaxed); } 106 | void decSwSources() noexcept { mCurrentSwSources.fetch_sub(1u, std::memory_order_relaxed); } 107 | 108 | static auto GetById(const GUID &deviceId) noexcept -> ds::expected,HRESULT>; 109 | }; 110 | 111 | 112 | class DSound8OAL final : IDirectSound8 { 113 | explicit DSound8OAL(bool is8); 114 | ~DSound8OAL(); 115 | 116 | class Unknown final : IUnknown { 117 | DSound8OAL *impl_from_base() noexcept 118 | { 119 | #ifdef __GNUC__ 120 | _Pragma("GCC diagnostic push") 121 | _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 122 | #endif 123 | return CONTAINING_RECORD(this, DSound8OAL, mUnknownIface); 124 | #ifdef __GNUC__ 125 | _Pragma("GCC diagnostic pop") 126 | #endif 127 | } 128 | 129 | public: 130 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 131 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 132 | ULONG STDMETHODCALLTYPE Release() noexcept override; 133 | 134 | Unknown() = default; 135 | Unknown(const Unknown&) = delete; 136 | Unknown& operator=(const Unknown&) = delete; 137 | 138 | template 139 | T as() noexcept { return static_cast(this); } 140 | }; 141 | Unknown mUnknownIface; 142 | 143 | std::atomic mTotalRef{1u}, mDsRef{1u}, mUnkRef{0u}; 144 | 145 | std::recursive_mutex mDsMutex; 146 | DWORD mPrioLevel{}; 147 | 148 | ComPtr mShared; 149 | 150 | std::bitset mExtensions; 151 | DWORD mRefresh{100u}; 152 | 153 | std::vector mSecondaryBuffers; 154 | PrimaryBuffer mPrimaryBuffer; 155 | 156 | std::vector m3dBuffers; 157 | std::vector mNotifyBuffers; 158 | 159 | std::condition_variable_any mNotifyCond; 160 | std::thread mNotifyThread; 161 | 162 | std::atomic mQuitNotify{false}; 163 | bool mIs8{}; 164 | 165 | ComPtr createSecondaryBuffer(IDirectSoundBuffer *original=nullptr); 166 | 167 | void notifyThread() noexcept; 168 | 169 | public: 170 | /*** IUnknown methods ***/ 171 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 172 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 173 | ULONG STDMETHODCALLTYPE Release() noexcept override; 174 | /*** IDirectSound8 methods ***/ 175 | HRESULT STDMETHODCALLTYPE CreateSoundBuffer(const DSBUFFERDESC *bufferDesc, IDirectSoundBuffer **dsBuffer, IUnknown *outer) noexcept override; 176 | HRESULT STDMETHODCALLTYPE GetCaps(DSCAPS *caps) noexcept override; 177 | HRESULT STDMETHODCALLTYPE DuplicateSoundBuffer(IDirectSoundBuffer *original, IDirectSoundBuffer **duplicate) noexcept override; 178 | HRESULT STDMETHODCALLTYPE SetCooperativeLevel(HWND hwnd, DWORD level) noexcept override; 179 | HRESULT STDMETHODCALLTYPE Compact() noexcept override; 180 | HRESULT STDMETHODCALLTYPE GetSpeakerConfig(DWORD *speakerConfig) noexcept override; 181 | HRESULT STDMETHODCALLTYPE SetSpeakerConfig(DWORD speakerConfig) noexcept override; 182 | HRESULT STDMETHODCALLTYPE Initialize(const GUID *deviceId) noexcept override; 183 | HRESULT STDMETHODCALLTYPE VerifyCertification(DWORD *certified) noexcept override; 184 | 185 | void finalize() noexcept 186 | { 187 | if(mTotalRef.fetch_sub(1u, std::memory_order_relaxed) == 1) [[unlikely]] 188 | delete this; 189 | } 190 | 191 | void dispose(Buffer *buffer) noexcept; 192 | 193 | void add3dBuffer(Buffer *buffer) 194 | { m3dBuffers.emplace_back(buffer); } 195 | 196 | void remove3dBuffer(Buffer *buffer) 197 | { 198 | auto iter = std::remove(m3dBuffers.begin(), m3dBuffers.end(), buffer); 199 | m3dBuffers.erase(iter, m3dBuffers.end()); 200 | } 201 | 202 | void addNotifyBuffer(Buffer *buffer); 203 | 204 | void removeNotifyBuffer(Buffer *buffer) 205 | { 206 | auto iter = std::remove(mNotifyBuffers.begin(), mNotifyBuffers.end(), buffer); 207 | mNotifyBuffers.erase(iter, mNotifyBuffers.end()); 208 | } 209 | 210 | [[nodiscard]] 211 | bool isPendingNotify(Buffer *buffer) const noexcept 212 | { 213 | const auto iter = std::find(mNotifyBuffers.cbegin(), mNotifyBuffers.cend(), buffer); 214 | return iter != mNotifyBuffers.cend(); 215 | } 216 | 217 | void triggerNotifies() noexcept; 218 | 219 | [[nodiscard]] 220 | std::vector &getSecondaryBuffers() noexcept { return mSecondaryBuffers; } 221 | 222 | [[nodiscard]] 223 | auto getMutex() noexcept -> std::recursive_mutex& { return mDsMutex; } 224 | 225 | [[nodiscard]] 226 | bool haveExtension(Extensions flag) const noexcept { return mExtensions.test(flag); } 227 | 228 | [[nodiscard]] 229 | std::bitset getExtensions() const noexcept { return mExtensions; } 230 | 231 | [[nodiscard]] 232 | auto getRefresh() const noexcept { return mRefresh; } 233 | 234 | [[nodiscard]] 235 | DWORD getPriorityLevel() const noexcept { return mPrioLevel; } 236 | 237 | [[nodiscard]] 238 | SharedDevice &getShared() noexcept { return *mShared; } 239 | 240 | [[nodiscard]] 241 | PrimaryBuffer &getPrimary() noexcept { return mPrimaryBuffer; } 242 | 243 | [[nodiscard]] 244 | auto get3dBuffers() noexcept -> std::span { return m3dBuffers; } 245 | 246 | template [[nodiscard]] 247 | T as() noexcept 248 | { 249 | /* MinGW headers do not have IDirectSound8 inherit from IDirectSound, 250 | * which MSVC apparently does. IDirectSound is a strict subset of 251 | * IDirectSound8, so the interface is ABI compatible. 252 | */ 253 | if constexpr(std::is_same_v 254 | && !std::is_base_of_v) 255 | return std::bit_cast(static_cast(this)); 256 | else 257 | return static_cast(this); 258 | } 259 | 260 | [[nodiscard]] 261 | static ComPtr Create(bool is8); 262 | }; 263 | 264 | #endif // DSOUNDOAL_H 265 | -------------------------------------------------------------------------------- /src/eax.h: -------------------------------------------------------------------------------- 1 | #ifndef EAX_H 2 | #define EAX_H 3 | 4 | #include 5 | 6 | 7 | inline constexpr GUID DSPROPSETID_EAX10_ListenerProperties{ 8 | 0x4A4E6FC1, 9 | 0xC341, 0x11D1, 10 | {0xB7, 0x3A, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} 11 | }; 12 | 13 | inline constexpr GUID DSPROPSETID_EAX10_BufferProperties{ 14 | 0x4A4E6FC0, 15 | 0xC341, 0x11D1, 16 | {0xB7, 0x3A, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} 17 | }; 18 | 19 | inline constexpr GUID DSPROPSETID_EAX20_ListenerProperties{ 20 | 0x306A6A8, 21 | 0xB224, 0x11D2, 22 | {0x99, 0xE5, 0x00, 0x00, 0xE8, 0xD8, 0xC7, 0x22} 23 | }; 24 | 25 | inline constexpr GUID DSPROPSETID_EAX20_BufferProperties{ 26 | 0x306A6A7, 27 | 0xB224, 0x11D2, 28 | {0x99, 0xE5, 0x00, 0x00, 0xE8, 0xD8, 0xC7, 0x22} 29 | }; 30 | 31 | inline constexpr GUID DSPROPSETID_EAX30_ListenerProperties{ 32 | 0xA8FA6882, 33 | 0xB476, 0x11D3, 34 | {0xBD, 0xB9, 0x00, 0xC0, 0xF0, 0x2D, 0xDF, 0x87} 35 | }; 36 | 37 | inline constexpr GUID DSPROPSETID_EAX30_BufferProperties { 38 | 0xA8FA6881, 39 | 0xB476, 0x11D3, 40 | {0xBD, 0xB9, 0x00, 0xC0, 0xF0, 0x2D, 0xDF, 0x87} 41 | }; 42 | 43 | inline constexpr GUID EAXPROPERTYID_EAX40_Context{ 44 | 0x1D4870AD, 45 | 0x0DEF, 0x43C0, 46 | {0xA4, 0xC, 0x52, 0x36, 0x32, 0x29, 0x63, 0x42} 47 | }; 48 | 49 | inline constexpr GUID EAXPROPERTYID_EAX40_FXSlot0{ 50 | 0xC4D79F1E, 51 | 0xF1AC, 0x436B, 52 | {0xA8, 0x1D, 0xA7, 0x38, 0xE7, 0x04, 0x54, 0x69} 53 | }; 54 | 55 | inline constexpr GUID EAXPROPERTYID_EAX40_FXSlot1{ 56 | 0x8C00E96, 57 | 0x74BE, 0x4491, 58 | {0x93, 0xAA, 0xE8, 0xAD, 0x35, 0xA4, 0x91, 0x17} 59 | }; 60 | 61 | inline constexpr GUID EAXPROPERTYID_EAX40_FXSlot2{ 62 | 0x1D433B88, 63 | 0xF0F6, 0x4637, 64 | {0x91, 0x9F, 0x60, 0xE7, 0xE0, 0x6B, 0x5E, 0xDD} 65 | }; 66 | 67 | inline constexpr GUID EAXPROPERTYID_EAX40_FXSlot3{ 68 | 0xEFFF08EA, 69 | 0xC7D8, 0x44AB, 70 | {0x93, 0xAD, 0x6D, 0xBD, 0x5F, 0x91, 0x00, 0x64} 71 | }; 72 | 73 | inline constexpr GUID EAXPROPERTYID_EAX40_Source{ 74 | 0x1B86B823, 75 | 0x22DF, 0x4EAE, 76 | {0x8B, 0x3C, 0x12, 0x78, 0xCE, 0x54, 0x42, 0x27} 77 | }; 78 | 79 | inline constexpr auto EAX_MAX_FXSLOTS = 4; 80 | 81 | inline constexpr auto EAX40_MAX_ACTIVE_FXSLOTS = 2; 82 | 83 | // Source object properties 84 | enum EAXSOURCE_PROPERTY : unsigned int { 85 | // EAX30 86 | EAXSOURCE_NONE, 87 | EAXSOURCE_ALLPARAMETERS, 88 | EAXSOURCE_OBSTRUCTIONPARAMETERS, 89 | EAXSOURCE_OCCLUSIONPARAMETERS, 90 | EAXSOURCE_EXCLUSIONPARAMETERS, 91 | EAXSOURCE_DIRECT, 92 | EAXSOURCE_DIRECTHF, 93 | EAXSOURCE_ROOM, 94 | EAXSOURCE_ROOMHF, 95 | EAXSOURCE_OBSTRUCTION, 96 | EAXSOURCE_OBSTRUCTIONLFRATIO, 97 | EAXSOURCE_OCCLUSION, 98 | EAXSOURCE_OCCLUSIONLFRATIO, 99 | EAXSOURCE_OCCLUSIONROOMRATIO, 100 | EAXSOURCE_OCCLUSIONDIRECTRATIO, 101 | EAXSOURCE_EXCLUSION, 102 | EAXSOURCE_EXCLUSIONLFRATIO, 103 | EAXSOURCE_OUTSIDEVOLUMEHF, 104 | EAXSOURCE_DOPPLERFACTOR, 105 | EAXSOURCE_ROLLOFFFACTOR, 106 | EAXSOURCE_ROOMROLLOFFFACTOR, 107 | EAXSOURCE_AIRABSORPTIONFACTOR, 108 | EAXSOURCE_FLAGS, 109 | 110 | // EAX40 111 | EAXSOURCE_SENDPARAMETERS, 112 | EAXSOURCE_ALLSENDPARAMETERS, 113 | EAXSOURCE_OCCLUSIONSENDPARAMETERS, 114 | EAXSOURCE_EXCLUSIONSENDPARAMETERS, 115 | EAXSOURCE_ACTIVEFXSLOTID, 116 | 117 | // EAX50 118 | EAXSOURCE_MACROFXFACTOR, 119 | EAXSOURCE_SPEAKERLEVELS, 120 | EAXSOURCE_ALL2DPARAMETERS, 121 | }; 122 | 123 | 124 | DWORD EAX4Context_Query(DWORD propid); 125 | DWORD EAX4Slot_Query(DWORD propid); 126 | DWORD EAX4Source_Query(DWORD propid); 127 | 128 | DWORD EAX3_Query(DWORD propid); 129 | DWORD EAX3Buffer_Query(DWORD propid); 130 | 131 | DWORD EAX2_Query(DWORD propid); 132 | DWORD EAX2Buffer_Query(DWORD propid); 133 | 134 | DWORD EAX1_Query(DWORD propid); 135 | DWORD EAX1Buffer_Query(DWORD propid); 136 | 137 | #endif // EAX_H 138 | -------------------------------------------------------------------------------- /src/enumerate.h: -------------------------------------------------------------------------------- 1 | #ifndef ENUMERATE_H 2 | #define ENUMERATE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "comhelpers.h" 13 | #include "comptr.h" 14 | #include "dsoal.h" 15 | #include "guidprinter.h" 16 | #include "logging.h" 17 | 18 | 19 | inline constexpr WCHAR aldriver_name[] = L"dsoal-aldrv.dll"; /* NOLINT(*-avoid-c-arrays) */ 20 | inline constexpr WCHAR primary_desc[] = L"Primary Sound Driver"; /* NOLINT(*-avoid-c-arrays) */ 21 | 22 | inline std::mutex gDeviceListMutex; 23 | inline std::deque gPlaybackDevices; 24 | inline std::deque gCaptureDevices; 25 | 26 | ComPtr GetMMDevice(ComWrapper&, EDataFlow flow, const GUID &id); 27 | 28 | #define PREFIX "enumerate_mmdev " 29 | template 30 | HRESULT enumerate_mmdev(const EDataFlow flow, std::deque &devlist, T&& cb) 31 | { 32 | ComWrapper com; 33 | 34 | ComPtr devenum; 35 | HRESULT hr{CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, 36 | IID_IMMDeviceEnumerator, ds::out_ptr(devenum))}; 37 | if(FAILED(hr)) 38 | { 39 | ERR("CoCreateInstance failed: {:08x}", as_unsigned(hr)); 40 | return hr; 41 | } 42 | 43 | ComPtr coll; 44 | hr = devenum->EnumAudioEndpoints(flow, DEVICE_STATE_ACTIVE, ds::out_ptr(coll)); 45 | if(FAILED(hr)) 46 | { 47 | WARN("IMMDeviceEnumerator::EnumAudioEndpoints failed: {:08x}", as_unsigned(hr)); 48 | return DS_OK; 49 | } 50 | 51 | UINT count{}; 52 | hr = coll->GetCount(&count); 53 | if(FAILED(hr)) 54 | { 55 | WARN("IMMDeviceCollection::GetCount failed: {:08x}", as_unsigned(hr)); 56 | return DS_OK; 57 | } 58 | 59 | if(count == 0) 60 | return DS_OK; 61 | 62 | std::deque{}.swap(devlist); 63 | 64 | TRACE("Calling back with NULL ({})", wstr_to_utf8(std::data(primary_desc))); 65 | auto keep_going = bool{cb(nullptr, primary_desc, L"")}; 66 | 67 | auto send_device = [&devlist,&cb,&keep_going](IMMDevice *device) 68 | { 69 | ComPtr ps; 70 | HRESULT hr2{device->OpenPropertyStore(STGM_READ, ds::out_ptr(ps))}; 71 | if(FAILED(hr2)) 72 | { 73 | WARN("IMMDevice::OpenPropertyStore failed: {:08x}", as_unsigned(hr2)); 74 | return; 75 | } 76 | 77 | PropVariant pv; 78 | hr2 = ps->GetValue(PKEY_AudioEndpoint_GUID, pv.get()); 79 | if(FAILED(hr2) || pv.type() != VT_LPWSTR) 80 | { 81 | WARN("IPropertyStore::GetValue(GUID) failed: {:08x}", as_unsigned(hr2)); 82 | return; 83 | } 84 | 85 | GUID guid{}; 86 | CLSIDFromString(pv.value(), &guid); 87 | pv.clear(); 88 | 89 | if(!devlist.empty() && devlist[0] == guid) 90 | return; 91 | 92 | devlist.emplace_back(guid); 93 | if(!keep_going) return; 94 | 95 | hr2 = ps->GetValue(std::bit_cast(DEVPKEY_Device_FriendlyName), pv.get()); 96 | if(FAILED(hr2)) 97 | { 98 | WARN("IPropertyStore::GetValue(FriendlyName) failed: {:08x}", as_unsigned(hr2)); 99 | return; 100 | } 101 | 102 | TRACE("Calling back with {} - {}", GuidPrinter{devlist.back()}.c_str(), 103 | wstr_to_utf8(pv.value())); 104 | keep_going = cb(&devlist.back(), pv.value(), std::data(aldriver_name)); 105 | }; 106 | 107 | ComPtr device; 108 | hr = devenum->GetDefaultAudioEndpoint(flow, eMultimedia, ds::out_ptr(device)); 109 | if(SUCCEEDED(hr)) 110 | send_device(device.get()); 111 | 112 | for(UINT i{0};i < count;++i) 113 | { 114 | hr = coll->Item(i, ds::out_ptr(device)); 115 | if(FAILED(hr)) 116 | { 117 | WARN("IMMDeviceCollection::Item failed: {:08x}", as_unsigned(hr)); 118 | continue; 119 | } 120 | 121 | send_device(device.get()); 122 | } 123 | 124 | return keep_going ? S_OK : S_FALSE; 125 | } 126 | #undef PREFIX 127 | 128 | #endif // ENUMERATE_H 129 | -------------------------------------------------------------------------------- /src/expected.h: -------------------------------------------------------------------------------- 1 | #ifndef EXPECTED_H 2 | #define EXPECTED_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ds { 9 | 10 | template 11 | class unexpected { 12 | E mError; 13 | 14 | public: 15 | constexpr unexpected(const unexpected&) = default; 16 | constexpr unexpected(unexpected&&) = default; 17 | template requires(!std::is_same_v, unexpected> 18 | && !std::is_same_v, std::in_place_t> 19 | && std::is_constructible_v) 20 | constexpr explicit unexpected(E2&& rhs) : mError{std::forward(rhs)} 21 | { } 22 | template requires(std::is_constructible_v) 23 | constexpr explicit unexpected(std::in_place_t, Args&& ...args) 24 | : mError{std::forward(args)...} 25 | { } 26 | template 27 | requires(std::is_constructible_v&, Args...>) 28 | constexpr explicit unexpected(std::in_place_t, std::initializer_list il, Args&& ...args) 29 | : mError{il, std::forward(args)...} 30 | { } 31 | 32 | constexpr const E& error() const& noexcept { return mError; } 33 | constexpr E& error() & noexcept { return mError; } 34 | constexpr const E&& error() const&& noexcept { return std::move(mError); } 35 | constexpr E&& error() && noexcept { return std::move(mError); } 36 | 37 | constexpr void swap(unexpected& other) noexcept(std::is_nothrow_swappable_v) 38 | { std::swap(mError, other.mError); } 39 | 40 | template 41 | friend constexpr bool operator==(const unexpected& lhs, const unexpected& rhs) 42 | { return lhs.error() == rhs.error(); } 43 | 44 | friend constexpr void swap(unexpected& lhs, unexpected& rhs) noexcept(noexcept(lhs.swap(rhs))) 45 | { lhs.swap(rhs); } 46 | }; 47 | 48 | template 49 | unexpected(E) -> unexpected; 50 | 51 | 52 | template 53 | class expected { 54 | using variant_type = std::variant; 55 | 56 | std::variant mValues; 57 | 58 | public: 59 | constexpr expected() noexcept(std::is_nothrow_default_constructible_v) = default; 60 | constexpr expected(const expected &rhs) noexcept(std::is_nothrow_copy_constructible_v) = default; 61 | constexpr expected(expected&& rhs) noexcept(std::is_nothrow_move_constructible_v) = default; 62 | 63 | /* Value constructors */ 64 | template requires(!std::is_same_v, std::in_place_t> 65 | && !std::is_same_v> 66 | && std::is_constructible_v) 67 | constexpr explicit(!std::is_convertible_v) expected(U&& v) 68 | : mValues{std::in_place_index_t<0>{}, std::forward(v)} 69 | { } 70 | 71 | /* Error constructors */ 72 | template requires(std::is_constructible_v) 73 | constexpr explicit(!std::is_convertible_v) expected(const unexpected &rhs) 74 | : mValues{variant_type{std::in_place_index<1>, rhs.error()}} 75 | { } 76 | 77 | template requires(std::is_constructible_v) 78 | constexpr explicit(!std::is_convertible_v) expected(unexpected&& rhs) 79 | : mValues{variant_type{std::in_place_index<1>, std::move(rhs.error())}} 80 | { } 81 | 82 | [[nodiscard]] 83 | constexpr bool has_value() const noexcept { return mValues.index() == 0; } 84 | [[nodiscard]] 85 | constexpr explicit operator bool() const noexcept { return has_value(); } 86 | 87 | constexpr S& value() & { return std::get<0>(mValues); } 88 | constexpr const S& value() const& { return std::get<0>(mValues); } 89 | constexpr S&& value() && { return std::move(std::get<0>(mValues)); } 90 | constexpr const S&& value() const&& { return std::move(std::get<0>(mValues)); } 91 | 92 | constexpr S* operator->() noexcept { return &std::get<0>(mValues); } 93 | constexpr const S* operator->() const noexcept { return &std::get<0>(mValues); } 94 | constexpr S& operator*() noexcept { return std::get<0>(mValues); } 95 | constexpr const S& operator*() const noexcept { return std::get<0>(mValues); } 96 | 97 | template 98 | constexpr S value_or(U&& defval) const& 99 | { return bool(*this) ? **this : static_cast(std::forward(defval)); } 100 | template 101 | constexpr S value_or(U&& defval) && 102 | { return bool(*this) ? std::move(**this) : static_cast(std::forward(defval)); } 103 | 104 | constexpr F& error() & { return std::get<1>(mValues); } 105 | constexpr const F& error() const& { return std::get<1>(mValues); } 106 | constexpr F&& error() && { return std::move(std::get<1>(mValues)); } 107 | constexpr const F&& error() const&& { return std::move(std::get<1>(mValues)); } 108 | }; 109 | 110 | } // namespace ds 111 | 112 | #endif // EXPECTED_H 113 | -------------------------------------------------------------------------------- /src/factory.cpp: -------------------------------------------------------------------------------- 1 | #include "factory.h" 2 | 3 | #include 4 | 5 | #include "capture.h" 6 | #include "dsoundoal.h" 7 | #include "fullduplex.h" 8 | #include "guidprinter.h" 9 | #include "logging.h" 10 | #include "propset.h" 11 | 12 | 13 | namespace { 14 | 15 | using voidp = void*; 16 | using cvoidp = const void*; 17 | 18 | template 19 | auto CreateObj(REFIID riid, void **ppvObject) -> HRESULT 20 | { 21 | return T::Create(Params...)->QueryInterface(riid, ppvObject); 22 | } 23 | 24 | std::array sFactories{ 25 | Factory{CLSID_DirectSound8, CreateObj}, 26 | Factory{CLSID_DirectSound, CreateObj}, 27 | Factory{CLSID_DirectSoundCapture8, CreateObj}, 28 | Factory{CLSID_DirectSoundCapture, CreateObj}, 29 | Factory{CLSID_DirectSoundFullDuplex, CreateObj}, 30 | Factory{CLSID_DirectSoundPrivate, CreateObj}, 31 | }; 32 | 33 | } // namespace 34 | 35 | 36 | #define CLASS_PREFIX "Factory::" 37 | #define PREFIX CLASS_PREFIX "GetFactory " 38 | HRESULT Factory::GetFactory(const GUID &clsid, const GUID &iid, void **out) 39 | { 40 | for(auto &factory : sFactories) 41 | { 42 | if(clsid == factory.getId()) 43 | return factory.QueryInterface(iid, out); 44 | } 45 | 46 | FIXME("No class found for {}", ClsidPrinter{clsid}.c_str()); 47 | return CLASS_E_CLASSNOTAVAILABLE; 48 | } 49 | #undef PREFIX 50 | 51 | #define PREFIX CLASS_PREFIX "QueryInterface " 52 | HRESULT STDMETHODCALLTYPE Factory::QueryInterface(REFIID riid, void** ppvObject) noexcept 53 | { 54 | DEBUG("({})->({}, {})", voidp{this}, IidPrinter{riid}.c_str(), voidp{ppvObject}); 55 | 56 | if(!ppvObject) 57 | return E_POINTER; 58 | *ppvObject = nullptr; 59 | 60 | if(riid == IID_IUnknown) 61 | { 62 | AddRef(); 63 | *ppvObject = as(); 64 | return S_OK; 65 | } 66 | if(riid == IID_IClassFactory) 67 | { 68 | AddRef(); 69 | *ppvObject = as(); 70 | return S_OK; 71 | } 72 | 73 | FIXME("Unhandled GUID: {}", IidPrinter{riid}.c_str()); 74 | return E_NOINTERFACE; 75 | } 76 | #undef PREFIX 77 | 78 | #define PREFIX CLASS_PREFIX "AddRef " 79 | ULONG STDMETHODCALLTYPE Factory::AddRef() noexcept 80 | { 81 | const auto ret = mRef.fetch_add(1u, std::memory_order_relaxed) + 1; 82 | DEBUG("({}) ref {}", voidp{this}, ret); 83 | return ret; 84 | } 85 | #undef PREFIX 86 | 87 | #define PREFIX CLASS_PREFIX "Release " 88 | ULONG STDMETHODCALLTYPE Factory::Release() noexcept 89 | { 90 | /* The factory is a static object and should not be deleted. Make sure the 91 | * reference count doesn't underflow. 92 | */ 93 | ULONG ret{mRef.load(std::memory_order_relaxed)}; 94 | do { 95 | if(ret == 0) [[unlikely]] 96 | { 97 | WARN("({}) ref already {}", voidp{this}, ret); 98 | return ret; 99 | } 100 | } while(!mRef.compare_exchange_weak(ret, ret-1, std::memory_order_relaxed)); 101 | ret -= 1; 102 | DEBUG("({}) ref {}", voidp{this}, ret); 103 | return ret; 104 | } 105 | #undef PREFIX 106 | 107 | #define PREFIX CLASS_PREFIX "CreateInstance " 108 | HRESULT STDMETHODCALLTYPE Factory::CreateInstance(IUnknown *unkOuter, REFIID riid, void **ppvObject) noexcept 109 | { 110 | TRACE("({})->({}, {}, {})", voidp{this}, voidp{unkOuter}, IidPrinter{riid}.c_str(), 111 | voidp{ppvObject}); 112 | 113 | if(!ppvObject) 114 | { 115 | WARN("NULL output parameter"); 116 | return DSERR_INVALIDPARAM; 117 | } 118 | *ppvObject = nullptr; 119 | 120 | if(unkOuter) 121 | return CLASS_E_NOAGGREGATION; 122 | 123 | return mCreateInstance(riid, ppvObject); 124 | } 125 | #undef PREFIX 126 | 127 | #define PREFIX CLASS_PREFIX "LockServer " 128 | HRESULT STDMETHODCALLTYPE Factory::LockServer(BOOL dolock) noexcept 129 | { 130 | FIXME("({})->({}): stub", voidp{this}, dolock); 131 | return S_OK; 132 | } 133 | #undef PREFIX 134 | #undef CLASS_PREFIX 135 | -------------------------------------------------------------------------------- /src/factory.h: -------------------------------------------------------------------------------- 1 | #ifndef FACTORY_H 2 | #define FACTORY_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | class Factory final : IClassFactory { 10 | using FunctionType = HRESULT(&)(REFIID riid, void **ppvObject); 11 | 12 | std::atomic mRef{0u}; 13 | 14 | const GUID &mId; 15 | FunctionType mCreateInstance; 16 | 17 | public: 18 | Factory(const GUID &id, FunctionType func) : mId{id}, mCreateInstance{func} { } 19 | 20 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 21 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 22 | ULONG STDMETHODCALLTYPE Release() noexcept override; 23 | HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *unkOuter, REFIID riid, void **ppvObject) noexcept override; 24 | HRESULT STDMETHODCALLTYPE LockServer(BOOL dolock) noexcept override; 25 | 26 | [[nodiscard]] 27 | const GUID &getId() const noexcept { return mId; } 28 | 29 | template [[nodiscard]] 30 | U as() noexcept { return static_cast(this); } 31 | 32 | [[nodiscard]] 33 | static HRESULT GetFactory(const GUID &clsid, const GUID &iid, void **out); 34 | }; 35 | 36 | #endif // FACTORY_H 37 | -------------------------------------------------------------------------------- /src/fullduplex.cpp: -------------------------------------------------------------------------------- 1 | #include "fullduplex.h" 2 | 3 | #include "capture.h" 4 | #include "dsoundoal.h" 5 | #include "guidprinter.h" 6 | #include "logging.h" 7 | 8 | 9 | namespace { 10 | 11 | using voidp = void*; 12 | using cvoidp = const void*; 13 | 14 | } // namespace 15 | 16 | #define CLASS_PREFIX "DSFullDuplex::" 17 | DSFullDuplex::DSFullDuplex() = default; 18 | DSFullDuplex::~DSFullDuplex() = default; 19 | 20 | ComPtr DSFullDuplex::Create() 21 | { 22 | return ComPtr{new DSFullDuplex{}}; 23 | } 24 | 25 | 26 | #define PREFIX CLASS_PREFIX "QueryInterface " 27 | HRESULT STDMETHODCALLTYPE DSFullDuplex::QueryInterface(REFIID riid, void **ppvObject) noexcept 28 | { 29 | DEBUG("({})->({}, {})", voidp{this}, IidPrinter{riid}.c_str(), voidp{ppvObject}); 30 | 31 | if(!ppvObject) 32 | return E_POINTER; 33 | *ppvObject = nullptr; 34 | 35 | if(riid == IID_IUnknown) 36 | { 37 | mUnknownIface.AddRef(); 38 | *ppvObject = mUnknownIface.as(); 39 | return S_OK; 40 | } 41 | if(riid == IID_IDirectSoundFullDuplex) 42 | { 43 | AddRef(); 44 | *ppvObject = as(); 45 | return S_OK; 46 | } 47 | if(riid == IID_IDirectSound8) 48 | { 49 | mDS8Iface.AddRef(); 50 | *ppvObject = mDS8Iface.as(); 51 | return S_OK; 52 | } 53 | if(riid == IID_IDirectSound) 54 | { 55 | mDS8Iface.AddRef(); 56 | *ppvObject = mDS8Iface.as(); 57 | return S_OK; 58 | } 59 | if(riid == IID_IDirectSoundCapture) 60 | { 61 | mDSCIface.AddRef(); 62 | *ppvObject = mDSCIface.as(); 63 | return S_OK; 64 | } 65 | 66 | FIXME("Unhandled GUID: {}", IidPrinter{riid}.c_str()); 67 | return E_NOINTERFACE; 68 | } 69 | #undef PREFIX 70 | 71 | #define PREFIX CLASS_PREFIX "AddRef " 72 | ULONG STDMETHODCALLTYPE DSFullDuplex::AddRef() noexcept 73 | { 74 | mTotalRef.fetch_add(1u, std::memory_order_relaxed); 75 | const auto ret = mFdRef.fetch_add(1u, std::memory_order_relaxed) + 1; 76 | DEBUG("({}) ref {}", voidp{this}, ret); 77 | return ret; 78 | } 79 | #undef PREFIX 80 | 81 | #define PREFIX CLASS_PREFIX "Release " 82 | ULONG STDMETHODCALLTYPE DSFullDuplex::Release() noexcept 83 | { 84 | const auto ret = mFdRef.fetch_sub(1u, std::memory_order_relaxed) - 1; 85 | DEBUG("({}) ref {}", voidp{this}, ret); 86 | finalize(); 87 | return ret; 88 | } 89 | #undef PREFIX 90 | 91 | #define PREFIX CLASS_PREFIX "Initialize " 92 | HRESULT STDMETHODCALLTYPE DSFullDuplex::Initialize(const GUID *captureGuid, const GUID *renderGuid, 93 | const DSCBUFFERDESC *dscBufferDesc, const DSBUFFERDESC *dsBufferDesc, HWND hwnd, DWORD level, 94 | IDirectSoundCaptureBuffer8 **dsCaptureBuffer8, IDirectSoundBuffer8 **dsBuffer8) noexcept 95 | { 96 | DEBUG("({})->({}, {}, {}, {}, {}, {}, {}, {})", voidp{this}, DevidPrinter{captureGuid}.c_str(), 97 | DevidPrinter{renderGuid}.c_str(), cvoidp{dscBufferDesc}, cvoidp{dsBufferDesc}, voidp{hwnd}, 98 | level, voidp{dsCaptureBuffer8}, voidp{dsBuffer8}); 99 | 100 | if(dsCaptureBuffer8) *dsCaptureBuffer8 = nullptr; 101 | if(dsBuffer8) *dsBuffer8 = nullptr; 102 | 103 | if(!dsCaptureBuffer8 || !dsBuffer8) 104 | { 105 | WARN("Null output pointers"); 106 | return DSERR_INVALIDPARAM; 107 | } 108 | 109 | if(mDS8Handle || mDSCHandle) 110 | { 111 | WARN("Already initialized"); 112 | return DSERR_ALREADYINITIALIZED; 113 | } 114 | 115 | try { 116 | mDS8Handle = DSound8OAL::Create(true); 117 | if(const auto hr = mDS8Handle->Initialize(renderGuid); FAILED(hr)) 118 | { 119 | mDS8Handle = nullptr; 120 | return hr; 121 | } 122 | } 123 | catch(std::exception &e) { 124 | ERR("Exception creating IDirectSound8: {}", e.what()); 125 | mDS8Handle = nullptr; 126 | return E_FAIL; 127 | } 128 | 129 | if(const auto hr = mDS8Handle->SetCooperativeLevel(hwnd, level); FAILED(hr)) 130 | { 131 | mDS8Handle = nullptr; 132 | return hr; 133 | } 134 | 135 | auto dsbuf = ComPtr{}; 136 | if(auto hr = mDS8Handle->CreateSoundBuffer(dsBufferDesc, ds::out_ptr(dsbuf), nullptr); 137 | FAILED(hr)) 138 | { 139 | mDS8Handle = nullptr; 140 | return hr; 141 | } 142 | 143 | try { 144 | mDSCHandle = DSCapture::Create(true); 145 | if(const auto hr = mDSCHandle->Initialize(captureGuid); FAILED(hr)) 146 | { 147 | mDS8Handle = nullptr; 148 | mDSCHandle = nullptr; 149 | return hr; 150 | } 151 | } 152 | catch(std::exception &e) { 153 | ERR("Exception creating IDirectSoundCapture8: {}", e.what()); 154 | mDS8Handle = nullptr; 155 | mDSCHandle = nullptr; 156 | return E_FAIL; 157 | } 158 | 159 | auto dscbuf = ComPtr{}; 160 | if(auto hr = mDSCHandle->CreateCaptureBuffer(dscBufferDesc, ds::out_ptr(dscbuf), nullptr); 161 | FAILED(hr)) 162 | { 163 | mDS8Handle = nullptr; 164 | mDSCHandle = nullptr; 165 | return hr; 166 | } 167 | 168 | auto dsbuf8 = ComPtr{}; 169 | if(auto hr = dsbuf->QueryInterface(IID_IDirectSoundBuffer8, ds::out_ptr(dsbuf8)); FAILED(hr)) 170 | return hr; 171 | 172 | auto dscbuf8 = ComPtr{}; 173 | if(auto hr = dscbuf->QueryInterface(IID_IDirectSoundCaptureBuffer8, ds::out_ptr(dscbuf8)); 174 | FAILED(hr)) 175 | return hr; 176 | 177 | *dsBuffer8 = dsbuf8.release(); 178 | *dsCaptureBuffer8 = dscbuf8.release(); 179 | 180 | return DS_OK; 181 | } 182 | #undef PREFIX 183 | #undef CLASS_PREFIX 184 | 185 | #define CLASS_PREFIX "DSFullDuplex::DS8::" 186 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::QueryInterface(REFIID riid, void **ppvObject) noexcept 187 | { return impl_from_base()->QueryInterface(riid, ppvObject); } 188 | 189 | #define PREFIX CLASS_PREFIX "AddRef " 190 | ULONG STDMETHODCALLTYPE DSFullDuplex::DS8::AddRef() noexcept 191 | { 192 | auto self = impl_from_base(); 193 | self->mTotalRef.fetch_add(1u, std::memory_order_relaxed); 194 | const auto ret = self->mDS8Ref.fetch_add(1u, std::memory_order_relaxed) + 1; 195 | DEBUG("({}) ref {}", voidp{this}, ret); 196 | return ret; 197 | } 198 | #undef PREFIX 199 | 200 | #define PREFIX CLASS_PREFIX "Release " 201 | ULONG STDMETHODCALLTYPE DSFullDuplex::DS8::Release() noexcept 202 | { 203 | auto self = impl_from_base(); 204 | const auto ret = self->mDS8Ref.fetch_sub(1u, std::memory_order_relaxed) - 1; 205 | DEBUG("({}) ref {}", voidp{this}, ret); 206 | self->finalize(); 207 | return ret; 208 | } 209 | #undef PREFIX 210 | 211 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::CreateSoundBuffer(const DSBUFFERDESC *bufferDesc, IDirectSoundBuffer **dsBuffer, IUnknown *outer) noexcept 212 | { return impl_from_base()->mDS8Handle->CreateSoundBuffer(bufferDesc, dsBuffer, outer); } 213 | 214 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::GetCaps(DSCAPS *dsCaps) noexcept 215 | { return impl_from_base()->mDS8Handle->GetCaps(dsCaps); } 216 | 217 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::DuplicateSoundBuffer(IDirectSoundBuffer *original, IDirectSoundBuffer **duplicate) noexcept 218 | { return impl_from_base()->mDS8Handle->DuplicateSoundBuffer(original, duplicate); } 219 | 220 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::SetCooperativeLevel(HWND hwnd, DWORD level) noexcept 221 | { return impl_from_base()->mDS8Handle->SetCooperativeLevel(hwnd, level); } 222 | 223 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::Compact() noexcept 224 | { return impl_from_base()->mDS8Handle->Compact(); } 225 | 226 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::GetSpeakerConfig(DWORD *speakerConfig) noexcept 227 | { return impl_from_base()->mDS8Handle->GetSpeakerConfig(speakerConfig); } 228 | 229 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::SetSpeakerConfig(DWORD speakerConfig) noexcept 230 | { return impl_from_base()->mDS8Handle->SetSpeakerConfig(speakerConfig); } 231 | 232 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::Initialize(const GUID *deviceId) noexcept 233 | { return impl_from_base()->mDS8Handle->Initialize(deviceId); } 234 | 235 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DS8::VerifyCertification(DWORD *certified) noexcept 236 | { return impl_from_base()->mDS8Handle->VerifyCertification(certified); } 237 | #undef CLASS_PREFIX 238 | 239 | #define CLASS_PREFIX "DSFullDuplex::DSC::" 240 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DSC::QueryInterface(REFIID riid, void **ppvObject) noexcept 241 | { return impl_from_base()->QueryInterface(riid, ppvObject); } 242 | 243 | #define PREFIX CLASS_PREFIX "AddRef " 244 | ULONG STDMETHODCALLTYPE DSFullDuplex::DSC::AddRef() noexcept 245 | { 246 | auto self = impl_from_base(); 247 | self->mTotalRef.fetch_add(1u, std::memory_order_relaxed); 248 | const auto ret = self->mDSCRef.fetch_add(1u, std::memory_order_relaxed) + 1; 249 | DEBUG("({}) ref {}", voidp{this}, ret); 250 | return ret; 251 | } 252 | #undef PREFIX 253 | 254 | #define PREFIX CLASS_PREFIX "Release " 255 | ULONG STDMETHODCALLTYPE DSFullDuplex::DSC::Release() noexcept 256 | { 257 | auto self = impl_from_base(); 258 | const auto ret = self->mDSCRef.fetch_sub(1u, std::memory_order_relaxed) - 1; 259 | DEBUG("({}) ref {}", voidp{this}, ret); 260 | self->finalize(); 261 | return ret; 262 | } 263 | #undef PREFIX 264 | 265 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DSC::CreateCaptureBuffer(const DSCBUFFERDESC *dscBufferDesc, IDirectSoundCaptureBuffer **dsCaptureBuffer, IUnknown *unk) noexcept 266 | { return impl_from_base()->mDSCHandle->CreateCaptureBuffer(dscBufferDesc, dsCaptureBuffer, unk); } 267 | 268 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DSC::GetCaps(DSCCAPS *dscCaps) noexcept 269 | { return impl_from_base()->mDSCHandle->GetCaps(dscCaps); } 270 | 271 | HRESULT STDMETHODCALLTYPE DSFullDuplex::DSC::Initialize(const GUID *guid) noexcept 272 | { return impl_from_base()->mDSCHandle->Initialize(guid); } 273 | #undef CLASS_PREFIX 274 | 275 | #define CLASS_PREFIX "DSFullDuplex::Unknown::" 276 | HRESULT STDMETHODCALLTYPE DSFullDuplex::Unknown::QueryInterface(REFIID riid, void **ppvObject) noexcept 277 | { return impl_from_base()->QueryInterface(riid, ppvObject); } 278 | 279 | #define PREFIX CLASS_PREFIX "AddRef " 280 | ULONG STDMETHODCALLTYPE DSFullDuplex::Unknown::AddRef() noexcept 281 | { 282 | auto self = impl_from_base(); 283 | self->mTotalRef.fetch_add(1u, std::memory_order_relaxed); 284 | const auto ret = self->mUnkRef.fetch_add(1u, std::memory_order_relaxed) + 1; 285 | DEBUG("({}) ref {}", voidp{this}, ret); 286 | return ret; 287 | } 288 | #undef PREFIX 289 | 290 | #define PREFIX CLASS_PREFIX "Release " 291 | ULONG STDMETHODCALLTYPE DSFullDuplex::Unknown::Release() noexcept 292 | { 293 | auto self = impl_from_base(); 294 | const auto ret = self->mUnkRef.fetch_sub(1u, std::memory_order_relaxed) - 1; 295 | DEBUG("({}) ref {}", voidp{this}, ret); 296 | self->finalize(); 297 | return ret; 298 | } 299 | #undef PREFIX 300 | #undef CLASS_PREFIX 301 | -------------------------------------------------------------------------------- /src/fullduplex.h: -------------------------------------------------------------------------------- 1 | #ifndef DSFULLDUPLEX_H 2 | #define DSFULLDUPLEX_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "comptr.h" 10 | 11 | class DSound8OAL; 12 | class DSCapture; 13 | 14 | 15 | class DSFullDuplex final : IDirectSoundFullDuplex { 16 | DSFullDuplex(); 17 | 18 | class Unknown final : IUnknown { 19 | DSFullDuplex *impl_from_base() noexcept 20 | { 21 | #ifdef __GNUC__ 22 | _Pragma("GCC diagnostic push") 23 | _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 24 | #endif 25 | return CONTAINING_RECORD(this, DSFullDuplex, mUnknownIface); 26 | #ifdef __GNUC__ 27 | _Pragma("GCC diagnostic pop") 28 | #endif 29 | } 30 | 31 | public: 32 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 33 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 34 | ULONG STDMETHODCALLTYPE Release() noexcept override; 35 | 36 | Unknown() = default; 37 | Unknown(const Unknown&) = delete; 38 | Unknown& operator=(const Unknown&) = delete; 39 | 40 | template 41 | T as() noexcept { return static_cast(this); } 42 | }; 43 | Unknown mUnknownIface; 44 | 45 | class DS8 final : IDirectSound8 { 46 | DSFullDuplex *impl_from_base() noexcept 47 | { 48 | #ifdef __GNUC__ 49 | _Pragma("GCC diagnostic push") 50 | _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 51 | #endif 52 | return CONTAINING_RECORD(this, DSFullDuplex, mDS8Iface); 53 | #ifdef __GNUC__ 54 | _Pragma("GCC diagnostic pop") 55 | #endif 56 | } 57 | 58 | public: 59 | /*** IUnknown methods ***/ 60 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 61 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 62 | ULONG STDMETHODCALLTYPE Release() noexcept override; 63 | /*** IDirectSound8 methods ***/ 64 | HRESULT STDMETHODCALLTYPE CreateSoundBuffer(const DSBUFFERDESC *bufferDesc, IDirectSoundBuffer **dsBuffer, IUnknown *outer) noexcept override; 65 | HRESULT STDMETHODCALLTYPE GetCaps(DSCAPS *caps) noexcept override; 66 | HRESULT STDMETHODCALLTYPE DuplicateSoundBuffer(IDirectSoundBuffer *original, IDirectSoundBuffer **duplicate) noexcept override; 67 | HRESULT STDMETHODCALLTYPE SetCooperativeLevel(HWND hwnd, DWORD level) noexcept override; 68 | HRESULT STDMETHODCALLTYPE Compact() noexcept override; 69 | HRESULT STDMETHODCALLTYPE GetSpeakerConfig(DWORD *speakerConfig) noexcept override; 70 | HRESULT STDMETHODCALLTYPE SetSpeakerConfig(DWORD speakerConfig) noexcept override; 71 | HRESULT STDMETHODCALLTYPE Initialize(const GUID *deviceId) noexcept override; 72 | HRESULT STDMETHODCALLTYPE VerifyCertification(DWORD *certified) noexcept override; 73 | 74 | DS8() = default; 75 | DS8(const DS8&) = delete; 76 | DS8& operator=(const DS8&) = delete; 77 | 78 | template 79 | T as() noexcept 80 | { 81 | /* MinGW headers do not have IDirectSound8 inherit from 82 | * IDirectSound, which MSVC apparently does. IDirectSound is a 83 | * strict subset of IDirectSound8, so the interface is ABI 84 | * compatible. 85 | */ 86 | if constexpr(std::is_same_v && !std::is_base_of_v) 87 | return std::bit_cast(static_cast(this)); 88 | else 89 | return static_cast(this); 90 | } 91 | }; 92 | DS8 mDS8Iface; 93 | 94 | class DSC final : IDirectSoundCapture { 95 | DSFullDuplex *impl_from_base() noexcept 96 | { 97 | #ifdef __GNUC__ 98 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 99 | #endif 100 | return CONTAINING_RECORD(this, DSFullDuplex, mDSCIface); 101 | #ifdef __GNUC__ 102 | _Pragma("GCC diagnostic pop") 103 | #endif 104 | } 105 | 106 | public: 107 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 108 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 109 | ULONG STDMETHODCALLTYPE Release() noexcept override; 110 | HRESULT STDMETHODCALLTYPE CreateCaptureBuffer(const DSCBUFFERDESC *dscBufferDesc, IDirectSoundCaptureBuffer **dsCaptureBuffer, IUnknown *unk) noexcept override; 111 | HRESULT STDMETHODCALLTYPE GetCaps(DSCCAPS *dscCaps) noexcept override; 112 | HRESULT STDMETHODCALLTYPE Initialize(const GUID *guid) noexcept override; 113 | 114 | DSC() = default; 115 | DSC(const DSC&) = delete; 116 | DSC& operator=(const DSC&) = delete; 117 | 118 | template 119 | T as() noexcept { return static_cast(this); } 120 | }; 121 | DSC mDSCIface; 122 | 123 | std::atomic mTotalRef{1u}, mFdRef{1u}, mDS8Ref{0u}, mDSCRef{0u}, mUnkRef{0u}; 124 | 125 | ComPtr mDS8Handle; 126 | ComPtr mDSCHandle; 127 | 128 | public: 129 | ~DSFullDuplex(); 130 | 131 | DSFullDuplex(const DSFullDuplex&) = delete; 132 | DSFullDuplex& operator=(const DSFullDuplex&) = delete; 133 | 134 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 135 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 136 | ULONG STDMETHODCALLTYPE Release() noexcept override; 137 | HRESULT STDMETHODCALLTYPE Initialize(const GUID *captureGuid, const GUID *renderGuid, const DSCBUFFERDESC *dscBufferDesc, const DSBUFFERDESC *dsBufferDesc, HWND hwnd, DWORD level, IDirectSoundCaptureBuffer8 **dsCaptureBuffer8, IDirectSoundBuffer8 **dsBuffer8) noexcept override; 138 | 139 | void finalize() noexcept 140 | { 141 | if(mTotalRef.fetch_sub(1u, std::memory_order_relaxed) == 1) [[unlikely]] 142 | delete this; 143 | } 144 | 145 | template [[nodiscard]] 146 | T as() noexcept { return static_cast(this); } 147 | 148 | static ComPtr Create(); 149 | }; 150 | 151 | #endif // DSFULLDUPLEX_H 152 | -------------------------------------------------------------------------------- /src/guidprinter.h: -------------------------------------------------------------------------------- 1 | #ifndef GUIDPRINTER_H 2 | #define GUIDPRINTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "eax.h" 16 | #include "vmanager.h" 17 | 18 | 19 | DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties, 0xcd5368e0, 0x3450, 0x11d3, 0x8b, 0x6e, 0x00, 0x10, 0x5a, 0x9b, 0x7b, 0xbc); 20 | DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties, 0xda0f0520, 0x300a, 0x11d3, 0x8a, 0x2b, 0x00, 0x60, 0x97, 0x0d, 0xb0, 0x11); 21 | DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties, 0xda0f0521, 0x300a, 0x11d3, 0x8a, 0x2b, 0x00, 0x60, 0x97, 0x0d, 0xb0, 0x11); 22 | 23 | 24 | struct IidTag { }; 25 | struct ClsidTag { }; 26 | struct PropidTag { }; 27 | struct DevidTag { }; 28 | struct Ds3dalgTag { }; 29 | struct FmtidTag { }; 30 | struct DsfxTag { }; 31 | 32 | class GuidPrinter { 33 | std::array mMsg{}; 34 | const char *mIdStr{}; 35 | 36 | void store(const GUID &guid) 37 | { 38 | std::snprintf(mMsg.data(), mMsg.size(), /* NOLINT(cppcoreguidelines-pro-type-vararg) */ 39 | "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", 40 | DWORD{guid.Data1}, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], 41 | guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); 42 | mIdStr = mMsg.data(); 43 | } 44 | 45 | void store_iid(const GUID &guid) 46 | { 47 | if(false) { } 48 | #define CHECKID(x) else if(guid == x) mIdStr = #x; 49 | CHECKID(GUID_NULL) 50 | CHECKID(IID_IDirectSound) 51 | CHECKID(IID_IDirectSound8) 52 | CHECKID(IID_IDirectSoundBuffer) 53 | CHECKID(IID_IDirectSoundBuffer8) 54 | CHECKID(IID_IDirectSound3DBuffer) 55 | CHECKID(IID_IDirectSound3DListener) 56 | CHECKID(IID_IDirectSoundNotify) 57 | CHECKID(IID_IDirectSoundCapture) 58 | CHECKID(IID_IDirectSoundCaptureBuffer) 59 | CHECKID(IID_IDirectSoundCaptureBuffer8) 60 | CHECKID(IID_IDirectSoundFullDuplex) 61 | CHECKID(IID_IKsPropertySet) 62 | CHECKID(IID_IClassFactory) 63 | CHECKID(IID_IUnknown) 64 | if(mIdStr) return; 65 | 66 | store(guid); 67 | } 68 | 69 | void store_propid(const GUID &guid) 70 | { 71 | if(false) { } 72 | CHECKID(DSPROPSETID_EAX10_ListenerProperties) 73 | CHECKID(DSPROPSETID_EAX10_BufferProperties) 74 | CHECKID(DSPROPSETID_EAX20_ListenerProperties) 75 | CHECKID(DSPROPSETID_EAX20_BufferProperties) 76 | CHECKID(DSPROPSETID_EAX30_ListenerProperties) 77 | CHECKID(DSPROPSETID_EAX30_BufferProperties) 78 | CHECKID(EAXPROPERTYID_EAX40_Context) 79 | CHECKID(EAXPROPERTYID_EAX40_FXSlot0) 80 | CHECKID(EAXPROPERTYID_EAX40_FXSlot1) 81 | CHECKID(EAXPROPERTYID_EAX40_FXSlot2) 82 | CHECKID(EAXPROPERTYID_EAX40_FXSlot3) 83 | CHECKID(EAXPROPERTYID_EAX40_Source) 84 | CHECKID(DSPROPSETID_VoiceManager) 85 | CHECKID(DSPROPSETID_DirectSoundDevice) 86 | CHECKID(DSPROPSETID_ZOOMFX_BufferProperties) 87 | CHECKID(DSPROPSETID_I3DL2_ListenerProperties) 88 | CHECKID(DSPROPSETID_I3DL2_BufferProperties) 89 | if(mIdStr) return; 90 | 91 | store(guid); 92 | } 93 | 94 | void store_dsfxid(const GUID &guid) 95 | { 96 | if(false) { } 97 | CHECKID(GUID_DSFX_STANDARD_CHORUS) 98 | CHECKID(GUID_DSFX_STANDARD_COMPRESSOR) 99 | CHECKID(GUID_DSFX_STANDARD_DISTORTION) 100 | CHECKID(GUID_DSFX_STANDARD_ECHO) 101 | CHECKID(GUID_DSFX_STANDARD_FLANGER) 102 | CHECKID(GUID_DSFX_STANDARD_GARGLE) 103 | CHECKID(GUID_DSFX_STANDARD_I3DL2REVERB) 104 | CHECKID(GUID_DSFX_STANDARD_PARAMEQ) 105 | CHECKID(GUID_DSFX_WAVES_REVERB) 106 | if(mIdStr) return; 107 | 108 | store(guid); 109 | } 110 | 111 | void store_ds3dalg(const GUID &guid) 112 | { 113 | if(false) { } 114 | CHECKID(DS3DALG_DEFAULT) 115 | CHECKID(DS3DALG_NO_VIRTUALIZATION) 116 | CHECKID(DS3DALG_HRTF_FULL) 117 | CHECKID(DS3DALG_HRTF_LIGHT) 118 | if(mIdStr) return; 119 | 120 | store(guid); 121 | } 122 | 123 | void store_devid(const GUID &guid) 124 | { 125 | if(false) { } 126 | CHECKID(GUID_NULL) 127 | CHECKID(DSDEVID_DefaultPlayback) 128 | CHECKID(DSDEVID_DefaultCapture) 129 | CHECKID(DSDEVID_DefaultVoicePlayback) 130 | CHECKID(DSDEVID_DefaultVoiceCapture) 131 | if(mIdStr) return; 132 | 133 | store(guid); 134 | } 135 | 136 | void store_clsid(const GUID &guid) 137 | { 138 | if(false) { } 139 | CHECKID(CLSID_DirectSound) 140 | CHECKID(CLSID_DirectSound8) 141 | CHECKID(CLSID_DirectSoundCapture) 142 | CHECKID(CLSID_DirectSoundCapture8) 143 | CHECKID(CLSID_DirectSoundFullDuplex) 144 | CHECKID(CLSID_DirectSoundPrivate) 145 | if(mIdStr) return; 146 | 147 | store(guid); 148 | } 149 | 150 | void store_fmtid(const GUID &guid) 151 | { 152 | if(false) { } 153 | CHECKID(KSDATAFORMAT_SUBTYPE_PCM) 154 | CHECKID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) 155 | #undef CHECKID 156 | if(mIdStr) return; 157 | 158 | store(guid); 159 | } 160 | 161 | public: 162 | explicit GuidPrinter(const GUID &guid) { store(guid); } 163 | GuidPrinter(IidTag, const GUID &guid) { store_iid(guid); } 164 | GuidPrinter(ClsidTag, const GUID &guid) { store_clsid(guid); } 165 | GuidPrinter(DevidTag, const GUID &guid) { store_devid(guid); } 166 | GuidPrinter(PropidTag, const GUID &guid) { store_propid(guid); } 167 | GuidPrinter(Ds3dalgTag, const GUID &guid) { store_ds3dalg(guid); } 168 | GuidPrinter(FmtidTag, const GUID &guid) { store_fmtid(guid); } 169 | GuidPrinter(DsfxTag, const GUID &guid) { store_dsfxid(guid); } 170 | 171 | explicit GuidPrinter(const GUID *guid) { if(!guid) mIdStr = "{null}"; else store(*guid); } 172 | GuidPrinter(ClsidTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_clsid(*guid); } 173 | GuidPrinter(DevidTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_devid(*guid); } 174 | GuidPrinter(PropidTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_propid(*guid); } 175 | GuidPrinter(Ds3dalgTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_ds3dalg(*guid); } 176 | GuidPrinter(FmtidTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_fmtid(*guid); } 177 | GuidPrinter(DsfxTag, const GUID *guid) { if(!guid) mIdStr = "{null}"; else store_dsfxid(*guid); } 178 | 179 | [[nodiscard]] 180 | const char *c_str() const { return mIdStr; } 181 | }; 182 | 183 | class IidPrinter : public GuidPrinter { 184 | public: 185 | template requires(!std::is_same_v,IidPrinter>) 186 | explicit IidPrinter(T&& guid) : GuidPrinter{IidTag{}, std::forward(guid)} { } 187 | }; 188 | 189 | class ClsidPrinter : public GuidPrinter { 190 | public: 191 | template requires(!std::is_same_v,ClsidPrinter>) 192 | explicit ClsidPrinter(T&& guid) : GuidPrinter{ClsidTag{}, std::forward(guid)} { } 193 | }; 194 | 195 | class PropidPrinter : public GuidPrinter { 196 | public: 197 | template requires(!std::is_same_v,PropidPrinter>) 198 | explicit PropidPrinter(T&& guid) : GuidPrinter{PropidTag{}, std::forward(guid)} { } 199 | }; 200 | 201 | class DevidPrinter : public GuidPrinter { 202 | public: 203 | template requires(!std::is_same_v,DevidPrinter>) 204 | explicit DevidPrinter(T&& guid) : GuidPrinter{DevidTag{}, std::forward(guid)} { } 205 | }; 206 | 207 | class Ds3dalgPrinter : public GuidPrinter { 208 | public: 209 | template requires(!std::is_same_v,Ds3dalgPrinter>) 210 | explicit Ds3dalgPrinter(T&& guid) : GuidPrinter{Ds3dalgTag{}, std::forward(guid)} { } 211 | }; 212 | 213 | class FmtidPrinter : public GuidPrinter { 214 | public: 215 | template requires(!std::is_same_v,FmtidPrinter>) 216 | explicit FmtidPrinter(T&& guid) : GuidPrinter{FmtidTag{}, std::forward(guid)} { } 217 | }; 218 | 219 | class DsfxPrinter : public GuidPrinter { 220 | public: 221 | template requires(!std::is_same_v,DsfxPrinter>) 222 | explicit DsfxPrinter(T&& guid) : GuidPrinter{DsfxTag{}, std::forward(guid)} { } 223 | }; 224 | 225 | #endif // GUIDPRINTER_H 226 | -------------------------------------------------------------------------------- /src/logging.cpp: -------------------------------------------------------------------------------- 1 | #include "logging.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define WIN32_LEAN_AND_MEAN 8 | #include 9 | 10 | #include "fmt/core.h" 11 | 12 | namespace { 13 | 14 | using namespace std::string_view_literals; 15 | 16 | std::mutex sLogMutex; 17 | 18 | } // namespace 19 | 20 | void dsoal_print_impl(LogLevel level, const fmt::string_view fmt, fmt::format_args args) 21 | { 22 | const auto msg = fmt::vformat(fmt, std::move(args)); 23 | 24 | auto prefix = "debug"sv; 25 | switch(level) 26 | { 27 | case LogLevel::Disable: break; 28 | case LogLevel::Debug: break; 29 | case LogLevel::Error: prefix = "err"sv; break; 30 | case LogLevel::Warning: prefix = "warn"sv; break; 31 | case LogLevel::Fixme: prefix = "fixme"sv; break; 32 | case LogLevel::Trace: prefix = "trace"sv; break; 33 | } 34 | 35 | auto _ = std::lock_guard{sLogMutex}; 36 | auto *logfile = gLogFile ? gLogFile : stderr; 37 | fmt::println(logfile, "{:04x}:{}:dsound:{}", GetCurrentThreadId(), prefix, msg); 38 | fflush(logfile); 39 | } 40 | -------------------------------------------------------------------------------- /src/logging.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGING_H 2 | #define LOGGING_H 3 | 4 | #include 5 | 6 | #include "dsoal.h" 7 | #include "fmt/core.h" 8 | 9 | 10 | namespace ds { 11 | 12 | template 13 | constexpr auto to_underlying(T e) noexcept -> std::underlying_type_t 14 | { return static_cast>(e); } 15 | 16 | } // namespace ds 17 | 18 | enum class LogLevel { 19 | Disable, 20 | Error, 21 | Fixme, 22 | Warning, 23 | Trace, 24 | Debug 25 | }; 26 | inline LogLevel gLogLevel{LogLevel::Error}; 27 | 28 | inline gsl::owner gLogFile{}; 29 | 30 | void dsoal_print_impl(LogLevel level, const fmt::string_view fmt, fmt::format_args args); 31 | 32 | template 33 | void dsoal_print(LogLevel level, fmt::format_string fmt, Args&& ...args) noexcept 34 | try { 35 | dsoal_print_impl(level, fmt, fmt::make_format_args(args...)); 36 | } catch(...) { } 37 | 38 | 39 | #define DEBUG(...) do { \ 40 | if(gLogLevel >= LogLevel::Debug) [[unlikely]] \ 41 | dsoal_print(LogLevel::Debug, PREFIX __VA_ARGS__); \ 42 | } while(0) 43 | 44 | #define TRACE(...) do { \ 45 | if(gLogLevel >= LogLevel::Trace) [[unlikely]] \ 46 | dsoal_print(LogLevel::Trace, PREFIX __VA_ARGS__); \ 47 | } while(0) 48 | 49 | #define WARN(...) do { \ 50 | if(gLogLevel >= LogLevel::Warning) [[unlikely]] \ 51 | dsoal_print(LogLevel::Warning, PREFIX __VA_ARGS__); \ 52 | } while(0) 53 | 54 | #define FIXME(...) do { \ 55 | if(gLogLevel >= LogLevel::Fixme) [[unlikely]] \ 56 | dsoal_print(LogLevel::Fixme, PREFIX __VA_ARGS__); \ 57 | } while(0) 58 | 59 | #define ERR(...) do { \ 60 | if(gLogLevel >= LogLevel::Error) [[unlikely]] \ 61 | dsoal_print(LogLevel::Error, PREFIX __VA_ARGS__); \ 62 | } while(0) 63 | 64 | #endif // LOGGING_H 65 | -------------------------------------------------------------------------------- /src/primarybuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIMARYBUFFER_H 2 | #define PRIMARYBUFFER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "AL/alc.h" 13 | 14 | 15 | class DSound8OAL; 16 | class Buffer; 17 | 18 | class PrimaryBuffer final : IDirectSoundBuffer { 19 | class Listener3D final : IDirectSound3DListener { 20 | auto impl_from_base() noexcept 21 | { 22 | #ifdef __GNUC__ 23 | _Pragma("GCC diagnostic push") 24 | _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 25 | #endif 26 | return CONTAINING_RECORD(this, PrimaryBuffer, mListener3D); 27 | #ifdef __GNUC__ 28 | _Pragma("GCC diagnostic pop") 29 | #endif 30 | } 31 | 32 | public: 33 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 34 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 35 | ULONG STDMETHODCALLTYPE Release() noexcept override; 36 | HRESULT STDMETHODCALLTYPE GetAllParameters(DS3DLISTENER *listener) noexcept override; 37 | HRESULT STDMETHODCALLTYPE GetDistanceFactor(D3DVALUE *distanceFactor) noexcept override; 38 | HRESULT STDMETHODCALLTYPE GetDopplerFactor(D3DVALUE *dopplerFactor) noexcept override; 39 | HRESULT STDMETHODCALLTYPE GetOrientation(D3DVECTOR *orientFront, D3DVECTOR *orientTop) noexcept override; 40 | HRESULT STDMETHODCALLTYPE GetPosition(D3DVECTOR *position) noexcept override; 41 | HRESULT STDMETHODCALLTYPE GetRolloffFactor(D3DVALUE *rolloffFactor) noexcept override; 42 | HRESULT STDMETHODCALLTYPE GetVelocity(D3DVECTOR *velocity) noexcept override; 43 | HRESULT STDMETHODCALLTYPE SetAllParameters(const DS3DLISTENER *listener, DWORD apply) noexcept override; 44 | HRESULT STDMETHODCALLTYPE SetDistanceFactor(D3DVALUE distanceFactor, DWORD apply) noexcept override; 45 | HRESULT STDMETHODCALLTYPE SetDopplerFactor(D3DVALUE dopplerFactor, DWORD apply) noexcept override; 46 | HRESULT STDMETHODCALLTYPE SetOrientation(D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, DWORD apply) noexcept override; 47 | HRESULT STDMETHODCALLTYPE SetPosition(D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply) noexcept override; 48 | HRESULT STDMETHODCALLTYPE SetRolloffFactor(D3DVALUE rolloffFactor, DWORD apply) noexcept override; 49 | HRESULT STDMETHODCALLTYPE SetVelocity(D3DVALUE x, D3DVALUE y, D3DVALUE z, DWORD apply) noexcept override; 50 | HRESULT STDMETHODCALLTYPE CommitDeferredSettings() noexcept override; 51 | 52 | Listener3D() = default; 53 | Listener3D(const Listener3D&) = delete; 54 | Listener3D& operator=(const Listener3D&) = delete; 55 | 56 | template 57 | T as() noexcept { return static_cast(this); } 58 | }; 59 | Listener3D mListener3D; 60 | 61 | class Prop final : IKsPropertySet { 62 | auto impl_from_base() noexcept 63 | { 64 | #ifdef __GNUC__ 65 | _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wcast-align\"") 66 | #endif 67 | return CONTAINING_RECORD(this, PrimaryBuffer, mProp); 68 | #ifdef __GNUC__ 69 | _Pragma("GCC diagnostic pop") 70 | #endif 71 | } 72 | 73 | public: 74 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 75 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 76 | ULONG STDMETHODCALLTYPE Release() noexcept override; 77 | HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ULONG cbPropData, ULONG *pcbReturned) noexcept override; 78 | HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ULONG cbPropData) noexcept override; 79 | HRESULT STDMETHODCALLTYPE QuerySupport(REFGUID guidPropSet, ULONG dwPropID, ULONG *pTypeSupport) noexcept override; 80 | 81 | Prop() = default; 82 | Prop(const Prop&) = delete; 83 | Prop& operator=(const Prop&) = delete; 84 | 85 | template 86 | T as() noexcept { return static_cast(this); } 87 | }; 88 | Prop mProp; 89 | 90 | std::atomic mTotalRef{0u}, mDsRef{0u}, mDs3dRef{0u}, mPropRef{0u}; 91 | 92 | DWORD mFlags{0u}; 93 | 94 | DSound8OAL &mParent; 95 | ALCcontext *mContext{}; 96 | 97 | std::recursive_mutex &mMutex; 98 | LONG mVolume{}; 99 | LONG mPan{}; 100 | 101 | DS3DLISTENER mImmediate{}; 102 | DS3DLISTENER mDeferred{}; 103 | enum DirtyFlags { 104 | Position, 105 | Velocity, 106 | Orientation, 107 | DistanceFactor, 108 | RolloffFactor, 109 | DopplerFactor, 110 | 111 | FlagCount 112 | }; 113 | std::bitset mDirty; 114 | 115 | std::unique_ptr mWriteEmu; 116 | WAVEFORMATEXTENSIBLE mFormat{}; 117 | bool mPlaying{false}; 118 | 119 | void setParams(const DS3DLISTENER ¶ms, const std::bitset flags); 120 | 121 | public: 122 | PrimaryBuffer() = delete; 123 | PrimaryBuffer(const PrimaryBuffer&) = delete; 124 | explicit PrimaryBuffer(DSound8OAL &parent); 125 | ~PrimaryBuffer(); 126 | 127 | PrimaryBuffer& operator=(const PrimaryBuffer&) = delete; 128 | 129 | /*** IUnknown methods ***/ 130 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 131 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 132 | ULONG STDMETHODCALLTYPE Release() noexcept override; 133 | /*** IDirectSoundBuffer methods ***/ 134 | HRESULT STDMETHODCALLTYPE GetCaps(DSBCAPS *bufferCaps) noexcept override; 135 | HRESULT STDMETHODCALLTYPE GetCurrentPosition(DWORD *playCursor, DWORD *writeCursor) noexcept override; 136 | HRESULT STDMETHODCALLTYPE GetFormat(WAVEFORMATEX *wfx, DWORD sizeAllocated, DWORD *sizeWritten) noexcept override; 137 | HRESULT STDMETHODCALLTYPE GetVolume(LONG *volume) noexcept override; 138 | HRESULT STDMETHODCALLTYPE GetPan(LONG *pan) noexcept override; 139 | HRESULT STDMETHODCALLTYPE GetFrequency(DWORD *frequency) noexcept override; 140 | HRESULT STDMETHODCALLTYPE GetStatus(DWORD *status) noexcept override; 141 | HRESULT STDMETHODCALLTYPE Initialize(IDirectSound *directSound, const DSBUFFERDESC *dsBufferDesc) noexcept override; 142 | HRESULT STDMETHODCALLTYPE Lock(DWORD offset, DWORD bytes, void **audioPtr1, DWORD *audioBytes1, void **audioPtr2, DWORD *audioBytes2, DWORD flags) noexcept override; 143 | HRESULT STDMETHODCALLTYPE Play(DWORD reserved1, DWORD reserved2, DWORD flags) noexcept override; 144 | HRESULT STDMETHODCALLTYPE SetCurrentPosition(DWORD newPosition) noexcept override; 145 | HRESULT STDMETHODCALLTYPE SetFormat(const WAVEFORMATEX *wfx) noexcept override; 146 | HRESULT STDMETHODCALLTYPE SetVolume(LONG volume) noexcept override; 147 | HRESULT STDMETHODCALLTYPE SetPan(LONG pan) noexcept override; 148 | HRESULT STDMETHODCALLTYPE SetFrequency(DWORD frequency) noexcept override; 149 | HRESULT STDMETHODCALLTYPE Stop() noexcept override; 150 | HRESULT STDMETHODCALLTYPE Unlock(void *audioPtr1, DWORD audioBytes1, void *audioPtr2, DWORD audioBytes2) noexcept override; 151 | HRESULT STDMETHODCALLTYPE Restore() noexcept override; 152 | 153 | void commit() noexcept; 154 | 155 | [[nodiscard]] 156 | float getCurrentRolloffFactor() const noexcept { return mImmediate.flRolloffFactor; } 157 | 158 | void setContext(ALCcontext *context) noexcept 159 | { mContext = context; } 160 | 161 | [[nodiscard]] 162 | auto getWriteEmu() const noexcept -> Buffer* { return mWriteEmu.get(); } 163 | 164 | [[nodiscard]] 165 | auto getFlags() const noexcept -> DWORD { return mFlags; } 166 | 167 | auto createWriteEmu(DWORD flags) noexcept -> HRESULT; 168 | 169 | void destroyWriteEmu() noexcept; 170 | 171 | template 172 | T as() noexcept { return static_cast(this); } 173 | }; 174 | 175 | #endif // PRIMARYBUFFER_H 176 | -------------------------------------------------------------------------------- /src/propset.h: -------------------------------------------------------------------------------- 1 | #ifndef PROPSET_H 2 | #define PROPSET_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "comptr.h" 9 | 10 | 11 | class DSPrivatePropertySet final : IKsPropertySet { 12 | std::atomic mRef{1u}; 13 | 14 | public: 15 | DSPrivatePropertySet(); 16 | ~DSPrivatePropertySet(); 17 | 18 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) noexcept override; 19 | ULONG STDMETHODCALLTYPE AddRef() noexcept override; 20 | ULONG STDMETHODCALLTYPE Release() noexcept override; 21 | HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ULONG cbPropData, ULONG *pcbReturned) noexcept override; 22 | HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData, ULONG cbPropData) noexcept override; 23 | HRESULT STDMETHODCALLTYPE QuerySupport(REFGUID guidPropSet, ULONG dwPropID, ULONG *pTypeSupport) noexcept override; 24 | 25 | template 26 | T as() noexcept { return static_cast(this); } 27 | 28 | static ComPtr Create(); 29 | }; 30 | 31 | #endif // PROPSET_H 32 | -------------------------------------------------------------------------------- /src/vmanager.h: -------------------------------------------------------------------------------- 1 | #ifndef VMANAGER_H 2 | #define VMANAGER_H 3 | 4 | #include 5 | 6 | 7 | inline constexpr GUID DSPROPSETID_VoiceManager{ 8 | 0x62a69bae, 9 | 0xdf9d,0x11d1, 10 | {0x99,0xa6,0x00,0xc0,0x4f,0xc9,0x9d,0x46} 11 | }; 12 | 13 | 14 | enum DSPROPERTY_VMANAGER { 15 | DSPROPERTY_VMANAGER_MODE = 0, 16 | DSPROPERTY_VMANAGER_PRIORITY, 17 | DSPROPERTY_VMANAGER_STATE 18 | }; 19 | 20 | 21 | enum VmMode { 22 | DSPROPERTY_VMANAGER_MODE_DEFAULT = 0, 23 | DSPROPERTY_VMANAGER_MODE_AUTO, 24 | DSPROPERTY_VMANAGER_MODE_REPORT, 25 | DSPROPERTY_VMANAGER_MODE_USER, 26 | VMANAGER_MODE_MAX 27 | }; 28 | 29 | 30 | enum VmState { 31 | DSPROPERTY_VMANAGER_STATE_PLAYING3DHW = 0, 32 | DSPROPERTY_VMANAGER_STATE_SILENT, 33 | DSPROPERTY_VMANAGER_STATE_BUMPED, 34 | DSPROPERTY_VMANAGER_STATE_PLAYFAILED, 35 | VMANAGER_STATE_MAX 36 | }; 37 | 38 | #endif // VMANAGER_H 39 | -------------------------------------------------------------------------------- /version.cmake: -------------------------------------------------------------------------------- 1 | EXECUTE_PROCESS( 2 | COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD 3 | OUTPUT_VARIABLE GIT_BRANCH 4 | OUTPUT_STRIP_TRAILING_WHITESPACE 5 | ) 6 | EXECUTE_PROCESS( 7 | COMMAND ${GIT_EXECUTABLE} log -1 --format=%h 8 | OUTPUT_VARIABLE GIT_COMMIT_HASH 9 | OUTPUT_STRIP_TRAILING_WHITESPACE 10 | ) 11 | CONFIGURE_FILE(${SRC} ${DST}) 12 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | /* Define to the library version */ 2 | #define DSOAL_VERSION "${LIB_VERSION}" 3 | 4 | /* Define the branch being built */ 5 | #define DSOAL_GIT_BRANCH "${GIT_BRANCH}" 6 | 7 | /* Define the hash of the head commit */ 8 | #define DSOAL_GIT_COMMIT_HASH "${GIT_COMMIT_HASH}" 9 | -------------------------------------------------------------------------------- /version.rc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2001 Ove Kaaven 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 | */ 18 | 19 | #define WINE_FILEDESCRIPTION_STR "Wine DirectSound" 20 | #define WINE_FILENAME_STR "dsound.dll" 21 | #define WINE_FILEVERSION 5,3,1,904 22 | #define WINE_FILEVERSION_STR "5.3.1.904" 23 | #define WINE_PRODUCTVERSION 5,3,1,904 24 | #define WINE_PRODUCTVERSION_STR "5.3.1.904" 25 | #define WINE_EXTRAVALUES VALUE "OLESelfRegister","" 26 | 27 | /* 28 | * Copyright 2001 Dmitry Timoshkov 29 | * Copyright 2004 Ivan Leo Puoti 30 | * 31 | * This library is free software; you can redistribute it and/or 32 | * modify it under the terms of the GNU Lesser General Public 33 | * License as published by the Free Software Foundation; either 34 | * version 2.1 of the License, or (at your option) any later version. 35 | * 36 | * This library is distributed in the hope that it will be useful, 37 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 38 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 39 | * Lesser General Public License for more details. 40 | * 41 | * You should have received a copy of the GNU Lesser General Public 42 | * License along with this library; if not, write to the Free Software 43 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 44 | */ 45 | 46 | #ifndef RC_INVOKED 47 | #include "windef.h" 48 | #include "winbase.h" 49 | #endif 50 | #include "winver.h" 51 | 52 | 53 | /* 54 | Assign WINE_FILEVERSION and WINE_FILEVERSION_STR high enough number 55 | to make sure that programs, relying on the version numbers, will 56 | never complain. 57 | */ 58 | 59 | #ifndef WINE_FILEVERSION_MAJOR 60 | #define WINE_FILEVERSION_MAJOR 10 61 | #endif 62 | 63 | #ifndef WINE_FILEVERSION_MINOR 64 | #define WINE_FILEVERSION_MINOR 0 65 | #endif 66 | 67 | #ifndef WINE_FILEVERSION_BUILD 68 | #define WINE_FILEVERSION_BUILD 0 69 | #endif 70 | 71 | #ifndef WINE_FILEVERSION_PLATFORMID 72 | #define WINE_FILEVERSION_PLATFORMID 0 73 | #endif 74 | 75 | #ifndef WINE_FILEVERSION 76 | #define WINE_FILEVERSION WINE_FILEVERSION_MAJOR,WINE_FILEVERSION_MINOR,\ 77 | WINE_FILEVERSION_BUILD,WINE_FILEVERSION_PLATFORMID 78 | #endif 79 | 80 | #define WINE_VER_STRINGIZE2(x) #x 81 | #define WINE_VER_STRINGIZE(x) WINE_VER_STRINGIZE2(x) 82 | 83 | #ifndef WINE_FILEVERSION_STR 84 | #define WINE_FILEVERSION_STR WINE_VER_STRINGIZE(WINE_FILEVERSION_MAJOR.WINE_FILEVERSION_MINOR.WINE_FILEVERSION_BUILD.WINE_FILEVERSION_PLATFORMID) 85 | #endif 86 | 87 | #ifndef WINE_FILEDESCRIPTION_STR 88 | #define WINE_FILEDESCRIPTION_STR "Wine core dll" 89 | #endif 90 | 91 | #ifndef WINE_FILENAME 92 | #define WINE_FILENAME "" 93 | #endif 94 | 95 | #ifndef WINE_FILENAME_STR 96 | #define WINE_FILENAME_STR "" 97 | #endif 98 | 99 | #ifndef WINE_FILETYPE 100 | #define WINE_FILETYPE VFT_DLL 101 | #endif 102 | 103 | #ifndef WINE_FILESUBTYPE 104 | #define WINE_FILESUBTYPE VFT2_UNKNOWN 105 | #endif 106 | 107 | #ifndef WINE_PRODUCTVERSION 108 | #define WINE_PRODUCTVERSION 1,0,0,0 109 | #endif 110 | 111 | #ifndef WINE_PRODUCTVERSION_STR 112 | #define WINE_PRODUCTVERSION_STR "1.0" 113 | #endif 114 | 115 | #ifndef WINE_PRODUCTNAME_STR 116 | #define WINE_PRODUCTNAME_STR "Wine" 117 | #endif 118 | 119 | #ifndef WINE_EXTRAVALUES 120 | #define WINE_EXTRAVALUES 121 | #endif 122 | 123 | VS_VERSION_INFO VERSIONINFO 124 | FILEVERSION WINE_FILEVERSION 125 | PRODUCTVERSION WINE_PRODUCTVERSION 126 | FILEFLAGSMASK 63 127 | FILEFLAGS 0 128 | FILEOS VOS_UNKNOWN 129 | FILETYPE WINE_FILETYPE 130 | FILESUBTYPE WINE_FILESUBTYPE 131 | { 132 | BLOCK "StringFileInfo" 133 | { 134 | BLOCK "040904E4" /* LANG_ENGLISH/SUBLANG_DEFAULT, CP 1252 */ 135 | { 136 | VALUE "CompanyName", "Microsoft Corporation" /* GameGuard depends on this */ 137 | VALUE "FileDescription", WINE_FILEDESCRIPTION_STR 138 | VALUE "FileVersion", WINE_FILEVERSION_STR 139 | VALUE "InternalName", WINE_FILENAME 140 | VALUE "LegalCopyright", "Copyright (c) 1993-2011 the Wine project authors (see the file AUTHORS for a complete list)" 141 | VALUE "OriginalFilename", WINE_FILENAME_STR 142 | VALUE "ProductName", WINE_PRODUCTNAME_STR 143 | VALUE "ProductVersion", WINE_PRODUCTVERSION_STR 144 | WINE_EXTRAVALUES 145 | } 146 | } 147 | BLOCK "VarFileInfo" 148 | { 149 | VALUE "Translation", 0x0409, 0x04E4 /* LANG_ENGLISH/SUBLANG_DEFAULT, CP 1252 */ 150 | } 151 | } 152 | --------------------------------------------------------------------------------