summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PrySDR.xcodeproj/project.pbxproj527
-rw-r--r--Radio/Utils/WaterfallFile/NaiveFFT.swift7
-rw-r--r--Radio/Utils/WaterfallFile/SimpleImage.swift116
-rw-r--r--Radio/Utils/WaterfallFile/main.swift113
-rw-r--r--WaterfallFile_UI/Assets.xcassets/AccentColor.colorset/Contents.json11
-rw-r--r--WaterfallFile_UI/Assets.xcassets/AppIcon.appiconset/Contents.json58
-rw-r--r--WaterfallFile_UI/Assets.xcassets/Contents.json6
-rw-r--r--WaterfallFile_UI/ContentView.swift94
-rw-r--r--WaterfallFile_UI/FileSpectrum.swift64
-rw-r--r--WaterfallFile_UI/Item.swift18
-rw-r--r--WaterfallFile_UI/Preview Content/Preview Assets.xcassets/Contents.json6
-rw-r--r--WaterfallFile_UI/WaterfallFile_UI.entitlements10
-rw-r--r--WaterfallFile_UI/WaterfallFile_UIApp.swift45
-rw-r--r--WaterfallFile_UITests/WaterfallFile_UITests.swift17
-rw-r--r--WaterfallFile_UIUITests/WaterfallFile_UIUITests.swift43
-rw-r--r--WaterfallFile_UIUITests/WaterfallFile_UIUITestsLaunchTests.swift33
16 files changed, 1167 insertions, 1 deletions
diff --git a/PrySDR.xcodeproj/project.pbxproj b/PrySDR.xcodeproj/project.pbxproj
index 233a68b..5d627d2 100644
--- a/PrySDR.xcodeproj/project.pbxproj
+++ b/PrySDR.xcodeproj/project.pbxproj
@@ -13,6 +13,8 @@
buildPhases = (
);
dependencies = (
+ 8D9A38892D19D4E1009A4186 /* PBXTargetDependency */,
+ 8D9A38872D19D4DC009A4186 /* PBXTargetDependency */,
8D4068682CFDC0940064C96D /* PBXTargetDependency */,
8D4068662CFDC0900064C96D /* PBXTargetDependency */,
8D4068642CFDC08D0064C96D /* PBXTargetDependency */,
@@ -65,6 +67,7 @@
8D9A334F2D0B0DD6009A4186 /* libusb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D5A5DDA2CD4B9100096CBD7 /* libusb.a */; };
8D9A33502D0B0DD8009A4186 /* libbladerf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D87709D2CD6B4BB0082EC54 /* libbladerf.a */; };
8D9A33522D0B0DE5009A4186 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 8D9A33512D0B0DE5009A4186 /* ArgumentParser */; };
+ 8D9A38852D19D427009A4186 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = 8D9A38842D19D427009A4186 /* ArgumentParser */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -208,6 +211,34 @@
remoteGlobalIDString = 8D87709C2CD6B4BB0082EC54;
remoteInfo = libbladerf;
};
+ 8D9A38592D194A41009A4186 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 8DD98C392CC592540062D678 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D9A38452D194A3D009A4186;
+ remoteInfo = WaterfallFile_UI;
+ };
+ 8D9A38632D194A41009A4186 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 8DD98C392CC592540062D678 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D9A38452D194A3D009A4186;
+ remoteInfo = WaterfallFile_UI;
+ };
+ 8D9A38862D19D4DC009A4186 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 8DD98C392CC592540062D678 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D9A33432D0B0D8D009A4186;
+ remoteInfo = BladeRFIQ;
+ };
+ 8D9A38882D19D4E1009A4186 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 8DD98C392CC592540062D678 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D9A38762D196510009A4186;
+ remoteInfo = WaterfallFile;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -283,6 +314,15 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
+ 8D9A38752D196510009A4186 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
8DD98C3F2CC592540062D678 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -311,6 +351,10 @@
8D876FFD2CD4F1620082EC54 /* test_bladerf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_bladerf; sourceTree = BUILT_PRODUCTS_DIR; };
8D87709D2CD6B4BB0082EC54 /* libbladerf.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libbladerf.a; sourceTree = BUILT_PRODUCTS_DIR; };
8D9A33442D0B0D8D009A4186 /* bladerf_iq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bladerf_iq; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D9A38462D194A3D009A4186 /* WaterfallFile_UI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WaterfallFile_UI.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D9A38582D194A41009A4186 /* WaterfallFile_UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WaterfallFile_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D9A38622D194A41009A4186 /* WaterfallFile_UIUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WaterfallFile_UIUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D9A38772D196510009A4186 /* waterfall_file */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = waterfall_file; sourceTree = BUILT_PRODUCTS_DIR; };
8DD98C412CC592540062D678 /* prysdr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = prysdr; sourceTree = BUILT_PRODUCTS_DIR; };
8DD98C722CC632040062D678 /* MatrixXT.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatrixXT.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -556,6 +600,9 @@
Utils/TestAirSpyHF/main.swift,
Utils/TestBladeRF/main.swift,
Utils/TestRtlSdr/main.swift,
+ Utils/WaterfallFile/main.swift,
+ Utils/WaterfallFile/NaiveFFT.swift,
+ Utils/WaterfallFile/SimpleImage.swift,
);
target = 8DD98C402CC592540062D678 /* PrySDR */;
};
@@ -753,6 +800,30 @@
);
target = 8D9A33432D0B0D8D009A4186 /* BladeRFIQ */;
};
+ 8D9A38812D196520009A4186 /* Exceptions for "Radio" folder in "WaterfallFile" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Utils/WaterfallFile/main.swift,
+ Utils/WaterfallFile/NaiveFFT.swift,
+ Utils/WaterfallFile/SimpleImage.swift,
+ );
+ target = 8D9A38762D196510009A4186 /* WaterfallFile */;
+ };
+ 8D9A38832D19D277009A4186 /* Exceptions for "Utils" folder in "WaterfallFile" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ PathUtils.swift,
+ );
+ target = 8D9A38762D196510009A4186 /* WaterfallFile */;
+ };
+ 8DBA9F602D2928DE008ECB92 /* Exceptions for "Radio" folder in "WaterfallFile_UI" target */ = {
+ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
+ membershipExceptions = (
+ Utils/WaterfallFile/NaiveFFT.swift,
+ Utils/WaterfallFile/SimpleImage.swift,
+ );
+ target = 8D9A38452D194A3D009A4186 /* WaterfallFile_UI */;
+ };
8DD98C7C2CC6320C0062D678 /* Exceptions for "LA" folder in "PrySDR" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
@@ -781,6 +852,21 @@
path = Gen;
sourceTree = "<group>";
};
+ 8D9A38472D194A3D009A4186 /* WaterfallFile_UI */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = WaterfallFile_UI;
+ sourceTree = "<group>";
+ };
+ 8D9A385B2D194A41009A4186 /* WaterfallFile_UITests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = WaterfallFile_UITests;
+ sourceTree = "<group>";
+ };
+ 8D9A38652D194A41009A4186 /* WaterfallFile_UIUITests */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = WaterfallFile_UIUITests;
+ sourceTree = "<group>";
+ };
8DD98C432CC592540062D678 /* PrySDR */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = PrySDR;
@@ -812,6 +898,8 @@
8D4068402CFDA6A30064C96D /* Exceptions for "Radio" folder in "AirSpyHFIQ" target */,
8D40684F2CFDA6BD0064C96D /* Exceptions for "Radio" folder in "AirSpyIQ" target */,
8D9A334E2D0B0D92009A4186 /* Exceptions for "Radio" folder in "BladeRFIQ" target */,
+ 8DBA9F602D2928DE008ECB92 /* Exceptions for "Radio" folder in "WaterfallFile_UI" target */,
+ 8D9A38812D196520009A4186 /* Exceptions for "Radio" folder in "WaterfallFile" target */,
);
path = Radio;
sourceTree = "<group>";
@@ -870,6 +958,7 @@
8D40686D2CFDE4C10064C96D /* Exceptions for "Utils" folder in "AirSpyHFIQ" target */,
8D406AB52CFF0D1F0064C96D /* Exceptions for "Utils" folder in "AirSpyIQ" target */,
8D9A37F12D180D4C009A4186 /* Exceptions for "Utils" folder in "BladeRFIQ" target */,
+ 8D9A38832D19D277009A4186 /* Exceptions for "Utils" folder in "WaterfallFile" target */,
);
path = Utils;
sourceTree = "<group>";
@@ -993,6 +1082,35 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8D9A38432D194A3D009A4186 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38552D194A41009A4186 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A385F2D194A41009A4186 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38742D196510009A4186 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D9A38852D19D427009A4186 /* ArgumentParser in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C3E2CC592540062D678 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1040,6 +1158,9 @@
8DD98C542CC5942F0062D678 /* Radio */,
8DD98C502CC5935B0062D678 /* LA */,
8DD98C432CC592540062D678 /* PrySDR */,
+ 8D9A38472D194A3D009A4186 /* WaterfallFile_UI */,
+ 8D9A385B2D194A41009A4186 /* WaterfallFile_UITests */,
+ 8D9A38652D194A41009A4186 /* WaterfallFile_UIUITests */,
8DD98C422CC592540062D678 /* Products */,
8DD98C642CC599CA0062D678 /* Series */,
8DD98C7F2CC7852E0062D678 /* Images */,
@@ -1065,6 +1186,10 @@
8D4068362CFDA69C0064C96D /* airspyhf_iq */,
8D4068452CFDA6B80064C96D /* airspy_iq */,
8D9A33442D0B0D8D009A4186 /* bladerf_iq */,
+ 8D9A38462D194A3D009A4186 /* WaterfallFile_UI.app */,
+ 8D9A38582D194A41009A4186 /* WaterfallFile_UITests.xctest */,
+ 8D9A38622D194A41009A4186 /* WaterfallFile_UIUITests.xctest */,
+ 8D9A38772D196510009A4186 /* waterfall_file */,
);
name = Products;
sourceTree = "<group>";
@@ -1384,6 +1509,94 @@
productReference = 8D9A33442D0B0D8D009A4186 /* bladerf_iq */;
productType = "com.apple.product-type.tool";
};
+ 8D9A38452D194A3D009A4186 /* WaterfallFile_UI */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8D9A386A2D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UI" */;
+ buildPhases = (
+ 8D9A38422D194A3D009A4186 /* Sources */,
+ 8D9A38432D194A3D009A4186 /* Frameworks */,
+ 8D9A38442D194A3D009A4186 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ 8D9A38472D194A3D009A4186 /* WaterfallFile_UI */,
+ );
+ name = WaterfallFile_UI;
+ packageProductDependencies = (
+ );
+ productName = WaterfallFile_UI;
+ productReference = 8D9A38462D194A3D009A4186 /* WaterfallFile_UI.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 8D9A38572D194A41009A4186 /* WaterfallFile_UITests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8D9A386D2D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UITests" */;
+ buildPhases = (
+ 8D9A38542D194A41009A4186 /* Sources */,
+ 8D9A38552D194A41009A4186 /* Frameworks */,
+ 8D9A38562D194A41009A4186 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 8D9A385A2D194A41009A4186 /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 8D9A385B2D194A41009A4186 /* WaterfallFile_UITests */,
+ );
+ name = WaterfallFile_UITests;
+ packageProductDependencies = (
+ );
+ productName = WaterfallFile_UITests;
+ productReference = 8D9A38582D194A41009A4186 /* WaterfallFile_UITests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 8D9A38612D194A41009A4186 /* WaterfallFile_UIUITests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8D9A38702D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UIUITests" */;
+ buildPhases = (
+ 8D9A385E2D194A41009A4186 /* Sources */,
+ 8D9A385F2D194A41009A4186 /* Frameworks */,
+ 8D9A38602D194A41009A4186 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 8D9A38642D194A41009A4186 /* PBXTargetDependency */,
+ );
+ fileSystemSynchronizedGroups = (
+ 8D9A38652D194A41009A4186 /* WaterfallFile_UIUITests */,
+ );
+ name = WaterfallFile_UIUITests;
+ packageProductDependencies = (
+ );
+ productName = WaterfallFile_UIUITests;
+ productReference = 8D9A38622D194A41009A4186 /* WaterfallFile_UIUITests.xctest */;
+ productType = "com.apple.product-type.bundle.ui-testing";
+ };
+ 8D9A38762D196510009A4186 /* WaterfallFile */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8D9A387B2D196510009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile" */;
+ buildPhases = (
+ 8D9A38732D196510009A4186 /* Sources */,
+ 8D9A38742D196510009A4186 /* Frameworks */,
+ 8D9A38752D196510009A4186 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = WaterfallFile;
+ packageProductDependencies = (
+ 8D9A38842D19D427009A4186 /* ArgumentParser */,
+ );
+ productName = WaterfallFile;
+ productReference = 8D9A38772D196510009A4186 /* waterfall_file */;
+ productType = "com.apple.product-type.tool";
+ };
8DD98C402CC592540062D678 /* PrySDR */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8DD98C482CC592540062D678 /* Build configuration list for PBXNativeTarget "PrySDR" */;
@@ -1444,7 +1657,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1620;
- LastUpgradeCheck = 1610;
+ LastUpgradeCheck = 1620;
TargetAttributes = {
8D0349172CF70DCD0026DA77 = {
CreatedOnToolsVersion = 16.1;
@@ -1491,6 +1704,20 @@
8D9A33432D0B0D8D009A4186 = {
CreatedOnToolsVersion = 16.2;
};
+ 8D9A38452D194A3D009A4186 = {
+ CreatedOnToolsVersion = 16.2;
+ };
+ 8D9A38572D194A41009A4186 = {
+ CreatedOnToolsVersion = 16.2;
+ TestTargetID = 8D9A38452D194A3D009A4186;
+ };
+ 8D9A38612D194A41009A4186 = {
+ CreatedOnToolsVersion = 16.2;
+ TestTargetID = 8D9A38452D194A3D009A4186;
+ };
+ 8D9A38762D196510009A4186 = {
+ CreatedOnToolsVersion = 16.2;
+ };
8DD98C402CC592540062D678 = {
CreatedOnToolsVersion = 16.0;
};
@@ -1532,11 +1759,36 @@
8D4068352CFDA69C0064C96D /* AirSpyHFIQ */,
8D4068442CFDA6B80064C96D /* AirSpyIQ */,
8D9A33432D0B0D8D009A4186 /* BladeRFIQ */,
+ 8D9A38452D194A3D009A4186 /* WaterfallFile_UI */,
+ 8D9A38572D194A41009A4186 /* WaterfallFile_UITests */,
+ 8D9A38612D194A41009A4186 /* WaterfallFile_UIUITests */,
+ 8D9A38762D196510009A4186 /* WaterfallFile */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 8D9A38442D194A3D009A4186 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38562D194A41009A4186 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38602D194A41009A4186 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C702CC632040062D678 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1638,6 +1890,34 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 8D9A38422D194A3D009A4186 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38542D194A41009A4186 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A385E2D194A41009A4186 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D9A38732D196510009A4186 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
8DD98C3D2CC592540062D678 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1755,6 +2035,26 @@
target = 8D87709C2CD6B4BB0082EC54 /* libbladerf */;
targetProxy = 8D87711B2CD79EAD0082EC54 /* PBXContainerItemProxy */;
};
+ 8D9A385A2D194A41009A4186 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D9A38452D194A3D009A4186 /* WaterfallFile_UI */;
+ targetProxy = 8D9A38592D194A41009A4186 /* PBXContainerItemProxy */;
+ };
+ 8D9A38642D194A41009A4186 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D9A38452D194A3D009A4186 /* WaterfallFile_UI */;
+ targetProxy = 8D9A38632D194A41009A4186 /* PBXContainerItemProxy */;
+ };
+ 8D9A38872D19D4DC009A4186 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D9A33432D0B0D8D009A4186 /* BladeRFIQ */;
+ targetProxy = 8D9A38862D19D4DC009A4186 /* PBXContainerItemProxy */;
+ };
+ 8D9A38892D19D4E1009A4186 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D9A38762D196510009A4186 /* WaterfallFile */;
+ targetProxy = 8D9A38882D19D4E1009A4186 /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
@@ -1762,6 +2062,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1774,6 +2075,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1786,6 +2088,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1798,6 +2101,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1810,6 +2114,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1822,6 +2127,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -1835,6 +2141,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1850,6 +2157,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1864,6 +2172,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1879,6 +2188,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1893,6 +2203,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1908,6 +2219,7 @@
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1921,6 +2233,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1932,6 +2245,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1943,6 +2257,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_rtlsdr;
@@ -1954,6 +2269,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_rtlsdr;
@@ -1965,6 +2281,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_airspy;
@@ -1976,6 +2293,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_airspy;
@@ -1987,6 +2305,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_airspyhf;
@@ -1998,6 +2317,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_airspyhf;
@@ -2009,6 +2329,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2018,6 +2339,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -2027,6 +2349,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_bladerf;
@@ -2039,6 +2362,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = test_bladerf;
@@ -2050,6 +2374,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
"HEADER_SEARCH_PATHS[arch=*]" = "$(PROJECT_DIR)/Radio/HW/BladeRF/src";
@@ -2065,6 +2390,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
EXECUTABLE_PREFIX = "";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -2077,6 +2403,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -2089,6 +2416,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 15.1;
@@ -2097,6 +2425,156 @@
};
name = Release;
};
+ 8D9A386B2D194A41009A4186 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = WaterfallFile_UI/WaterfallFile_UI.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"WaterfallFile_UI/Preview Content\"";
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UI";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 8D9A386C2D194A41009A4186 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = WaterfallFile_UI/WaterfallFile_UI.entitlements;
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"WaterfallFile_UI/Preview Content\"";
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UI";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+ 8D9A386E2D194A41009A4186 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WaterfallFile_UI.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/WaterfallFile_UI";
+ };
+ name = Debug;
+ };
+ 8D9A386F2D194A41009A4186 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WaterfallFile_UI.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/WaterfallFile_UI";
+ };
+ name = Release;
+ };
+ 8D9A38712D194A41009A4186 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UIUITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TEST_TARGET_NAME = WaterfallFile_UI;
+ };
+ name = Debug;
+ };
+ 8D9A38722D194A41009A4186 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ GENERATE_INFOPLIST_FILE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "RadioTeam.WaterfallFile-UIUITests";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TEST_TARGET_NAME = WaterfallFile_UI;
+ };
+ name = Release;
+ };
+ 8D9A387C2D196510009A4186 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ PRODUCT_NAME = waterfall_file;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 8D9A387D2D196510009A4186 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = 53B26AJZ4Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.1;
+ PRODUCT_NAME = waterfall_file;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
8DD98C462CC592540062D678 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -2131,6 +2609,7 @@
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;
@@ -2194,6 +2673,7 @@
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;
@@ -2219,6 +2699,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = prysdr;
@@ -2230,6 +2711,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
ENABLE_HARDENED_RUNTIME = YES;
PRODUCT_NAME = prysdr;
@@ -2242,6 +2724,7 @@
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -2257,6 +2740,7 @@
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
+ DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 53B26AJZ4Z;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
@@ -2396,6 +2880,42 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 8D9A386A2D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UI" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8D9A386B2D194A41009A4186 /* Debug */,
+ 8D9A386C2D194A41009A4186 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8D9A386D2D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UITests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8D9A386E2D194A41009A4186 /* Debug */,
+ 8D9A386F2D194A41009A4186 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8D9A38702D194A41009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile_UIUITests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8D9A38712D194A41009A4186 /* Debug */,
+ 8D9A38722D194A41009A4186 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8D9A387B2D196510009A4186 /* Build configuration list for PBXNativeTarget "WaterfallFile" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8D9A387C2D196510009A4186 /* Debug */,
+ 8D9A387D2D196510009A4186 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
8DD98C3C2CC592540062D678 /* Build configuration list for PBXProject "PrySDR" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -2462,6 +2982,11 @@
package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
productName = ArgumentParser;
};
+ 8D9A38842D19D427009A4186 /* ArgumentParser */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 8D0349232CF70E180026DA77 /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
+ productName = ArgumentParser;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 8DD98C392CC592540062D678 /* Project object */;
diff --git a/Radio/Utils/WaterfallFile/NaiveFFT.swift b/Radio/Utils/WaterfallFile/NaiveFFT.swift
new file mode 100644
index 0000000..79393b7
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/NaiveFFT.swift
@@ -0,0 +1,7 @@
+//
+// NaiveFFT.swift
+// PrySDR
+//
+// Created by Jacky Jack on 05/01/2025.
+//
+
diff --git a/Radio/Utils/WaterfallFile/SimpleImage.swift b/Radio/Utils/WaterfallFile/SimpleImage.swift
new file mode 100644
index 0000000..c05709f
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/SimpleImage.swift
@@ -0,0 +1,116 @@
+//
+// Image.swift
+// PrySDR
+//
+// Created by Jacky Jack on 27/12/2024.
+//
+
+import Foundation
+import AppKit
+
+// https://stackoverflow.com/questions/30958427/pixel-array-to-uiimage-in-swift
+public struct PixelData {
+ var a: UInt8
+ var r: UInt8
+ var g: UInt8
+ var b: UInt8
+}
+
+public class SimpleImage {
+
+ private var pixels: [PixelData] = []
+ private var width:Int = 0
+ private var height:Int = 0
+
+ init(width: Int, height: Int) {
+ self.width = width
+ self.height = height
+ pixels = .init(repeating: .init(a: 255, r: 0, g: 0, b: 0), count: width*height)
+ }
+
+
+ func drawPalletLine(line: Int, pixelLine:[Float]) {
+ for i in 0..<self.width {
+ var pixel = pixelLine[i]
+ if pixel>256.0 {
+ //print("values to high")
+ pixel = 255.0
+ }
+ if pixel < 0.0 {
+ pixel = 0.0
+ }
+ self.pixels[line*self.width + i].a = 255
+ self.pixels[line*self.width + i].r = UInt8(pixel)
+ self.pixels[line*self.width + i].g = UInt8(pixel)
+ self.pixels[line*self.width + i].b = UInt8(pixel)
+ }
+ }
+
+ func drawPixel(_ w: Int, _ h: Int, _ pixel: PixelData) {
+ self.pixels[h*self.height+w] = pixel
+ }
+
+ func toCGImage() -> CGImage? {
+ guard self.width > 0 && self.height > 0 else { return nil }
+ guard self.pixels.count == self.width * self.height else { return nil }
+
+ let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
+ let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedFirst.rawValue)
+ let bitsPerComponent = 8
+ let bitsPerPixel = 32
+
+ var data = self.pixels // Copy to mutable []
+ guard let providerRef = CGDataProvider(data: NSData(bytes: &data,
+ length: data.count * MemoryLayout<PixelData>.size)
+ )
+ else { return nil }
+
+ guard let cgim = CGImage(
+ width: self.width,
+ height: self.height,
+ bitsPerComponent: bitsPerComponent,
+ bitsPerPixel: bitsPerPixel,
+ bytesPerRow: self.width * MemoryLayout<PixelData>.size,
+ space: rgbColorSpace,
+ bitmapInfo: bitmapInfo,
+ provider: providerRef,
+ decode: nil,
+ shouldInterpolate: true,
+ intent: .defaultIntent
+ )
+ else { return nil }
+
+ return cgim
+ }
+
+ func toNSImage() -> NSImage? {
+ guard let cgim = toCGImage() else { return nil }
+ return NSImage(cgImage: cgim, size:.zero)
+ }
+
+ func saveAsJPEG(_ image: NSImage, _ name: String) {
+ if let imageData = image.tiffRepresentation {
+ do {
+ let bundlePath = Bundle.main.resourcePath!
+ let imageUrl = URL(fileURLWithPath:bundlePath+"/"+name)
+ try imageData.write(to: imageUrl)
+
+ } catch {
+ print("Cant save image to disk")
+ }
+
+ } else {
+ print("cant get tiff representation")
+ }
+ }
+
+ func saveAsJPEG(_ name: String) {
+ if let img = self.toNSImage() {
+ saveAsJPEG(img, name)
+ }
+ }
+}
+
+
+
+
diff --git a/Radio/Utils/WaterfallFile/main.swift b/Radio/Utils/WaterfallFile/main.swift
new file mode 100644
index 0000000..cf72d56
--- /dev/null
+++ b/Radio/Utils/WaterfallFile/main.swift
@@ -0,0 +1,113 @@
+//
+// main.swift
+// WaterfallFile
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import Foundation
+import Accelerate
+
+print("Read binary file")
+
+let input_filename="rtlsdr_100M_m.cu8"
+
+
+//get data from u8 file
+let dir = getCurrentExecutableDir()
+let filemgr = FileManager.default
+
+if !filemgr.fileExists(atPath: input_filename) {
+ print("Cant find file \(input_filename)")
+ exit(0)
+}
+
+let fileHandle: FileHandle? = FileHandle(forReadingAtPath: dir+"/"+input_filename)
+var i8_arr:[Int8]? = nil
+if let file = fileHandle {
+ file.seek(toFileOffset: 0)
+ do {
+ if let databuf = try file.readToEnd() {
+
+ print("read \(databuf.count) \(databuf) bytes")
+ //let temp_arr = [Int8](databuf)
+ i8_arr = [Int8](repeating: 0, count: databuf.count)
+
+ for i in 0..<i8_arr!.count {
+ print(String(format:"%02X", databuf[i]),terminator: "")
+ //convert from 0..255 to -127..128
+ let val = databuf[i]
+ if val <= 127 {
+ i8_arr![i] = Int8(val)-127
+ } else {
+ i8_arr![i] = Int8(val-128)
+ }
+ //print(String(format:"%02X", i8_arr![i]),terminator: "")
+ }
+ }
+ } catch {
+ print(error)
+ exit(0)
+ }
+
+}
+fileHandle?.closeFile()
+
+//all data in buffer lets process data
+//convert all u8 data to float's
+
+//is there other ways to do that?
+/*for i in 0..<dataFloat.count {
+ dataFloat[i] = Float(u8_arr![i])
+}*/
+//will generate 512x512 image
+let sampleCount = 512
+let img = SimpleImage(width: sampleCount, height: sampleCount)
+let number_of_lines = (i8_arr!.count/sampleCount)
+let forwardDCT = vDSP.DCT(count: sampleCount, transformType: .II)!
+var frequencyDomain:[Float] = []
+var transform_result:[Float] = .init(repeating: 0.0, count: sampleCount)
+var dataFloat = [Float](repeating: 0.0, count: sampleCount)
+for i in 0..<sampleCount {
+ let sample_idx = i*sampleCount
+ if i < number_of_lines {
+ let processingSlice = i8_arr![sample_idx...sample_idx+512-1]
+ let processingArray = Array(processingSlice)
+ vDSP.convertElements(of: processingArray, to: &dataFloat)
+ //dataFloat = vDSP.add(127.0, dataFloat)
+ //print(dataFloat)
+
+ //move from -127.0 to 128.0 range -1.0...1.0
+ //var adjusted = vDSP.divide(dataFloat, Float(sampleCount))
+ var adjusted = dataFloat
+ //print(adjusted)
+
+ transform_result = forwardDCT.transform(adjusted)
+ transform_result = vDSP.absolute(transform_result)
+ let max = vDSP.maximum(transform_result)
+ //print("max=\(max)")
+ //frequencyDomain.append(contentsOf: transform_result)
+ img.drawPalletLine(line: i, pixelLine: transform_result)
+ //print(transform_result)
+ } else {
+ img.drawPalletLine(line: i, pixelLine: transform_result)
+ }
+
+}
+
+img.drawPixel(0, 0, PixelData(a: 255, r: 255, g: 0, b: 0))
+img.drawPixel(sampleCount-1, 0, PixelData(a: 255, r: 0, g: 255, b: 0))
+img.drawPixel(0, sampleCount-1, PixelData(a: 255, r: 0, g: 255, b: 0))
+img.drawPixel(sampleCount-1, sampleCount-1, PixelData(a: 255, r: 0, g: 0, b: 255))
+
+
+//print(dataFloat)
+
+
+
+//output data to image file
+img.saveAsJPEG("fft_100m_512.jpeg")
+
+
+
+print("All computations are done")
diff --git a/WaterfallFile_UI/Assets.xcassets/AccentColor.colorset/Contents.json b/WaterfallFile_UI/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000..eb87897
--- /dev/null
+++ b/WaterfallFile_UI/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallFile_UI/Assets.xcassets/AppIcon.appiconset/Contents.json b/WaterfallFile_UI/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..3f00db4
--- /dev/null
+++ b/WaterfallFile_UI/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,58 @@
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "16x16"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "32x32"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "128x128"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "256x256"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "1x",
+ "size" : "512x512"
+ },
+ {
+ "idiom" : "mac",
+ "scale" : "2x",
+ "size" : "512x512"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallFile_UI/Assets.xcassets/Contents.json b/WaterfallFile_UI/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallFile_UI/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallFile_UI/ContentView.swift b/WaterfallFile_UI/ContentView.swift
new file mode 100644
index 0000000..92445d8
--- /dev/null
+++ b/WaterfallFile_UI/ContentView.swift
@@ -0,0 +1,94 @@
+//
+// ContentView.swift
+// WaterfallFile_UI
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import SwiftUI
+import SwiftData
+import AppKit
+
+
+struct ContentView: View {
+ @Environment(\.modelContext) private var modelContext
+
+ @EnvironmentObject var fileSpectrum: FileSpectrum
+
+ @State private var image: Image?
+
+ @Query private var items: [Item]
+
+ var body: some View {
+ /*
+ NavigationSplitView {
+ List {
+ ForEach(items) { item in
+ NavigationLink {
+ Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
+ } label: {
+ Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
+ }
+ }
+ .onDelete(perform: deleteItems)
+ }
+ .navigationSplitViewColumnWidth(min: 180, ideal: 200)
+ .toolbar {
+ ToolbarItem {
+ Button(action: addItem) {
+ Label("Add Item", systemImage: "plus")
+ }
+ }
+ }
+ } detail: {
+ Text("Select an item")
+ }
+ */
+ //Image(decorative: fileSpectrum.makeSpectrogramImage(), scale: 1.0, orientation: .left)
+ VStack {
+ //Image(nsImage:fileSpectrum.outputImage)
+ Image(decorative: fileSpectrum.outputImage,
+ scale: 1,
+ orientation: .left)
+ //.resizable()
+
+
+ //Image(fileSpectrum.makeSpectrogramImage(), scale: 1, orientation:.left, label: "Image")
+ //Image(decorative: fileSpectrum.makeSpectrogramImage(), scale: 1.0, orientation: .left)
+ //Image(nsImage: fileSpectrum.makeSpectrogramImage())
+ HStack {
+ Text("Hello world")
+ .padding()
+ Button("Start") {
+ print("Start")
+ }
+ Button("Stop") {
+ print("Stop")
+ }
+ Button("Load") {
+ print("Load")
+ }
+ }
+ }
+ }
+
+ private func addItem() {
+ withAnimation {
+ let newItem = Item(timestamp: Date())
+ modelContext.insert(newItem)
+ }
+ }
+
+ private func deleteItems(offsets: IndexSet) {
+ withAnimation {
+ for index in offsets {
+ modelContext.delete(items[index])
+ }
+ }
+ }
+}
+
+#Preview {
+ ContentView()
+ .modelContainer(for: Item.self, inMemory: true)
+}
diff --git a/WaterfallFile_UI/FileSpectrum.swift b/WaterfallFile_UI/FileSpectrum.swift
new file mode 100644
index 0000000..6415dfa
--- /dev/null
+++ b/WaterfallFile_UI/FileSpectrum.swift
@@ -0,0 +1,64 @@
+//
+// FileSpectrum.swift
+// PrySDR
+//
+// Created by Jacky Jack on 01/01/2025.
+//
+
+import Accelerate
+import AppKit
+import Combine
+import CoreImage
+
+
+class FileSpectrum: NSObject, ObservableObject {
+
+ let default_width = 512
+ let default_height = 512
+
+ let sessionQueue = DispatchQueue(label: "sessionQueue",
+ attributes: [],
+ autoreleaseFrequency: .workItem)
+
+ @Published var outputImage = emptyCGImage
+
+ let simpleImage = SimpleImage(width: 256, height: 256)
+
+ /// A 1x1 Core Graphics image.
+ static var emptyCGImage: CGImage = {
+ let buffer = vImage.PixelBuffer(
+ pixelValues: [0],
+ size: .init(width: 1, height: 1),
+ pixelFormat: vImage.Planar8.self)
+
+ let fmt = vImage_CGImageFormat(
+ bitsPerComponent: 8,
+ bitsPerPixel: 8 ,
+ colorSpace: CGColorSpaceCreateDeviceGray(),
+ bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
+ renderingIntent: .defaultIntent)
+
+ return buffer.makeCGImage(cgImageFormat: fmt!)!
+ }()
+
+ func makeSpectrogramImage() -> NSImage {
+
+ return NSImage(cgImage: FileSpectrum.emptyCGImage, size: .zero)
+ }
+
+
+
+ func startRunning() {
+ sessionQueue.async {
+ print("lets start the task for spectrum analysis")
+ for i in 0..<100 {
+ print("Process the task \(i)")
+ self.simpleImage.drawPixel(i, i, PixelData(a: 255, r: 255, g: 0, b: 0))
+ DispatchQueue.main.async {
+ self.outputImage = self.simpleImage.toCGImage()!
+ }
+ sleep(1)
+ }
+ }
+ }
+}
diff --git a/WaterfallFile_UI/Item.swift b/WaterfallFile_UI/Item.swift
new file mode 100644
index 0000000..f20bc8d
--- /dev/null
+++ b/WaterfallFile_UI/Item.swift
@@ -0,0 +1,18 @@
+//
+// Item.swift
+// WaterfallFile_UI
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import Foundation
+import SwiftData
+
+@Model
+final class Item {
+ var timestamp: Date
+
+ init(timestamp: Date) {
+ self.timestamp = timestamp
+ }
+}
diff --git a/WaterfallFile_UI/Preview Content/Preview Assets.xcassets/Contents.json b/WaterfallFile_UI/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/WaterfallFile_UI/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/WaterfallFile_UI/WaterfallFile_UI.entitlements b/WaterfallFile_UI/WaterfallFile_UI.entitlements
new file mode 100644
index 0000000..18aff0c
--- /dev/null
+++ b/WaterfallFile_UI/WaterfallFile_UI.entitlements
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+</dict>
+</plist>
diff --git a/WaterfallFile_UI/WaterfallFile_UIApp.swift b/WaterfallFile_UI/WaterfallFile_UIApp.swift
new file mode 100644
index 0000000..959fe55
--- /dev/null
+++ b/WaterfallFile_UI/WaterfallFile_UIApp.swift
@@ -0,0 +1,45 @@
+//
+// WaterfallFile_UIApp.swift
+// WaterfallFile_UI
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import SwiftUI
+import SwiftData
+
+@main
+struct WaterfallFile_UIApp: App {
+
+ let fileSpectrum = FileSpectrum()
+
+ @Environment(\.scenePhase) private var scenePhase
+
+ var sharedModelContainer: ModelContainer = {
+ let schema = Schema([
+ Item.self,
+ ])
+ let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
+
+ do {
+ return try ModelContainer(for: schema, configurations: [modelConfiguration])
+ } catch {
+ fatalError("Could not create ModelContainer: \(error)")
+ }
+ }()
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ .environmentObject(fileSpectrum)
+ .onChange(of: scenePhase) { phase in
+ if phase == .active {
+ Task(priority: .userInitiated) {
+ fileSpectrum.startRunning()
+ }
+ }
+ }
+ }
+ .modelContainer(sharedModelContainer)
+ }
+}
diff --git a/WaterfallFile_UITests/WaterfallFile_UITests.swift b/WaterfallFile_UITests/WaterfallFile_UITests.swift
new file mode 100644
index 0000000..1338c5e
--- /dev/null
+++ b/WaterfallFile_UITests/WaterfallFile_UITests.swift
@@ -0,0 +1,17 @@
+//
+// WaterfallFile_UITests.swift
+// WaterfallFile_UITests
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import Testing
+@testable import WaterfallFile_UI
+
+struct WaterfallFile_UITests {
+
+ @Test func example() async throws {
+ // Write your test here and use APIs like `#expect(...)` to check expected conditions.
+ }
+
+}
diff --git a/WaterfallFile_UIUITests/WaterfallFile_UIUITests.swift b/WaterfallFile_UIUITests/WaterfallFile_UIUITests.swift
new file mode 100644
index 0000000..c3348da
--- /dev/null
+++ b/WaterfallFile_UIUITests/WaterfallFile_UIUITests.swift
@@ -0,0 +1,43 @@
+//
+// WaterfallFile_UIUITests.swift
+// WaterfallFile_UIUITests
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import XCTest
+
+final class WaterfallFile_UIUITests: XCTestCase {
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+
+ // In UI tests it is usually best to stop immediately when a failure occurs.
+ continueAfterFailure = false
+
+ // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ @MainActor
+ func testExample() throws {
+ // UI tests must launch the application that they test.
+ let app = XCUIApplication()
+ app.launch()
+
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ }
+
+ @MainActor
+ func testLaunchPerformance() throws {
+ if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
+ // This measures how long it takes to launch your application.
+ measure(metrics: [XCTApplicationLaunchMetric()]) {
+ XCUIApplication().launch()
+ }
+ }
+ }
+}
diff --git a/WaterfallFile_UIUITests/WaterfallFile_UIUITestsLaunchTests.swift b/WaterfallFile_UIUITests/WaterfallFile_UIUITestsLaunchTests.swift
new file mode 100644
index 0000000..99aaf0c
--- /dev/null
+++ b/WaterfallFile_UIUITests/WaterfallFile_UIUITestsLaunchTests.swift
@@ -0,0 +1,33 @@
+//
+// WaterfallFile_UIUITestsLaunchTests.swift
+// WaterfallFile_UIUITests
+//
+// Created by Jacky Jack on 23/12/2024.
+//
+
+import XCTest
+
+final class WaterfallFile_UIUITestsLaunchTests: XCTestCase {
+
+ override class var runsForEachTargetApplicationUIConfiguration: Bool {
+ true
+ }
+
+ override func setUpWithError() throws {
+ continueAfterFailure = false
+ }
+
+ @MainActor
+ func testLaunch() throws {
+ let app = XCUIApplication()
+ app.launch()
+
+ // Insert steps here to perform after app launch but before taking a screenshot,
+ // such as logging into a test account or navigating somewhere in the app
+
+ let attachment = XCTAttachment(screenshot: app.screenshot())
+ attachment.name = "Launch Screen"
+ attachment.lifetime = .keepAlways
+ add(attachment)
+ }
+}