From e2d0f24a0d9cff4f0f6c695d74c4f1b202cfa5a6 Mon Sep 17 00:00:00 2001 From: Scott Miller <73297684+ScottThomasMiller@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:38:19 -0400 Subject: [PATCH] Swift Bindings with updated cmake files and standalone executable CI tests --- .github/workflows/run_unix.yml | 79 + .gitignore | 9 +- src/board_controller/ant_neuro/build.cmake | 1 + src/board_controller/build.cmake | 1 + src/board_controller/gtec/build.cmake | 2 + .../muse/muse_bglib/build.cmake | 3 +- .../neuromd/brainbit_bglib/build.cmake | 3 +- src/board_controller/neuromd/build.cmake | 3 +- .../openbci/ganglion_bglib/build.cmake | 1 + src/data_handler/build.cmake | 1 + src/ml/build.cmake | 1 + src/ml/onnx/build.cmake | 3 +- src/utils/bluetooth/build.cmake | 1 + swift_package/BrainFlow/BrainFlow.h | 13 + swift_package/BrainFlow/Package.resolved | 16 + swift_package/BrainFlow/Package.swift | 33 + swift_package/BrainFlow/README.md | 4 + .../BrainFlow/Sources/BoardDescription.swift | 47 + .../BrainFlow/Sources/BoardShim.swift | 606 ++++ .../BrainFlow/Sources/BrainFlow/dummy.swift | 7 + .../BrainFlowBindings/BoardDescription.swift | 47 + .../Sources/BrainFlowBindings/BoardShim.swift | 606 ++++ .../BrainFlowConstants.swift | 234 ++ .../BrainFlowException.swift | 32 + .../BrainFlowExtensions.swift | 59 + .../BrainFlowInputParams.swift | 44 + .../BrainFlowBindings/DataFilter.swift | 650 +++++ .../Sources/BrainFlowBindings/MLModule.swift | 101 + .../Sources/BrainFlowConstants.swift | 234 ++ .../Sources/BrainFlowException.swift | 32 + .../Sources/BrainFlowExtensions.swift | 59 + .../Sources/BrainFlowInputParams.swift | 44 + .../BrainFlow/Sources/DataFilter.swift | 650 +++++ .../BrainFlow/Sources/MLModule.swift | 101 + .../Tests/BrainFlowTests/BoardShimTests.swift | 176 ++ .../BrainFlowTests/BrainFlowCITests.swift | 404 +++ .../Tests/BrainFlowTests/BrainFlowTests.swift | 11 + .../BrainFlowTests/DataFilterTests.swift | 110 + .../BrainFlowCI.xcodeproj/project.pbxproj | 2573 +++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../xcshareddata/swiftpm/Package.resolved | 25 + .../xcschemes/BrainFlowCI.xcscheme | 96 + .../xcschemes/BrainFlowCITests.xcscheme | 73 + .../xcschemes/band_power.xcscheme | 79 + .../xcschemes/band_power_all.xcscheme | 79 + .../xcschemes/brainflow_get_data.xcscheme | 85 + .../xcshareddata/xcschemes/denoising.xcscheme | 79 + .../xcschemes/downsampling.xcscheme | 79 + .../xcschemes/eeg_metrics.xcscheme | 79 + .../xcshareddata/xcschemes/ica.xcscheme | 79 + .../xcshareddata/xcschemes/markers.xcscheme | 79 + .../xcschemes/read_write_file.xcscheme | 79 + .../xcschemes/signal_filtering.xcscheme | 79 + .../xcschemes/transforms.xcscheme | 79 + swift_package/BrainFlowCI/Headers/BrainFlow.h | 13 + swift_package/LICENSE.txt | 21 + swift_package/README.md | 65 + .../examples/tests/band_power/main.swift | 51 + .../examples/tests/band_power_all/main.swift | 37 + .../brainflow_get_data.swift | 65 + .../examples/tests/denoising/main.swift | 66 + .../examples/tests/downsampling/main.swift | 48 + .../tests/eeg_metrics/eeg_metrics.swift | 103 + swift_package/examples/tests/ica/main.swift | 49 + .../examples/tests/markers/markers.swift | 79 + .../examples/tests/read_write_file/main.swift | 37 + .../tests/signal_filtering/main.swift | 61 + .../examples/tests/transforms/main.swift | 54 + 70 files changed, 8834 insertions(+), 5 deletions(-) create mode 100644 swift_package/BrainFlow/BrainFlow.h create mode 100644 swift_package/BrainFlow/Package.resolved create mode 100644 swift_package/BrainFlow/Package.swift create mode 100644 swift_package/BrainFlow/README.md create mode 100644 swift_package/BrainFlow/Sources/BoardDescription.swift create mode 100644 swift_package/BrainFlow/Sources/BoardShim.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlow/dummy.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BoardDescription.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BoardShim.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowConstants.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowException.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowExtensions.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowInputParams.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/DataFilter.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowBindings/MLModule.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowConstants.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowException.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowExtensions.swift create mode 100644 swift_package/BrainFlow/Sources/BrainFlowInputParams.swift create mode 100644 swift_package/BrainFlow/Sources/DataFilter.swift create mode 100644 swift_package/BrainFlow/Sources/MLModule.swift create mode 100644 swift_package/BrainFlow/Tests/BrainFlowTests/BoardShimTests.swift create mode 100644 swift_package/BrainFlow/Tests/BrainFlowTests/BrainFlowCITests.swift create mode 100644 swift_package/BrainFlow/Tests/BrainFlowTests/BrainFlowTests.swift create mode 100644 swift_package/BrainFlow/Tests/BrainFlowTests/DataFilterTests.swift create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.pbxproj create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCI.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCITests.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power_all.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/brainflow_get_data.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/denoising.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/downsampling.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/eeg_metrics.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/ica.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/markers.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/read_write_file.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/signal_filtering.xcscheme create mode 100644 swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/transforms.xcscheme create mode 100644 swift_package/BrainFlowCI/Headers/BrainFlow.h create mode 100644 swift_package/LICENSE.txt create mode 100644 swift_package/README.md create mode 100644 swift_package/examples/tests/band_power/main.swift create mode 100644 swift_package/examples/tests/band_power_all/main.swift create mode 100644 swift_package/examples/tests/brainflow_get_data/brainflow_get_data.swift create mode 100644 swift_package/examples/tests/denoising/main.swift create mode 100644 swift_package/examples/tests/downsampling/main.swift create mode 100644 swift_package/examples/tests/eeg_metrics/eeg_metrics.swift create mode 100644 swift_package/examples/tests/ica/main.swift create mode 100644 swift_package/examples/tests/markers/markers.swift create mode 100644 swift_package/examples/tests/read_write_file/main.swift create mode 100644 swift_package/examples/tests/signal_filtering/main.swift create mode 100644 swift_package/examples/tests/transforms/main.swift diff --git a/.github/workflows/run_unix.yml b/.github/workflows/run_unix.yml index e8eeaeb59..00a68ee54 100644 --- a/.github/workflows/run_unix.yml +++ b/.github/workflows/run_unix.yml @@ -149,6 +149,51 @@ jobs: sudo -H python3 -m pip install -U . - name: Install Python test Dependencies run: sudo -H python3 -m pip install -r $GITHUB_WORKSPACE/python_package/examples/tests/requirements.txt + # build Swift tests: + - name: build band_power Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme band_power + - name: build band_power_all Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme band_power_all + - name: build brainflow_get_data Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme brainflow_get_data + - name: build denoising Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme denoising + - name: build downsampling Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme downsampling + - name: build eeg_metrics Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme eeg_metrics + - name: build ica Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme ica + - name: build markers Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme markers + - name: build read_write_file Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme read_write_file + - name: build signal_filtering Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme signal_filtering + - name: build transforms Swift + run: | + cd $GITHUB_WORKSPACE/swift_package/BrainFlowCI + xcodebuild -project BrainFlowCI.xcodeproj -destination 'platform=My Mac' -scheme transforms # start testing - name: Run unit tests @@ -415,3 +460,37 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + - name: band_power Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/band_power + - name: band_power_all Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/band_power_all + - name: brainflow_get_data Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/brainflow_get_data + - name: denoising Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/denoising + - name: downsampling Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/downsampling + - name: eeg_metrics Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/eeg_metrics + - name: ica Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/ica + - name: markers Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/markers + - name: read_write_file Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/read_write_file + - name: signal_filtering Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/signal_filtering + - name: transforms Swift + run: | + $GITHUB_WORKSPACE/swift_package/BrainFlowCI/Build/Products/Debug/transforms + diff --git a/.gitignore b/.gitignore index 48a24aa52..129d3a01b 100644 --- a/.gitignore +++ b/.gitignore @@ -362,6 +362,7 @@ java_package/brainflow/src/main/resources/ matlab_package/brainflow/inc/ matlab_package/brainflow/lib/ python_package/brainflow/lib/ +swift_package/BrainFlow/lib/ rust_package/brainflow/lib/ rust_package/brainflow/inc/ src/ml/train/data/ @@ -379,4 +380,10 @@ Makefile CMakeSettings.json ._.gitignore -build/ \ No newline at end of file +build/ + +# swift_package stuff: +*.xcuserdata* +xcuserdata +.DS_Store +swift_package/BrainFlowCI/Frameworks diff --git a/src/board_controller/ant_neuro/build.cmake b/src/board_controller/ant_neuro/build.cmake index df9e966cd..a6f9be7b2 100644 --- a/src/board_controller/ant_neuro/build.cmake +++ b/src/board_controller/ant_neuro/build.cmake @@ -29,6 +29,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT APPLE AND NOT ANDROID) file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ant_neuro/linux/${ANT_LIB_NAME}" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/") + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ant_neuro/linux/${ANT_LIB_NAME}" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ant_neuro/linux/${ANT_LIB_NAME}" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ant_neuro/linux/${ANT_LIB_NAME}" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/ant_neuro/linux/${ANT_LIB_NAME}" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/") diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake index 4dad340b3..42ab0b5e6 100644 --- a/src/board_controller/build.cmake +++ b/src/board_controller/build.cmake @@ -188,6 +188,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${BOARD_CONTROLLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" diff --git a/src/board_controller/gtec/build.cmake b/src/board_controller/gtec/build.cmake index 98a480ef3..265c4b263 100644 --- a/src/board_controller/gtec/build.cmake +++ b/src/board_controller/gtec/build.cmake @@ -8,11 +8,13 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT APPLE AND NOT ANDROID) file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/") + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/matlab_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn_raspberry.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/") + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn_raspberry.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn_raspberry.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn_raspberry.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unicorn/lib/libunicorn_raspberry.so" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/") diff --git a/src/board_controller/muse/muse_bglib/build.cmake b/src/board_controller/muse/muse_bglib/build.cmake index f72d8587a..a88a0de3d 100644 --- a/src/board_controller/muse/muse_bglib/build.cmake +++ b/src/board_controller/muse/muse_bglib/build.cmake @@ -63,6 +63,7 @@ endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${MUSE_BLED_LIB} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${MUSE_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${MUSE_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${MUSE_BLED_LIB_NAME}" @@ -78,4 +79,4 @@ install ( LIBRARY DESTINATION lib INCLUDES DESTINATION inc ARCHIVE DESTINATION lib -) \ No newline at end of file +) diff --git a/src/board_controller/neuromd/brainbit_bglib/build.cmake b/src/board_controller/neuromd/brainbit_bglib/build.cmake index f4f1ffe93..e04c826b7 100644 --- a/src/board_controller/neuromd/brainbit_bglib/build.cmake +++ b/src/board_controller/neuromd/brainbit_bglib/build.cmake @@ -59,6 +59,7 @@ endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${BRAINBIT_BLED_LIB} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BRAINBIT_BLED_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BRAINBIT_BLED_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BRAINBIT_BLED_LIB_NAME}" @@ -74,4 +75,4 @@ install ( LIBRARY DESTINATION lib INCLUDES DESTINATION inc ARCHIVE DESTINATION lib -) \ No newline at end of file +) diff --git a/src/board_controller/neuromd/build.cmake b/src/board_controller/neuromd/build.cmake index 604adc530..3d50589bc 100644 --- a/src/board_controller/neuromd/build.cmake +++ b/src/board_controller/neuromd/build.cmake @@ -22,6 +22,7 @@ if (MSVC) endif (MSVC) if (APPLE) file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/") + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/") @@ -42,4 +43,4 @@ if (APPLE) ${CMAKE_CURRENT_SOURCE_DIR}/third_party/neurosdk/lib/lib${NEUROSDK_LIB_NAME}.dylib DESTINATION lib ) -endif (APPLE) \ No newline at end of file +endif (APPLE) diff --git a/src/board_controller/openbci/ganglion_bglib/build.cmake b/src/board_controller/openbci/ganglion_bglib/build.cmake index f72af74c9..e066d7ac3 100644 --- a/src/board_controller/openbci/ganglion_bglib/build.cmake +++ b/src/board_controller/openbci/ganglion_bglib/build.cmake @@ -57,6 +57,7 @@ endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${GANGLION_LIB} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${GANGLION_LIB_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${GANGLION_LIB_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${GANGLION_LIB_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${GANGLION_LIB_NAME}" diff --git a/src/data_handler/build.cmake b/src/data_handler/build.cmake index a9be27a29..903ea22a7 100644 --- a/src/data_handler/build.cmake +++ b/src/data_handler/build.cmake @@ -92,6 +92,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${DATA_HANDLER_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" diff --git a/src/ml/build.cmake b/src/ml/build.cmake index 120eaf4c3..a7e5f049c 100644 --- a/src/ml/build.cmake +++ b/src/ml/build.cmake @@ -95,6 +95,7 @@ endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${ML_MODULE_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/nodejs_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${ML_MODULE_COMPILED_NAME}" diff --git a/src/ml/onnx/build.cmake b/src/ml/onnx/build.cmake index 19cb534b3..40d40053f 100644 --- a/src/ml/onnx/build.cmake +++ b/src/ml/onnx/build.cmake @@ -28,6 +28,7 @@ endif (APPLE) if (NOT ANDROID) file (COPY ${ONNXRUNTIME_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/csharp_package/brainflow/brainflow/lib/) + file (COPY ${ONNXRUNTIME_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/) file (COPY ${ONNXRUNTIME_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/) file (COPY ${ONNXRUNTIME_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/) file (COPY ${ONNXRUNTIME_PATH} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/) @@ -39,4 +40,4 @@ install ( FILES ${ONNXRUNTIME_PATH} DESTINATION lib -) \ No newline at end of file +) diff --git a/src/utils/bluetooth/build.cmake b/src/utils/bluetooth/build.cmake index 43df2aa98..1343d102d 100644 --- a/src/utils/bluetooth/build.cmake +++ b/src/utils/bluetooth/build.cmake @@ -74,6 +74,7 @@ if (MSVC) endif (MSVC) if (UNIX AND NOT ANDROID) add_custom_command (TARGET ${BLUETOOTH_LIB_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/swift_package/BrainFlow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/python_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/julia_package/brainflow/lib/${BLUETOOTH_LIB_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/compiled/${BLUETOOTH_LIB_COMPILED_NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/java_package/brainflow/src/main/resources/${BLUETOOTH_LIB_COMPILED_NAME}" diff --git a/swift_package/BrainFlow/BrainFlow.h b/swift_package/BrainFlow/BrainFlow.h new file mode 100644 index 000000000..91ebeaafc --- /dev/null +++ b/swift_package/BrainFlow/BrainFlow.h @@ -0,0 +1,13 @@ +// +// Created by Scott Miller on 4/9/22. +// + +#ifndef BrainFlow_h +#define BrainFlow_h + +#include "board_controller.h" +#include "data_handler.h" +#include "board_info_getter.h" +#include "ml_module.h" + +#endif /* BrainFlow_h */ diff --git a/swift_package/BrainFlow/Package.resolved b/swift_package/BrainFlow/Package.resolved new file mode 100644 index 000000000..59404d3ee --- /dev/null +++ b/swift_package/BrainFlow/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "swift-numerics", + "repositoryURL": "https://github.com/apple/swift-numerics.git", + "state": { + "branch": null, + "revision": "0a5bc04095a675662cf24757cc0640aa2204253b", + "version": "1.0.2" + } + } + ] + }, + "version": 1 +} diff --git a/swift_package/BrainFlow/Package.swift b/swift_package/BrainFlow/Package.swift new file mode 100644 index 000000000..50a5dca83 --- /dev/null +++ b/swift_package/BrainFlow/Package.swift @@ -0,0 +1,33 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "BrainFlow", + platforms: [ + .macOS(.v10_15), .iOS(.v13) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library(name: "BrainFlow", + targets: ["BrainFlow"]) + ], + dependencies: [ + .package(name: "swift-numerics", + url: "https://github.com/apple/swift-numerics.git", .upToNextMajor(from: "1.0.0")) + ], + targets: [ + .target( + name: "BrainFlow", + dependencies: [.product(name: "Numerics", package: "swift-numerics")] + ), + .testTarget( + name: "BrainFlowTests", + dependencies: ["BrainFlow", .product(name: "Numerics", package: "swift-numerics")], + sources: ["BoardShimTests.swift", + "BrainFlowCItests.swift", + "BrainFlowTests.swift", + "DataFilterTests.swift"] + ) + ] +) + diff --git a/swift_package/BrainFlow/README.md b/swift_package/BrainFlow/README.md new file mode 100644 index 000000000..302f10337 --- /dev/null +++ b/swift_package/BrainFlow/README.md @@ -0,0 +1,4 @@ +# BrainFlow + +Swift bindings for the BrainFlow C++ API. Contributed by Scott Miller for Aeris Rising, LLC. + diff --git a/swift_package/BrainFlow/Sources/BoardDescription.swift b/swift_package/BrainFlow/Sources/BoardDescription.swift new file mode 100644 index 000000000..3d5824ac4 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BoardDescription.swift @@ -0,0 +1,47 @@ +// +// BoardDescription.swift +// a Swift reimagining of BrainFlow's board_description data type +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// +import Foundation +//import BrainFlow + +struct BoardDescription: Codable, Equatable { + let package_num_channel: Int32 + let timestamp_channel: Int32 + let accel_channels: [Int32]? + let ecg_channels: [Int32]? + let eeg_channels: [Int32]? + let eeg_names: String? + let emg_channels: [Int32]? + let eog_channels: [Int32]? + let marker_channel: Int32? + let name: String? + let num_rows: Int32? + let sampling_rate: Int32? + let battery_channel: Int32? + let eda_channels: [Int32]? + let gyro_channels: [Int32]? + let ppg_channels: [Int32]? + let resistance_channels: [Int32]? + let temperature_channels: [Int32]? + + // decode the input JSON into self: + init(_ descriptionJSON: String) throws { + guard descriptionJSON != "" else { + throw BrainFlowException("Nil board description JSON", .JSON_NOT_FOUND_ERROR) + } + + let decoder = JSONDecoder() + let jsonData = Data(descriptionJSON.utf8) + + do { + let json = try decoder.decode(type(of: self), from: jsonData) + self = json + } catch { + try? BoardShim.logMessage(.LEVEL_CRITICAL, "board description JSON decoding error:\n \(error)") + throw BrainFlowException("Invalid board description JSON", .NO_SUCH_DATA_IN_JSON_ERROR) + } + } +} diff --git a/swift_package/BrainFlow/Sources/BoardShim.swift b/swift_package/BrainFlow/Sources/BoardShim.swift new file mode 100644 index 000000000..ec13068b7 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BoardShim.swift @@ -0,0 +1,606 @@ +// +// BoardShim.swift +// a Swift binding for BrainFlow's board_shim high-level API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// + +import Foundation +//import BrainFlow + +struct BoardShim { + let boardId: BoardIds + let masterBoardId: BoardIds + let bfParams: BrainFlowInputParams + private let jsonBrainFlowInputParams: [CChar] + + init (_ boardId: BoardIds, _ params: BrainFlowInputParams) throws { + self.boardId = boardId + self.bfParams = params + self.masterBoardId = try BoardShim.getMasterBoardID(boardId: boardId, params: params) + self.jsonBrainFlowInputParams = params.json().cString(using: String.Encoding.utf8)! + } + + /** + * enable BrainFlow logger with level INFO + */ + static func enableBoardLogger() throws { + try setLogLevel(.LEVEL_INFO) + } + + /** + * enable BrainFlow logger with level TRACE + */ + static func enableDevBoardLogger() throws { + try setLogLevel(.LEVEL_TRACE) + } + + /** + * disable BrainFlow logger + */ + static func disableBoardLogger() throws { + try setLogLevel(.LEVEL_OFF) + } + + /** + * redirect logger from stderr to a file + */ + static func setLogFile (_ logFile: String) throws + { + var cLogFile = logFile.cString(using: String.Encoding.utf8)! + let errorCode = set_log_file_board_controller(&cLogFile) + try checkErrorCode("failed to set log file", errorCode) + } + + /** + * set log level + */ + static func setLogLevel (_ logLevel: LogLevels) throws + { + let errorCode = set_log_level_board_controller (logLevel.rawValue) + try checkErrorCode("failed to set log level", errorCode) + } + + /** + * send user defined strings to BrainFlow logger + */ + static func logMessage (_ logLevel: LogLevels, _ message: String) throws { + var cMessage = message.cString(using: String.Encoding.utf8)! + let errorCode = log_message_board_controller (logLevel.rawValue, &cMessage) + try checkErrorCode("Error in log_message", errorCode) + } + + /** + * get sampling rate for this board + */ + static func getSamplingRate (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var samplingRate: Int32 = 0 + let errorCode = get_sampling_rate (boardId.rawValue, preset.rawValue, &samplingRate) + try checkErrorCode("Error in board info getter", errorCode) + + return samplingRate + } + + /** + * get row index in returned by get_board_data() 2d array which contains timestamps + */ + static func getTimestampChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var timestampChannel: Int32 = 0 + let errorCode = get_timestamp_channel (boardId.rawValue, preset.rawValue, ×tampChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return timestampChannel + } + + /** + * get row index in returned by get_board_data() 2d array which contains markers + */ + static func getMarkerChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 + { + var markerChannel: Int32 = 0 + let errorCode = get_marker_channel (boardId.rawValue, preset.rawValue, &markerChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return markerChannel + } + + /** + * get number of rows in returned by get_board_data() 2d array + */ + static func getNumRows (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var numRows: Int32 = 0 + let errorCode = get_num_rows (boardId.rawValue, preset.rawValue, &numRows) + try checkErrorCode("Error in board info getter", errorCode) + + return numRows + } + + /** + * get row index in returned by get_board_data() 2d array which contains package nums + */ + static func getPackageNumChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var pkgNumChannel: Int32 = 0 + let errorCode = get_package_num_channel (boardId.rawValue, preset.rawValue, &pkgNumChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return pkgNumChannel + } + + /** + * get row index in returned by get_board_data() 2d array which contains battery level + */ + static func getBatteryChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var batteryChannel: Int32 = 0 + let errorCode = get_battery_channel (boardId.rawValue, preset.rawValue, &batteryChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return batteryChannel + } + + /** + * Get names of EEG electrodes in 10-20 system. Only if electrodes have freezed + * locations + */ + static func getEEGnames (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [String] { + var stringLen: Int32 = 0 + var bytes = [CChar](repeating: 0, count: 4096) + let errorCode = get_eeg_names (boardId.rawValue, preset.rawValue, &bytes, &stringLen) + try checkErrorCode("Error in board info getter", errorCode) + let EEGnames = bytes.toString(stringLen) + + return EEGnames.components(separatedBy: ",") + } + + /** + * Get board description + */ + static func getBoardDescr (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> BoardDescription { + var boardDescrStr = [CChar](repeating: CChar(0), count: 16000) + var stringLen: Int32 = 0 + let errorCode = get_board_descr (boardId.rawValue, preset.rawValue, &boardDescrStr, &stringLen) + try checkErrorCode("failed to get board info", errorCode) + + return try BoardDescription(boardDescrStr.toString(stringLen)) + } + + /** + * Get device name + */ + static func getDeviceName (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> String { + var stringLen: Int32 = 0 + var deviceName = [CChar](repeating: CChar(0), count: 4096) + let errorCode = get_device_name (boardId.rawValue, preset.rawValue, &deviceName, &stringLen) + try checkErrorCode("Error in board info getter", errorCode) + + return deviceName.toString(stringLen) + } + + /** + * get row indices in returned by get_board_data() 2d array which contain channel + * data, for some boards we can not split EEG\EMG\... and return the same array + */ + static func getEEGchannels (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eeg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_emg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_ecg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_temperature_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var presets = [Int32](repeating: 0, count: 512) + let errorCode = get_board_presets (boardId.rawValue, &presets, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(presets[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_resistance_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eog_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_exg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eda_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_ppg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_accel_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_analog_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_gyro_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_other_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. BoardIds { + guard ((boardId == BoardIds.STREAMING_BOARD) || (boardId == BoardIds.PLAYBACK_FILE_BOARD)) else { + return boardId + } + if let otherInfoInt = Int32(params.other_info) { + if let masterBoardId = BoardIds(rawValue: otherInfoInt) { + return masterBoardId + } + } + throw BrainFlowException ("need to set params.otherInfo to master board id", + BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR) + } + + /** + * prepare steaming session, allocate resources + */ + func prepareSession() throws { + try? BoardShim.logMessage(.LEVEL_INFO, "prepare session") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = prepare_session(boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to prepare session", errorCode) + } + + /** + * Get Board Id, can be different than provided (playback or streaming board) + */ + func getBoardId () throws -> BoardIds { + return self.masterBoardId + } + + /** + * send string to a board, use this method carefully and only if you understand what you are doing + */ + func configBoard (_ config: String) throws -> String { + var responseLen: Int32 = 0 + var response = [CChar](repeating: CChar(0), count: 4096) + var cConfig = config.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = config_board (&cConfig, &response, &responseLen, boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in config_board", errorCode) + + return response.toString(responseLen) + } + + /** + * start streaming thread, store data in internal ringbuffer and stream them + * from brainflow at the same time + * + * @param buffer_size size of internal ringbuffer + * + * @param streamer_params supported vals: "file://%file_name%:w", + * "file://%file_name%:a", + * "streaming_board://%multicast_group_ip%:%port%". Range + * for multicast addresses is from "224.0.0.0" to + * "239.255.255.255" + */ + func startStream (bufferSize: Int32, streamerParams: String) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "start streaming. buffer size: \(bufferSize)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = start_stream (bufferSize, &cStreamerParams, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * start streaming thread, store data in internal ringbuffer + */ + func startStream () throws { + try startStream (bufferSize: 450000, streamerParams: "") + } + + /** + * start streaming thread, store data in internal ringbuffer + */ + func startStream (bufferSize: Int32) throws { + try startStream (bufferSize: bufferSize, streamerParams: "") + } + + /** + * add streamer + * @param streamer_params use it to pass data packages further or store them directly during + streaming, supported values: "file://%file_name%:w", "file://%file_name%:a", + "streaming_board://%multicast_group_ip%:%port%"". Range for multicast addresses is from + "224.0.0.0" to "239.255.255.255" + */ + func addStreamer (streamerParams: String, preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "add streamer. streamer params: \(streamerParams)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = add_streamer (&cStreamerParams, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * delete streamer + * @param streamer_params use it to pass data packages further or store them directly during + streaming, supported values: "file://%file_name%:w", "file://%file_name%:a", + "streaming_board://%multicast_group_ip%:%port%"". Range for multicast addresses is from + "224.0.0.0" to "239.255.255.255" + */ + func deleteStreamer (streamerParams: String, preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "add streamer. streamer params: \(streamerParams)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = delete_streamer (&cStreamerParams, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * stop streaming thread + */ + func stopStream () throws { + try? BoardShim.logMessage(.LEVEL_INFO, "stop streaming") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = stop_stream (boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in stop_stream", errorCode) + } + + /** + * release all resources + */ + func releaseSession () throws { + try? BoardShim.logMessage(.LEVEL_INFO, "release session") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = release_session (boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to release session", errorCode) + } + + /** + * get number of packages in ringbuffer + */ + func getBoardDataCount (_ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var dataCount: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = get_board_data_count (preset.rawValue, &dataCount, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to get board data count", errorCode) + + return dataCount + } + + /** + * insert marker to data stream + */ + func insertMarker (value: Double, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = insert_marker (value, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in insert_marker", errorCode) + } + + /** + * check session status + */ + func isPrepared () throws -> Bool { + var intPrepared: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = is_prepared (&intPrepared, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to check session", errorCode) + + return NSNumber(value: intPrepared).boolValue + } + + /** + * get latest collected data, can return less than "num_samples", doesnt flush + * it from ringbuffer + */ + func getCurrentBoardData (_ numSamples: Int32, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [[Double]] + { + var numRows: Int32 = 0 + var currentSize: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + + do { + numRows = try BoardShim.getNumRows (getBoardId()) } + catch { + throw error + } + + var buffer = [Double](repeating: 0.0, count: Int(numSamples * numRows)) + let errorCode = get_current_board_data (numSamples, preset.rawValue, &buffer, ¤tSize, + boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in get_current_board_data", errorCode) + + return buffer.matrix2D(rowLength: Int(numSamples)) + } + + /** + * get all data from the default ringbuffer and flush it + */ + func getDefData () throws -> [[Double]] { + let size = try getBoardDataCount() + guard size > 0 else { + return [[Double]]() + } + + return try getBoardData(size) + } + + /** + * get all data from the auxiliary ringbuffer and flush it + */ + func getAuxData () throws -> [[Double]] { + let preset = BrainFlowPresets.AUXILIARY_PRESET + let size = try getBoardDataCount(preset) + guard size > 0 else { + return [[Double]]() + } + + return try getBoardData(size, preset) + } + + /** + * get all data from the ancillary ringbuffer and flush it + */ + func getAncData () throws -> [[Double]] { + let preset = BrainFlowPresets.ANCILLARY_PRESET + let size = try getBoardDataCount(preset) + + guard size > 0 else { + return [[Double]]() + } + return try getBoardData(size, preset) + } + + func getBoardData (_ size: Int32? = nil, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [[Double]] { + var jsonBFParams = self.jsonBrainFlowInputParams + let numRows = try BoardShim.getNumRows (getBoardId()) + var numSamples: Int32 = 0 + if let testSize = size { + // size is not nil + if testSize < 1 { + throw BrainFlowException("invalid num_samples", BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR) + } + numSamples = testSize + } else { + // size is nil, so get all available data: + numSamples = try getBoardDataCount(preset) + } + var buffer = [Double](repeating: 0.0, count: Int(numSamples * numRows)) + let errorCode = get_board_data (numSamples, preset.rawValue, &buffer, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to get board data", errorCode) + + return buffer.matrix2D(rowLength: Int(numSamples)) + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlow/dummy.swift b/swift_package/BrainFlow/Sources/BrainFlow/dummy.swift new file mode 100644 index 000000000..201f7bfd4 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlow/dummy.swift @@ -0,0 +1,7 @@ + +import Foundation + +struct dummy { + let num = 1 +} + diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardDescription.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardDescription.swift new file mode 100644 index 000000000..3d5824ac4 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardDescription.swift @@ -0,0 +1,47 @@ +// +// BoardDescription.swift +// a Swift reimagining of BrainFlow's board_description data type +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// +import Foundation +//import BrainFlow + +struct BoardDescription: Codable, Equatable { + let package_num_channel: Int32 + let timestamp_channel: Int32 + let accel_channels: [Int32]? + let ecg_channels: [Int32]? + let eeg_channels: [Int32]? + let eeg_names: String? + let emg_channels: [Int32]? + let eog_channels: [Int32]? + let marker_channel: Int32? + let name: String? + let num_rows: Int32? + let sampling_rate: Int32? + let battery_channel: Int32? + let eda_channels: [Int32]? + let gyro_channels: [Int32]? + let ppg_channels: [Int32]? + let resistance_channels: [Int32]? + let temperature_channels: [Int32]? + + // decode the input JSON into self: + init(_ descriptionJSON: String) throws { + guard descriptionJSON != "" else { + throw BrainFlowException("Nil board description JSON", .JSON_NOT_FOUND_ERROR) + } + + let decoder = JSONDecoder() + let jsonData = Data(descriptionJSON.utf8) + + do { + let json = try decoder.decode(type(of: self), from: jsonData) + self = json + } catch { + try? BoardShim.logMessage(.LEVEL_CRITICAL, "board description JSON decoding error:\n \(error)") + throw BrainFlowException("Invalid board description JSON", .NO_SUCH_DATA_IN_JSON_ERROR) + } + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardShim.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardShim.swift new file mode 100644 index 000000000..ec13068b7 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BoardShim.swift @@ -0,0 +1,606 @@ +// +// BoardShim.swift +// a Swift binding for BrainFlow's board_shim high-level API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// + +import Foundation +//import BrainFlow + +struct BoardShim { + let boardId: BoardIds + let masterBoardId: BoardIds + let bfParams: BrainFlowInputParams + private let jsonBrainFlowInputParams: [CChar] + + init (_ boardId: BoardIds, _ params: BrainFlowInputParams) throws { + self.boardId = boardId + self.bfParams = params + self.masterBoardId = try BoardShim.getMasterBoardID(boardId: boardId, params: params) + self.jsonBrainFlowInputParams = params.json().cString(using: String.Encoding.utf8)! + } + + /** + * enable BrainFlow logger with level INFO + */ + static func enableBoardLogger() throws { + try setLogLevel(.LEVEL_INFO) + } + + /** + * enable BrainFlow logger with level TRACE + */ + static func enableDevBoardLogger() throws { + try setLogLevel(.LEVEL_TRACE) + } + + /** + * disable BrainFlow logger + */ + static func disableBoardLogger() throws { + try setLogLevel(.LEVEL_OFF) + } + + /** + * redirect logger from stderr to a file + */ + static func setLogFile (_ logFile: String) throws + { + var cLogFile = logFile.cString(using: String.Encoding.utf8)! + let errorCode = set_log_file_board_controller(&cLogFile) + try checkErrorCode("failed to set log file", errorCode) + } + + /** + * set log level + */ + static func setLogLevel (_ logLevel: LogLevels) throws + { + let errorCode = set_log_level_board_controller (logLevel.rawValue) + try checkErrorCode("failed to set log level", errorCode) + } + + /** + * send user defined strings to BrainFlow logger + */ + static func logMessage (_ logLevel: LogLevels, _ message: String) throws { + var cMessage = message.cString(using: String.Encoding.utf8)! + let errorCode = log_message_board_controller (logLevel.rawValue, &cMessage) + try checkErrorCode("Error in log_message", errorCode) + } + + /** + * get sampling rate for this board + */ + static func getSamplingRate (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var samplingRate: Int32 = 0 + let errorCode = get_sampling_rate (boardId.rawValue, preset.rawValue, &samplingRate) + try checkErrorCode("Error in board info getter", errorCode) + + return samplingRate + } + + /** + * get row index in returned by get_board_data() 2d array which contains timestamps + */ + static func getTimestampChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var timestampChannel: Int32 = 0 + let errorCode = get_timestamp_channel (boardId.rawValue, preset.rawValue, ×tampChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return timestampChannel + } + + /** + * get row index in returned by get_board_data() 2d array which contains markers + */ + static func getMarkerChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 + { + var markerChannel: Int32 = 0 + let errorCode = get_marker_channel (boardId.rawValue, preset.rawValue, &markerChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return markerChannel + } + + /** + * get number of rows in returned by get_board_data() 2d array + */ + static func getNumRows (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var numRows: Int32 = 0 + let errorCode = get_num_rows (boardId.rawValue, preset.rawValue, &numRows) + try checkErrorCode("Error in board info getter", errorCode) + + return numRows + } + + /** + * get row index in returned by get_board_data() 2d array which contains package nums + */ + static func getPackageNumChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var pkgNumChannel: Int32 = 0 + let errorCode = get_package_num_channel (boardId.rawValue, preset.rawValue, &pkgNumChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return pkgNumChannel + } + + /** + * get row index in returned by get_board_data() 2d array which contains battery level + */ + static func getBatteryChannel (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var batteryChannel: Int32 = 0 + let errorCode = get_battery_channel (boardId.rawValue, preset.rawValue, &batteryChannel) + try checkErrorCode("Error in board info getter", errorCode) + + return batteryChannel + } + + /** + * Get names of EEG electrodes in 10-20 system. Only if electrodes have freezed + * locations + */ + static func getEEGnames (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [String] { + var stringLen: Int32 = 0 + var bytes = [CChar](repeating: 0, count: 4096) + let errorCode = get_eeg_names (boardId.rawValue, preset.rawValue, &bytes, &stringLen) + try checkErrorCode("Error in board info getter", errorCode) + let EEGnames = bytes.toString(stringLen) + + return EEGnames.components(separatedBy: ",") + } + + /** + * Get board description + */ + static func getBoardDescr (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> BoardDescription { + var boardDescrStr = [CChar](repeating: CChar(0), count: 16000) + var stringLen: Int32 = 0 + let errorCode = get_board_descr (boardId.rawValue, preset.rawValue, &boardDescrStr, &stringLen) + try checkErrorCode("failed to get board info", errorCode) + + return try BoardDescription(boardDescrStr.toString(stringLen)) + } + + /** + * Get device name + */ + static func getDeviceName (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> String { + var stringLen: Int32 = 0 + var deviceName = [CChar](repeating: CChar(0), count: 4096) + let errorCode = get_device_name (boardId.rawValue, preset.rawValue, &deviceName, &stringLen) + try checkErrorCode("Error in board info getter", errorCode) + + return deviceName.toString(stringLen) + } + + /** + * get row indices in returned by get_board_data() 2d array which contain channel + * data, for some boards we can not split EEG\EMG\... and return the same array + */ + static func getEEGchannels (_ boardId: BoardIds, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eeg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_emg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_ecg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_temperature_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var presets = [Int32](repeating: 0, count: 512) + let errorCode = get_board_presets (boardId.rawValue, &presets, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(presets[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_resistance_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eog_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_exg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_eda_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_ppg_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_accel_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_analog_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_gyro_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. [Int32] { + var len: Int32 = 0 + var channels = [Int32](repeating: 0, count: 512) + let errorCode = get_other_channels (boardId.rawValue, preset.rawValue, &channels, &len) + try checkErrorCode("Error in board info getter", errorCode) + + return Array(channels[0.. BoardIds { + guard ((boardId == BoardIds.STREAMING_BOARD) || (boardId == BoardIds.PLAYBACK_FILE_BOARD)) else { + return boardId + } + if let otherInfoInt = Int32(params.other_info) { + if let masterBoardId = BoardIds(rawValue: otherInfoInt) { + return masterBoardId + } + } + throw BrainFlowException ("need to set params.otherInfo to master board id", + BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR) + } + + /** + * prepare steaming session, allocate resources + */ + func prepareSession() throws { + try? BoardShim.logMessage(.LEVEL_INFO, "prepare session") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = prepare_session(boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to prepare session", errorCode) + } + + /** + * Get Board Id, can be different than provided (playback or streaming board) + */ + func getBoardId () throws -> BoardIds { + return self.masterBoardId + } + + /** + * send string to a board, use this method carefully and only if you understand what you are doing + */ + func configBoard (_ config: String) throws -> String { + var responseLen: Int32 = 0 + var response = [CChar](repeating: CChar(0), count: 4096) + var cConfig = config.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = config_board (&cConfig, &response, &responseLen, boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in config_board", errorCode) + + return response.toString(responseLen) + } + + /** + * start streaming thread, store data in internal ringbuffer and stream them + * from brainflow at the same time + * + * @param buffer_size size of internal ringbuffer + * + * @param streamer_params supported vals: "file://%file_name%:w", + * "file://%file_name%:a", + * "streaming_board://%multicast_group_ip%:%port%". Range + * for multicast addresses is from "224.0.0.0" to + * "239.255.255.255" + */ + func startStream (bufferSize: Int32, streamerParams: String) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "start streaming. buffer size: \(bufferSize)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = start_stream (bufferSize, &cStreamerParams, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * start streaming thread, store data in internal ringbuffer + */ + func startStream () throws { + try startStream (bufferSize: 450000, streamerParams: "") + } + + /** + * start streaming thread, store data in internal ringbuffer + */ + func startStream (bufferSize: Int32) throws { + try startStream (bufferSize: bufferSize, streamerParams: "") + } + + /** + * add streamer + * @param streamer_params use it to pass data packages further or store them directly during + streaming, supported values: "file://%file_name%:w", "file://%file_name%:a", + "streaming_board://%multicast_group_ip%:%port%"". Range for multicast addresses is from + "224.0.0.0" to "239.255.255.255" + */ + func addStreamer (streamerParams: String, preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "add streamer. streamer params: \(streamerParams)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = add_streamer (&cStreamerParams, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * delete streamer + * @param streamer_params use it to pass data packages further or store them directly during + streaming, supported values: "file://%file_name%:w", "file://%file_name%:a", + "streaming_board://%multicast_group_ip%:%port%"". Range for multicast addresses is from + "224.0.0.0" to "239.255.255.255" + */ + func deleteStreamer (streamerParams: String, preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + try? BoardShim.logMessage(.LEVEL_INFO, "add streamer. streamer params: \(streamerParams)") + var cStreamerParams = streamerParams.cString(using: String.Encoding.utf8)! + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = delete_streamer (&cStreamerParams, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to start stream", errorCode) + } + + /** + * stop streaming thread + */ + func stopStream () throws { + try? BoardShim.logMessage(.LEVEL_INFO, "stop streaming") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = stop_stream (boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in stop_stream", errorCode) + } + + /** + * release all resources + */ + func releaseSession () throws { + try? BoardShim.logMessage(.LEVEL_INFO, "release session") + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = release_session (boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to release session", errorCode) + } + + /** + * get number of packages in ringbuffer + */ + func getBoardDataCount (_ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> Int32 { + var dataCount: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = get_board_data_count (preset.rawValue, &dataCount, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to get board data count", errorCode) + + return dataCount + } + + /** + * insert marker to data stream + */ + func insertMarker (value: Double, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws { + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = insert_marker (value, preset.rawValue, boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in insert_marker", errorCode) + } + + /** + * check session status + */ + func isPrepared () throws -> Bool { + var intPrepared: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + let errorCode = is_prepared (&intPrepared, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to check session", errorCode) + + return NSNumber(value: intPrepared).boolValue + } + + /** + * get latest collected data, can return less than "num_samples", doesnt flush + * it from ringbuffer + */ + func getCurrentBoardData (_ numSamples: Int32, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [[Double]] + { + var numRows: Int32 = 0 + var currentSize: Int32 = 0 + var jsonBFParams = self.jsonBrainFlowInputParams + + do { + numRows = try BoardShim.getNumRows (getBoardId()) } + catch { + throw error + } + + var buffer = [Double](repeating: 0.0, count: Int(numSamples * numRows)) + let errorCode = get_current_board_data (numSamples, preset.rawValue, &buffer, ¤tSize, + boardId.rawValue, &jsonBFParams) + try checkErrorCode("Error in get_current_board_data", errorCode) + + return buffer.matrix2D(rowLength: Int(numSamples)) + } + + /** + * get all data from the default ringbuffer and flush it + */ + func getDefData () throws -> [[Double]] { + let size = try getBoardDataCount() + guard size > 0 else { + return [[Double]]() + } + + return try getBoardData(size) + } + + /** + * get all data from the auxiliary ringbuffer and flush it + */ + func getAuxData () throws -> [[Double]] { + let preset = BrainFlowPresets.AUXILIARY_PRESET + let size = try getBoardDataCount(preset) + guard size > 0 else { + return [[Double]]() + } + + return try getBoardData(size, preset) + } + + /** + * get all data from the ancillary ringbuffer and flush it + */ + func getAncData () throws -> [[Double]] { + let preset = BrainFlowPresets.ANCILLARY_PRESET + let size = try getBoardDataCount(preset) + + guard size > 0 else { + return [[Double]]() + } + return try getBoardData(size, preset) + } + + func getBoardData (_ size: Int32? = nil, _ preset: BrainFlowPresets = .DEFAULT_PRESET) throws -> [[Double]] { + var jsonBFParams = self.jsonBrainFlowInputParams + let numRows = try BoardShim.getNumRows (getBoardId()) + var numSamples: Int32 = 0 + if let testSize = size { + // size is not nil + if testSize < 1 { + throw BrainFlowException("invalid num_samples", BrainFlowExitCodes.INVALID_ARGUMENTS_ERROR) + } + numSamples = testSize + } else { + // size is nil, so get all available data: + numSamples = try getBoardDataCount(preset) + } + var buffer = [Double](repeating: 0.0, count: Int(numSamples * numRows)) + let errorCode = get_board_data (numSamples, preset.rawValue, &buffer, boardId.rawValue, &jsonBFParams) + try checkErrorCode("failed to get board data", errorCode) + + return buffer.matrix2D(rowLength: Int(numSamples)) + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowConstants.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowConstants.swift new file mode 100644 index 000000000..a0ae2e23b --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowConstants.swift @@ -0,0 +1,234 @@ +// +// BrainFlowConstants.swift +// a Swift binding for BrainFlow's enumeration types +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// + +import Darwin + +enum BrainFlowExitCodes : Int32, Error { + case STATUS_OK = 0 + case PORT_ALREADY_OPEN_ERROR = 1 + case UNABLE_TO_OPEN_PORT_ERROR = 2 + case SET_PORT_ERROR = 3 + case BOARD_WRITE_ERROR = 4 + case INCOMMING_MSG_ERROR = 5 + case INITIAL_MSG_ERROR = 6 + case BOARD_NOT_READY_ERROR = 7 + case STREAM_ALREADY_RUN_ERROR = 8 + case INVALID_BUFFER_SIZE_ERROR = 9 + case STREAM_THREAD_ERROR = 10 + case STREAM_THREAD_IS_NOT_RUNNING = 11 + case EMPTY_BUFFER_ERROR = 12 + case INVALID_ARGUMENTS_ERROR = 13 + case UNSUPPORTED_BOARD_ERROR = 14 + case BOARD_NOT_CREATED_ERROR = 15 + case ANOTHER_BOARD_IS_CREATED_ERROR = 16 + case GENERAL_ERROR = 17 + case SYNC_TIMEOUT_ERROR = 18 + case JSON_NOT_FOUND_ERROR = 19 + case NO_SUCH_DATA_IN_JSON_ERROR = 20 + case CLASSIFIER_IS_NOT_PREPARED_ERROR = 21 + case ANOTHER_CLASSIFIER_IS_PREPARED_ERROR = 22 + case UNSUPPORTED_CLASSIFIER_AND_METRIC_COMBINATION_ERROR = 23 +} + +enum BoardIds : Int32, CaseIterable, Equatable { + case NO_BOARD = -100 // only for internal usage + case PLAYBACK_FILE_BOARD = -3 + case STREAMING_BOARD = -2 + case SYNTHETIC_BOARD = -1 + case CYTON_BOARD = 0 + case GANGLION_BOARD = 1 + case CYTON_DAISY_BOARD = 2 + case GALEA_BOARD = 3 + case GANGLION_WIFI_BOARD = 4 + case CYTON_WIFI_BOARD = 5 + case CYTON_DAISY_WIFI_BOARD = 6 + case BRAINBIT_BOARD = 7 + case UNICORN_BOARD = 8 + case CALLIBRI_EEG_BOARD = 9 + case CALLIBRI_EMG_BOARD = 10 + case CALLIBRI_ECG_BOARD = 11 + case NOTION_1_BOARD = 13 + case NOTION_2_BOARD = 14 + case GFORCE_PRO_BOARD = 16 + case FREEEEG32_BOARD = 17 + case BRAINBIT_BLED_BOARD = 18 + case GFORCE_DUAL_BOARD = 19 + case GALEA_SERIAL_BOARD = 20 + case MUSE_S_BLED_BOARD = 21 + case MUSE_2_BLED_BOARD = 22 + case CROWN_BOARD = 23 + case ANT_NEURO_EE_410_BOARD = 24 + case ANT_NEURO_EE_411_BOARD = 25 + case ANT_NEURO_EE_430_BOARD = 26 + case ANT_NEURO_EE_211_BOARD = 27 + case ANT_NEURO_EE_212_BOARD = 28 + case ANT_NEURO_EE_213_BOARD = 29 + case ANT_NEURO_EE_214_BOARD = 30 + case ANT_NEURO_EE_215_BOARD = 31 + case ANT_NEURO_EE_221_BOARD = 32 + case ANT_NEURO_EE_222_BOARD = 33 + case ANT_NEURO_EE_223_BOARD = 34 + case ANT_NEURO_EE_224_BOARD = 35 + case ANT_NEURO_EE_225_BOARD = 36 + case ENOPHONE_BOARD = 37 + case MUSE_2_BOARD = 38 + case MUSE_S_BOARD = 39 + case BRAINALIVE_BOARD = 40 + case MUSE_2016_BOARD = 41 + case MUSE_2016_BLED_BOARD = 42 + case EXPLORE_4_CHAN_BOARD = 44 + case EXPLORE_8_CHAN_BOARD = 45 + case GANGLION_NATIVE_BOARD = 46 + case EMOTIBIT_BOARD = 47 + case GALEA_BOARD_V4 = 48 + case GALEA_SERIAL_BOARD_V4 = 49 + case NTL_WIFI_BOARD = 50 + case ANT_NEURO_EE_511_BOARD = 51 + case FREEEEG128_BOARD = 52 + case AAVAA_V3_BOARD = 53 + + var name: String { + get { String(describing: self) } + } +} + +enum IpProtocolType : Int32 { + case NONE = 0 + case UDP = 1 + case TCP = 2 +} + +enum FilterTypes : Int32 { + case BUTTERWORTH = 0 + case CHEBYSHEV_TYPE_1 = 1 + case BESSEL = 2 + case BUTTERWORTH_ZERO_PHASE = 3 + case CHEBYSHEV_TYPE_1_ZERO_PHASE = 4 + case BESSEL_ZERO_PHASE = 5 +} + +enum AggOperations : Int32 { + case MEAN = 0 + case MEDIAN = 1 + case EACH = 2 +} + +enum WindowFunctions : Int32, CaseIterable { + case NO_WINDOW = 0 + case HANNING = 1 + case HAMMING = 2 + case BLACKMAN_HARRIS = 3 +} + +enum DetrendOperations : Int32 { + case NONE = 0 + case CONSTANT = 1 + case LINEAR = 2 +} + +enum BrainFlowMetrics : Int32, Encodable { + case MINDFULNESS = 0 + case RESTFULNESS = 1 + case USER_DEFINED = 2 +} + +enum BrainFlowClassifiers : Int32, Encodable { + case DEFAULT_CLASSIFIER = 0 + case DYN_LIB_CLASSIFIER = 1 + case ONNX_CLASSIFIER = 2 +} + +enum BrainFlowPresets : Int32 { + case DEFAULT_PRESET = 0 + case AUXILIARY_PRESET = 1 + case ANCILLARY_PRESET = 2 +} + +enum LogLevels : Int32 { + case LEVEL_TRACE = 0 + case LEVEL_DEBUG = 1 + case LEVEL_INFO = 2 + case LEVEL_WARN = 3 + case LEVEL_ERROR = 4 + case LEVEL_CRITICAL = 5 + case LEVEL_OFF = 6 +} + +enum NoiseTypes : Int32 { + case FIFTY = 0 + case SIXTY = 1 + case FIFTY_AND_SIXTY = 2 +} + +enum WaveletDenoisingTypes : Int32 { + case VISUSHRINK = 0 + case SURESHRINK = 1 +} + +enum ThresholdTypes : Int32 { + case SOFT = 0 + case HARD = 1 +} + +enum WaveletExtensionTypes : Int32 { + case SYMMETRIC = 0 + case PERIODIC = 1 +} + +enum NoiseEstimationLevelTypes: Int32 { + case FIRST_LEVEL = 0 + case ALL_LEVELS = 1 +} + +enum WaveletTypes: Int32 { + case HAAR = 0 + case DB1 = 1 + case DB2 = 2 + case DB3 = 3 + case DB4 = 4 + case DB5 = 5 + case DB6 = 6 + case DB7 = 7 + case DB8 = 8 + case DB9 = 9 + case DB10 = 10 + case DB11 = 11 + case DB12 = 12 + case DB13 = 13 + case DB14 = 14 + case DB15 = 15 + case BIOR1_1 = 16 + case BIOR1_3 = 17 + case BIOR1_5 = 18 + case BIOR2_2 = 19 + case BIOR2_4 = 20 + case BIOR2_6 = 21 + case BIOR2_8 = 22 + case BIOR3_1 = 23 + case BIOR3_3 = 24 + case BIOR3_5 = 25 + case BIOR3_7 = 26 + case BIOR3_9 = 27 + case BIOR4_4 = 28 + case BIOR5_5 = 29 + case BIOR6_8 = 30 + case COIF1 = 31 + case COIF2 = 32 + case COIF3 = 33 + case COIF4 = 34 + case COIF5 = 35 + case SYM2 = 36 + case SYM3 = 37 + case SYM4 = 38 + case SYM5 = 39 + case SYM6 = 40 + case SYM7 = 41 + case SYM8 = 42 + case SYM9 = 43 + case SYM10 = 44 +} + diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowException.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowException.swift new file mode 100644 index 000000000..aec593b65 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowException.swift @@ -0,0 +1,32 @@ +// +// BrainFlowException.swift +// a Swift binding for BrainFlow's brainflow_exception.h +// +// Created by Scott Miller on 8/23/21. +// + +import Foundation + +class BrainFlowException: Error, Equatable { + static func == (lhs: BrainFlowException, rhs: BrainFlowException) -> Bool { + return (lhs.errorCode == rhs.errorCode) + } + + var message: String + var errorCode: BrainFlowExitCodes + + init(_ errorMessage: String, _ code: BrainFlowExitCodes) { + message = errorMessage + errorCode = code + } +} + +func checkErrorCode(_ errorMsg: String, _ errorCode: Int32) throws { + if let bfErrorCode = BrainFlowExitCodes(rawValue: errorCode) { + if bfErrorCode != BrainFlowExitCodes.STATUS_OK { + throw BrainFlowException (errorMsg, bfErrorCode) + } + } else { + throw BrainFlowException("Invalid error code: \(errorCode)", .GENERAL_ERROR) + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowExtensions.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowExtensions.swift new file mode 100644 index 000000000..17fa423ed --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowExtensions.swift @@ -0,0 +1,59 @@ +// +// BrainFlowExtensions.swift +// helper functions for the Swift binding of BrainFlow's API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/25/21. +// + +import Foundation + +extension Array { + // Convert a 1D array into a 2D matrix: + func matrix2D(rowLength: Int) -> [[Element]] { + return stride(from: 0, to: count, by: rowLength).map { + Array(self[$0 ..< Swift.min($0 + rowLength, count)]) + } + } +} + +extension Array where Element == CChar { + // convert an array of characters returned from a C++ API, into a String + func toString(_ len: Int32) -> String { + let data = Data(bytes: self, count: Int(len)) + if let result = String(data: data, encoding: .utf8) { + return result } + else { + return "*** Array.toString: INVALID [CChar] ***" + } + } +} + +extension String { + func convertToDictionary() -> [String: Any]? { + if let data = data(using: .utf8) { + return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + } + return nil + } +} + +extension Encodable { + // Convert the current struct to a JSON string: + func encodeJSON() throws -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted.union(.withoutEscapingSlashes) + + do { +// return try encoder.encode(self).description + let data = try encoder.encode(self) + if let str = String(data: data, encoding: .utf8) { + return str + } else { + return "" + } + } catch { + throw BrainFlowException("Invalid JSON", .NO_SUCH_DATA_IN_JSON_ERROR) + } + } +} + diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowInputParams.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowInputParams.swift new file mode 100644 index 000000000..4e81eadf1 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/BrainFlowInputParams.swift @@ -0,0 +1,44 @@ +// +// BrainFlowInputParams.swift +// a Swift binding for BrainFlow's brainflow_input_params.h +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// + +import Foundation +//import BrainFlow + +struct BrainFlowInputParams: Encodable { + var serial_port: String = "" + var mac_address: String = "" + var ip_address: String = "" + var ip_address_aux: String = "" + var ip_address_anc: String = "" + var ip_port: Int = 0 + var ip_port_aux: Int = 0 + var ip_port_anc: Int = 0 + var ip_protocol: Int = 0 + var other_info: String = "" + var timeout: Int = 0 + var serial_number: String = "" + var file: String = "" + var file_aux: String = "" + var file_anc: String = "" + var master_board: Int = 0 + + // Convert the BrainFlowInputParams struct to a JSON string: + func json() -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted.union(.withoutEscapingSlashes) + + guard let jsonParams = try? encoder.encode(self) else { + try? BoardShim.logMessage(.LEVEL_ERROR, "Cannot convert BrainFlowInputParams to JSON") + return "" + } + + let stringParams = String(data: jsonParams, encoding: .utf8) + return stringParams! + } +} + + diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/DataFilter.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/DataFilter.swift new file mode 100644 index 000000000..964463f0e --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/DataFilter.swift @@ -0,0 +1,650 @@ +// +// DataFilter.swift +// A binding for BrainFlow's data_filter API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/27/21. +// + + +import Foundation +import Numerics + +struct DataFilter { + /** + * enable Data logger with level INFO + */ + static func enableDataLogger () throws { + do { + try DataFilter.setLogLevel (.LEVEL_INFO) } + catch { + throw error + } + } + + /** + * enable Data logger with level TRACE + */ + static func enableDevDataLogger () throws { + do { + try setLogLevel (.LEVEL_TRACE) } + catch { + throw error + } + } + + /** + * disable Data logger + */ + static func disableDataLogger () throws { + do { + try setLogLevel (.LEVEL_OFF) } + catch { + throw error + } + } + + /** + * redirect logger from stderr to a file + */ + static func setLogFile (_ logFile: String) throws { + var cLogFile = logFile.cString(using: String.Encoding.utf8)! + let errorCode = set_log_file_data_handler (&cLogFile) + try checkErrorCode("Error in set_log_file", errorCode) + } + + /** + * set log level + */ + static func setLogLevel (_ logLevel: LogLevels) throws { + let errorCode = set_log_level_data_handler (logLevel.rawValue) + try checkErrorCode("Error in set_log_level", errorCode) + } + + /** + * perform lowpass filter in-place + */ + static func performLowpass (data: inout [Double], samplingRate: Int32, cutoff: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_lowpass (&data, dataLen, samplingRate, cutoff, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform highpass filter in-place + */ + static func performHighpass (data: inout [Double], samplingRate: Int32, cutoff: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_highpass (&data, dataLen, samplingRate, cutoff, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform bandpass filter in-place + */ + static func performBandpass (data: inout [Double], samplingRate: Int32, startFreq: Double, stopFreq: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_bandpass(&data, dataLen, samplingRate, startFreq, + stopFreq, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform bandstop filter in-place + */ + static func performBandstop (data: inout [Double], samplingRate: Int32, startFreq: Double, stopFreq: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_bandstop(&data, dataLen, samplingRate, startFreq, + stopFreq, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform moving average or moving median filter in-place + */ + static func performRollingFilter (data: inout [Double], period: Int32, operation: AggOperations) throws { + let dataLen = Int32(data.count) + let errorCode = perform_rolling_filter (&data, dataLen, period, operation.rawValue) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * subtract trend from data in-place + */ + static func deTrend (data: inout [Double], operation: DetrendOperations) throws { + let dataLen = Int32(data.count) + let errorCode = detrend (&data, dataLen, operation.rawValue) + try checkErrorCode("Failed to detrend", errorCode) + } + + /** + * perform data downsampling, it doesnt apply lowpass filter for you, it just + * aggregates several data points + */ + static func performDownsampling (data: [Double], period: Int32, operation: AggOperations) throws -> [Double] { + guard (period > 0) else { + throw BrainFlowException("Invalid period", .INVALID_ARGUMENTS_ERROR) + } + + let dataLen = Int32(data.count) + let newSize = dataLen / period + + if (newSize <= 0) { + throw BrainFlowException ("Invalid data size", .INVALID_ARGUMENTS_ERROR) + } + + var downsampledData = [Double](repeating: 0.0, count: Int(newSize)) + var cData = data + let errorCode = perform_downsampling (&cData, dataLen, period, operation.rawValue, &downsampledData) + try checkErrorCode("Failed to perform downsampling", errorCode) + + return downsampledData + } + + /** + * removes noise using notch filter in-place + */ + static func removeEnvironmentalNoise (data: inout [Double], samplingRate: Int32, noiseType: NoiseTypes) throws { + let dataLen = Int32(data.count) + let errorCode = remove_environmental_noise (&data, dataLen, samplingRate, noiseType.rawValue) + try checkErrorCode("Failed to remove noise", errorCode) + } + + /**perform wavelet denoising + + :param data: data to denoise + :type data: NDArray[Float64] + :param wavelet: use WaveletTypes enum + :type wavelet: int + :param decomposition_level: decomposition level + :type decomposition_level: int + :param wavelet_denoising: use WaveletDenoisingTypes enum + :type wavelet_denoising: int + :param threshold: use ThresholdTypes enum + :type threshold: int + :param extension_type: use WaveletExtensionTypes enum + :type extension_type: int + :param noise_level: use NoiseEstimationLevelTypes enum + :type noise_level: int + **/ + static func performWaveletDenoising (data: inout [Double], wavelet: WaveletTypes, decompositionLevel: Int32, + waveletDenoising: WaveletDenoisingTypes = .SURESHRINK, + threshold: ThresholdTypes = .HARD, + extensionType: WaveletExtensionTypes = .SYMMETRIC, + noiseLevel: NoiseEstimationLevelTypes = .FIRST_LEVEL) throws { + let dataLen = Int32(data.count) + let wvVal = wavelet.rawValue + let wvDenVal = waveletDenoising.rawValue + let thrVal = threshold.rawValue + let extVal = extensionType.rawValue + let noiseVal = noiseLevel.rawValue + + let errorCode = perform_wavelet_denoising (&data, dataLen, wvVal, + decompositionLevel, wvDenVal, thrVal, extVal, noiseVal) + try checkErrorCode("Failed to perform denoising", errorCode) + + return + } + + /** + * perform wavelet transform + * + * @param wavelet supported vals: + * db1..db15,haar,sym2..sym10,coif1..coif5,bior1.1,bior1.3,bior1.5,bior2.2,bior2.4,bior2.6,bior2.8,bior3.1,bior3.3,bior3.5 + * ,bior3.7,bior3.9,bior4.4,bior5.5,bior6.8 + */ + static func performWaveletTransform(data: [Double], wavelet: WaveletTypes, + decompositionLevel: Int32, + extensionType: WaveletExtensionTypes = .SYMMETRIC) throws -> ([Double], [Int32]) { + guard (decompositionLevel > 0) else { + throw BrainFlowException ("Invalid decomposition level", .INVALID_ARGUMENTS_ERROR) + } + + let dataLen = Int32(data.count) + let waveletVal = wavelet.rawValue + let extVal = extensionType.rawValue + var lengths = [Int32](repeating: 0, count: Int(decompositionLevel) + 1) + let outputLen = dataLen + 2 * decompositionLevel * (40 + 1) + var outputArray = [Double](repeating: 0.0, count: Int(outputLen)) + + var cData = data + let errorCode = perform_wavelet_transform (&cData, dataLen, waveletVal, decompositionLevel, extVal, + &outputArray, &lengths) + try checkErrorCode("Failed to perform wavelet transform", errorCode) + + let totalLen = Int(lengths.reduce(0, +)) + let result = Array(outputArray[.. [Double] { + guard (decompositionLevel > 0) else { + throw BrainFlowException ("Invalid decomposition level", .INVALID_ARGUMENTS_ERROR) + } + + let waveletVal = wavelet.rawValue + let extVal = extensionType.rawValue + var outputArray = [Double](repeating: 0.0, count: Int(originalDataLen)) + var waveletCoeffs = waveletTuple.0 + var decompositionLengths = waveletTuple.1 + let errorCode = perform_inverse_wavelet_transform (&waveletCoeffs, originalDataLen, waveletVal, + decompositionLevel, extVal, &decompositionLengths, + &outputArray) + try checkErrorCode("Failed to perform inverse wavelet transform", errorCode) + + return outputArray + } + + /** + * get common spatial filters + */ + static func getCSP (data: [[[Double]]], labels: [Double]) throws -> ([[Double]], [Double]) { + let nEpochs = data.count + let nChannels = data[0].count + let nTimes = data[0][0].count + var cLabels = labels + + var tempData1d = [Double](repeating: 0.0, count: Int(nEpochs * nChannels * nTimes)) + for e in 0.. [Double] { + guard windowLen > 0 else { + throw BrainFlowException("Window length must be >= 0", .INVALID_ARGUMENTS_ERROR) + } + var windowData = [Double](repeating: 0.0, count: Int(windowLen)) + let errorCode = get_window (window.rawValue, windowLen, &windowData) + try checkErrorCode("Failed to perform windowing", errorCode) + + return windowData + } + + /** + * perform direct fft + * + * @param data data for fft transform + * @param start_pos starting position to calc fft + * @param end_pos end position to calc fft, total_len must be a power of two + * @param window window function + * @return array of complex values with size N / 2 + 1 + */ + static func performFFT (data: [Double], window: WindowFunctions) throws -> [Complex] { + if let startPos = data.indices.first { + let endPos = startPos + data.count + return try performFFT(data: data, startPos: Int32(startPos), endPos: Int32(endPos), window: window) + } else { + throw BrainFlowException("Empty data buffer in performFFT", .EMPTY_BUFFER_ERROR) + } + } + + static func performFFT (data: [Double], startPos: Int32, endPos: Int32, window: WindowFunctions) throws -> [Complex] { + let dataLen = data.count + guard (startPos >= 0) && (endPos <= dataLen) && (startPos < endPos) else { + throw BrainFlowException ("Invalid position arguments in performFFT", .INVALID_ARGUMENTS_ERROR) + } + + // I didnt find a way to pass an offset using pointers, copy array + var dataToProcess = Array(data[Int(startPos)..($0, $1)} + return complexResult + } + + /** + * perform inverse fft + * + * @param data data from fft transform(array of complex values) + * @return restored data + */ + static func performIFFT (data: [Complex]) throws -> [Double] + { + var complexReal = data.map{$0.real} + var complexImaginary = data.map{$0.imaginary} + + let len = (data.count - 1) * 2 + var output = [Double](repeating: 0.0, count: len) + let errorCode = perform_ifft (&complexReal, &complexImaginary, Int32(len), &output) + try checkErrorCode("Failed to perform ifft", errorCode) + + return output + } + + /** + calculate avg and stddev of BandPowers across selected channels + + :param data: 2d array for calculation + :type data: NDArray + :param bands: List of typles with bands to use. E.g [(1.5, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + :type bands: List + :param channels: channels - rows of data array which should be used for calculation + :type channels: List + :param sampling_rate: sampling rate + :type sampling_rate: int + :param apply_filter: apply bandpass and bandstop filtrers or not + :type apply_filter: bool + :return: avg and stddev arrays for bandpowers + :rtype: tuple + **/ + static func getCustomBandPowers(data: [[Double]]?, bands: [(Double,Double)]?, channels: [Int32]?, samplingRate: Int32, + applyFilter: Bool) throws -> ([Double],[Double]) { + guard ((data != nil) && (channels != nil) && (bands != nil)) else { + throw BrainFlowException ("data or channels or bands are null", .INVALID_ARGUMENTS_ERROR) } + guard ((channels!.count > 0) && (bands!.count > 0)) else { + throw BrainFlowException("wrong input for channels or bands", .INVALID_ARGUMENTS_ERROR) } + + // convert channels from [Int32]? to [Int] for syntactic sugar: + let iChannels = channels!.map{Int($0)} + + let filtersOn = Int32(applyFilter ? 1 : 0) + let numRows = iChannels.count + let numCols = data![iChannels[0]].count + let numBands = bands!.count + var avgBands = [Double](repeating: 0.0, count: numBands) + var stddevBands = [Double](repeating: 0.0, count: numBands) + var data1d = [Double](repeating: 0.0, count: iChannels.count * numCols) + var startFreqs = [Double](repeating: 0.0, count: numBands) + var stopFreqs = [Double](repeating: 0.0, count: numBands) + for i in 0.. ([Double], [Double]) { + guard ((data != nil) && (channels != nil)) else { + throw BrainFlowException ("data or channels null", .INVALID_ARGUMENTS_ERROR) + } + + let bands = [(2.0, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + return try getCustomBandPowers(data: data, bands: bands, channels: channels, + samplingRate: samplingRate, applyFilter: applyFilter) + } + + /** + * get PSD + * + * @param data data to process + * @param start_pos starting position to calc PSD + * @param end_pos end position to calc PSD, total_len must be a power of + * two + * @param sampling_rate sampling rate + * @param window window function + * @return pair of ampl and freq arrays with len N / 2 + 1 + */ + static func getPSD (data: [Double], startPos: Int32, endPos: Int32, samplingRate: Int32, window: Int32) throws -> ([Double], [Double]) { + guard ((startPos >= 0) && (endPos <= data.count) && (startPos < endPos)) else { + throw BrainFlowException ("invalid position arguments", .INVALID_ARGUMENTS_ERROR) + } + + // I didnt find a way to pass an offset using pointers, copy array + var dataToProcess = Array(data[Int(startPos).. ([Double], [Double]) { + guard ((nfft & (nfft - 1)) == 0) else { + throw BrainFlowException ("nfft must be a power of 2", .INVALID_ARGUMENTS_ERROR) + } + + var cData = data + var ampls = [Double](repeating: 0.0, count: Int(nfft) / 2 + 1) + var freqs = [Double](repeating: 0.0, count: Int(nfft) / 2 + 1) + let errorCode = get_psd_welch (&cData, Int32(data.count), nfft, overlap, samplingRate, + window.rawValue, &ls, + &freqs) + try checkErrorCode("Failed to get_psd_welch", errorCode) + + return (ampls, freqs) + } + + /** + * get band power + * + * @param psd PSD from get_psd or get_log_psd + * @param freq_start lowest frequency of band + * @param freq_end highest frequency of band + * @return band power + */ + static func getBandPower (psd: ([Double], [Double]), freqStart: Double, freqEnd: Double) throws -> Double { + var result = [Double](repeating: 0.0, count: 1) + var psdLeft = psd.0 + var psdRight = psd.1 + let errorCode = get_band_power (&psdLeft, &psdRight, Int32(psdLeft.count), freqStart, freqEnd, + &result) + try checkErrorCode("Failed to get band power", errorCode) + return result[0] + } + + /** + * calculate nearest power of two + */ + static func getNearestPowerOfTwo (_ value: Int32) throws -> Int32 { + var powerOfTwo = [Int32](repeating: 0, count: 1) + let errorCode = get_nearest_power_of_two (value, &powerOfTwo) + try checkErrorCode("Failed to calc nearest power of two", errorCode) + return powerOfTwo[0] + } + + /** + * write data to tsv file, in file data will be transposed + */ + static func writeFile (data: [[Double]], fileName: String, fileMode: String) throws { + guard data.count > 0 else { + throw BrainFlowException ("empty data array", .INVALID_ARGUMENTS_ERROR) + } + + var linearData = data.flatMap {$0} + let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileURL = docDir.appendingPathComponent(fileName) + var cFileName = fileURL.path.cString(using: String.Encoding.utf8)! + var cFileMode = fileMode.cString(using: String.Encoding.utf8)! + + let errorCode = write_file (&linearData, Int32(data.count), Int32(data[0].count), &cFileName, &cFileMode) + try checkErrorCode("Failed to write data to file: \(fileName)", errorCode) + } + + /** + * read data from file, transpose it back to original format + */ + static func readFile (fileName: String) throws -> [[Double]] { + var numElements = [Int32](repeating: 0, count: 1) + let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileURL = docDir.appendingPathComponent(fileName) + var cFileName = fileURL.path.cString(using: String.Encoding.utf8)! + var errorCode = get_num_elements_in_file (&cFileName, &numElements) + try checkErrorCode("Failed to determine number of elements in file: \(fileName)", errorCode) + + var dataArr = [Double](repeating: 0.0, count: Int(numElements[0])) + var numRows = [Int32](repeating: 0, count: 1) + var numCols = [Int32](repeating: 0, count: 1) + errorCode = read_file (&dataArr, &numRows, &numCols, &cFileName, numElements[0]) + try checkErrorCode("Failed to read data from file: \(fileName)", errorCode) + + return dataArr.matrix2D(rowLength: Int(numCols[0])) + } + + static func performICA(data: [[Double]], numComponents: Int, channels: [Int]? = nil) throws -> + ([[Double]], [[Double]], [[Double]], [[Double]]) { + var channelsToUse: [Int] = [] + guard data.isRectangular() else { + throw BrainFlowException("input data is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + guard numComponents >= 1 else { + throw BrainFlowException("wrong number of components", .INVALID_ARGUMENTS_ERROR) + } + + if let channelIndexes = channels { + channelsToUse = channelIndexes + } else { + let indexRange = 0.. Int { + let numCols = self.map { $0.count } + return numCols.count + } + + // Return true only if the 2D array is rectangular, i.e., all rows are the same length. + func isRectangular() -> Bool { + let numCols = self.map { $0.count } + let set = Set(numCols) + return set.count == 1 + } + + // Return a tuple of (numRows, numCols) for the given 2D array: + func shapeOfRectangular() throws -> (Int, Int) { + guard self.isRectangular() else { + throw BrainFlowException("array is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + let numRows = self.numRows() + let numCols = self[0].count + return (numRows, numCols) + } +} +// Based on https://stackoverflow.com/questions/48088882/how-can-split-from-string-to-array-by-chunks-of-given-size +extension Array where Element == Double { + func reshapeRectangular(size: Int) throws -> [[Element]] { + let result = stride(from: 0, to: count, by: size).map { + Array(self[$0 ..< Swift.min($0 + size, count)]) + } + guard result.isRectangular() else { + throw BrainFlowException("reshape result is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + return result + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlowBindings/MLModule.swift b/swift_package/BrainFlow/Sources/BrainFlowBindings/MLModule.swift new file mode 100644 index 000000000..b5f41e4d8 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowBindings/MLModule.swift @@ -0,0 +1,101 @@ +// +// MLModule.swift +// a Swift binding for BrainFlow's MLModule API +// +// Created by Scott Miller on 9/22/21 on behalf of Aeris Rising, LLC. +// + +import Foundation + +struct BrainFlowModelParams: Encodable { + let metric: BrainFlowMetrics + let classifier: BrainFlowClassifiers + let file: String + let other_info: String + let output_name: String + let max_array_size = 8192 + + init (metric: BrainFlowMetrics, classifier: BrainFlowClassifiers, + file: String = "", otherInfo: String = "", outputName: String = "") { + self.metric = metric + self.classifier = classifier + self.file = file + self.other_info = otherInfo + self.output_name = outputName + } +} + +struct MLModule { + //MLModule class used to calc derivative metrics from raw data + + let modelParams: BrainFlowModelParams + + static func setLogLevel(_ logLevel: LogLevels) throws { + //set BrainFlow log level, use it only if you want to write your own messages to BrainFlow logger, + //otherwise use enable_ml_logger, enable_dev_ml_logger or disable_ml_logger + //:param log_level: log level, to specify it you should use values from LogLevels enum + //:type log_level: int + + let errorCode = set_log_level_ml_module(logLevel.rawValue) + try checkErrorCode("unable to enable logger", errorCode) + } + + static func enableMLlogger() throws { + //enable ML Logger with level INFO, uses stderr for log messages by default + try setLogLevel(.LEVEL_INFO) + } + + static func disableMLlogger() throws { + ///disable BrainFlow Logger + try setLogLevel(.LEVEL_OFF) + } + + static func enableDevMLlogger() throws { + //enable ML Logger with level TRACE, uses stderr for log messages by default + try setLogLevel(.LEVEL_TRACE) + } + + static func setLogFile(logFile: String) throws { + //redirect logger from stderr to file, can be called any time + //:param log_file: log file name + //:type log_file: str + + var cFile = [CChar](repeating: CChar(0), count: 4096) + let errorCode = set_log_file_ml_module(&cFile) + try checkErrorCode("Cannot set log file to: \(logFile)", errorCode) + } + + func prepareClassifier() throws { + ///prepare classifier + print("modelParams: \(modelParams)") + let json = try self.modelParams.encodeJSON() + var params = json.cString(using: .utf8)! + let errorCode = prepare(¶ms) + try checkErrorCode("Cannot prepare classifier", errorCode) + } + + func releaseClassifier() throws { + ///release classifier + var params = try self.modelParams.encodeJSON().cString(using: .utf8)! + let errorCode = release(¶ms) + try checkErrorCode("Cannot release classifier", errorCode) + } + + func predictClass(data: [Double]) throws -> [Double] { + //calculate metric from data + //:param data: input array + //:type data: NDArray + //:return: metric value + //:rtype: float + + let len = Int32(data.count) + var vData = data + var output = [Double](repeating: 0.0, count: modelParams.max_array_size) + var outputLen = [Int32](repeating: 0, count: 1) + var params = try self.modelParams.encodeJSON().cString(using: .utf8)! + let errorCode = predict(&vData, len, &output, &outputLen, ¶ms) + try checkErrorCode("unable to calc metric", errorCode) + + return Array(output[0.. Bool { + return (lhs.errorCode == rhs.errorCode) + } + + var message: String + var errorCode: BrainFlowExitCodes + + init(_ errorMessage: String, _ code: BrainFlowExitCodes) { + message = errorMessage + errorCode = code + } +} + +func checkErrorCode(_ errorMsg: String, _ errorCode: Int32) throws { + if let bfErrorCode = BrainFlowExitCodes(rawValue: errorCode) { + if bfErrorCode != BrainFlowExitCodes.STATUS_OK { + throw BrainFlowException (errorMsg, bfErrorCode) + } + } else { + throw BrainFlowException("Invalid error code: \(errorCode)", .GENERAL_ERROR) + } +} diff --git a/swift_package/BrainFlow/Sources/BrainFlowExtensions.swift b/swift_package/BrainFlow/Sources/BrainFlowExtensions.swift new file mode 100644 index 000000000..17fa423ed --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowExtensions.swift @@ -0,0 +1,59 @@ +// +// BrainFlowExtensions.swift +// helper functions for the Swift binding of BrainFlow's API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/25/21. +// + +import Foundation + +extension Array { + // Convert a 1D array into a 2D matrix: + func matrix2D(rowLength: Int) -> [[Element]] { + return stride(from: 0, to: count, by: rowLength).map { + Array(self[$0 ..< Swift.min($0 + rowLength, count)]) + } + } +} + +extension Array where Element == CChar { + // convert an array of characters returned from a C++ API, into a String + func toString(_ len: Int32) -> String { + let data = Data(bytes: self, count: Int(len)) + if let result = String(data: data, encoding: .utf8) { + return result } + else { + return "*** Array.toString: INVALID [CChar] ***" + } + } +} + +extension String { + func convertToDictionary() -> [String: Any]? { + if let data = data(using: .utf8) { + return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] + } + return nil + } +} + +extension Encodable { + // Convert the current struct to a JSON string: + func encodeJSON() throws -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted.union(.withoutEscapingSlashes) + + do { +// return try encoder.encode(self).description + let data = try encoder.encode(self) + if let str = String(data: data, encoding: .utf8) { + return str + } else { + return "" + } + } catch { + throw BrainFlowException("Invalid JSON", .NO_SUCH_DATA_IN_JSON_ERROR) + } + } +} + diff --git a/swift_package/BrainFlow/Sources/BrainFlowInputParams.swift b/swift_package/BrainFlow/Sources/BrainFlowInputParams.swift new file mode 100644 index 000000000..4e81eadf1 --- /dev/null +++ b/swift_package/BrainFlow/Sources/BrainFlowInputParams.swift @@ -0,0 +1,44 @@ +// +// BrainFlowInputParams.swift +// a Swift binding for BrainFlow's brainflow_input_params.h +// +// Created by Scott Miller for Aeris Rising, LLC on 8/23/21. +// + +import Foundation +//import BrainFlow + +struct BrainFlowInputParams: Encodable { + var serial_port: String = "" + var mac_address: String = "" + var ip_address: String = "" + var ip_address_aux: String = "" + var ip_address_anc: String = "" + var ip_port: Int = 0 + var ip_port_aux: Int = 0 + var ip_port_anc: Int = 0 + var ip_protocol: Int = 0 + var other_info: String = "" + var timeout: Int = 0 + var serial_number: String = "" + var file: String = "" + var file_aux: String = "" + var file_anc: String = "" + var master_board: Int = 0 + + // Convert the BrainFlowInputParams struct to a JSON string: + func json() -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted.union(.withoutEscapingSlashes) + + guard let jsonParams = try? encoder.encode(self) else { + try? BoardShim.logMessage(.LEVEL_ERROR, "Cannot convert BrainFlowInputParams to JSON") + return "" + } + + let stringParams = String(data: jsonParams, encoding: .utf8) + return stringParams! + } +} + + diff --git a/swift_package/BrainFlow/Sources/DataFilter.swift b/swift_package/BrainFlow/Sources/DataFilter.swift new file mode 100644 index 000000000..964463f0e --- /dev/null +++ b/swift_package/BrainFlow/Sources/DataFilter.swift @@ -0,0 +1,650 @@ +// +// DataFilter.swift +// A binding for BrainFlow's data_filter API +// +// Created by Scott Miller for Aeris Rising, LLC on 8/27/21. +// + + +import Foundation +import Numerics + +struct DataFilter { + /** + * enable Data logger with level INFO + */ + static func enableDataLogger () throws { + do { + try DataFilter.setLogLevel (.LEVEL_INFO) } + catch { + throw error + } + } + + /** + * enable Data logger with level TRACE + */ + static func enableDevDataLogger () throws { + do { + try setLogLevel (.LEVEL_TRACE) } + catch { + throw error + } + } + + /** + * disable Data logger + */ + static func disableDataLogger () throws { + do { + try setLogLevel (.LEVEL_OFF) } + catch { + throw error + } + } + + /** + * redirect logger from stderr to a file + */ + static func setLogFile (_ logFile: String) throws { + var cLogFile = logFile.cString(using: String.Encoding.utf8)! + let errorCode = set_log_file_data_handler (&cLogFile) + try checkErrorCode("Error in set_log_file", errorCode) + } + + /** + * set log level + */ + static func setLogLevel (_ logLevel: LogLevels) throws { + let errorCode = set_log_level_data_handler (logLevel.rawValue) + try checkErrorCode("Error in set_log_level", errorCode) + } + + /** + * perform lowpass filter in-place + */ + static func performLowpass (data: inout [Double], samplingRate: Int32, cutoff: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_lowpass (&data, dataLen, samplingRate, cutoff, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform highpass filter in-place + */ + static func performHighpass (data: inout [Double], samplingRate: Int32, cutoff: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_highpass (&data, dataLen, samplingRate, cutoff, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform bandpass filter in-place + */ + static func performBandpass (data: inout [Double], samplingRate: Int32, startFreq: Double, stopFreq: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_bandpass(&data, dataLen, samplingRate, startFreq, + stopFreq, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform bandstop filter in-place + */ + static func performBandstop (data: inout [Double], samplingRate: Int32, startFreq: Double, stopFreq: Double, + order: Int32, filterType: FilterTypes, ripple: Double) throws { + let dataLen = Int32(data.count) + let filterVal = filterType.rawValue + let errorCode = perform_bandstop(&data, dataLen, samplingRate, startFreq, + stopFreq, order, filterVal, ripple) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * perform moving average or moving median filter in-place + */ + static func performRollingFilter (data: inout [Double], period: Int32, operation: AggOperations) throws { + let dataLen = Int32(data.count) + let errorCode = perform_rolling_filter (&data, dataLen, period, operation.rawValue) + try checkErrorCode("Failed to apply filter", errorCode) + } + + /** + * subtract trend from data in-place + */ + static func deTrend (data: inout [Double], operation: DetrendOperations) throws { + let dataLen = Int32(data.count) + let errorCode = detrend (&data, dataLen, operation.rawValue) + try checkErrorCode("Failed to detrend", errorCode) + } + + /** + * perform data downsampling, it doesnt apply lowpass filter for you, it just + * aggregates several data points + */ + static func performDownsampling (data: [Double], period: Int32, operation: AggOperations) throws -> [Double] { + guard (period > 0) else { + throw BrainFlowException("Invalid period", .INVALID_ARGUMENTS_ERROR) + } + + let dataLen = Int32(data.count) + let newSize = dataLen / period + + if (newSize <= 0) { + throw BrainFlowException ("Invalid data size", .INVALID_ARGUMENTS_ERROR) + } + + var downsampledData = [Double](repeating: 0.0, count: Int(newSize)) + var cData = data + let errorCode = perform_downsampling (&cData, dataLen, period, operation.rawValue, &downsampledData) + try checkErrorCode("Failed to perform downsampling", errorCode) + + return downsampledData + } + + /** + * removes noise using notch filter in-place + */ + static func removeEnvironmentalNoise (data: inout [Double], samplingRate: Int32, noiseType: NoiseTypes) throws { + let dataLen = Int32(data.count) + let errorCode = remove_environmental_noise (&data, dataLen, samplingRate, noiseType.rawValue) + try checkErrorCode("Failed to remove noise", errorCode) + } + + /**perform wavelet denoising + + :param data: data to denoise + :type data: NDArray[Float64] + :param wavelet: use WaveletTypes enum + :type wavelet: int + :param decomposition_level: decomposition level + :type decomposition_level: int + :param wavelet_denoising: use WaveletDenoisingTypes enum + :type wavelet_denoising: int + :param threshold: use ThresholdTypes enum + :type threshold: int + :param extension_type: use WaveletExtensionTypes enum + :type extension_type: int + :param noise_level: use NoiseEstimationLevelTypes enum + :type noise_level: int + **/ + static func performWaveletDenoising (data: inout [Double], wavelet: WaveletTypes, decompositionLevel: Int32, + waveletDenoising: WaveletDenoisingTypes = .SURESHRINK, + threshold: ThresholdTypes = .HARD, + extensionType: WaveletExtensionTypes = .SYMMETRIC, + noiseLevel: NoiseEstimationLevelTypes = .FIRST_LEVEL) throws { + let dataLen = Int32(data.count) + let wvVal = wavelet.rawValue + let wvDenVal = waveletDenoising.rawValue + let thrVal = threshold.rawValue + let extVal = extensionType.rawValue + let noiseVal = noiseLevel.rawValue + + let errorCode = perform_wavelet_denoising (&data, dataLen, wvVal, + decompositionLevel, wvDenVal, thrVal, extVal, noiseVal) + try checkErrorCode("Failed to perform denoising", errorCode) + + return + } + + /** + * perform wavelet transform + * + * @param wavelet supported vals: + * db1..db15,haar,sym2..sym10,coif1..coif5,bior1.1,bior1.3,bior1.5,bior2.2,bior2.4,bior2.6,bior2.8,bior3.1,bior3.3,bior3.5 + * ,bior3.7,bior3.9,bior4.4,bior5.5,bior6.8 + */ + static func performWaveletTransform(data: [Double], wavelet: WaveletTypes, + decompositionLevel: Int32, + extensionType: WaveletExtensionTypes = .SYMMETRIC) throws -> ([Double], [Int32]) { + guard (decompositionLevel > 0) else { + throw BrainFlowException ("Invalid decomposition level", .INVALID_ARGUMENTS_ERROR) + } + + let dataLen = Int32(data.count) + let waveletVal = wavelet.rawValue + let extVal = extensionType.rawValue + var lengths = [Int32](repeating: 0, count: Int(decompositionLevel) + 1) + let outputLen = dataLen + 2 * decompositionLevel * (40 + 1) + var outputArray = [Double](repeating: 0.0, count: Int(outputLen)) + + var cData = data + let errorCode = perform_wavelet_transform (&cData, dataLen, waveletVal, decompositionLevel, extVal, + &outputArray, &lengths) + try checkErrorCode("Failed to perform wavelet transform", errorCode) + + let totalLen = Int(lengths.reduce(0, +)) + let result = Array(outputArray[.. [Double] { + guard (decompositionLevel > 0) else { + throw BrainFlowException ("Invalid decomposition level", .INVALID_ARGUMENTS_ERROR) + } + + let waveletVal = wavelet.rawValue + let extVal = extensionType.rawValue + var outputArray = [Double](repeating: 0.0, count: Int(originalDataLen)) + var waveletCoeffs = waveletTuple.0 + var decompositionLengths = waveletTuple.1 + let errorCode = perform_inverse_wavelet_transform (&waveletCoeffs, originalDataLen, waveletVal, + decompositionLevel, extVal, &decompositionLengths, + &outputArray) + try checkErrorCode("Failed to perform inverse wavelet transform", errorCode) + + return outputArray + } + + /** + * get common spatial filters + */ + static func getCSP (data: [[[Double]]], labels: [Double]) throws -> ([[Double]], [Double]) { + let nEpochs = data.count + let nChannels = data[0].count + let nTimes = data[0][0].count + var cLabels = labels + + var tempData1d = [Double](repeating: 0.0, count: Int(nEpochs * nChannels * nTimes)) + for e in 0.. [Double] { + guard windowLen > 0 else { + throw BrainFlowException("Window length must be >= 0", .INVALID_ARGUMENTS_ERROR) + } + var windowData = [Double](repeating: 0.0, count: Int(windowLen)) + let errorCode = get_window (window.rawValue, windowLen, &windowData) + try checkErrorCode("Failed to perform windowing", errorCode) + + return windowData + } + + /** + * perform direct fft + * + * @param data data for fft transform + * @param start_pos starting position to calc fft + * @param end_pos end position to calc fft, total_len must be a power of two + * @param window window function + * @return array of complex values with size N / 2 + 1 + */ + static func performFFT (data: [Double], window: WindowFunctions) throws -> [Complex] { + if let startPos = data.indices.first { + let endPos = startPos + data.count + return try performFFT(data: data, startPos: Int32(startPos), endPos: Int32(endPos), window: window) + } else { + throw BrainFlowException("Empty data buffer in performFFT", .EMPTY_BUFFER_ERROR) + } + } + + static func performFFT (data: [Double], startPos: Int32, endPos: Int32, window: WindowFunctions) throws -> [Complex] { + let dataLen = data.count + guard (startPos >= 0) && (endPos <= dataLen) && (startPos < endPos) else { + throw BrainFlowException ("Invalid position arguments in performFFT", .INVALID_ARGUMENTS_ERROR) + } + + // I didnt find a way to pass an offset using pointers, copy array + var dataToProcess = Array(data[Int(startPos)..($0, $1)} + return complexResult + } + + /** + * perform inverse fft + * + * @param data data from fft transform(array of complex values) + * @return restored data + */ + static func performIFFT (data: [Complex]) throws -> [Double] + { + var complexReal = data.map{$0.real} + var complexImaginary = data.map{$0.imaginary} + + let len = (data.count - 1) * 2 + var output = [Double](repeating: 0.0, count: len) + let errorCode = perform_ifft (&complexReal, &complexImaginary, Int32(len), &output) + try checkErrorCode("Failed to perform ifft", errorCode) + + return output + } + + /** + calculate avg and stddev of BandPowers across selected channels + + :param data: 2d array for calculation + :type data: NDArray + :param bands: List of typles with bands to use. E.g [(1.5, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + :type bands: List + :param channels: channels - rows of data array which should be used for calculation + :type channels: List + :param sampling_rate: sampling rate + :type sampling_rate: int + :param apply_filter: apply bandpass and bandstop filtrers or not + :type apply_filter: bool + :return: avg and stddev arrays for bandpowers + :rtype: tuple + **/ + static func getCustomBandPowers(data: [[Double]]?, bands: [(Double,Double)]?, channels: [Int32]?, samplingRate: Int32, + applyFilter: Bool) throws -> ([Double],[Double]) { + guard ((data != nil) && (channels != nil) && (bands != nil)) else { + throw BrainFlowException ("data or channels or bands are null", .INVALID_ARGUMENTS_ERROR) } + guard ((channels!.count > 0) && (bands!.count > 0)) else { + throw BrainFlowException("wrong input for channels or bands", .INVALID_ARGUMENTS_ERROR) } + + // convert channels from [Int32]? to [Int] for syntactic sugar: + let iChannels = channels!.map{Int($0)} + + let filtersOn = Int32(applyFilter ? 1 : 0) + let numRows = iChannels.count + let numCols = data![iChannels[0]].count + let numBands = bands!.count + var avgBands = [Double](repeating: 0.0, count: numBands) + var stddevBands = [Double](repeating: 0.0, count: numBands) + var data1d = [Double](repeating: 0.0, count: iChannels.count * numCols) + var startFreqs = [Double](repeating: 0.0, count: numBands) + var stopFreqs = [Double](repeating: 0.0, count: numBands) + for i in 0.. ([Double], [Double]) { + guard ((data != nil) && (channels != nil)) else { + throw BrainFlowException ("data or channels null", .INVALID_ARGUMENTS_ERROR) + } + + let bands = [(2.0, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + return try getCustomBandPowers(data: data, bands: bands, channels: channels, + samplingRate: samplingRate, applyFilter: applyFilter) + } + + /** + * get PSD + * + * @param data data to process + * @param start_pos starting position to calc PSD + * @param end_pos end position to calc PSD, total_len must be a power of + * two + * @param sampling_rate sampling rate + * @param window window function + * @return pair of ampl and freq arrays with len N / 2 + 1 + */ + static func getPSD (data: [Double], startPos: Int32, endPos: Int32, samplingRate: Int32, window: Int32) throws -> ([Double], [Double]) { + guard ((startPos >= 0) && (endPos <= data.count) && (startPos < endPos)) else { + throw BrainFlowException ("invalid position arguments", .INVALID_ARGUMENTS_ERROR) + } + + // I didnt find a way to pass an offset using pointers, copy array + var dataToProcess = Array(data[Int(startPos).. ([Double], [Double]) { + guard ((nfft & (nfft - 1)) == 0) else { + throw BrainFlowException ("nfft must be a power of 2", .INVALID_ARGUMENTS_ERROR) + } + + var cData = data + var ampls = [Double](repeating: 0.0, count: Int(nfft) / 2 + 1) + var freqs = [Double](repeating: 0.0, count: Int(nfft) / 2 + 1) + let errorCode = get_psd_welch (&cData, Int32(data.count), nfft, overlap, samplingRate, + window.rawValue, &ls, + &freqs) + try checkErrorCode("Failed to get_psd_welch", errorCode) + + return (ampls, freqs) + } + + /** + * get band power + * + * @param psd PSD from get_psd or get_log_psd + * @param freq_start lowest frequency of band + * @param freq_end highest frequency of band + * @return band power + */ + static func getBandPower (psd: ([Double], [Double]), freqStart: Double, freqEnd: Double) throws -> Double { + var result = [Double](repeating: 0.0, count: 1) + var psdLeft = psd.0 + var psdRight = psd.1 + let errorCode = get_band_power (&psdLeft, &psdRight, Int32(psdLeft.count), freqStart, freqEnd, + &result) + try checkErrorCode("Failed to get band power", errorCode) + return result[0] + } + + /** + * calculate nearest power of two + */ + static func getNearestPowerOfTwo (_ value: Int32) throws -> Int32 { + var powerOfTwo = [Int32](repeating: 0, count: 1) + let errorCode = get_nearest_power_of_two (value, &powerOfTwo) + try checkErrorCode("Failed to calc nearest power of two", errorCode) + return powerOfTwo[0] + } + + /** + * write data to tsv file, in file data will be transposed + */ + static func writeFile (data: [[Double]], fileName: String, fileMode: String) throws { + guard data.count > 0 else { + throw BrainFlowException ("empty data array", .INVALID_ARGUMENTS_ERROR) + } + + var linearData = data.flatMap {$0} + let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileURL = docDir.appendingPathComponent(fileName) + var cFileName = fileURL.path.cString(using: String.Encoding.utf8)! + var cFileMode = fileMode.cString(using: String.Encoding.utf8)! + + let errorCode = write_file (&linearData, Int32(data.count), Int32(data[0].count), &cFileName, &cFileMode) + try checkErrorCode("Failed to write data to file: \(fileName)", errorCode) + } + + /** + * read data from file, transpose it back to original format + */ + static func readFile (fileName: String) throws -> [[Double]] { + var numElements = [Int32](repeating: 0, count: 1) + let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileURL = docDir.appendingPathComponent(fileName) + var cFileName = fileURL.path.cString(using: String.Encoding.utf8)! + var errorCode = get_num_elements_in_file (&cFileName, &numElements) + try checkErrorCode("Failed to determine number of elements in file: \(fileName)", errorCode) + + var dataArr = [Double](repeating: 0.0, count: Int(numElements[0])) + var numRows = [Int32](repeating: 0, count: 1) + var numCols = [Int32](repeating: 0, count: 1) + errorCode = read_file (&dataArr, &numRows, &numCols, &cFileName, numElements[0]) + try checkErrorCode("Failed to read data from file: \(fileName)", errorCode) + + return dataArr.matrix2D(rowLength: Int(numCols[0])) + } + + static func performICA(data: [[Double]], numComponents: Int, channels: [Int]? = nil) throws -> + ([[Double]], [[Double]], [[Double]], [[Double]]) { + var channelsToUse: [Int] = [] + guard data.isRectangular() else { + throw BrainFlowException("input data is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + guard numComponents >= 1 else { + throw BrainFlowException("wrong number of components", .INVALID_ARGUMENTS_ERROR) + } + + if let channelIndexes = channels { + channelsToUse = channelIndexes + } else { + let indexRange = 0.. Int { + let numCols = self.map { $0.count } + return numCols.count + } + + // Return true only if the 2D array is rectangular, i.e., all rows are the same length. + func isRectangular() -> Bool { + let numCols = self.map { $0.count } + let set = Set(numCols) + return set.count == 1 + } + + // Return a tuple of (numRows, numCols) for the given 2D array: + func shapeOfRectangular() throws -> (Int, Int) { + guard self.isRectangular() else { + throw BrainFlowException("array is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + let numRows = self.numRows() + let numCols = self[0].count + return (numRows, numCols) + } +} +// Based on https://stackoverflow.com/questions/48088882/how-can-split-from-string-to-array-by-chunks-of-given-size +extension Array where Element == Double { + func reshapeRectangular(size: Int) throws -> [[Element]] { + let result = stride(from: 0, to: count, by: size).map { + Array(self[$0 ..< Swift.min($0 + size, count)]) + } + guard result.isRectangular() else { + throw BrainFlowException("reshape result is not rectangular", .INVALID_ARGUMENTS_ERROR) + } + return result + } +} diff --git a/swift_package/BrainFlow/Sources/MLModule.swift b/swift_package/BrainFlow/Sources/MLModule.swift new file mode 100644 index 000000000..b5f41e4d8 --- /dev/null +++ b/swift_package/BrainFlow/Sources/MLModule.swift @@ -0,0 +1,101 @@ +// +// MLModule.swift +// a Swift binding for BrainFlow's MLModule API +// +// Created by Scott Miller on 9/22/21 on behalf of Aeris Rising, LLC. +// + +import Foundation + +struct BrainFlowModelParams: Encodable { + let metric: BrainFlowMetrics + let classifier: BrainFlowClassifiers + let file: String + let other_info: String + let output_name: String + let max_array_size = 8192 + + init (metric: BrainFlowMetrics, classifier: BrainFlowClassifiers, + file: String = "", otherInfo: String = "", outputName: String = "") { + self.metric = metric + self.classifier = classifier + self.file = file + self.other_info = otherInfo + self.output_name = outputName + } +} + +struct MLModule { + //MLModule class used to calc derivative metrics from raw data + + let modelParams: BrainFlowModelParams + + static func setLogLevel(_ logLevel: LogLevels) throws { + //set BrainFlow log level, use it only if you want to write your own messages to BrainFlow logger, + //otherwise use enable_ml_logger, enable_dev_ml_logger or disable_ml_logger + //:param log_level: log level, to specify it you should use values from LogLevels enum + //:type log_level: int + + let errorCode = set_log_level_ml_module(logLevel.rawValue) + try checkErrorCode("unable to enable logger", errorCode) + } + + static func enableMLlogger() throws { + //enable ML Logger with level INFO, uses stderr for log messages by default + try setLogLevel(.LEVEL_INFO) + } + + static func disableMLlogger() throws { + ///disable BrainFlow Logger + try setLogLevel(.LEVEL_OFF) + } + + static func enableDevMLlogger() throws { + //enable ML Logger with level TRACE, uses stderr for log messages by default + try setLogLevel(.LEVEL_TRACE) + } + + static func setLogFile(logFile: String) throws { + //redirect logger from stderr to file, can be called any time + //:param log_file: log file name + //:type log_file: str + + var cFile = [CChar](repeating: CChar(0), count: 4096) + let errorCode = set_log_file_ml_module(&cFile) + try checkErrorCode("Cannot set log file to: \(logFile)", errorCode) + } + + func prepareClassifier() throws { + ///prepare classifier + print("modelParams: \(modelParams)") + let json = try self.modelParams.encodeJSON() + var params = json.cString(using: .utf8)! + let errorCode = prepare(¶ms) + try checkErrorCode("Cannot prepare classifier", errorCode) + } + + func releaseClassifier() throws { + ///release classifier + var params = try self.modelParams.encodeJSON().cString(using: .utf8)! + let errorCode = release(¶ms) + try checkErrorCode("Cannot release classifier", errorCode) + } + + func predictClass(data: [Double]) throws -> [Double] { + //calculate metric from data + //:param data: input array + //:type data: NDArray + //:return: metric value + //:rtype: float + + let len = Int32(data.count) + var vData = data + var output = [Double](repeating: 0.0, count: modelParams.max_array_size) + var outputLen = [Int32](repeating: 0, count: 1) + var params = try self.modelParams.encodeJSON().cString(using: .utf8)! + let errorCode = predict(&vData, len, &output, &outputLen, ¶ms) + try checkErrorCode("unable to calc metric", errorCode) + + return Array(output[0.. 100)) + print(data) + } catch let bfError as BrainFlowException { + try? BoardShim.logMessage (.LEVEL_ERROR, bfError.message) + try? BoardShim.logMessage (.LEVEL_ERROR, "Error code: \(bfError.errorCode)") + XCTFail() + } + } + + func testMarkers() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + let boardDescription = try BoardShim.getBoardDescr(board.boardId) + + try board.startStream(bufferSize: 45000) + for i in 0..<10 { + sleep(1) + try board.insertMarker(value: Double(i + 1)) } + let size = try board.getBoardDataCount() + let data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + if let markerChInt32 = boardDescription.marker_channel { + let markerCh = Int(markerChInt32) + let uqMarkers = Set(data[markerCh]) + XCTAssert(uqMarkers.count == 10) + print(data) + } else { + XCTAssert(false) + } + } + + func testReadWriteFile() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(10) + let size = try board.getBoardDataCount() + let data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + // demo how to convert it to pandas DF and plot data + _ = try BoardShim.getEEGchannels(.SYNTHETIC_BOARD) + print("Data From the Board") + print(Array(data[..<10])) + + // demo for data serialization using brainflow API, we recommend to use it instead pandas.to_csv() + try DataFilter.writeFile(data: data, fileName: "test.csv", fileMode: "w") // use 'a' for append mode + + let restoredData = try DataFilter.readFile(fileName: "test.csv") + print("Data From the File") + print(Array(restoredData)) + + for channel in data.indices { + XCTAssert(compareData(from: data[channel], to: restoredData[channel], tol: 1e-3)) } + } + + func testDownsampleData() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(10) + let data = try board.getBoardData(20) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(.SYNTHETIC_BOARD) + // demo for downsampling, it just aggregates data + for count in EEGchannels.indices { + let channel = Int(EEGchannels[count]) + print("Original data for channel \(channel)") + print(data[channel]) + var downsampledData = [Double]() + let beforeSum = Double(data[channel].compactMap( {$0} ).reduce(0, +)) + + switch count { + case 0: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 3, operation: .MEDIAN) + case 1: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 2, operation: .MEAN) + default: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 2, operation: .EACH) + } + + let afterSum = Double(downsampledData.compactMap{$0}.reduce(0, +)) + XCTAssert(beforeSum != afterSum) + print("Downsampled data for channel \(channel)") + print(downsampledData) + } + } + + private func compareData(from: [Double], to: [Double], tol: Double) -> Bool { + // return true if all elements match to within given tolerance + guard ((from.count > 0) && (from.indices == to.indices)) else { + print("compareData: sizes mismatch") + return false + } + + for i in from.indices { + if abs(from[i] - to[i]) > tol { + return false + } + } + + return true + } + + func testTransforms() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + let samplingRate = try BoardShim.getSamplingRate(board.boardId) + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(10) + let data = try board.getCurrentBoardData(DataFilter.getNearestPowerOfTwo(samplingRate)) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(board.boardId) + // demo for transforms + for count in EEGchannels.indices { + let channel = Int(EEGchannels[count]) + print("Original data for channel \(channel)") + print(data[channel]) + // demo for wavelet transforms + //wavelet_coeffs format is[A(J) D(J) D(J-1) ..... D(1)] where J is decomposition level, A - app coeffs, D - detailed coeffs + // lengths array stores lengths for each block + let (waveletCoeffs, lengths) = try DataFilter.performWaveletTransform(data: data[channel], wavelet: .DB5, decompositionLevel: 3) + //let appCoefs = Array(waveletCoeffs[0..= 100.0) + } + + func testEEGmetrics() throws { + try BoardShim.enableBoardLogger() + try DataFilter.enableDataLogger() + try MLModule.enableMLlogger() + + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + let masterBoardId = try board.getBoardId() + let samplingRate = try BoardShim.getSamplingRate(masterBoardId) + try board.prepareSession() + try board.startStream(bufferSize: 45000) + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(5) // recommended window size for eeg metric calculation is at least 4 seconds, bigger is better + let size = try board.getBoardDataCount() + let data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(masterBoardId) + + // avg band power + let bands = try DataFilter.getAvgBandPowers(data: data, channels: EEGchannels, + samplingRate: samplingRate, applyFilter: true) + let avgFeatureVector = bands.0 + bands.1 + print("testEEGmetrics->avg featureVector: \(avgFeatureVector)") + XCTAssert(avgFeatureVector.count == 10) + XCTAssert((avgFeatureVector.min()! >= 0.0) && (avgFeatureVector.max()! <= 2.0)) + + // custom band power + let avgBands = [(2.0, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + let newBands = try DataFilter.getCustomBandPowers(data: data, bands: avgBands, channels: EEGchannels, samplingRate: samplingRate, applyFilter: true) + let featureVector = newBands.0 + newBands.1 + print("testEEGmetrics->custom featureVector: \(featureVector)") + XCTAssert(featureVector.count == 10) + XCTAssert((featureVector.min()! >= 0.0) && (featureVector.max()! <= 2.0)) + + // calc concentration + let concentrationParams = BrainFlowModelParams(metric: .MINDFULNESS, classifier: .DEFAULT_CLASSIFIER) + let concentration = MLModule(modelParams: concentrationParams) + try concentration.prepareClassifier() + let concClass = try concentration.predictClass(data: featureVector) + print("testEEGmetrics->concClass: \(concClass)") + try concentration.releaseClassifier() + XCTAssert(concClass.count == 1) + XCTAssert((concClass.min()! >= 0.0) && (concClass.max()! <= 1.0)) + + // restfulness + onnx is not supported: + let relaxationParams = BrainFlowModelParams(metric: .RESTFULNESS, classifier: .ONNX_CLASSIFIER) + let relaxation = MLModule(modelParams: relaxationParams) + XCTAssertThrowsError(try relaxation.prepareClassifier()) + } + +} diff --git a/swift_package/BrainFlow/Tests/BrainFlowTests/BrainFlowTests.swift b/swift_package/BrainFlow/Tests/BrainFlowTests/BrainFlowTests.swift new file mode 100644 index 000000000..0c4a4dc86 --- /dev/null +++ b/swift_package/BrainFlow/Tests/BrainFlowTests/BrainFlowTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import BrainFlow + +final class BrainFlowTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + //XCTAssertEqual(BrainFlow().text, "Hello, World!") + } +} diff --git a/swift_package/BrainFlow/Tests/BrainFlowTests/DataFilterTests.swift b/swift_package/BrainFlow/Tests/BrainFlowTests/DataFilterTests.swift new file mode 100644 index 000000000..17cae4c0e --- /dev/null +++ b/swift_package/BrainFlow/Tests/BrainFlowTests/DataFilterTests.swift @@ -0,0 +1,110 @@ +// +// DataFilterTests.swift +// These are the unit tests for DataFilter.swift. They are modeled after +// https://github.com/brainflow-dev/brainflow/tree/master/tests/python + +import XCTest +//import BrainFlow +@testable import BrainFlow + +class DataFilterTests: XCTestCase { + func testBandPowerAll() { + // use synthetic board for demo + let params = BrainFlowInputParams() + let boardId = BoardIds.SYNTHETIC_BOARD + do { + try BoardShim.enableDevBoardLogger() + let samplingRate = try BoardShim.getSamplingRate(boardId) + let board = try BoardShim(boardId, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(5) + let data = try board.getBoardData(256) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(boardId) + let bands = try DataFilter.getAvgBandPowers(data: data, channels: EEGchannels, + samplingRate: samplingRate, applyFilter: true) + + let avgSum = bands.0.reduce(0, +) + let stdSum = bands.1.reduce(0, +) + XCTAssert((bands.0.count == 5) && (bands.1.count == 5) && + (avgSum > 0) && (avgSum <= 1) && (stdSum > 0) && (stdSum < 10)) + } + catch let bfError as BrainFlowException { + try? BoardShim.logMessage (.LEVEL_ERROR, bfError.message) + try? BoardShim.logMessage (.LEVEL_ERROR, "Error code: \(bfError.errorCode)") + } + catch { + try? BoardShim.logMessage (.LEVEL_ERROR, "undefined exception") + } + } + + func testCSP() { + let labels: [Double] = [0.0, 1.0] + let data: [[[Double]]] = [[[6, 3, 1, 5], [3, 0, 5, 1]], [[1, 5, 6, 2], [5, 1, 2, 2]]] + let trueFilters: [[String]] = [["-0.313406", "0.079215"], ["-0.280803", "-0.480046"]] + let trueEigVals: [String] = ["0.456713", "0.752979"] + + do { + let (filters, eigVals) = try DataFilter.getCSP(data: data, labels: labels) + + let roundFilters = filters.map( { $0.map( {String(format: "%.6f", $0)}) } ) + let roundEigVals = eigVals.map( {String(format: "%.6f", $0)} ) + + XCTAssert(roundFilters == trueFilters) + XCTAssert(roundEigVals == trueEigVals) + } + catch let bfError as BrainFlowException { + try? BoardShim.logMessage (.LEVEL_ERROR, bfError.message) + try? BoardShim.logMessage (.LEVEL_ERROR, "Error code: \(bfError.errorCode)") + } + catch { + try? BoardShim.logMessage (.LEVEL_ERROR, "undefined exception") + } + } + + func stdDev(_ data : [Double]) -> Double + { + let len = Double(data.count) + let mean = data.reduce(0, {$0 + $1}) / len + let sumOfSq = data.map { pow($0 - mean, 2.0)}.reduce(0, {$0 + $1}) + return sqrt(sumOfSq / len) + } + + // round to the 5th decimal place before comparing each item in the two arrays + func compareFFT(_ preData: [Double], _ postData: [Double]) { + for i in preData.indices { + let format = "%.5f" + let preString = String(format: format, preData[i]) + let postString = String(format: format, postData[i]) + + XCTAssert(preString == postString) + } + } + + func testWindowing () { + let windowLen: Int32 = 20 + let testError = BrainFlowException("test message", .INVALID_ARGUMENTS_ERROR) + + do { + for window in WindowFunctions.allCases { + let windowData = try DataFilter.getWindow(window: window, windowLen: windowLen) + XCTAssert(windowData.count == windowLen) + XCTAssertThrowsError(try DataFilter.getWindow(window: window, windowLen: -1)) { error in + if let bfError = error as? BrainFlowException { + XCTAssertEqual(bfError, testError) + } + } + } + } + catch let bfError as BrainFlowException { + try? BoardShim.logMessage (.LEVEL_ERROR, bfError.message) + } + catch { + try? BoardShim.logMessage (.LEVEL_ERROR, "undefined exception") + } + } +} diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.pbxproj b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.pbxproj new file mode 100644 index 000000000..369a154e4 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.pbxproj @@ -0,0 +1,2573 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 5F17B7832BA8B89C00DD1263 /* BoardShimTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643A285617B2001AA429 /* BoardShimTests.swift */; }; + 5F17B7842BA8B89F00DD1263 /* BrainFlowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643B285617B2001AA429 /* BrainFlowTests.swift */; }; + 5F17B7852BA8B8A100DD1263 /* BrainFlowCITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643C285617B2001AA429 /* BrainFlowCITests.swift */; }; + 5F17B7862BA8B8A400DD1263 /* DataFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643D285617B2001AA429 /* DataFilterTests.swift */; }; + 5F20CCB7285DDE5500F2CEB5 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F20CCB6285DDE5500F2CEB5 /* Numerics */; }; + 5F20CCB9285DDE8200F2CEB5 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F20CCB8285DDE8200F2CEB5 /* Numerics */; }; + 5F20CCBB285DDE8E00F2CEB5 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F20CCBA285DDE8E00F2CEB5 /* BrainFlow */; }; + 5F466F962BC4576400E129A7 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F466F952BC4576400E129A7 /* Numerics */; }; + 5F466FA22BC465CD00E129A7 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 5F466FA12BC465CD00E129A7 /* ArgumentParser */; }; + 5F466FA72BC474B500E129A7 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F466FA62BC474B500E129A7 /* BrainFlow */; }; + 5F52BA412BC4D39600AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BA422BC4D39600AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BA442BC4D39600AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BA452BC4D55500AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BA462BC97D2D00AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BA472BC97D2E00AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BA672BC9A3D000AC74F4 /* libsimpleble-c.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA662BC9A3D000AC74F4 /* libsimpleble-c.dylib */; }; + 5F52BA682BC9A3DE00AC74F4 /* libsimpleble-c.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA662BC9A3D000AC74F4 /* libsimpleble-c.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BA8C2BC9A98600AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BA8D2BC9A98600AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BA8E2BC9A98600AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BA8F2BC9A98600AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BA902BC9A98600AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BA912BC9A98600AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BA922BC9A98600AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BA932BC9A98600AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BA952BC9A98600AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BA982BC9A98600AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BA9A2BC9A98600AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BA852BC9A98600AC74F4 /* Numerics */; }; + 5F52BA9B2BC9A98600AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BA892BC9A98600AC74F4 /* BrainFlow */; }; + 5F52BAAC2BC9E83800AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAAD2BC9E86700AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAAE2BC9E8C400AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAAF2BC9E8D800AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BAB52BCA18C300AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BAB62BCA18C300AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BAB72BCA18C300AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BAB82BCA18C300AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BAB92BCA18C300AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BABB2BCA18C300AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BABC2BCA18C300AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BABD2BCA18C300AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BABF2BCA18C300AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BAC02BCA18C300AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BAC12BCA18C300AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BAC22BCA18C300AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAB12BCA18C300AC74F4 /* Numerics */; }; + 5F52BAC32BCA18C300AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAB32BCA18C300AC74F4 /* BrainFlow */; }; + 5F52BAC62BCA18C300AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAC72BCA18C300AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAC82BCA18C300AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAD52BCAA88000AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BAD62BCAA88000AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BAD72BCAA88000AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BAD82BCAA88000AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BAD92BCAA88000AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BADB2BCAA88000AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BADC2BCAA88000AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BADD2BCAA88000AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BADF2BCAA88000AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BAE02BCAA88000AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BAE12BCAA88000AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BAE22BCAA88000AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAD12BCAA88000AC74F4 /* Numerics */; }; + 5F52BAE32BCAA88000AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAD32BCAA88000AC74F4 /* BrainFlow */; }; + 5F52BAE62BCAA88000AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAE72BCAA88000AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAE82BCAA88000AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BAF12BCAA9E700AC74F4 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAF02BCAA9E700AC74F4 /* ArgumentParser */; }; + 5F52BAF72BCAAB3400AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BAF82BCAAB3400AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BAF92BCAAB3400AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BAFA2BCAAB3400AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BAFB2BCAAB3400AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BAFD2BCAAB3400AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BAFE2BCAAB3400AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BAFF2BCAAB3400AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BB012BCAAB3400AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BB022BCAAB3400AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BB032BCAAB3400AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BB042BCAAB3400AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAF32BCAAB3400AC74F4 /* Numerics */; }; + 5F52BB052BCAAB3400AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BAF52BCAAB3400AC74F4 /* BrainFlow */; }; + 5F52BB082BCAAB3400AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB092BCAAB3400AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB0A2BCAAB3400AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB172BCAAC7900AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BB182BCAAC7900AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BB192BCAAC7900AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BB1A2BCAAC7900AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BB1B2BCAAC7900AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BB1D2BCAAC7900AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BB1E2BCAAC7900AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BB1F2BCAAC7900AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BB212BCAAC7900AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BB222BCAAC7900AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BB232BCAAC7900AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BB242BCAAC7900AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB132BCAAC7900AC74F4 /* Numerics */; }; + 5F52BB252BCAAC7900AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB152BCAAC7900AC74F4 /* BrainFlow */; }; + 5F52BB282BCAAC7900AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB292BCAAC7900AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB2A2BCAAC7900AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB392BCAADF900AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BB3A2BCAADF900AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BB3C2BCAADF900AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BB3D2BCAADF900AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BB3E2BCAADF900AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BB3F2BCAADF900AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BB402BCAADF900AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BB412BCAADF900AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BB432BCAADF900AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BB442BCAADF900AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BB452BCAADF900AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BB462BCAADF900AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB352BCAADF900AC74F4 /* Numerics */; }; + 5F52BB472BCAADF900AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB372BCAADF900AC74F4 /* BrainFlow */; }; + 5F52BB4A2BCAADF900AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB4B2BCAADF900AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB4C2BCAADF900AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB592BCAAF1300AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BB5A2BCAAF1300AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BB5C2BCAAF1300AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BB5D2BCAAF1300AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BB5E2BCAAF1300AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BB5F2BCAAF1300AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BB602BCAAF1300AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BB612BCAAF1300AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BB632BCAAF1300AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BB642BCAAF1300AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BB652BCAAF1300AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BB662BCAAF1300AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB552BCAAF1300AC74F4 /* Numerics */; }; + 5F52BB672BCAAF1300AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB572BCAAF1300AC74F4 /* BrainFlow */; }; + 5F52BB6A2BCAAF1300AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB6B2BCAAF1300AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB6C2BCAAF1300AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB792BCAAFCE00AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BB7A2BCAAFCE00AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BB7C2BCAAFCE00AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BB7D2BCAAFCE00AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BB7E2BCAAFCE00AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BB7F2BCAAFCE00AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BB802BCAAFCE00AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BB812BCAAFCE00AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BB832BCAAFCE00AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BB842BCAAFCE00AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BB852BCAAFCE00AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BB862BCAAFCE00AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB752BCAAFCE00AC74F4 /* Numerics */; }; + 5F52BB872BCAAFCE00AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB772BCAAFCE00AC74F4 /* BrainFlow */; }; + 5F52BB8A2BCAAFCE00AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB8B2BCAAFCE00AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB8C2BCAAFCE00AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BB9B2BCAB23700AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BB9C2BCAB23700AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BB9D2BCAB23700AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BB9E2BCAB23700AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BB9F2BCAB23700AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BBA02BCAB23700AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BBA12BCAB23700AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BBA32BCAB23700AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BBA52BCAB23700AC74F4 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB982BCAB23700AC74F4 /* ArgumentParser */; }; + 5F52BBA62BCAB23700AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BBA72BCAB23700AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BBA82BCAB23700AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BBA92BCAB23700AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB952BCAB23700AC74F4 /* Numerics */; }; + 5F52BBAA2BCAB23700AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BB972BCAB23700AC74F4 /* BrainFlow */; }; + 5F52BBAD2BCAB23700AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BBAE2BCAB23700AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BBAF2BCAB23700AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BBBC2BCAB5DC00AC74F4 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5F52BBBD2BCAB5DC00AC74F4 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5F52BBBF2BCAB5DC00AC74F4 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5F52BBC02BCAB5DC00AC74F4 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5F52BBC12BCAB5DC00AC74F4 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5F52BBC22BCAB5DC00AC74F4 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5F52BBC32BCAB5DC00AC74F4 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5F52BBC42BCAB5DC00AC74F4 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5F52BBC62BCAB5DC00AC74F4 /* libDataHandler.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; }; + 5F52BBC72BCAB5DC00AC74F4 /* libMLModule.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; }; + 5F52BBC82BCAB5DC00AC74F4 /* libBoardController.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; }; + 5F52BBC92BCAB5DC00AC74F4 /* Numerics in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BBB82BCAB5DC00AC74F4 /* Numerics */; }; + 5F52BBCA2BCAB5DC00AC74F4 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5F52BBBA2BCAB5DC00AC74F4 /* BrainFlow */; }; + 5F52BBCD2BCAB5DC00AC74F4 /* libDataHandler.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BBCE2BCAB5DC00AC74F4 /* libMLModule.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5F52BBCF2BCAB5DC00AC74F4 /* libBoardController.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5FD91A3A2BC49D9600AC3CCB /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5FD91A3B2BC49D9600AC3CCB /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5FD91A3C2BC49D9600AC3CCB /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5FD91A3D2BC49D9600AC3CCB /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5FD91A3E2BC49D9600AC3CCB /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5FD91A3F2BC49D9600AC3CCB /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5FD91A402BC49D9600AC3CCB /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5FD91A412BC49D9600AC3CCB /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5FD91A442BC49F1000AC3CCB /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5FD91A452BC49F1000AC3CCB /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5FD91A462BC49F1000AC3CCB /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5FD91A472BC49F1000AC3CCB /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5FD91A482BC49F1000AC3CCB /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5FD91A492BC49F1000AC3CCB /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5FD91A4A2BC49F1000AC3CCB /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5FD91A4B2BC49F1000AC3CCB /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5FDD640328560B36001AA429 /* BrainFlow in Frameworks */ = {isa = PBXBuildFile; productRef = 5FDD640228560B36001AA429 /* BrainFlow */; }; + 5FDD643E285617B2001AA429 /* BoardShimTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643A285617B2001AA429 /* BoardShimTests.swift */; }; + 5FDD643F285617B2001AA429 /* BrainFlowTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643B285617B2001AA429 /* BrainFlowTests.swift */; }; + 5FDD6440285617B2001AA429 /* BrainFlowCITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643C285617B2001AA429 /* BrainFlowCITests.swift */; }; + 5FDD6441285617B2001AA429 /* DataFilterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD643D285617B2001AA429 /* DataFilterTests.swift */; }; + 5FDD644228561815001AA429 /* BrainFlowExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */; }; + 5FDD644328561815001AA429 /* DataFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640E28560C67001AA429 /* DataFilter.swift */; }; + 5FDD644428561815001AA429 /* MLModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641428560C67001AA429 /* MLModule.swift */; }; + 5FDD644528561815001AA429 /* BrainFlowConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */; }; + 5FDD644628561815001AA429 /* BrainFlowInputParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */; }; + 5FDD644728561815001AA429 /* BrainFlowException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641128560C67001AA429 /* BrainFlowException.swift */; }; + 5FDD644828561815001AA429 /* BoardDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641528560C67001AA429 /* BoardDescription.swift */; }; + 5FDD644928561815001AA429 /* BoardShim.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FDD641328560C67001AA429 /* BoardShim.swift */; }; + 5FE97CE22BCDEC810056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CE12BCDEC810056EC80 /* main.swift */; }; + 5FE97CE42BCDEDC50056EC80 /* eeg_metrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CE32BCDEDC50056EC80 /* eeg_metrics.swift */; }; + 5FE97CE62BCDEE350056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CE52BCDEE350056EC80 /* main.swift */; }; + 5FE97CE82BCDEF6C0056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CE72BCDEF6C0056EC80 /* main.swift */; }; + 5FE97CEA2BCDF0360056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CE92BCDF0360056EC80 /* main.swift */; }; + 5FE97CEC2BCDF1BA0056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CEB2BCDF1BA0056EC80 /* main.swift */; }; + 5FE97CEE2BCDF1DD0056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CED2BCDF1DD0056EC80 /* main.swift */; }; + 5FE97CF02BCDF20A0056EC80 /* markers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CEF2BCDF20A0056EC80 /* markers.swift */; }; + 5FE97CF22BCDF33C0056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CF12BCDF33C0056EC80 /* main.swift */; }; + 5FE97CF42BCDF3930056EC80 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CF32BCDF3930056EC80 /* main.swift */; }; + 5FE97CF62BCE94DF0056EC80 /* brainflow_get_data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FE97CF52BCE94DF0056EC80 /* brainflow_get_data.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5F466F8A2BC454A900E129A7 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F466F9D2BC4577A00E129A7 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BA682BC9A3DE00AC74F4 /* libsimpleble-c.dylib in Embed Libraries */, + 5F52BA452BC4D55500AC74F4 /* libBoardController.dylib in Embed Libraries */, + 5F52BA462BC97D2D00AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BA472BC97D2E00AC74F4 /* libMLModule.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BA9C2BC9A98600AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BA9D2BC9A98600AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BAAE2BC9E8C400AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BAAD2BC9E86700AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BAAC2BC9E83800AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BAC42BCA18C300AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BAC52BCA18C300AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BAC62BCA18C300AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BAC72BCA18C300AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BAC82BCA18C300AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BAE42BCAA88000AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BAE52BCAA88000AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BAE62BCAA88000AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BAE72BCAA88000AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BAE82BCAA88000AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB062BCAAB3400AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BB072BCAAB3400AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BB082BCAAB3400AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BB092BCAAB3400AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BB0A2BCAAB3400AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB262BCAAC7900AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BB272BCAAC7900AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BB282BCAAC7900AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BB292BCAAC7900AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BB2A2BCAAC7900AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB482BCAADF900AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BB492BCAADF900AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BB4A2BCAADF900AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BB4B2BCAADF900AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BB4C2BCAADF900AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB682BCAAF1300AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BB692BCAAF1300AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BB6A2BCAAF1300AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BB6B2BCAAF1300AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BB6C2BCAAF1300AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB882BCAAFCE00AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BB892BCAAFCE00AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BB8A2BCAAFCE00AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BB8B2BCAAFCE00AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BB8C2BCAAFCE00AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BBAB2BCAB23700AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BBAC2BCAB23700AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BBAD2BCAB23700AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BBAE2BCAB23700AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BBAF2BCAB23700AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BBCB2BCAB5DC00AC74F4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5F52BBCC2BCAB5DC00AC74F4 /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = PackageFrameworks; + dstSubfolderSpec = 10; + files = ( + 5F52BBCD2BCAB5DC00AC74F4 /* libDataHandler.dylib in Embed Libraries */, + 5F52BBCE2BCAB5DC00AC74F4 /* libMLModule.dylib in Embed Libraries */, + 5F52BBCF2BCAB5DC00AC74F4 /* libBoardController.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5FDD63F328560953001AA429 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5FE20CE02BA7D70B003C194A /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; + 5FE20CF22BA7D7A0003C194A /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 5F466F8C2BC454A900E129A7 /* brainflow_get_data */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = brainflow_get_data; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libDataHandler.dylib; path = Frameworks/libDataHandler.dylib; sourceTree = ""; }; + 5F52BA3C2BC4D32F00AC74F4 /* libMuseLib.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMuseLib.dylib; path = Frameworks/libMuseLib.dylib; sourceTree = ""; }; + 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libBoardController.dylib; path = Frameworks/libBoardController.dylib; sourceTree = ""; }; + 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMLModule.dylib; path = Frameworks/libMLModule.dylib; sourceTree = ""; }; + 5F52BA662BC9A3D000AC74F4 /* libsimpleble-c.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libsimpleble-c.dylib"; path = "Frameworks/libsimpleble-c.dylib"; sourceTree = ""; }; + 5F52BAA52BC9A98600AC74F4 /* band_power */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = band_power; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BACC2BCA18C300AC74F4 /* band_power_all */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = band_power_all; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BAEC2BCAA88000AC74F4 /* markers */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = markers; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BB0E2BCAAB3400AC74F4 /* read_write_file */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = read_write_file; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BB2E2BCAAC7900AC74F4 /* downsampling */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = downsampling; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BB502BCAADF900AC74F4 /* transforms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = transforms; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BB702BCAAF1300AC74F4 /* signal_filtering */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = signal_filtering; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BB902BCAAFCE00AC74F4 /* denoising */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = denoising; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BBB32BCAB23700AC74F4 /* eeg_metrics */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = eeg_metrics; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F52BBD32BCAB5DC00AC74F4 /* ica */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ica; sourceTree = BUILT_PRODUCTS_DIR; }; + 5FDD63F528560953001AA429 /* BrainFlowCI */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BrainFlowCI; sourceTree = BUILT_PRODUCTS_DIR; }; + 5FDD640028560986001AA429 /* BrainFlow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrainFlow; path = ../BrainFlow; sourceTree = ""; }; + 5FDD640E28560C67001AA429 /* DataFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataFilter.swift; sourceTree = ""; }; + 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowConstants.swift; sourceTree = ""; }; + 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowExtensions.swift; sourceTree = ""; }; + 5FDD641128560C67001AA429 /* BrainFlowException.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowException.swift; sourceTree = ""; }; + 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowInputParams.swift; sourceTree = ""; }; + 5FDD641328560C67001AA429 /* BoardShim.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardShim.swift; sourceTree = ""; }; + 5FDD641428560C67001AA429 /* MLModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MLModule.swift; sourceTree = ""; }; + 5FDD641528560C67001AA429 /* BoardDescription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardDescription.swift; sourceTree = ""; }; + 5FDD643028560DBF001AA429 /* BrainFlowCITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BrainFlowCITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5FDD643A285617B2001AA429 /* BoardShimTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoardShimTests.swift; sourceTree = ""; }; + 5FDD643B285617B2001AA429 /* BrainFlowTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowTests.swift; sourceTree = ""; }; + 5FDD643C285617B2001AA429 /* BrainFlowCITests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrainFlowCITests.swift; sourceTree = ""; }; + 5FDD643D285617B2001AA429 /* DataFilterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataFilterTests.swift; sourceTree = ""; }; + 5FE97CE12BCDEC810056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/ica/main.swift; sourceTree = ""; }; + 5FE97CE32BCDEDC50056EC80 /* eeg_metrics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = eeg_metrics.swift; path = ../../examples/tests/eeg_metrics/eeg_metrics.swift; sourceTree = ""; }; + 5FE97CE52BCDEE350056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/denoising/main.swift; sourceTree = ""; }; + 5FE97CE72BCDEF6C0056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/signal_filtering/main.swift; sourceTree = ""; }; + 5FE97CE92BCDF0360056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/transforms/main.swift; sourceTree = ""; }; + 5FE97CEB2BCDF1BA0056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/downsampling/main.swift; sourceTree = ""; }; + 5FE97CED2BCDF1DD0056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/read_write_file/main.swift; sourceTree = ""; }; + 5FE97CEF2BCDF20A0056EC80 /* markers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = markers.swift; path = ../../examples/tests/markers/markers.swift; sourceTree = ""; }; + 5FE97CF12BCDF33C0056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/band_power_all/main.swift; sourceTree = ""; }; + 5FE97CF32BCDF3930056EC80 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../../examples/tests/band_power/main.swift; sourceTree = ""; }; + 5FE97CF52BCE94DF0056EC80 /* brainflow_get_data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = brainflow_get_data.swift; path = ../../examples/tests/brainflow_get_data/brainflow_get_data.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5F466F892BC454A900E129A7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BA442BC4D39600AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BA672BC9A3D000AC74F4 /* libsimpleble-c.dylib in Frameworks */, + 5F52BA412BC4D39600AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BA422BC4D39600AC74F4 /* libBoardController.dylib in Frameworks */, + 5F466FA22BC465CD00E129A7 /* ArgumentParser in Frameworks */, + 5F466F962BC4576400E129A7 /* Numerics in Frameworks */, + 5F466FA72BC474B500E129A7 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BA942BC9A98600AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BAAF2BC9E8D800AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BA952BC9A98600AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BA982BC9A98600AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BA9A2BC9A98600AC74F4 /* Numerics in Frameworks */, + 5F52BA9B2BC9A98600AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BABE2BCA18C300AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BABF2BCA18C300AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BAC02BCA18C300AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BAC12BCA18C300AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BAC22BCA18C300AC74F4 /* Numerics in Frameworks */, + 5F52BAC32BCA18C300AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BADE2BCAA88000AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BAF12BCAA9E700AC74F4 /* ArgumentParser in Frameworks */, + 5F52BADF2BCAA88000AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BAE02BCAA88000AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BAE12BCAA88000AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BAE22BCAA88000AC74F4 /* Numerics in Frameworks */, + 5F52BAE32BCAA88000AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB002BCAAB3400AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB012BCAAB3400AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BB022BCAAB3400AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BB032BCAAB3400AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BB042BCAAB3400AC74F4 /* Numerics in Frameworks */, + 5F52BB052BCAAB3400AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB202BCAAC7900AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB212BCAAC7900AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BB222BCAAC7900AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BB232BCAAC7900AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BB242BCAAC7900AC74F4 /* Numerics in Frameworks */, + 5F52BB252BCAAC7900AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB422BCAADF900AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB432BCAADF900AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BB442BCAADF900AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BB452BCAADF900AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BB462BCAADF900AC74F4 /* Numerics in Frameworks */, + 5F52BB472BCAADF900AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB622BCAAF1300AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB632BCAAF1300AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BB642BCAAF1300AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BB652BCAAF1300AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BB662BCAAF1300AC74F4 /* Numerics in Frameworks */, + 5F52BB672BCAAF1300AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB822BCAAFCE00AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB832BCAAFCE00AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BB842BCAAFCE00AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BB852BCAAFCE00AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BB862BCAAFCE00AC74F4 /* Numerics in Frameworks */, + 5F52BB872BCAAFCE00AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BBA42BCAB23700AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BBA52BCAB23700AC74F4 /* ArgumentParser in Frameworks */, + 5F52BBA62BCAB23700AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BBA72BCAB23700AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BBA82BCAB23700AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BBA92BCAB23700AC74F4 /* Numerics in Frameworks */, + 5F52BBAA2BCAB23700AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BBC52BCAB5DC00AC74F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BBC62BCAB5DC00AC74F4 /* libDataHandler.dylib in Frameworks */, + 5F52BBC72BCAB5DC00AC74F4 /* libMLModule.dylib in Frameworks */, + 5F52BBC82BCAB5DC00AC74F4 /* libBoardController.dylib in Frameworks */, + 5F52BBC92BCAB5DC00AC74F4 /* Numerics in Frameworks */, + 5F52BBCA2BCAB5DC00AC74F4 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5FDD63F228560953001AA429 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F20CCB7285DDE5500F2CEB5 /* Numerics in Frameworks */, + 5FDD640328560B36001AA429 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5FDD642D28560DBF001AA429 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F20CCB9285DDE8200F2CEB5 /* Numerics in Frameworks */, + 5F20CCBB285DDE8E00F2CEB5 /* BrainFlow in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5F466F8D2BC454A900E129A7 /* brainflow_get_data */ = { + isa = PBXGroup; + children = ( + 5FE97CF52BCE94DF0056EC80 /* brainflow_get_data.swift */, + ); + path = brainflow_get_data; + sourceTree = ""; + }; + 5F52BAA92BC9AAF300AC74F4 /* band_power */ = { + isa = PBXGroup; + children = ( + 5FE97CF32BCDF3930056EC80 /* main.swift */, + ); + path = band_power; + sourceTree = ""; + }; + 5F52BACD2BCAA42A00AC74F4 /* band_power_all */ = { + isa = PBXGroup; + children = ( + 5FE97CF12BCDF33C0056EC80 /* main.swift */, + ); + path = band_power_all; + sourceTree = ""; + }; + 5F52BAED2BCAA89400AC74F4 /* markers */ = { + isa = PBXGroup; + children = ( + 5FE97CEF2BCDF20A0056EC80 /* markers.swift */, + ); + path = markers; + sourceTree = ""; + }; + 5F52BB0F2BCAAB7100AC74F4 /* read_write_file */ = { + isa = PBXGroup; + children = ( + 5FE97CED2BCDF1DD0056EC80 /* main.swift */, + ); + path = read_write_file; + sourceTree = ""; + }; + 5F52BB2F2BCAAC8800AC74F4 /* downsampling */ = { + isa = PBXGroup; + children = ( + 5FE97CEB2BCDF1BA0056EC80 /* main.swift */, + ); + path = downsampling; + sourceTree = ""; + }; + 5F52BB512BCAAE1800AC74F4 /* transforms */ = { + isa = PBXGroup; + children = ( + 5FE97CE92BCDF0360056EC80 /* main.swift */, + ); + path = transforms; + sourceTree = ""; + }; + 5F52BB712BCAAF2B00AC74F4 /* signal_filtering */ = { + isa = PBXGroup; + children = ( + 5FE97CE72BCDEF6C0056EC80 /* main.swift */, + ); + path = signal_filtering; + sourceTree = ""; + }; + 5F52BB912BCAAFDC00AC74F4 /* denoising */ = { + isa = PBXGroup; + children = ( + 5FE97CE52BCDEE350056EC80 /* main.swift */, + ); + path = denoising; + sourceTree = ""; + }; + 5F52BBB42BCAB26E00AC74F4 /* eeg_metrics */ = { + isa = PBXGroup; + children = ( + 5FE97CE32BCDEDC50056EC80 /* eeg_metrics.swift */, + ); + path = eeg_metrics; + sourceTree = ""; + }; + 5F52BBD42BCAB60E00AC74F4 /* ica */ = { + isa = PBXGroup; + children = ( + 5FE97CE12BCDEC810056EC80 /* main.swift */, + ); + path = ica; + sourceTree = ""; + }; + 5FDD63EC28560953001AA429 = { + isa = PBXGroup; + children = ( + 5F52BBD42BCAB60E00AC74F4 /* ica */, + 5F52BBB42BCAB26E00AC74F4 /* eeg_metrics */, + 5F52BB912BCAAFDC00AC74F4 /* denoising */, + 5F52BB712BCAAF2B00AC74F4 /* signal_filtering */, + 5F52BB512BCAAE1800AC74F4 /* transforms */, + 5F52BB2F2BCAAC8800AC74F4 /* downsampling */, + 5F52BB0F2BCAAB7100AC74F4 /* read_write_file */, + 5F52BAED2BCAA89400AC74F4 /* markers */, + 5F52BACD2BCAA42A00AC74F4 /* band_power_all */, + 5F52BAA92BC9AAF300AC74F4 /* band_power */, + 5FDD63FF28560986001AA429 /* Packages */, + 5FDD63F728560953001AA429 /* BrainFlowCI */, + 5F466F8D2BC454A900E129A7 /* brainflow_get_data */, + 5FDD63F628560953001AA429 /* Products */, + 5FDD640128560B36001AA429 /* Frameworks */, + ); + sourceTree = ""; + }; + 5FDD63F628560953001AA429 /* Products */ = { + isa = PBXGroup; + children = ( + 5FDD63F528560953001AA429 /* BrainFlowCI */, + 5FDD643028560DBF001AA429 /* BrainFlowCITests.xctest */, + 5F466F8C2BC454A900E129A7 /* brainflow_get_data */, + 5F52BAA52BC9A98600AC74F4 /* band_power */, + 5F52BACC2BCA18C300AC74F4 /* band_power_all */, + 5F52BAEC2BCAA88000AC74F4 /* markers */, + 5F52BB0E2BCAAB3400AC74F4 /* read_write_file */, + 5F52BB2E2BCAAC7900AC74F4 /* downsampling */, + 5F52BB502BCAADF900AC74F4 /* transforms */, + 5F52BB702BCAAF1300AC74F4 /* signal_filtering */, + 5F52BB902BCAAFCE00AC74F4 /* denoising */, + 5F52BBB32BCAB23700AC74F4 /* eeg_metrics */, + 5F52BBD32BCAB5DC00AC74F4 /* ica */, + ); + name = Products; + sourceTree = ""; + }; + 5FDD63F728560953001AA429 /* BrainFlowCI */ = { + isa = PBXGroup; + children = ( + 5FDD6439285617B2001AA429 /* BrainFlowTests */, + 5FDD640D28560C67001AA429 /* BrainFlowBindings */, + ); + path = BrainFlowCI; + sourceTree = ""; + }; + 5FDD63FF28560986001AA429 /* Packages */ = { + isa = PBXGroup; + children = ( + 5FDD640028560986001AA429 /* BrainFlow */, + ); + name = Packages; + sourceTree = ""; + }; + 5FDD640128560B36001AA429 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5F52BA662BC9A3D000AC74F4 /* libsimpleble-c.dylib */, + 5F52BA432BC4D39600AC74F4 /* libMLModule.dylib */, + 5F52BA3D2BC4D32F00AC74F4 /* libBoardController.dylib */, + 5F52BA3B2BC4D32F00AC74F4 /* libDataHandler.dylib */, + 5F52BA3C2BC4D32F00AC74F4 /* libMuseLib.dylib */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5FDD640D28560C67001AA429 /* BrainFlowBindings */ = { + isa = PBXGroup; + children = ( + 5FDD640E28560C67001AA429 /* DataFilter.swift */, + 5FDD640F28560C67001AA429 /* BrainFlowConstants.swift */, + 5FDD641028560C67001AA429 /* BrainFlowExtensions.swift */, + 5FDD641128560C67001AA429 /* BrainFlowException.swift */, + 5FDD641228560C67001AA429 /* BrainFlowInputParams.swift */, + 5FDD641328560C67001AA429 /* BoardShim.swift */, + 5FDD641428560C67001AA429 /* MLModule.swift */, + 5FDD641528560C67001AA429 /* BoardDescription.swift */, + ); + name = BrainFlowBindings; + path = ../../BrainFlow/Sources/BrainFlowBindings; + sourceTree = ""; + }; + 5FDD6439285617B2001AA429 /* BrainFlowTests */ = { + isa = PBXGroup; + children = ( + 5FDD643A285617B2001AA429 /* BoardShimTests.swift */, + 5FDD643B285617B2001AA429 /* BrainFlowTests.swift */, + 5FDD643C285617B2001AA429 /* BrainFlowCITests.swift */, + 5FDD643D285617B2001AA429 /* DataFilterTests.swift */, + ); + name = BrainFlowTests; + path = ../../BrainFlow/Tests/BrainFlowTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5F466F8B2BC454A900E129A7 /* brainflow_get_data */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F466F922BC454A900E129A7 /* Build configuration list for PBXNativeTarget "brainflow_get_data" */; + buildPhases = ( + 5F466F882BC454A900E129A7 /* Sources */, + 5F466F892BC454A900E129A7 /* Frameworks */, + 5F466F8A2BC454A900E129A7 /* CopyFiles */, + 5F466F9D2BC4577A00E129A7 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = brainflow_get_data; + packageProductDependencies = ( + 5F466F952BC4576400E129A7 /* Numerics */, + 5F466FA12BC465CD00E129A7 /* ArgumentParser */, + 5F466FA62BC474B500E129A7 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F466F8C2BC454A900E129A7 /* brainflow_get_data */; + productType = "com.apple.product-type.tool"; + }; + 5F52BA842BC9A98600AC74F4 /* band_power */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BAA22BC9A98600AC74F4 /* Build configuration list for PBXNativeTarget "band_power" */; + buildPhases = ( + 5F52BA8A2BC9A98600AC74F4 /* Sources */, + 5F52BA942BC9A98600AC74F4 /* Frameworks */, + 5F52BA9C2BC9A98600AC74F4 /* CopyFiles */, + 5F52BA9D2BC9A98600AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = band_power; + packageProductDependencies = ( + 5F52BA852BC9A98600AC74F4 /* Numerics */, + 5F52BA892BC9A98600AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BAA52BC9A98600AC74F4 /* band_power */; + productType = "com.apple.product-type.tool"; + }; + 5F52BAB02BCA18C300AC74F4 /* band_power_all */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BAC92BCA18C300AC74F4 /* Build configuration list for PBXNativeTarget "band_power_all" */; + buildPhases = ( + 5F52BAB42BCA18C300AC74F4 /* Sources */, + 5F52BABE2BCA18C300AC74F4 /* Frameworks */, + 5F52BAC42BCA18C300AC74F4 /* CopyFiles */, + 5F52BAC52BCA18C300AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = band_power_all; + packageProductDependencies = ( + 5F52BAB12BCA18C300AC74F4 /* Numerics */, + 5F52BAB32BCA18C300AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BACC2BCA18C300AC74F4 /* band_power_all */; + productType = "com.apple.product-type.tool"; + }; + 5F52BAD02BCAA88000AC74F4 /* markers */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BAE92BCAA88000AC74F4 /* Build configuration list for PBXNativeTarget "markers" */; + buildPhases = ( + 5F52BAD42BCAA88000AC74F4 /* Sources */, + 5F52BADE2BCAA88000AC74F4 /* Frameworks */, + 5F52BAE42BCAA88000AC74F4 /* CopyFiles */, + 5F52BAE52BCAA88000AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = markers; + packageProductDependencies = ( + 5F52BAD12BCAA88000AC74F4 /* Numerics */, + 5F52BAD32BCAA88000AC74F4 /* BrainFlow */, + 5F52BAF02BCAA9E700AC74F4 /* ArgumentParser */, + ); + productName = brainflow_get_data; + productReference = 5F52BAEC2BCAA88000AC74F4 /* markers */; + productType = "com.apple.product-type.tool"; + }; + 5F52BAF22BCAAB3400AC74F4 /* read_write_file */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BB0B2BCAAB3400AC74F4 /* Build configuration list for PBXNativeTarget "read_write_file" */; + buildPhases = ( + 5F52BAF62BCAAB3400AC74F4 /* Sources */, + 5F52BB002BCAAB3400AC74F4 /* Frameworks */, + 5F52BB062BCAAB3400AC74F4 /* CopyFiles */, + 5F52BB072BCAAB3400AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = read_write_file; + packageProductDependencies = ( + 5F52BAF32BCAAB3400AC74F4 /* Numerics */, + 5F52BAF52BCAAB3400AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BB0E2BCAAB3400AC74F4 /* read_write_file */; + productType = "com.apple.product-type.tool"; + }; + 5F52BB122BCAAC7900AC74F4 /* downsampling */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BB2B2BCAAC7900AC74F4 /* Build configuration list for PBXNativeTarget "downsampling" */; + buildPhases = ( + 5F52BB162BCAAC7900AC74F4 /* Sources */, + 5F52BB202BCAAC7900AC74F4 /* Frameworks */, + 5F52BB262BCAAC7900AC74F4 /* CopyFiles */, + 5F52BB272BCAAC7900AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = downsampling; + packageProductDependencies = ( + 5F52BB132BCAAC7900AC74F4 /* Numerics */, + 5F52BB152BCAAC7900AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BB2E2BCAAC7900AC74F4 /* downsampling */; + productType = "com.apple.product-type.tool"; + }; + 5F52BB342BCAADF900AC74F4 /* transforms */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BB4D2BCAADF900AC74F4 /* Build configuration list for PBXNativeTarget "transforms" */; + buildPhases = ( + 5F52BB382BCAADF900AC74F4 /* Sources */, + 5F52BB422BCAADF900AC74F4 /* Frameworks */, + 5F52BB482BCAADF900AC74F4 /* CopyFiles */, + 5F52BB492BCAADF900AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = transforms; + packageProductDependencies = ( + 5F52BB352BCAADF900AC74F4 /* Numerics */, + 5F52BB372BCAADF900AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BB502BCAADF900AC74F4 /* transforms */; + productType = "com.apple.product-type.tool"; + }; + 5F52BB542BCAAF1300AC74F4 /* signal_filtering */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BB6D2BCAAF1300AC74F4 /* Build configuration list for PBXNativeTarget "signal_filtering" */; + buildPhases = ( + 5F52BB582BCAAF1300AC74F4 /* Sources */, + 5F52BB622BCAAF1300AC74F4 /* Frameworks */, + 5F52BB682BCAAF1300AC74F4 /* CopyFiles */, + 5F52BB692BCAAF1300AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = signal_filtering; + packageProductDependencies = ( + 5F52BB552BCAAF1300AC74F4 /* Numerics */, + 5F52BB572BCAAF1300AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BB702BCAAF1300AC74F4 /* signal_filtering */; + productType = "com.apple.product-type.tool"; + }; + 5F52BB742BCAAFCE00AC74F4 /* denoising */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BB8D2BCAAFCE00AC74F4 /* Build configuration list for PBXNativeTarget "denoising" */; + buildPhases = ( + 5F52BB782BCAAFCE00AC74F4 /* Sources */, + 5F52BB822BCAAFCE00AC74F4 /* Frameworks */, + 5F52BB882BCAAFCE00AC74F4 /* CopyFiles */, + 5F52BB892BCAAFCE00AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = denoising; + packageProductDependencies = ( + 5F52BB752BCAAFCE00AC74F4 /* Numerics */, + 5F52BB772BCAAFCE00AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BB902BCAAFCE00AC74F4 /* denoising */; + productType = "com.apple.product-type.tool"; + }; + 5F52BB942BCAB23700AC74F4 /* eeg_metrics */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BBB02BCAB23700AC74F4 /* Build configuration list for PBXNativeTarget "eeg_metrics" */; + buildPhases = ( + 5F52BB9A2BCAB23700AC74F4 /* Sources */, + 5F52BBA42BCAB23700AC74F4 /* Frameworks */, + 5F52BBAB2BCAB23700AC74F4 /* CopyFiles */, + 5F52BBAC2BCAB23700AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = eeg_metrics; + packageProductDependencies = ( + 5F52BB952BCAB23700AC74F4 /* Numerics */, + 5F52BB972BCAB23700AC74F4 /* BrainFlow */, + 5F52BB982BCAB23700AC74F4 /* ArgumentParser */, + ); + productName = brainflow_get_data; + productReference = 5F52BBB32BCAB23700AC74F4 /* eeg_metrics */; + productType = "com.apple.product-type.tool"; + }; + 5F52BBB72BCAB5DC00AC74F4 /* ica */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F52BBD02BCAB5DC00AC74F4 /* Build configuration list for PBXNativeTarget "ica" */; + buildPhases = ( + 5F52BBBB2BCAB5DC00AC74F4 /* Sources */, + 5F52BBC52BCAB5DC00AC74F4 /* Frameworks */, + 5F52BBCB2BCAB5DC00AC74F4 /* CopyFiles */, + 5F52BBCC2BCAB5DC00AC74F4 /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ica; + packageProductDependencies = ( + 5F52BBB82BCAB5DC00AC74F4 /* Numerics */, + 5F52BBBA2BCAB5DC00AC74F4 /* BrainFlow */, + ); + productName = brainflow_get_data; + productReference = 5F52BBD32BCAB5DC00AC74F4 /* ica */; + productType = "com.apple.product-type.tool"; + }; + 5FDD63F428560953001AA429 /* BrainFlowCI */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5FDD63FC28560953001AA429 /* Build configuration list for PBXNativeTarget "BrainFlowCI" */; + buildPhases = ( + 5FDD63F128560953001AA429 /* Sources */, + 5FDD63F228560953001AA429 /* Frameworks */, + 5FDD63F328560953001AA429 /* CopyFiles */, + 5FE20CE02BA7D70B003C194A /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BrainFlowCI; + packageProductDependencies = ( + 5FDD640228560B36001AA429 /* BrainFlow */, + 5F20CCB6285DDE5500F2CEB5 /* Numerics */, + ); + productName = BrainFlowCI; + productReference = 5FDD63F528560953001AA429 /* BrainFlowCI */; + productType = "com.apple.product-type.tool"; + }; + 5FDD642F28560DBF001AA429 /* BrainFlowCITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5FDD643428560DBF001AA429 /* Build configuration list for PBXNativeTarget "BrainFlowCITests" */; + buildPhases = ( + 5FDD642C28560DBF001AA429 /* Sources */, + 5FDD642D28560DBF001AA429 /* Frameworks */, + 5FDD642E28560DBF001AA429 /* Resources */, + 5FE20CF22BA7D7A0003C194A /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BrainFlowCITests; + packageProductDependencies = ( + 5F20CCB8285DDE8200F2CEB5 /* Numerics */, + 5F20CCBA285DDE8E00F2CEB5 /* BrainFlow */, + ); + productName = BrainFlowCITests; + productReference = 5FDD643028560DBF001AA429 /* BrainFlowCITests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5FDD63ED28560953001AA429 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1530; + LastUpgradeCheck = 1530; + TargetAttributes = { + 5F466F8B2BC454A900E129A7 = { + CreatedOnToolsVersion = 15.3; + }; + 5FDD63F428560953001AA429 = { + CreatedOnToolsVersion = 13.4.1; + }; + 5FDD642F28560DBF001AA429 = { + CreatedOnToolsVersion = 13.4.1; + }; + }; + }; + buildConfigurationList = 5FDD63F028560953001AA429 /* Build configuration list for PBXProject "BrainFlowCI" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5FDD63EC28560953001AA429; + packageReferences = ( + 5FDD644A285618BF001AA429 /* XCRemoteSwiftPackageReference "swift-numerics" */, + 5F466FA02BC465C600E129A7 /* XCRemoteSwiftPackageReference "swift-argument-parser" */, + ); + productRefGroup = 5FDD63F628560953001AA429 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5FDD63F428560953001AA429 /* BrainFlowCI */, + 5FDD642F28560DBF001AA429 /* BrainFlowCITests */, + 5F466F8B2BC454A900E129A7 /* brainflow_get_data */, + 5F52BA842BC9A98600AC74F4 /* band_power */, + 5F52BAB02BCA18C300AC74F4 /* band_power_all */, + 5F52BAD02BCAA88000AC74F4 /* markers */, + 5F52BAF22BCAAB3400AC74F4 /* read_write_file */, + 5F52BB122BCAAC7900AC74F4 /* downsampling */, + 5F52BB342BCAADF900AC74F4 /* transforms */, + 5F52BB542BCAAF1300AC74F4 /* signal_filtering */, + 5F52BB742BCAAFCE00AC74F4 /* denoising */, + 5F52BB942BCAB23700AC74F4 /* eeg_metrics */, + 5F52BBB72BCAB5DC00AC74F4 /* ica */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5FDD642E28560DBF001AA429 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5F466F882BC454A900E129A7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5FD91A3A2BC49D9600AC3CCB /* BrainFlowConstants.swift in Sources */, + 5FD91A3B2BC49D9600AC3CCB /* BrainFlowInputParams.swift in Sources */, + 5FE97CF62BCE94DF0056EC80 /* brainflow_get_data.swift in Sources */, + 5FD91A3C2BC49D9600AC3CCB /* BoardShim.swift in Sources */, + 5FD91A3D2BC49D9600AC3CCB /* BoardDescription.swift in Sources */, + 5FD91A3E2BC49D9600AC3CCB /* BrainFlowExtensions.swift in Sources */, + 5FD91A3F2BC49D9600AC3CCB /* MLModule.swift in Sources */, + 5FD91A402BC49D9600AC3CCB /* BrainFlowException.swift in Sources */, + 5FD91A412BC49D9600AC3CCB /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BA8A2BC9A98600AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BA8C2BC9A98600AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BA8D2BC9A98600AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CF42BCDF3930056EC80 /* main.swift in Sources */, + 5F52BA8E2BC9A98600AC74F4 /* BoardShim.swift in Sources */, + 5F52BA8F2BC9A98600AC74F4 /* BoardDescription.swift in Sources */, + 5F52BA902BC9A98600AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BA912BC9A98600AC74F4 /* MLModule.swift in Sources */, + 5F52BA922BC9A98600AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BA932BC9A98600AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BAB42BCA18C300AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BAB52BCA18C300AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BAB62BCA18C300AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CF22BCDF33C0056EC80 /* main.swift in Sources */, + 5F52BAB72BCA18C300AC74F4 /* BoardShim.swift in Sources */, + 5F52BAB82BCA18C300AC74F4 /* BoardDescription.swift in Sources */, + 5F52BAB92BCA18C300AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BABB2BCA18C300AC74F4 /* MLModule.swift in Sources */, + 5F52BABC2BCA18C300AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BABD2BCA18C300AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BAD42BCAA88000AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BAD52BCAA88000AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BAD62BCAA88000AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5F52BAD72BCAA88000AC74F4 /* BoardShim.swift in Sources */, + 5F52BAD82BCAA88000AC74F4 /* BoardDescription.swift in Sources */, + 5F52BAD92BCAA88000AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BADB2BCAA88000AC74F4 /* MLModule.swift in Sources */, + 5F52BADC2BCAA88000AC74F4 /* BrainFlowException.swift in Sources */, + 5FE97CF02BCDF20A0056EC80 /* markers.swift in Sources */, + 5F52BADD2BCAA88000AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BAF62BCAAB3400AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BAF72BCAAB3400AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BAF82BCAAB3400AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CEE2BCDF1DD0056EC80 /* main.swift in Sources */, + 5F52BAF92BCAAB3400AC74F4 /* BoardShim.swift in Sources */, + 5F52BAFA2BCAAB3400AC74F4 /* BoardDescription.swift in Sources */, + 5F52BAFB2BCAAB3400AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BAFD2BCAAB3400AC74F4 /* MLModule.swift in Sources */, + 5F52BAFE2BCAAB3400AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BAFF2BCAAB3400AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB162BCAAC7900AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB172BCAAC7900AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BB182BCAAC7900AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CEC2BCDF1BA0056EC80 /* main.swift in Sources */, + 5F52BB192BCAAC7900AC74F4 /* BoardShim.swift in Sources */, + 5F52BB1A2BCAAC7900AC74F4 /* BoardDescription.swift in Sources */, + 5F52BB1B2BCAAC7900AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BB1D2BCAAC7900AC74F4 /* MLModule.swift in Sources */, + 5F52BB1E2BCAAC7900AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BB1F2BCAAC7900AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB382BCAADF900AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB392BCAADF900AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BB3A2BCAADF900AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CEA2BCDF0360056EC80 /* main.swift in Sources */, + 5F52BB3C2BCAADF900AC74F4 /* BoardShim.swift in Sources */, + 5F52BB3D2BCAADF900AC74F4 /* BoardDescription.swift in Sources */, + 5F52BB3E2BCAADF900AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BB3F2BCAADF900AC74F4 /* MLModule.swift in Sources */, + 5F52BB402BCAADF900AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BB412BCAADF900AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB582BCAAF1300AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB592BCAAF1300AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BB5A2BCAAF1300AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CE82BCDEF6C0056EC80 /* main.swift in Sources */, + 5F52BB5C2BCAAF1300AC74F4 /* BoardShim.swift in Sources */, + 5F52BB5D2BCAAF1300AC74F4 /* BoardDescription.swift in Sources */, + 5F52BB5E2BCAAF1300AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BB5F2BCAAF1300AC74F4 /* MLModule.swift in Sources */, + 5F52BB602BCAAF1300AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BB612BCAAF1300AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB782BCAAFCE00AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB792BCAAFCE00AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BB7A2BCAAFCE00AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CE62BCDEE350056EC80 /* main.swift in Sources */, + 5F52BB7C2BCAAFCE00AC74F4 /* BoardShim.swift in Sources */, + 5F52BB7D2BCAAFCE00AC74F4 /* BoardDescription.swift in Sources */, + 5F52BB7E2BCAAFCE00AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BB7F2BCAAFCE00AC74F4 /* MLModule.swift in Sources */, + 5F52BB802BCAAFCE00AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BB812BCAAFCE00AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BB9A2BCAB23700AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BB9B2BCAB23700AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BB9C2BCAB23700AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5F52BB9D2BCAB23700AC74F4 /* BoardShim.swift in Sources */, + 5F52BB9E2BCAB23700AC74F4 /* BoardDescription.swift in Sources */, + 5F52BB9F2BCAB23700AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BBA02BCAB23700AC74F4 /* MLModule.swift in Sources */, + 5F52BBA12BCAB23700AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BBA32BCAB23700AC74F4 /* DataFilter.swift in Sources */, + 5FE97CE42BCDEDC50056EC80 /* eeg_metrics.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F52BBBB2BCAB5DC00AC74F4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5F52BBBC2BCAB5DC00AC74F4 /* BrainFlowConstants.swift in Sources */, + 5F52BBBD2BCAB5DC00AC74F4 /* BrainFlowInputParams.swift in Sources */, + 5FE97CE22BCDEC810056EC80 /* main.swift in Sources */, + 5F52BBBF2BCAB5DC00AC74F4 /* BoardShim.swift in Sources */, + 5F52BBC02BCAB5DC00AC74F4 /* BoardDescription.swift in Sources */, + 5F52BBC12BCAB5DC00AC74F4 /* BrainFlowExtensions.swift in Sources */, + 5F52BBC22BCAB5DC00AC74F4 /* MLModule.swift in Sources */, + 5F52BBC32BCAB5DC00AC74F4 /* BrainFlowException.swift in Sources */, + 5F52BBC42BCAB5DC00AC74F4 /* DataFilter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5FDD63F128560953001AA429 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5FD91A442BC49F1000AC3CCB /* DataFilter.swift in Sources */, + 5FD91A452BC49F1000AC3CCB /* BrainFlowExtensions.swift in Sources */, + 5FD91A462BC49F1000AC3CCB /* BrainFlowConstants.swift in Sources */, + 5FD91A472BC49F1000AC3CCB /* BrainFlowInputParams.swift in Sources */, + 5FD91A482BC49F1000AC3CCB /* BrainFlowException.swift in Sources */, + 5FD91A492BC49F1000AC3CCB /* BoardShim.swift in Sources */, + 5FD91A4A2BC49F1000AC3CCB /* MLModule.swift in Sources */, + 5FD91A4B2BC49F1000AC3CCB /* BoardDescription.swift in Sources */, + 5F17B7832BA8B89C00DD1263 /* BoardShimTests.swift in Sources */, + 5F17B7842BA8B89F00DD1263 /* BrainFlowTests.swift in Sources */, + 5F17B7862BA8B8A400DD1263 /* DataFilterTests.swift in Sources */, + 5F17B7852BA8B8A100DD1263 /* BrainFlowCITests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5FDD642C28560DBF001AA429 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5FDD644728561815001AA429 /* BrainFlowException.swift in Sources */, + 5FDD644428561815001AA429 /* MLModule.swift in Sources */, + 5FDD644628561815001AA429 /* BrainFlowInputParams.swift in Sources */, + 5FDD6440285617B2001AA429 /* BrainFlowCITests.swift in Sources */, + 5FDD644328561815001AA429 /* DataFilter.swift in Sources */, + 5FDD644828561815001AA429 /* BoardDescription.swift in Sources */, + 5FDD6441285617B2001AA429 /* DataFilterTests.swift in Sources */, + 5FDD644528561815001AA429 /* BrainFlowConstants.swift in Sources */, + 5FDD643E285617B2001AA429 /* BoardShimTests.swift in Sources */, + 5FDD644228561815001AA429 /* BrainFlowExtensions.swift in Sources */, + 5FDD643F285617B2001AA429 /* BrainFlowTests.swift in Sources */, + 5FDD644928561815001AA429 /* BoardShim.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 5F466F902BC454A900E129A7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F466F912BC454A900E129A7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BAA32BC9A98600AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BAA42BC9A98600AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BACA2BCA18C300AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BACB2BCA18C300AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BAEA2BCAA88000AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BAEB2BCAA88000AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BB0C2BCAAB3400AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BB0D2BCAAB3400AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BB2C2BCAAC7900AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BB2D2BCAAC7900AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BB4E2BCAADF900AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BB4F2BCAADF900AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BB6E2BCAAF1300AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BB6F2BCAAF1300AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BB8E2BCAAFCE00AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BB8F2BCAAFCE00AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BBB12BCAB23700AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BBB22BCAB23700AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5F52BBD12BCAB5DC00AC74F4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5F52BBD22BCAB5DC00AC74F4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 46TC788J42; + ENABLE_HARDENED_RUNTIME = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + "$(PROJECT_DIR)", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5FDD63FA28560953001AA429 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5FDD63FB28560953001AA429 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 5FDD63FD28560953001AA429 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = Y8JL76N88P; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_TESTING_SEARCH_PATHS = YES; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = Scott.Miller.BrainFlowCI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5FDD63FE28560953001AA429 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = Y8JL76N88P; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_TESTING_SEARCH_PATHS = YES; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = Scott.Miller.BrainFlowCI; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5FDD643528560DBF001AA429 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = Y8JL76N88P; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Scott.Miller.BrainFlowCITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5FDD643628560DBF001AA429 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = Y8JL76N88P; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = "$SRCROOT/../../src/**"; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = Scott.Miller.BrainFlowCITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OBJC_BRIDGING_HEADER = ../BrainFlow/BrainFlow.h; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5F466F922BC454A900E129A7 /* Build configuration list for PBXNativeTarget "brainflow_get_data" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F466F902BC454A900E129A7 /* Debug */, + 5F466F912BC454A900E129A7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BAA22BC9A98600AC74F4 /* Build configuration list for PBXNativeTarget "band_power" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BAA32BC9A98600AC74F4 /* Debug */, + 5F52BAA42BC9A98600AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BAC92BCA18C300AC74F4 /* Build configuration list for PBXNativeTarget "band_power_all" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BACA2BCA18C300AC74F4 /* Debug */, + 5F52BACB2BCA18C300AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BAE92BCAA88000AC74F4 /* Build configuration list for PBXNativeTarget "markers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BAEA2BCAA88000AC74F4 /* Debug */, + 5F52BAEB2BCAA88000AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BB0B2BCAAB3400AC74F4 /* Build configuration list for PBXNativeTarget "read_write_file" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BB0C2BCAAB3400AC74F4 /* Debug */, + 5F52BB0D2BCAAB3400AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BB2B2BCAAC7900AC74F4 /* Build configuration list for PBXNativeTarget "downsampling" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BB2C2BCAAC7900AC74F4 /* Debug */, + 5F52BB2D2BCAAC7900AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BB4D2BCAADF900AC74F4 /* Build configuration list for PBXNativeTarget "transforms" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BB4E2BCAADF900AC74F4 /* Debug */, + 5F52BB4F2BCAADF900AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BB6D2BCAAF1300AC74F4 /* Build configuration list for PBXNativeTarget "signal_filtering" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BB6E2BCAAF1300AC74F4 /* Debug */, + 5F52BB6F2BCAAF1300AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BB8D2BCAAFCE00AC74F4 /* Build configuration list for PBXNativeTarget "denoising" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BB8E2BCAAFCE00AC74F4 /* Debug */, + 5F52BB8F2BCAAFCE00AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BBB02BCAB23700AC74F4 /* Build configuration list for PBXNativeTarget "eeg_metrics" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BBB12BCAB23700AC74F4 /* Debug */, + 5F52BBB22BCAB23700AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F52BBD02BCAB5DC00AC74F4 /* Build configuration list for PBXNativeTarget "ica" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5F52BBD12BCAB5DC00AC74F4 /* Debug */, + 5F52BBD22BCAB5DC00AC74F4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FDD63F028560953001AA429 /* Build configuration list for PBXProject "BrainFlowCI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FDD63FA28560953001AA429 /* Debug */, + 5FDD63FB28560953001AA429 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FDD63FC28560953001AA429 /* Build configuration list for PBXNativeTarget "BrainFlowCI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FDD63FD28560953001AA429 /* Debug */, + 5FDD63FE28560953001AA429 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FDD643428560DBF001AA429 /* Build configuration list for PBXNativeTarget "BrainFlowCITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5FDD643528560DBF001AA429 /* Debug */, + 5FDD643628560DBF001AA429 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 5F466FA02BC465C600E129A7 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-argument-parser.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.3.1; + }; + }; + 5F52BA862BC9A98600AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BAB22BCA18C300AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BAD22BCAA88000AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BAF42BCAAB3400AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB142BCAAC7900AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB362BCAADF900AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB562BCAAF1300AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB762BCAAFCE00AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB962BCAB23700AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5F52BB992BCAB23700AC74F4 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-argument-parser.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.3.1; + }; + }; + 5F52BBB92BCAB5DC00AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + 5FDD644A285618BF001AA429 /* XCRemoteSwiftPackageReference "swift-numerics" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/apple/swift-numerics.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 5F20CCB6285DDE5500F2CEB5 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5FDD644A285618BF001AA429 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F20CCB8285DDE8200F2CEB5 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5FDD644A285618BF001AA429 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F20CCBA285DDE8E00F2CEB5 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F466F952BC4576400E129A7 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5FDD644A285618BF001AA429 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F466FA12BC465CD00E129A7 /* ArgumentParser */ = { + isa = XCSwiftPackageProductDependency; + package = 5F466FA02BC465C600E129A7 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; + productName = ArgumentParser; + }; + 5F466FA62BC474B500E129A7 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BA852BC9A98600AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BA862BC9A98600AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BA892BC9A98600AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BAB12BCA18C300AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BAB22BCA18C300AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BAB32BCA18C300AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BAD12BCAA88000AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BAD22BCAA88000AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BAD32BCAA88000AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BAF02BCAA9E700AC74F4 /* ArgumentParser */ = { + isa = XCSwiftPackageProductDependency; + package = 5F466FA02BC465C600E129A7 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; + productName = ArgumentParser; + }; + 5F52BAF32BCAAB3400AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BAF42BCAAB3400AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BAF52BCAAB3400AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB132BCAAC7900AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB142BCAAC7900AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BB152BCAAC7900AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB352BCAADF900AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB362BCAADF900AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BB372BCAADF900AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB552BCAAF1300AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB562BCAAF1300AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BB572BCAAF1300AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB752BCAAFCE00AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB762BCAAFCE00AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BB772BCAAFCE00AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB952BCAB23700AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB962BCAB23700AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BB972BCAB23700AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5F52BB982BCAB23700AC74F4 /* ArgumentParser */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BB992BCAB23700AC74F4 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; + productName = ArgumentParser; + }; + 5F52BBB82BCAB5DC00AC74F4 /* Numerics */ = { + isa = XCSwiftPackageProductDependency; + package = 5F52BBB92BCAB5DC00AC74F4 /* XCRemoteSwiftPackageReference "swift-numerics" */; + productName = Numerics; + }; + 5F52BBBA2BCAB5DC00AC74F4 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; + 5FDD640228560B36001AA429 /* BrainFlow */ = { + isa = XCSwiftPackageProductDependency; + productName = BrainFlow; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 5FDD63ED28560953001AA429 /* Project object */; +} diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..d1f10e5c8 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,25 @@ +{ + "object": { + "pins": [ + { + "package": "swift-argument-parser", + "repositoryURL": "https://github.com/apple/swift-argument-parser.git", + "state": { + "branch": null, + "revision": "46989693916f56d1186bd59ac15124caef896560", + "version": "1.3.1" + } + }, + { + "package": "swift-numerics", + "repositoryURL": "https://github.com/apple/swift-numerics.git", + "state": { + "branch": null, + "revision": "0a5bc04095a675662cf24757cc0640aa2204253b", + "version": "1.0.2" + } + } + ] + }, + "version": 1 +} diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCI.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCI.xcscheme new file mode 100644 index 000000000..56c582cec --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCI.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCITests.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCITests.xcscheme new file mode 100644 index 000000000..f1430fa8e --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/BrainFlowCITests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power.xcscheme new file mode 100644 index 000000000..df78ac270 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power_all.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power_all.xcscheme new file mode 100644 index 000000000..3a575aeb0 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/band_power_all.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/brainflow_get_data.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/brainflow_get_data.xcscheme new file mode 100644 index 000000000..cf0dd341b --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/brainflow_get_data.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/denoising.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/denoising.xcscheme new file mode 100644 index 000000000..1fb3d6235 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/denoising.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/downsampling.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/downsampling.xcscheme new file mode 100644 index 000000000..3ad882470 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/downsampling.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/eeg_metrics.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/eeg_metrics.xcscheme new file mode 100644 index 000000000..4b5aad914 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/eeg_metrics.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/ica.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/ica.xcscheme new file mode 100644 index 000000000..44b2ed1d6 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/ica.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/markers.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/markers.xcscheme new file mode 100644 index 000000000..da2e59c79 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/markers.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/read_write_file.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/read_write_file.xcscheme new file mode 100644 index 000000000..308a5d10d --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/read_write_file.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/signal_filtering.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/signal_filtering.xcscheme new file mode 100644 index 000000000..f5f88e316 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/signal_filtering.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/transforms.xcscheme b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/transforms.xcscheme new file mode 100644 index 000000000..8ee094803 --- /dev/null +++ b/swift_package/BrainFlowCI/BrainFlowCI.xcodeproj/xcshareddata/xcschemes/transforms.xcscheme @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swift_package/BrainFlowCI/Headers/BrainFlow.h b/swift_package/BrainFlowCI/Headers/BrainFlow.h new file mode 100644 index 000000000..91ebeaafc --- /dev/null +++ b/swift_package/BrainFlowCI/Headers/BrainFlow.h @@ -0,0 +1,13 @@ +// +// Created by Scott Miller on 4/9/22. +// + +#ifndef BrainFlow_h +#define BrainFlow_h + +#include "board_controller.h" +#include "data_handler.h" +#include "board_info_getter.h" +#include "ml_module.h" + +#endif /* BrainFlow_h */ diff --git a/swift_package/LICENSE.txt b/swift_package/LICENSE.txt new file mode 100644 index 000000000..6a1b5f8c9 --- /dev/null +++ b/swift_package/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Andrey Parfenov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/swift_package/README.md b/swift_package/README.md new file mode 100644 index 000000000..f2b6d0d0f --- /dev/null +++ b/swift_package/README.md @@ -0,0 +1,65 @@ +

+ +

+ +BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG and other kinds of data from biosensors. + +It provides a uniform SDK to work with biosensors with primary focus on neurointerfaces, all features available for free! + +#### Advantages of BrainFlow: + +* powerful API with many features to simplify development + * Straightforward API for data acquisition + * Powerful API for signal filtering, denoising, downsampling... + * Development tools like Synthetic board, Streaming board, logging API +* easy to use + * BrainFlow has many bindings, you can choose programming language you like + * All programming languages provide the same API, so it's simple to switch + * API is uniform for all boards, it makes applications on top of BrainFlow almost board agnostic +* easy to support and extend + * Code to read data and to perform signal processing is implemented only once in C/C++, bindings just call C/C++ methods + * Powerful CI/CD system which runs integrations tests for each commit automatically using BrainFlow's Emulator + * Simplified process to add new boards and methods + +## [BrainFlow Docs, Dev and User guides and other information](https://brainflow.readthedocs.io) + +## [BrainFlow's slack workspace](https://openbraintalk.slack.com/), use this [link to join](https://c6ber255cc.execute-api.eu-west-1.amazonaws.com/Express/) + +## Build Status + +Compiled with: +* MSVC on Windows +* Android NDK with Ninja +* GCC on Linux +* Clang on MacOS + +*Linux and MacOS*: + +[![Run Unix](https://github.com/brainflow-dev/brainflow/workflows/Run%20Unix//badge.svg?branch=master)](https://github.com/brainflow-dev/brainflow/actions) + +*Windows*: + +[![Run Unix](https://github.com/brainflow-dev/brainflow/workflows/Run%20Windows//badge.svg?branch=master)](https://github.com/brainflow-dev/brainflow/actions) + +*Android NDK*: + +[![Run Android NDK](https://github.com/brainflow-dev/brainflow/workflows/Run%20Android%20NDK//badge.svg?branch=master)](https://github.com/brainflow-dev/brainflow/actions) + +## Brainflow Bindings + +We support bindings for: +* [Python](./python-package) +* [Java](./java-package/brainflow/) +* [R](./r-package/) +* [C++](./cpp-package/) +* [C#](./csharp-package/brainflow/) +* [Matlab](./matlab-package/brainflow) +* [Julia](.julia-package/brainflow) +* [Swift](.swift-package/BrainFlow) + +## Partners and Sponsors + +[![OpenBCI](https://live.staticflickr.com/65535/49913349191_0cbd41157c_w.jpg)](https://openbci.com/) + +## License: +MIT diff --git a/swift_package/examples/tests/band_power/main.swift b/swift_package/examples/tests/band_power/main.swift new file mode 100644 index 000000000..452ee2e06 --- /dev/null +++ b/swift_package/examples/tests/band_power/main.swift @@ -0,0 +1,51 @@ +// +// main.swift +// band_power +// +// Created by Scott Miller on 4/12/24. +// + +import Foundation +import BrainFlow + +func testBandPower() throws { + // use synthetic board for demo + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let boardId = BoardIds.SYNTHETIC_BOARD + let boardDescription = try BoardShim.getBoardDescr(boardId) + guard let samplingRate = boardDescription.sampling_rate else { + try? BoardShim.logMessage(.LEVEL_ERROR, "null sampling rate in board description") + return + } + let board = try BoardShim(boardId, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(5) + let nfft = try DataFilter.getNearestPowerOfTwo(samplingRate) + let size = try board.getBoardDataCount() + var data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + guard let EEGchannels = boardDescription.eeg_channels else { + try? BoardShim.logMessage(.LEVEL_ERROR, "null EEG channels in board description") + return + } + // second eeg channel of synthetic board is a sine wave at 10Hz, should see huge alpha + let eegChannel = Int(EEGchannels[1]) + // optional detrend + try DataFilter.deTrend(data: &data[eegChannel], operation: .LINEAR) + + let overlap = Int32(floor(Double(Int(nfft) / 2))) + let psd = try DataFilter.getPSDwelch(data: data[eegChannel], nfft: nfft, + overlap: overlap, samplingRate: samplingRate, + window: .BLACKMAN_HARRIS) + + let bandPowerAlpha = try DataFilter.getBandPower(psd: psd, freqStart: 7.0, freqEnd: 13.0) + let bandPowerBeta = try DataFilter.getBandPower(psd: psd, freqStart: 14.0, freqEnd: 30.0) + print("alpha/beta:\(bandPowerAlpha / bandPowerBeta)") +} + +try? testBandPower() diff --git a/swift_package/examples/tests/band_power_all/main.swift b/swift_package/examples/tests/band_power_all/main.swift new file mode 100644 index 000000000..24fe98498 --- /dev/null +++ b/swift_package/examples/tests/band_power_all/main.swift @@ -0,0 +1,37 @@ +// +// main.swift +// band_power_all +// +// Created by Scott Miller on 4/12/24. +// + +import Foundation +import BrainFlow + +func testBandPowerAll() throws { + // use synthetic board for demo + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let boardId = BoardIds.SYNTHETIC_BOARD + let boardDescription = try BoardShim.getBoardDescr(boardId) + guard let samplingRate = boardDescription.sampling_rate else { + try? BoardShim.logMessage(.LEVEL_ERROR, "null sampling rate in board description") + return + } + let board = try BoardShim(boardId, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(5) + let nfft = try DataFilter.getNearestPowerOfTwo(samplingRate) + var data = try board.getBoardData() + try board.stopStream() + try board.releaseSession() + + let eegChannels = try BoardShim.getEEGchannels(boardId) + let bands = try DataFilter.getAvgBandPowers(data: data, channels: eegChannels, samplingRate: samplingRate, applyFilter: true) + print("avg band powers : \(bands.0)") + print("stddev band powers : \(bands.1)") +} + +try? testBandPowerAll() diff --git a/swift_package/examples/tests/brainflow_get_data/brainflow_get_data.swift b/swift_package/examples/tests/brainflow_get_data/brainflow_get_data.swift new file mode 100644 index 000000000..a3e676e34 --- /dev/null +++ b/swift_package/examples/tests/brainflow_get_data/brainflow_get_data.swift @@ -0,0 +1,65 @@ +// +// brainflow_get_data.swift +// brainflow_get_data +// +// Created by Scott Miller on 4/8/24. +// + +import Foundation +import BrainFlow +import ArgumentParser + +@main +struct brainflow_get_data: ParsableCommand { + @Option(name: [.long], help: "timeout for device discovery or connection") + var timeout: Int = 0 + @Option(name: [.long, .customLong("ip-port")], help: "ip port") + var ip_port: Int = 0 + @Option(name: [.long, .customLong("ip-protocol")], help: "ip protocol, check IpProtocolType enum") + var ip_protocol: Int = 0 + @Option(name: [.long, .customLong("ip-address")], help: "ip address") + var ip_address: String = "" + @Option(name: [.long, .customLong("serial-port")], help: "serial port") + var serial_port: String = "" + @Option(name: [.long, .customLong("mac-address")], help: "mac address") + var mac_address: String = "" + @Option(name: [.long, .customLong("other-info")], help: "other info") + var other_info: String = "" + @Option(name: [.long, .customLong("serial-number")], help: "serial number") + var serial_number: String = "" + @Option(name: [.long, .customLong("board-id")], help: "board id, check docs to get a list of supported boards") + var board_id: Int32 = -1 + @Option(name: [.long], help: "file") + var file: String = "" + @Option(name: [.long, .customLong("master-board")], help: "master board id for streaming and playback boards") + var master_board: Int = -1 + + mutating func run() throws { + var params = BrainFlowInputParams() + params.ip_port = ip_port + params.serial_port = serial_port + params.mac_address = mac_address + params.other_info = other_info + params.serial_number = serial_number + params.ip_address = ip_address + params.ip_protocol = ip_protocol + params.timeout = timeout + params.file = file + params.master_board = master_board + guard let boardId = BoardIds(rawValue: board_id) else { + try? BoardShim.logMessage (.LEVEL_ERROR, "Invalid board ID: \(board_id)") + return + } + + let board = try BoardShim(boardId, params) + try board.prepareSession() + try board.startStream() + sleep(10) + let size = try board.getBoardDataCount() + let data = try board.getBoardData(size) // get all data and remove it from internal buffer + try board.stopStream() + try board.releaseSession() + print("\(data)") + } +} + diff --git a/swift_package/examples/tests/denoising/main.swift b/swift_package/examples/tests/denoising/main.swift new file mode 100644 index 000000000..1f3367f3a --- /dev/null +++ b/swift_package/examples/tests/denoising/main.swift @@ -0,0 +1,66 @@ +// +// main.swift +// denoising +// +// Created by Scott Miller on 4/13/24. +// + +import Foundation +import BrainFlow + +func testDenoising() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(20) + let size = try board.getBoardDataCount() + var data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(board.boardId) + + // demo for denoising, apply different methods to different channels for demo + for count in EEGchannels.indices { + let channel = Int(EEGchannels[count]) + let beforeSum = Double(data[channel].compactMap( {$0} ).reduce(0, +)) + let beforeShape = (data.count, data[0].count) + + // first of all you can try simple moving median or moving average with different window size + switch count { + case 0: + try DataFilter.performRollingFilter(data: &data[channel], period: 3, operation: .MEAN) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + case 1: + try DataFilter.performRollingFilter(data: &data[channel], period: 3, operation: .MEDIAN) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + // if methods above dont work for your signal you can try wavelet based denoising + // feel free to try different functions and decomposition levels + case 2: + try DataFilter.performWaveletDenoising (data: &data[channel], wavelet: .DB6, decompositionLevel: 3) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + case 3: + try DataFilter.performWaveletDenoising(data: &data[channel], wavelet: .BIOR3_9, + decompositionLevel: 3) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + case 4: + try DataFilter.performWaveletDenoising(data: &data[channel], wavelet: .SYM7, + decompositionLevel: 3) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + case 5: + // with synthetic board this one looks like the best option, but it depends on many circumstances + try DataFilter.performWaveletDenoising(data: &data[channel], wavelet: .COIF3, + decompositionLevel: 3) + let afterSum = Double(data[channel].compactMap{$0}.reduce(0, +)) + default: + print("Skipping channel \(channel)") + } + + let afterShape = (data.count, data[0].count) + } +} + +try? testDenoising() diff --git a/swift_package/examples/tests/downsampling/main.swift b/swift_package/examples/tests/downsampling/main.swift new file mode 100644 index 000000000..87cc65ccb --- /dev/null +++ b/swift_package/examples/tests/downsampling/main.swift @@ -0,0 +1,48 @@ +// +// main.swift +// downsampling +// +// Created by Scott Miller on 4/12/24. +// + +import Foundation +import BrainFlow + +func testDownsampleData() throws { + try BoardShim.enableDevBoardLogger() + let params = BrainFlowInputParams() + let board = try BoardShim(.SYNTHETIC_BOARD, params) + try board.prepareSession() + try board.startStream() + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(10) + let data = try board.getBoardData(20) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(.SYNTHETIC_BOARD) + // demo for downsampling, it just aggregates data + for count in EEGchannels.indices { + let channel = Int(EEGchannels[count]) + print("Original data for channel \(channel)") + print(data[channel]) + var downsampledData = [Double]() + let beforeSum = Double(data[channel].compactMap( {$0} ).reduce(0, +)) + + switch count { + case 0: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 3, operation: .MEDIAN) + case 1: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 2, operation: .MEAN) + default: + downsampledData = try DataFilter.performDownsampling(data: data[channel], period: 2, operation: .EACH) + } + + let afterSum = Double(downsampledData.compactMap{$0}.reduce(0, +)) + print("Downsampled data for channel \(channel)") + print("before sum: \(beforeSum), after sum: \(afterSum)") + print(downsampledData) + } +} + +try? testDownsampleData() diff --git a/swift_package/examples/tests/eeg_metrics/eeg_metrics.swift b/swift_package/examples/tests/eeg_metrics/eeg_metrics.swift new file mode 100644 index 000000000..5b3c8e9f5 --- /dev/null +++ b/swift_package/examples/tests/eeg_metrics/eeg_metrics.swift @@ -0,0 +1,103 @@ +// +// eeg_metrics.swift +// eeg_metrics +// +// Created by Scott Miller on 4/8/24. +// + +import Foundation +import BrainFlow +import ArgumentParser + +@main +struct eeg_metrics: ParsableCommand { + @Option(name: [.long], help: "timeout for device discovery or connection") + var timeout: Int = 0 + @Option(name: [.long, .customLong("ip-port")], help: "ip port") + var ip_port: Int = 0 + @Option(name: [.long, .customLong("ip-protocol")], help: "ip protocol, check IpProtocolType enum") + var ip_protocol: Int = 0 + @Option(name: [.long, .customLong("ip-address")], help: "ip address") + var ip_address: String = "" + @Option(name: [.long, .customLong("serial-port")], help: "serial port") + var serial_port: String = "" + @Option(name: [.long, .customLong("mac-address")], help: "mac address") + var mac_address: String = "" + @Option(name: [.long, .customLong("other-info")], help: "other info") + var other_info: String = "" + @Option(name: [.long, .customLong("serial-number")], help: "serial number") + var serial_number: String = "" + @Option(name: [.long, .customLong("board-id")], help: "board id, check docs to get a list of supported boards") + var board_id: Int32 = -1 + @Option(name: [.long], help: "file") + var file: String = "" + @Option(name: [.long, .customLong("master-board")], help: "master board id for streaming and playback boards") + var master_board: Int = -1 + + mutating func run() throws { + var params = BrainFlowInputParams() + params.ip_port = ip_port + params.serial_port = serial_port + params.mac_address = mac_address + params.other_info = other_info + params.serial_number = serial_number + params.ip_address = ip_address + params.ip_protocol = ip_protocol + params.timeout = timeout + params.file = file + params.master_board = master_board + guard let boardId = BoardIds(rawValue: board_id) else { + try? BoardShim.logMessage (.LEVEL_ERROR, "Invalid board ID: \(board_id)") + return + } + + try BoardShim.enableBoardLogger() + try DataFilter.enableDataLogger() + try MLModule.enableMLlogger() + + let board = try BoardShim(boardId, params) + let masterBoardId = try board.getBoardId() + let samplingRate = try BoardShim.getSamplingRate(masterBoardId) + try board.prepareSession() + try board.startStream(bufferSize: 45000) + try BoardShim.logMessage(.LEVEL_INFO, "start sleeping in the main thread") + sleep(5) // recommended window size for eeg metric calculation is at least 4 seconds, bigger is better + let size = try board.getBoardDataCount() + let data = try board.getBoardData(size) + try board.stopStream() + try board.releaseSession() + + let EEGchannels = try BoardShim.getEEGchannels(masterBoardId) + + // avg band power + let bands = try DataFilter.getAvgBandPowers(data: data, channels: EEGchannels, + samplingRate: samplingRate, applyFilter: true) + let avgFeatureVector = bands.0 + bands.1 + print("testEEGmetrics->avg featureVector: \(avgFeatureVector)") + + // custom band power + let avgBands = [(2.0, 4.0), (4.0, 8.0), (8.0, 13.0), (13.0, 30.0), (30.0, 45.0)] + let newBands = try DataFilter.getCustomBandPowers(data: data, bands: avgBands, channels: EEGchannels, samplingRate: samplingRate, applyFilter: true) + let featureVector = newBands.0 + newBands.1 + print("testEEGmetrics->custom featureVector: \(featureVector)") + + // calc concentration + let concentrationParams = BrainFlowModelParams(metric: .MINDFULNESS, classifier: .DEFAULT_CLASSIFIER) + let concentration = MLModule(modelParams: concentrationParams) + try concentration.prepareClassifier() + let concClass = try concentration.predictClass(data: featureVector) + print("testEEGmetrics->concClass: \(concClass)") + try concentration.releaseClassifier() + + // restfulness + onnx is not supported: + let restfulnessParams = BrainFlowModelParams(metric: .RESTFULNESS, classifier: .DEFAULT_CLASSIFIER) + let restfulness = MLModule(modelParams: restfulnessParams) + try restfulness.prepareClassifier() + let restClass = try restfulness.predictClass(data: featureVector) + print("testEEGmetrics->restClass: \(restClass)") + try restfulness.releaseClassifier() + } +} + + + diff --git a/swift_package/examples/tests/ica/main.swift b/swift_package/examples/tests/ica/main.swift new file mode 100644 index 000000000..ea7e3623b --- /dev/null +++ b/swift_package/examples/tests/ica/main.swift @@ -0,0 +1,49 @@ +// +// main.swift +// ica +// +// Created by Scott Miller on 4/13/24. +// + +import Foundation +import BrainFlow + +// From https://stackoverflow.com/questions/48088882/how-can-split-from-string-to-array-by-chunks-of-given-size +extension Array { + func chunks(size: Int) -> [[Element]] { + return stride(from: 0, to: count, by: size).map { + Array(self[$0 ..< Swift.min($0 + size, count)]) + } + } +} + +// From https://stackoverflow.com/questions/39889568/how-to-transpose-an-array-more-swiftly +func matrixTranspose(_ matrix: [[T]]) -> [[T]] { + if matrix.isEmpty {return matrix} + var result = [[T]]() + for index in 0..