Compare commits

..

1 Commits

Author SHA1 Message Date
denny
415a7017f9 Extends JTransforms to reduce memory allocation on a per FFT iteration. 2026-11-02 04:35:18 -05:00
508 changed files with 65742 additions and 8127 deletions

View File

@@ -21,14 +21,14 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v4
- name: Set up JDK 27
uses: actions/setup-java@v6
uses: actions/setup-java@v3
with:
java-version: '27'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
- name: Build with Gradle
run: ./gradlew clean build
uses: gradle/gradle-build-action@v2
with:
arguments: clean build

View File

@@ -13,31 +13,32 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v4
- name: Set up JDK 27
uses: actions/setup-java@v6
uses: actions/setup-java@v3
with:
# Must match the JDK version downloaded in build.gradle (jdk_download_base) - jlink requires an exact version match
java-version: '27.0.0'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
- name: Build Linux and Mac releases with Gradle
run: ./gradlew runtimeZipOthers -PprojectVersion=nightly
uses: gradle/gradle-build-action@v2
with:
arguments: runtimeZipOthers -PprojectVersion=nightly
- name: Build Windows release with Gradle
run: ./gradlew runtimeZipWindows -PprojectVersion=nightly
uses: gradle/gradle-build-action@v2
with:
arguments: runtimeZipWindows -PprojectVersion=nightly
- name: Create Build Info file
run: |
echo -e "ref: $GITHUB_REF \ncommit: $GITHUB_SHA\nbuild: $(date +"%Y-%m-%dT%H:%M:%SZ")" > build/image/build_info.txt
- name: Add build artifacts to nightly release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v2
with:
tag_name: nightly
prerelease: true

View File

@@ -1,130 +0,0 @@
# Publishes a release when a version tag is pushed. The tag has to match
# projectVersion in gradle.properties with a leading 'v': v0.6.2 for a final
# release, or v0.6.2-beta-1 / v0.6.2-alpha-1 for a pre-release.
name: Release
on:
push:
tags: ['v[0-9]+.[0-9]+.[0-9]+*']
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
previous_tag: ${{ steps.previous.outputs.tag }}
steps:
- uses: actions/checkout@v7
with:
# Full history and tags, to find the previous release tag for the release notes
fetch-depth: 0
- id: version
run: |
expected="v$(sed -n 's/^projectVersion=//p' gradle.properties | tr -d '[:space:]')"
if [ "$GITHUB_REF_NAME" != "$expected" ]; then
echo "::error::Tag $GITHUB_REF_NAME does not match projectVersion in gradle.properties ($expected)"
exit 1
fi
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
# Release notes list the PRs since the previous version tag (never 'nightly'). A final release
# starts from the previous final release, so it covers every alpha and beta in between.
- id: previous
run: |
exclude=(--exclude "$GITHUB_REF_NAME")
if [[ "$GITHUB_REF_NAME" != *-* ]]; then
exclude+=(--exclude '*-*')
fi
tag="$(git describe --tags --abbrev=0 --match 'v[0-9]*' "${exclude[@]}" HEAD 2>/dev/null || true)"
echo "Release notes start from: ${tag:-(GitHub default)}"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Set up JDK 27
uses: actions/setup-java@v6
with:
# Must match the JDK version downloaded in build.gradle (jdk_download_base) - jlink requires an exact version match
java-version: '27.0.0'
distribution: 'liberica'
java-package: 'jdk+fx'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
- name: Build and test
run: ./gradlew clean build --console=plain
# The runtime plugin can't build Windows and the other platforms in the same invocation.
- name: Build Linux and Mac releases
run: ./gradlew runtimeZipOthers --console=plain
- name: Build Windows release
run: ./gradlew runtimeZipWindows --console=plain
- name: Check release zips
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
missing=0
for platform in linux-aarch64 linux-x86_64 osx-aarch64 osx-x86_64 windows-aarch64 windows-x86_64; do
zip="build/image/sdr-trunk-${platform}-v${VERSION}.zip"
if [ ! -f "$zip" ]; then
echo "::error::Missing $zip"
missing=1
fi
done
ls -l build/image/*.zip
exit $missing
- uses: actions/upload-artifact@v7
with:
name: release-zips
path: build/image/*.zip
if-no-files-found: error
retention-days: 7
publish:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
name: release-zips
path: zips
# Publishing is split into steps that can all be repeated, so a failed
# upload or a re-run finishes the draft left behind rather than failing on
# it: gh retries uploads, and a retry of an upload that had in fact
# succeeded fails with "ReleaseAsset.name already exists" unless clobbering.
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
VERSION: ${{ needs.build.outputs.version }}
PREVIOUS_TAG: ${{ needs.build.outputs.previous_tag }}
run: |
(cd zips && sha256sum *.zip > SHA256SUMS)
prerelease=()
if [[ "$GITHUB_REF_NAME" == *-* ]]; then
prerelease=(--prerelease)
fi
notes_start=()
if [ -n "$PREVIOUS_TAG" ]; then
notes_start=(--notes-start-tag "$PREVIOUS_TAG")
fi
if gh release view "$GITHUB_REF_NAME" --json isDraft --jq .isDraft 2>/dev/null | grep -qx false; then
echo "::error::Release $GITHUB_REF_NAME is already published"
exit 1
elif gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
echo "Reusing the draft release $GITHUB_REF_NAME"
else
gh release create "$GITHUB_REF_NAME" --draft "${prerelease[@]}" \
--verify-tag --generate-notes "${notes_start[@]}" --title "Version $VERSION"
fi
gh release upload "$GITHUB_REF_NAME" zips/* --clobber
gh release edit "$GITHUB_REF_NAME" --draft=false

View File

@@ -49,28 +49,3 @@ committed to the code base, so it's not really 'nightly' as much as it is 'curre
* **Operating System:** Windows (~~32 or~~ 64-bit), Linux (~~32 or~~ 64-bit) or Mac (64-bit, 12.x or higher)
* **CPU:** 4-core
* **RAM:** 8GB or more (preferred). Depending on usage, 4GB may be sufficient.
## Creating a Release (Maintainers)
Releases are built and published automatically by the [Release](.github/workflows/release.yml) GitHub workflow
whenever a version tag is pushed to the repository.
1. Update `projectVersion` in `gradle.properties` to the new version, following the naming convention described in
that file (e.g. `0.6.2-alpha-1`, `0.6.2-beta-1` or `0.6.2`).
2. Commit and push the change to `master`.
3. Create and push a tag that matches the version with a leading `v`:
```
git tag v0.6.2-beta-1
git push origin v0.6.2-beta-1
```
The workflow then:
* Verifies that the tag matches `projectVersion` in `gradle.properties` and fails if it does not.
* Builds and tests the code, then creates the release zips for Linux, Mac and Windows (x86-64 and aarch64).
* Creates a GitHub release titled `Version <version>` with auto-generated release notes (a "What's Changed" list of
the PRs merged since the previous version tag), and attaches the six zip
files plus a `SHA256SUMS` checksum file.
* Marks tags containing a dash (alpha and beta versions) as pre-releases. Tags without a dash become full releases.
If the workflow fails part way through, fix the problem and re-run it from the Actions tab. It resumes from the
draft release left behind. It won't modify a release that has already been published. To rebuild a published
release, delete the release and the tag on GitHub, then push the tag again.

View File

@@ -0,0 +1,229 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.07)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
sdrplay_api_ErrT sdrplay_api_Open(void);
sdrplay_api_ErrT sdrplay_api_Close(void);
sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate);
sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,78 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,45 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_60 20 // Number of LNA states when using AM Port 2 between 12 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 26 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -0,0 +1,230 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
//#if defined(_M_X64) || defined(_M_IX86)
//#include "windows.h"
//#elif defined (__GNUC__)
typedef void *HANDLE;
//#endif
//
//#ifndef _SDRPLAY_DLL_QUALIFIER
//#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86))
//#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
//#elif defined(STATIC_LIB) || defined(__GNUC__)
//#define _SDRPLAY_DLL_QUALIFIER
//#endif
//#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.08)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
unsigned char valid;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate, double newSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// // Comman API function definitions
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Open(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Close(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
//
// // Device API function definitions
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate, double newSampleRate);
// _SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
// sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
// sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,78 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,40 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,45 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_60 20 // Number of LNA states when using AM Port 2 between 12 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 26 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -0,0 +1,235 @@
#ifndef SDRPLAY_API_H
#define SDRPLAY_API_H
#include "sdrplay_api_dev.h"
#include "sdrplay_api_rx_channel.h"
#include "sdrplay_api_callback.h"
#if defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64)
#include "windows.h"
#elif defined (__GNUC__)
typedef void *HANDLE;
#endif
#ifndef _SDRPLAY_DLL_QUALIFIER
#if !defined(STATIC_LIB) && (defined(_M_X64) || defined(_M_IX86) || defined(_M_ARM64))
#define _SDRPLAY_DLL_QUALIFIER __declspec(dllimport)
#elif defined(STATIC_LIB) || defined(__GNUC__)
#define _SDRPLAY_DLL_QUALIFIER
#endif
#endif // _SDRPLAY_DLL_QUALIFIER
// Application code should check that it is compiled against the same API version
// sdrplay_api_ApiVersion() returns the API version
#define SDRPLAY_API_VERSION (float)(3.15)
// API Constants
#define SDRPLAY_MAX_DEVICES (16)
#define SDRPLAY_MAX_TUNERS_PER_DEVICE (2)
#define SDRPLAY_MAX_SER_NO_LEN (64)
#define SDRPLAY_MAX_ROOT_NM_LEN (32)
#define SDRPLAY_RSP1_ID (1)
#define SDRPLAY_RSP1A_ID (255)
#define SDRPLAY_RSP2_ID (2)
#define SDRPLAY_RSPduo_ID (3)
#define SDRPLAY_RSPdx_ID (4)
#define SDRPLAY_RSP1B_ID (6)
#define SDRPLAY_RSPdxR2_ID (7)
// Enum types
typedef enum
{
sdrplay_api_Success = 0,
sdrplay_api_Fail = 1,
sdrplay_api_InvalidParam = 2,
sdrplay_api_OutOfRange = 3,
sdrplay_api_GainUpdateError = 4,
sdrplay_api_RfUpdateError = 5,
sdrplay_api_FsUpdateError = 6,
sdrplay_api_HwError = 7,
sdrplay_api_AliasingError = 8,
sdrplay_api_AlreadyInitialised = 9,
sdrplay_api_NotInitialised = 10,
sdrplay_api_NotEnabled = 11,
sdrplay_api_HwVerError = 12,
sdrplay_api_OutOfMemError = 13,
sdrplay_api_ServiceNotResponding = 14,
sdrplay_api_StartPending = 15,
sdrplay_api_StopPending = 16,
sdrplay_api_InvalidMode = 17,
sdrplay_api_FailedVerification1 = 18,
sdrplay_api_FailedVerification2 = 19,
sdrplay_api_FailedVerification3 = 20,
sdrplay_api_FailedVerification4 = 21,
sdrplay_api_FailedVerification5 = 22,
sdrplay_api_FailedVerification6 = 23,
sdrplay_api_InvalidServiceVersion = 24
} sdrplay_api_ErrT;
typedef enum
{
sdrplay_api_Update_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_Dev_Fs = 0x00000001,
sdrplay_api_Update_Dev_Ppm = 0x00000002,
sdrplay_api_Update_Dev_SyncUpdate = 0x00000004,
sdrplay_api_Update_Dev_ResetFlags = 0x00000008,
sdrplay_api_Update_Rsp1a_BiasTControl = 0x00000010,
sdrplay_api_Update_Rsp1a_RfNotchControl = 0x00000020,
sdrplay_api_Update_Rsp1a_RfDabNotchControl = 0x00000040,
sdrplay_api_Update_Rsp2_BiasTControl = 0x00000080,
sdrplay_api_Update_Rsp2_AmPortSelect = 0x00000100,
sdrplay_api_Update_Rsp2_AntennaControl = 0x00000200,
sdrplay_api_Update_Rsp2_RfNotchControl = 0x00000400,
sdrplay_api_Update_Rsp2_ExtRefControl = 0x00000800,
sdrplay_api_Update_RspDuo_ExtRefControl = 0x00001000,
sdrplay_api_Update_Master_Spare_1 = 0x00002000,
sdrplay_api_Update_Master_Spare_2 = 0x00004000,
// Reasons for master and slave mode
// Note: sdrplay_api_Update_Tuner_Gr MUST be the first value defined in this section!
sdrplay_api_Update_Tuner_Gr = 0x00008000,
sdrplay_api_Update_Tuner_GrLimits = 0x00010000,
sdrplay_api_Update_Tuner_Frf = 0x00020000,
sdrplay_api_Update_Tuner_BwType = 0x00040000,
sdrplay_api_Update_Tuner_IfType = 0x00080000,
sdrplay_api_Update_Tuner_DcOffset = 0x00100000,
sdrplay_api_Update_Tuner_LoMode = 0x00200000,
sdrplay_api_Update_Ctrl_DCoffsetIQimbalance = 0x00400000,
sdrplay_api_Update_Ctrl_Decimation = 0x00800000,
sdrplay_api_Update_Ctrl_Agc = 0x01000000,
sdrplay_api_Update_Ctrl_AdsbMode = 0x02000000,
sdrplay_api_Update_Ctrl_OverloadMsgAck = 0x04000000,
sdrplay_api_Update_RspDuo_BiasTControl = 0x08000000,
sdrplay_api_Update_RspDuo_AmPortSelect = 0x10000000,
sdrplay_api_Update_RspDuo_Tuner1AmNotchControl = 0x20000000,
sdrplay_api_Update_RspDuo_RfNotchControl = 0x40000000,
sdrplay_api_Update_RspDuo_RfDabNotchControl = 0x80000000,
} sdrplay_api_ReasonForUpdateT;
typedef enum
{
sdrplay_api_Update_Ext1_None = 0x00000000,
// Reasons for master only mode
sdrplay_api_Update_RspDx_HdrEnable = 0x00000001,
sdrplay_api_Update_RspDx_BiasTControl = 0x00000002,
sdrplay_api_Update_RspDx_AntennaControl = 0x00000004,
sdrplay_api_Update_RspDx_RfNotchControl = 0x00000008,
sdrplay_api_Update_RspDx_RfDabNotchControl = 0x00000010,
sdrplay_api_Update_RspDx_HdrBw = 0x00000020,
sdrplay_api_Update_RspDuo_ResetSlaveFlags = 0x00000040,
// Reasons for master and slave mode
} sdrplay_api_ReasonForUpdateExtension1T;
typedef enum
{
sdrplay_api_DbgLvl_Disable = 0,
sdrplay_api_DbgLvl_Verbose = 1,
sdrplay_api_DbgLvl_Warning = 2,
sdrplay_api_DbgLvl_Error = 3,
sdrplay_api_DbgLvl_Message = 4,
} sdrplay_api_DbgLvl_t;
// Device structure
typedef struct
{
char SerNo[SDRPLAY_MAX_SER_NO_LEN];
unsigned char hwVer;
sdrplay_api_TunerSelectT tuner;
sdrplay_api_RspDuoModeT rspDuoMode;
unsigned char valid;
double rspDuoSampleFreq;
HANDLE dev;
} sdrplay_api_DeviceT;
// Device parameter structure
typedef struct
{
sdrplay_api_DevParamsT *devParams;
sdrplay_api_RxChannelParamsT *rxChannelA;
sdrplay_api_RxChannelParamsT *rxChannelB;
} sdrplay_api_DeviceParamsT;
// Extended error message structure
typedef struct
{
char file[256];
char function[256];
int line;
char message[1024];
} sdrplay_api_ErrorInfoT;
// Comman API function types
typedef sdrplay_api_ErrT (*sdrplay_api_Open_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_Close_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_ApiVersion_t)(float *apiVer);
typedef sdrplay_api_ErrT (*sdrplay_api_LockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_UnlockDeviceApi_t)(void);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDevices_t)(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
typedef sdrplay_api_ErrT (*sdrplay_api_SelectDevice_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrT (*sdrplay_api_ReleaseDevice_t)(sdrplay_api_DeviceT *device);
typedef const char* (*sdrplay_api_GetErrorString_t)(sdrplay_api_ErrT err);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastError_t)(sdrplay_api_DeviceT *device);
typedef sdrplay_api_ErrorInfoT* (*sdrplay_api_GetLastErrorByType_t)(sdrplay_api_DeviceT *device, int type, unsigned long long *time);
typedef sdrplay_api_ErrT (*sdrplay_api_DisableHeartbeat_t)(void);
// Device API function types
typedef sdrplay_api_ErrT (*sdrplay_api_DebugEnable_t)(HANDLE dev, sdrplay_api_DbgLvl_t dbgLvl);
typedef sdrplay_api_ErrT (*sdrplay_api_GetDeviceParams_t)(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
typedef sdrplay_api_ErrT (*sdrplay_api_Init_t)(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
typedef sdrplay_api_ErrT (*sdrplay_api_Uninit_t)(HANDLE dev);
typedef sdrplay_api_ErrT (*sdrplay_api_Update_t)(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoActiveTuner_t)(HANDLE dev, sdrplay_api_TunerSelectT *tuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoDualTunerModeSampleRate_t)(double *currentSampleRate, double newSampleRate);
typedef sdrplay_api_ErrT (*sdrplay_api_SwapRspDuoMode_t)(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
// API function definitions
#ifdef __cplusplus
extern "C"
{
#endif
// Comman API function definitions
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Open(void);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Close(void);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ApiVersion(float *apiVer);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_LockDeviceApi(void);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_UnlockDeviceApi(void);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDevices(sdrplay_api_DeviceT *devices, unsigned int *numDevs, unsigned int maxDevs);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SelectDevice(sdrplay_api_DeviceT *device);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_ReleaseDevice(sdrplay_api_DeviceT *device);
_SDRPLAY_DLL_QUALIFIER const char* sdrplay_api_GetErrorString(sdrplay_api_ErrT err);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrorInfoT* sdrplay_api_GetLastError(sdrplay_api_DeviceT *device);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrorInfoT* sdrplay_api_GetLastErrorByType(sdrplay_api_DeviceT *device, int type, unsigned long long *time);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DisableHeartbeat(void); // Must be called before sdrplay_api_SelectDevice()
// Device API function definitions
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_DebugEnable(HANDLE dev, sdrplay_api_DbgLvl_t enable);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_GetDeviceParams(HANDLE dev, sdrplay_api_DeviceParamsT **deviceParams);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Init(HANDLE dev, sdrplay_api_CallbackFnsT *callbackFns, void *cbContext);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Uninit(HANDLE dev);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_Update(HANDLE dev, sdrplay_api_TunerSelectT tuner, sdrplay_api_ReasonForUpdateT reasonForUpdate, sdrplay_api_ReasonForUpdateExtension1T reasonForUpdateExt1);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoActiveTuner(HANDLE dev, sdrplay_api_TunerSelectT *currentTuner, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoDualTunerModeSampleRate(HANDLE dev, double *currentSampleRate, double newSampleRate);
_SDRPLAY_DLL_QUALIFIER sdrplay_api_ErrT sdrplay_api_SwapRspDuoMode(sdrplay_api_DeviceT *currDevice, sdrplay_api_DeviceParamsT **deviceParams,
sdrplay_api_RspDuoModeT rspDuoMode, double sampleRate, sdrplay_api_TunerSelectT tuner,
sdrplay_api_Bw_MHzT bwType, sdrplay_api_If_kHzT ifType, sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel);
#ifdef __cplusplus
}
#endif
#endif //SDRPLAY_API_H

View File

@@ -0,0 +1,79 @@
#ifndef SDRPLAY_API_CALLBACK_H
#define SDRPLAY_API_CALLBACK_H
// Event callback enums
typedef enum
{
sdrplay_api_Overload_Detected = 0,
sdrplay_api_Overload_Corrected = 1,
} sdrplay_api_PowerOverloadCbEventIdT;
typedef enum
{
sdrplay_api_MasterInitialised = 0,
sdrplay_api_SlaveAttached = 1,
sdrplay_api_SlaveDetached = 2,
sdrplay_api_SlaveInitialised = 3,
sdrplay_api_SlaveUninitialised = 4,
sdrplay_api_MasterDllDisappeared = 5,
sdrplay_api_SlaveDllDisappeared = 6,
} sdrplay_api_RspDuoModeCbEventIdT;
typedef enum
{
sdrplay_api_GainChange = 0,
sdrplay_api_PowerOverloadChange = 1,
sdrplay_api_DeviceRemoved = 2,
sdrplay_api_RspDuoModeChange = 3,
sdrplay_api_DeviceFailure = 4,
} sdrplay_api_EventT;
// Event callback parameter structs
typedef struct
{
unsigned int gRdB;
unsigned int lnaGRdB;
double currGain;
} sdrplay_api_GainCbParamT;
typedef struct
{
sdrplay_api_PowerOverloadCbEventIdT powerOverloadChangeType;
} sdrplay_api_PowerOverloadCbParamT;
typedef struct
{
sdrplay_api_RspDuoModeCbEventIdT modeChangeType;
} sdrplay_api_RspDuoModeCbParamT;
// Event parameters overlay
typedef union
{
sdrplay_api_GainCbParamT gainParams;
sdrplay_api_PowerOverloadCbParamT powerOverloadParams;
sdrplay_api_RspDuoModeCbParamT rspDuoModeParams;
} sdrplay_api_EventParamsT;
// Stream callback parameter structs
typedef struct
{
unsigned int firstSampleNum;
int grChanged;
int rfChanged;
int fsChanged;
unsigned int numSamples;
} sdrplay_api_StreamCbParamsT;
// Callback function prototypes
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
// Callback function struct
typedef struct
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
#endif //SDRPLAY_API_CALLBACK_H

View File

@@ -0,0 +1,55 @@
#ifndef SDRPLAY_API_CONTROL_H
#define SDRPLAY_API_CONTROL_H
// Control parameter enums
typedef enum
{
sdrplay_api_AGC_DISABLE = 0,
sdrplay_api_AGC_100HZ = 1,
sdrplay_api_AGC_50HZ = 2,
sdrplay_api_AGC_5HZ = 3,
sdrplay_api_AGC_CTRL_EN = 4
} sdrplay_api_AgcControlT;
typedef enum
{
sdrplay_api_ADSB_DECIMATION = 0,
sdrplay_api_ADSB_NO_DECIMATION_LOWPASS = 1,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_2MHZ = 2,
sdrplay_api_ADSB_NO_DECIMATION_BANDPASS_3MHZ = 3
} sdrplay_api_AdsbModeT;
// Control parameter structs
typedef struct
{
unsigned char DCenable; // default: 1
unsigned char IQenable; // default: 1
} sdrplay_api_DcOffsetT;
typedef struct
{
unsigned char enable; // default: 0
unsigned char decimationFactor; // default: 1
unsigned char wideBandSignal; // default: 0
} sdrplay_api_DecimationT;
typedef struct
{
sdrplay_api_AgcControlT enable; // default: sdrplay_api_AGC_50HZ
int setPoint_dBfs; // default: -60
unsigned short attack_ms; // default: 0
unsigned short decay_ms; // default: 0
unsigned short decay_delay_ms; // default: 0
unsigned short decay_threshold_dB; // default: 0
int syncUpdate; // default: 0
} sdrplay_api_AgcT;
typedef struct
{
sdrplay_api_DcOffsetT dcOffset;
sdrplay_api_DecimationT decimation;
sdrplay_api_AgcT agc;
sdrplay_api_AdsbModeT adsbMode; //default: sdrplay_api_ADSB_DECIMATION
} sdrplay_api_ControlParamsT;
#endif //SDRPLAY_API_CONTROL_H

View File

@@ -0,0 +1,51 @@
#ifndef SDRPLAY_API_DEV_H
#define SDRPLAY_API_DEV_H
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
// Dev parameter enums
typedef enum
{
sdrplay_api_ISOCH = 0,
sdrplay_api_BULK = 1
} sdrplay_api_TransferModeT;
// Dev parameter structs
typedef struct
{
double fsHz; // default: 2000000.0
unsigned char syncUpdate; // default: 0
unsigned char reCal; // default: 0
} sdrplay_api_FsFreqT;
typedef struct
{
unsigned int sampleNum; // default: 0
unsigned int period; // default: 0
} sdrplay_api_SyncUpdateT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
unsigned char resetFsUpdate; // default: 0
} sdrplay_api_ResetFlagsT;
typedef struct
{
double ppm; // default: 0.0
sdrplay_api_FsFreqT fsFreq;
sdrplay_api_SyncUpdateT syncUpdate;
sdrplay_api_ResetFlagsT resetFlags;
sdrplay_api_TransferModeT mode; // default: sdrplay_api_ISOCH
unsigned int samplesPerPkt; // default: 0 (output param)
sdrplay_api_Rsp1aParamsT rsp1aParams;
sdrplay_api_Rsp2ParamsT rsp2Params;
sdrplay_api_RspDuoParamsT rspDuoParams;
sdrplay_api_RspDxParamsT rspDxParams;
} sdrplay_api_DevParamsT;
#endif //SDRPLAY_API_DEV_H

View File

@@ -0,0 +1,22 @@
#ifndef SDRPLAY_API_RSP1A_H
#define SDRPLAY_API_RSP1A_H
#define RSPIA_NUM_LNA_STATES 10
#define RSPIA_NUM_LNA_STATES_AM 7
#define RSPIA_NUM_LNA_STATES_LBAND 9
// RSP1A parameter enums
// RSP1A parameter structs
typedef struct
{
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_Rsp1aParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
} sdrplay_api_Rsp1aTunerParamsT;
#endif //SDRPLAY_API_RSP1A_H

View File

@@ -0,0 +1,35 @@
#ifndef SDRPLAY_API_RSP2_H
#define SDRPLAY_API_RSP2_H
#define RSPII_NUM_LNA_STATES 9
#define RSPII_NUM_LNA_STATES_AMPORT 5
#define RSPII_NUM_LNA_STATES_420MHZ 6
// RSP2 parameter enums
typedef enum
{
sdrplay_api_Rsp2_ANTENNA_A = 5,
sdrplay_api_Rsp2_ANTENNA_B = 6,
} sdrplay_api_Rsp2_AntennaSelectT;
typedef enum
{
sdrplay_api_Rsp2_AMPORT_1 = 1,
sdrplay_api_Rsp2_AMPORT_2 = 0,
} sdrplay_api_Rsp2_AmPortSelectT;
// RSP2 parameter structs
typedef struct
{
unsigned char extRefOutputEn; // default: 0
} sdrplay_api_Rsp2ParamsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_Rsp2_AmPortSelectT amPortSel; // default: sdrplay_api_Rsp2_AMPORT_2
sdrplay_api_Rsp2_AntennaSelectT antennaSel; // default: sdrplay_api_Rsp2_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
} sdrplay_api_Rsp2TunerParamsT;
#endif //SDRPLAY_API_RSP2_H

View File

@@ -0,0 +1,47 @@
#ifndef SDRPLAY_API_RSPduo_H
#define SDRPLAY_API_RSPduo_H
#define RSPDUO_NUM_LNA_STATES 10
#define RSPDUO_NUM_LNA_STATES_AMPORT 5
#define RSPDUO_NUM_LNA_STATES_AM 7
#define RSPDUO_NUM_LNA_STATES_LBAND 9
// RSPduo parameter enums
typedef enum
{
sdrplay_api_RspDuoMode_Unknown = 0,
sdrplay_api_RspDuoMode_Single_Tuner = 1,
sdrplay_api_RspDuoMode_Dual_Tuner = 2,
sdrplay_api_RspDuoMode_Master = 4,
sdrplay_api_RspDuoMode_Slave = 8,
} sdrplay_api_RspDuoModeT;
typedef enum
{
sdrplay_api_RspDuo_AMPORT_1 = 1,
sdrplay_api_RspDuo_AMPORT_2 = 0,
} sdrplay_api_RspDuo_AmPortSelectT;
// RSPduo parameter structs
typedef struct
{
int extRefOutputEn; // default: 0
} sdrplay_api_RspDuoParamsT;
typedef struct
{
unsigned char resetGainUpdate; // default: 0
unsigned char resetRfUpdate; // default: 0
} sdrplay_api_RspDuo_ResetSlaveFlagsT;
typedef struct
{
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDuo_AmPortSelectT tuner1AmPortSel; // default: sdrplay_api_RspDuo_AMPORT_2
unsigned char tuner1AmNotchEnable; // default: 0
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
sdrplay_api_RspDuo_ResetSlaveFlagsT resetSlaveFlags;
} sdrplay_api_RspDuoTunerParamsT;
#endif //SDRPLAY_API_RSPduo_H

View File

@@ -0,0 +1,46 @@
#ifndef SDRPLAY_API_RSPDX_H
#define SDRPLAY_API_RSPDX_H
#include "sdrplay_api_tuner.h"
#define RSPDX_NUM_LNA_STATES 28 // Number of LNA states in all bands (except where defined differently below)
#define RSPDX_NUM_LNA_STATES_AMPORT2_0_12 19 // Number of LNA states when using AM Port 2 between 0 and 12MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_12_50 20 // Number of LNA states when using AM Port 2 between 12 and 50MHz
#define RSPDX_NUM_LNA_STATES_AMPORT2_50_60 25 // Number of LNA states when using AM Port 2 between 50 and 60MHz
#define RSPDX_NUM_LNA_STATES_VHF_BAND3 27 // Number of LNA states in VHF and Band3
#define RSPDX_NUM_LNA_STATES_420MHZ 21 // Number of LNA states in 420MHz band
#define RSPDX_NUM_LNA_STATES_LBAND 19 // Number of LNA states in L-band
#define RSPDX_NUM_LNA_STATES_DX 22 // Number of LNA states in DX path
// RSPdx parameter enums
typedef enum
{
sdrplay_api_RspDx_ANTENNA_A = 0,
sdrplay_api_RspDx_ANTENNA_B = 1,
sdrplay_api_RspDx_ANTENNA_C = 2,
} sdrplay_api_RspDx_AntennaSelectT;
typedef enum
{
sdrplay_api_RspDx_HDRMODE_BW_0_200 = 0,
sdrplay_api_RspDx_HDRMODE_BW_0_500 = 1,
sdrplay_api_RspDx_HDRMODE_BW_1_200 = 2,
sdrplay_api_RspDx_HDRMODE_BW_1_700 = 3,
} sdrplay_api_RspDx_HdrModeBwT;
// RSPdx parameter structs
typedef struct
{
unsigned char hdrEnable; // default: 0
unsigned char biasTEnable; // default: 0
sdrplay_api_RspDx_AntennaSelectT antennaSel; // default: sdrplay_api_RspDx_ANTENNA_A
unsigned char rfNotchEnable; // default: 0
unsigned char rfDabNotchEnable; // default: 0
} sdrplay_api_RspDxParamsT;
typedef struct
{
sdrplay_api_RspDx_HdrModeBwT hdrBw; // default: sdrplay_api_RspDx_HDRMODE_BW_1_700
} sdrplay_api_RspDxTunerParamsT;
#endif //SDRPLAY_API_RSPDX_H

View File

@@ -0,0 +1,21 @@
#ifndef SDRPLAY_API_RX_CHANNEL_H
#define SDRPLAY_API_RX_CHANNEL_H
#include "sdrplay_api_tuner.h"
#include "sdrplay_api_control.h"
#include "sdrplay_api_rsp1a.h"
#include "sdrplay_api_rsp2.h"
#include "sdrplay_api_rspDuo.h"
#include "sdrplay_api_rspDx.h"
typedef struct
{
sdrplay_api_TunerParamsT tunerParams;
sdrplay_api_ControlParamsT ctrlParams;
sdrplay_api_Rsp1aTunerParamsT rsp1aTunerParams;
sdrplay_api_Rsp2TunerParamsT rsp2TunerParams;
sdrplay_api_RspDuoTunerParamsT rspDuoTunerParams;
sdrplay_api_RspDxTunerParamsT rspDxTunerParams;
} sdrplay_api_RxChannelParamsT;
#endif //SDRPLAY_API_RX_CHANNEL_H

View File

@@ -0,0 +1,93 @@
#ifndef SDRPLAY_API_TUNER_H
#define SDRPLAY_API_TUNER_H
#define MAX_BB_GR (59)
// Tuner parameter enums
typedef enum
{
sdrplay_api_BW_Undefined = 0,
sdrplay_api_BW_0_200 = 200,
sdrplay_api_BW_0_300 = 300,
sdrplay_api_BW_0_600 = 600,
sdrplay_api_BW_1_536 = 1536,
sdrplay_api_BW_5_000 = 5000,
sdrplay_api_BW_6_000 = 6000,
sdrplay_api_BW_7_000 = 7000,
sdrplay_api_BW_8_000 = 8000
} sdrplay_api_Bw_MHzT;
typedef enum
{
sdrplay_api_IF_Undefined = -1,
sdrplay_api_IF_Zero = 0,
sdrplay_api_IF_0_450 = 450,
sdrplay_api_IF_1_620 = 1620,
sdrplay_api_IF_2_048 = 2048
} sdrplay_api_If_kHzT;
typedef enum
{
sdrplay_api_LO_Undefined = 0,
sdrplay_api_LO_Auto = 1,
sdrplay_api_LO_120MHz = 2,
sdrplay_api_LO_144MHz = 3,
sdrplay_api_LO_168MHz = 4
} sdrplay_api_LoModeT;
typedef enum
{
sdrplay_api_EXTENDED_MIN_GR = 0,
sdrplay_api_NORMAL_MIN_GR = 20
} sdrplay_api_MinGainReductionT;
typedef enum
{
sdrplay_api_Tuner_Neither = 0,
sdrplay_api_Tuner_A = 1,
sdrplay_api_Tuner_B = 2,
sdrplay_api_Tuner_Both = 3,
} sdrplay_api_TunerSelectT;
// Tuner parameter structs
typedef struct
{
float curr;
float max;
float min;
} sdrplay_api_GainValuesT;
typedef struct
{
int gRdB; // default: 50
unsigned char LNAstate; // default: 0
unsigned char syncUpdate; // default: 0
sdrplay_api_MinGainReductionT minGr; // default: sdrplay_api_NORMAL_MIN_GR
sdrplay_api_GainValuesT gainVals; // output parameter
} sdrplay_api_GainT;
typedef struct
{
double rfHz; // default: 200000000.0
unsigned char syncUpdate; // default: 0
} sdrplay_api_RfFreqT;
typedef struct
{
unsigned char dcCal; // default: 3 (Periodic mode)
unsigned char speedUp; // default: 0 (No speedup)
int trackTime; // default: 1 (=> time in uSec = (72 * 3 * trackTime) / 24e6 = 9uSec)
int refreshRateTime; // default: 2048 (=> time in uSec = (72 * 3 * refreshRateTime) / 24e6 = 18432uSec)
} sdrplay_api_DcOffsetTunerT;
typedef struct
{
sdrplay_api_Bw_MHzT bwType; // default: sdrplay_api_BW_0_200
sdrplay_api_If_kHzT ifType; // default: sdrplay_api_IF_Zero
sdrplay_api_LoModeT loMode; // default: sdrplay_api_LO_Auto
sdrplay_api_GainT gain;
sdrplay_api_RfFreqT rfFreq;
sdrplay_api_DcOffsetTunerT dcOffsetTuner;
} sdrplay_api_TunerParamsT;
#endif //SDRPLAY_API_TUNER_H

View File

@@ -124,19 +124,12 @@ dependencies {
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'commons-io:commons-io:2.22.0'
implementation 'eu.hansolo:charts:1.0.5'
implementation 'io.github.dsheirer:jairspy:1.0.12' //Airspy tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jairspyhf:1.8.1' //Airspy HF+ tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jbladerf:2.6.0' //bladeRF tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jhackrf:2026.01.3' //HackRF tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jhydrasdr:1.1.4' //HydraSDR tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jrtl:1.4.0.1' //RTL-SDR tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jsdrplay:3.15.3' //SDRplay RSP tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:jhydrasdr:1.1.3' //HydraSDR tuners - GitHub release, see settings.gradle
implementation 'io.github.dsheirer:radio-reference-api:18.0.0'
implementation 'io.github.dsheirer:usb4java-native-libraries:1.3.3' //OSX & Windows aarch64 native libs
implementation('io.github.dsheirer:usb4java:1.3.5') { //Fork with Loader support for OSX Multi-Version
//Excludes the javax.usb API and the duplicate original usb4java classes. The native libraries are listed below.
exclude group: 'org.usb4java', module: 'usb4java-javax'
}
implementation 'io.github.dsheirer:usb4java:1.3.5' //Fork with Loader support for OSX Multi-Version
implementation 'javax.usb:usb-api:1.0.2'
implementation 'net.coderazzi:tablefilter-swing:5.5.4'
implementation 'org.apache.commons:commons-compress:1.28.0'
implementation 'org.apache.commons:commons-lang3:3.20.0'
@@ -147,13 +140,8 @@ dependencies {
implementation 'org.controlsfx:controlsfx:11.2.3'
implementation 'org.rauschig:jarchivelib:1.2.0'
implementation 'org.slf4j:slf4j-api:2.0.17'
implementation 'org.usb4java:libusb4java:1.3.0:darwin-x86-64' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:linux-aarch64' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:linux-arm' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:linux-x86' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:linux-x86-64' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:win32-x86' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0:win32-x86-64' //usb4java native library
implementation 'org.usb4java:libusb4java:1.3.0'
implementation 'org.usb4java:usb4java-javax:1.3.0'
implementation 'pl.edu.icm:JLargeArrays:1.6'
}
@@ -177,7 +165,8 @@ def jvmArgsWindows =
'--enable-preview', //Project Panama Vector API is still in incubator
'--enable-native-access=ALL-UNNAMED', //Suppress unsafe warnings for FFM API Foreign Memory calls
'--enable-native-access=javafx.graphics', //JDK24 - suppress restricted java.lang.System calls
'--sun-misc-unsafe-memory-access=allow'] //JDK24 - suppress sun.misc.Unsafe::allocateMemory warning
'--sun-misc-unsafe-memory-access=allow', //JDK24 - suppress sun.misc.Unsafe::allocateMemory warning
'-Djava.library.path=c:\\Program Files\\SDRplay\\API\\x64'] //SDRPlay API library path
/**
* JVM Arguments for running the application on Linux.
@@ -188,7 +177,7 @@ def jvmArgsLinux =
'--enable-preview', //Project Panama Vector & Foreign Function APIs remain in incubator
'--sun-misc-unsafe-memory-access=allow', //JDK24 - suppress sun.misc.Unsafe::allocateMemory warning
'--enable-native-access=javafx.graphics', //JDK24 - suppress restricted java.lang.System calls
'--enable-native-access=ALL-UNNAMED'] //Suppress warnings for FFM API native calls (tuner libraries)
'--enable-native-access=ALL-UNNAMED'] //SDRPlay API library path
application {
mainClass = "io.github.dsheirer.gui.SDRTrunk"

View File

@@ -9,38 +9,6 @@ dependencyResolutionManagement {
mavenCentral()
maven { url 'https://jitpack.io' }
//jAirspy is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jAirspy/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'io.github.dsheirer', 'jairspy' }
}
//jAirspyHF is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jAirspyHF/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'io.github.dsheirer', 'jairspyhf' }
}
//jRTL is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jRTL/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'io.github.dsheirer', 'jrtl' }
}
//jHackRF is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jHackRF/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'io.github.dsheirer', 'jhackrf' }
}
//jHydraSDR is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jHydraSDR/releases/download'
@@ -49,15 +17,6 @@ dependencyResolutionManagement {
content { includeModule 'io.github.dsheirer', 'jhydrasdr' }
}
//jsdrplay is published as a GitHub release. The jar does not contain the SDRplay API native library, which
//users install separately from sdrplay.com
ivy {
url = 'https://github.com/DSheirer/jsdrplay/releases/download'
patternLayout { artifact 'v[revision]/[artifact]-[revision].[ext]' }
metadataSources { artifact() }
content { includeModule 'io.github.dsheirer', 'jsdrplay' }
}
//jBladeRF is published as a GitHub release, with the native libraries for all platforms in the jar
ivy {
url = 'https://github.com/DSheirer/jBladeRF/releases/download'

View File

@@ -0,0 +1,132 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.buffer.AbstractNativeBuffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import java.util.Iterator;
/**
* Native buffer implementation for Airspy HF+ & Discovery tuners.
*/
public class AirspyHfNativeBuffer extends AbstractNativeBuffer
{
public static final float SCALE = 1.0f / 32768.0f;
private short[] mInterleavedSamples;
private float mAverageDc;
/**
* Constructs an instance.
* @param timestamp of the first sample of the buffer
* @param interleavedSamples pairs of 16-bit complex samples.
*/
public AirspyHfNativeBuffer(long timestamp, float samplesPerMillisecond, float averageDc, short[] interleavedSamples)
{
super(timestamp, samplesPerMillisecond);
mInterleavedSamples = interleavedSamples;
mAverageDc = averageDc;
}
@Override
public Iterator<ComplexSamples> iterator()
{
return new IteratorComplexSamples();
}
@Override
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
{
return new IteratorInterleaved();
}
@Override
public int sampleCount()
{
return mInterleavedSamples.length / 2;
}
/**
* Scalar implementation of complex samples buffer iterator
*/
public class IteratorComplexSamples implements Iterator<ComplexSamples>
{
private boolean mHasNext = true;
@Override
public boolean hasNext()
{
return mHasNext;
}
@Override
public ComplexSamples next()
{
int length = mInterleavedSamples.length / 2;
float[] i = new float[length];
float[] q = new float[length];
int index = 0;
for(int x = 0; x < mInterleavedSamples.length; x += 2)
{
index = x / 2;
//Native ordering is in Q, I, Q, I ... reverse it to I, Q, I, Q
i[index] = (mInterleavedSamples[x + 1] * SCALE) - mAverageDc;
q[index] = (mInterleavedSamples[x] * SCALE) - mAverageDc;
}
mHasNext = false;
return new ComplexSamples(i, q, getTimestamp());
}
}
/**
* Scalar implementation of interleaved sample buffer iterator.
*/
public class IteratorInterleaved implements Iterator<InterleavedComplexSamples>
{
private boolean mHasNext = true;
@Override
public boolean hasNext()
{
return mHasNext;
}
@Override
public InterleavedComplexSamples next()
{
float[] samples = new float[mInterleavedSamples.length];
for(int x = 0; x < mInterleavedSamples.length; x += 2)
{
//Native ordering is in Q, I, Q, I ... reverse it to I, Q, I, Q
samples[x] = (mInterleavedSamples[x + 1] * SCALE) - mAverageDc;
samples[x + 1] = (mInterleavedSamples[x] * SCALE) - mAverageDc;
}
mHasNext = false;
return new InterleavedComplexSamples(samples, getTimestamp());
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.airspy;
import io.github.dsheirer.buffer.AbstractNativeBufferFactory;
import io.github.dsheirer.buffer.DcCorrectionManager;
import io.github.dsheirer.buffer.INativeBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
/**
* Airspy HF+ native buffer factory.
*
* Note: the tuner provides 1024 samples in each transfer where samples are 16-bit interleaved complex.
*/
public class AirspyHfNativeBufferFactory extends AbstractNativeBufferFactory
{
private DcCorrectionManager mDcCorrectionManager = new DcCorrectionManager();
/**
* Constructs an instance
*/
public AirspyHfNativeBufferFactory()
{
}
/**
* Converts the samples byte buffer into a native buffer and calculates DC offset
* @param samples byte array copied from native memory
* @param timestamp of the samples
* @return constructed native buffer
*/
@Override
public INativeBuffer getBuffer(ByteBuffer samples, long timestamp)
{
ShortBuffer shortBuffer = samples.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
short[] converted = new short[shortBuffer.capacity()];
shortBuffer.get(converted);
if(mDcCorrectionManager.shouldCalculateDc())
{
calculateDc(converted);
}
return new AirspyHfNativeBuffer(timestamp, getSamplesPerMillisecond(), mDcCorrectionManager.getAverageDc(), converted);
}
/**
* Calculates the average DC in the sample stream so that it can be subtracted from the samples when the
* native buffer is used.
* @param samples containing DC offset
*/
private void calculateDc(short[] samples)
{
float dcAccumulator = 0;
for(short sample: samples)
{
dcAccumulator += sample;
}
dcAccumulator /= samples.length;
mDcCorrectionManager.adjust(dcAccumulator * AirspyHfNativeBuffer.SCALE);
}
}

View File

@@ -1,6 +1,6 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 Dennis Sheirer
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,23 +16,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.record.wave;
import java.io.IOException;
import java.nio.file.Path;
package io.github.dsheirer.buffer.sample;
import java.nio.ByteBuffer;
/**
* Provides the file path for a new baseband recording file. Invoked each time a recorder creates a new file
* (start, sample rate change, or file size rollover) so that time-stamped and sample-rate-bearing file names are
* current.
* Interface to convert samples from a byte buffer to an array of shorts.
*/
@FunctionalInterface
public interface IRecordingPathProvider
public interface ISampleConverter
{
/**
* @param sampleRate of the recording
* @return path for the new recording file
* @throws IOException if a unique path can't be determined
* Converts the byte samples contained in the byte buffer to their short-valued representation
* @param buffer of samples
* @return converted samples
*/
Path getPath(float sampleRate) throws IOException;
short[] convert(ByteBuffer buffer);
/**
* Current DC average of the samples that have been processed thus far.
*/
float getAverageDc();
}

View File

@@ -0,0 +1,119 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.dsp.filter.hilbert.HilbertTransform;
import java.util.Iterator;
/**
* Base complex samples iterator for raw sample buffers. Incorporates a Hilbert transform filter
* for converting the real sample array to complex samples.
* @param <T> either ComplexSamples or InterleavedComplexSamples
*/
public abstract class SampleBufferIterator<T> implements Iterator<T>
{
protected static final float SCALE_SIGNED_12_BIT_TO_FLOAT = 1.0f / 2048.0f;
protected static final int FRAGMENT_SIZE = 4096;
protected static final float[] COEFFICIENTS =
HilbertTransform.convertHalfBandToHilbert(HilbertTransform.HALF_BAND_FILTER_47_TAP);
public static final int I_OVERLAP = 11;
public static final int Q_OVERLAP = 23;
protected float[] mIBuffer = new float[FRAGMENT_SIZE + I_OVERLAP];
protected float[] mQBuffer = new float[FRAGMENT_SIZE + Q_OVERLAP];
protected short[] mSamples;
protected int mSamplesPointer = 0;
protected float mAverageDc;
private long mTimestamp;
private float mSamplesPerMillisecond;
/**
* Constructs an instance
* @param samples from the tuner.
* @param residualI samples from previous buffer
* @param residualQ samples from previous buffer
* @param averageDc as measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIterator(short[] samples, short[] residualI, short[] residualQ, float averageDc, long timestamp,
float samplesPerMillisecond)
{
if(residualI.length != I_OVERLAP || residualQ.length != Q_OVERLAP)
{
throw new IllegalArgumentException("Residual I length [" + residualI.length +
"] must be " + I_OVERLAP + " and Residual Q length [" + residualQ.length +
"] must be " + Q_OVERLAP);
}
int requiredInterval = FRAGMENT_SIZE * 2; //requires 4 bytes (2 samples) per fragment
if(samples.length % requiredInterval != 0)
{
throw new IllegalArgumentException("Samples short array length [" + mSamples.length +
"]must be an integer multiple of " + requiredInterval);
}
mAverageDc = averageDc;
mSamples = samples;
mTimestamp = timestamp;
mSamplesPerMillisecond = samplesPerMillisecond;
//Transfer and scale the residual I & Q samples from the previous buffer
for(int i = 0; i < residualI.length; i++)
{
mIBuffer[i] = scale(residualI[i], averageDc);
}
for(int q = 0; q < residualQ.length; q++)
{
mQBuffer[q] = scale(residualQ[q], averageDc);
}
}
/**
* Calculates the timestamp for a samples buffer fragment based on where it is extracted from relative to the
* native buffer starting timestamp.
* @param samplesPointer for the start of the fragment. Note: this value will be divided by 2 to account for I/Q sample pairs.
* @return timestamp adjusted to the fragment or sub-buffer start sample.
*/
protected long getFragmentTimestamp(int samplesPointer)
{
return mTimestamp + (long)(samplesPointer / 2 / mSamplesPerMillisecond);
}
@Override
public boolean hasNext()
{
return mSamplesPointer < mSamples.length;
}
/**
* Scales the short sample value to a 12-bit floating point and subtracts the average DC offset
* @param value to scale
* @param averageDc detected
* @return scaled and normalized sample
*/
public static float scale(short value, float averageDc)
{
return ((float)value - 2048) * SCALE_SIGNED_12_BIT_TO_FLOAT - averageDc;
}
}

View File

@@ -0,0 +1,98 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Arrays;
/**
* Scalar implementation for non-packed native buffers
*/
public class SampleBufferIteratorScalar extends SampleBufferIterator<ComplexSamples>
{
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIteratorScalar(short[] samples, short[] residualI, short[] residualQ, float averageDc, long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public ComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
mIBuffer[x + I_OVERLAP] = scale(mSamples[offset++], mAverageDc);
mQBuffer[x + Q_OVERLAP] = scale(mSamples[offset++], mAverageDc);
}
mSamplesPointer = offset;
//The i line is a simple delay line, so we'll just copy those as a new array here.
float[] i = Arrays.copyOf(mIBuffer, FRAGMENT_SIZE);
float[] q = new float[FRAGMENT_SIZE];
float accumulator;
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = 0;
for(int tap = 0; tap < COEFFICIENTS.length; tap++)
{
accumulator += COEFFICIENTS[tap] * mQBuffer[x + tap];
}
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
q[x] = accumulator;
}
else
{
i[x] = -i[x];
q[x] = -accumulator;
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new ComplexSamples(i, q, timestamp);
}
}

View File

@@ -0,0 +1,128 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleBufferIteratorVector128Bits extends SampleBufferIterator<ComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_128;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIteratorVector128Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public ComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
//The i line is a simple delay line, so we'll just copy those as a new array here.
float[] i = Arrays.copyOf(mIBuffer, FRAGMENT_SIZE);
float[] q = new float[FRAGMENT_SIZE];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 4);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f4 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 12);
FloatVector f5 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
FloatVector f6 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 20);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 4), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f4.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 12), accumulator);
accumulator = f5.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
accumulator = f6.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 20), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
q[x] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
i[x] = -i[x];
q[x] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new ComplexSamples(i, q, timestamp);
}
}

View File

@@ -0,0 +1,122 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleBufferIteratorVector256Bits extends SampleBufferIterator<ComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_256;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIteratorVector256Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public ComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
//The i line is a simple delay line, so we'll just copy those as a new array here.
float[] i = Arrays.copyOf(mIBuffer, FRAGMENT_SIZE);
float[] q = new float[FRAGMENT_SIZE];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
q[x] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
i[x] = -i[x];
q[x] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new ComplexSamples(i, q, timestamp);
}
}

View File

@@ -0,0 +1,125 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleBufferIteratorVector512Bits extends SampleBufferIterator<ComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_512;
private float[] mFilterPart2;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIteratorVector512Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
//Arrange the last 8 taps of the filter into the higher indices of an array to align for SIMD
mFilterPart2 = new float[16];
System.arraycopy(COEFFICIENTS, 16, mFilterPart2, 8, 8);
}
@Override
public ComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
//The i line is a simple delay line, so we'll just copy those as a new array here.
float[] i = Arrays.copyOf(mIBuffer, FRAGMENT_SIZE);
float[] q = new float[FRAGMENT_SIZE];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, mFilterPart2, 0);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
q[x] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
i[x] = -i[x];
q[x] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new ComplexSamples(i, q, timestamp);
}
}

View File

@@ -0,0 +1,141 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.ComplexSamples;
import java.util.Arrays;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleBufferIteratorVector64Bits extends SampleBufferIterator<ComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_64;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleBufferIteratorVector64Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public ComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
//The i line is a simple delay line, so we'll just copy those as a new array here.
float[] i = Arrays.copyOf(mIBuffer, FRAGMENT_SIZE);
float[] q = new float[FRAGMENT_SIZE];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 2);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 4);
FloatVector f4 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 6);
FloatVector f5 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f6 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 10);
FloatVector f7 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 12);
FloatVector f8 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 14);
FloatVector f9 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
FloatVector f10 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 18);
FloatVector f11 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 20);
FloatVector f12 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 22);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 2), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 4), accumulator);
accumulator = f4.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 6), accumulator);
accumulator = f5.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f6.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 10), accumulator);
accumulator = f7.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 12), accumulator);
accumulator = f8.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 14), accumulator);
accumulator = f9.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
accumulator = f10.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 18), accumulator);
accumulator = f11.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 20), accumulator);
accumulator = f12.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 22), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
q[x] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
i[x] = -i[x];
q[x] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new ComplexSamples(i, q, timestamp);
}
}

View File

@@ -0,0 +1,96 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
/**
* Scalar implementation for non-packed native buffers
*/
public class SampleInterleavedBufferIteratorScalar extends SampleBufferIterator<InterleavedComplexSamples>
{
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleInterleavedBufferIteratorScalar(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public InterleavedComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
mIBuffer[x + I_OVERLAP] = scale(mSamples[offset++], mAverageDc);
mQBuffer[x + Q_OVERLAP] = scale(mSamples[offset++], mAverageDc);
}
mSamplesPointer = offset;
float[] samples = new float[FRAGMENT_SIZE * 2];
float accumulator;
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = 0;
for(int tap = 0; tap < COEFFICIENTS.length; tap++)
{
accumulator += COEFFICIENTS[tap] * mQBuffer[x + tap];
}
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
samples[2 * x] = mIBuffer[x];
samples[2 * x + 1] = accumulator;
}
else
{
samples[2 * x] = -mIBuffer[x];
samples[2 * x + 1] = -accumulator;
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new InterleavedComplexSamples(samples, timestamp);
}
}

View File

@@ -0,0 +1,125 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleInterleavedBufferIteratorVector128Bits extends SampleBufferIterator<InterleavedComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_128;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleInterleavedBufferIteratorVector128Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public InterleavedComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
float[] samples = new float[FRAGMENT_SIZE * 2];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 4);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f4 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 12);
FloatVector f5 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
FloatVector f6 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 20);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 4), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f4.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 12), accumulator);
accumulator = f5.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
accumulator = f6.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 20), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
samples[2 * x] = mIBuffer[x];
samples[2 * x + 1] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
samples[2 * x] = -mIBuffer[x];
samples[2 * x + 1] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new InterleavedComplexSamples(samples, timestamp);
}
}

View File

@@ -0,0 +1,119 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleInterleavedBufferIteratorVector256Bits extends SampleBufferIterator<InterleavedComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_256;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleInterleavedBufferIteratorVector256Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public InterleavedComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
float[] samples = new float[FRAGMENT_SIZE * 2];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
samples[2 * x] = mIBuffer[x];
samples[2 * x + 1] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
samples[2 * x] = -mIBuffer[x];
samples[2 * x + 1] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new InterleavedComplexSamples(samples, timestamp);
}
}

View File

@@ -0,0 +1,122 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleInterleavedBufferIteratorVector512Bits extends SampleBufferIterator<InterleavedComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_512;
private float[] mFilterPart2;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleInterleavedBufferIteratorVector512Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
//Arrange the last 8 taps of the filter into the higher indices of an array to align for SIMD
mFilterPart2 = new float[16];
System.arraycopy(COEFFICIENTS, 16, mFilterPart2, 8, 8);
}
@Override
public InterleavedComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
float[] samples = new float[FRAGMENT_SIZE * 2];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, mFilterPart2, 0);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
samples[2 * x] = mIBuffer[x];
samples[2 * x + 1] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
samples[2 * x] = -mIBuffer[x];
samples[2 * x + 1] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new InterleavedComplexSamples(samples, timestamp);
}
}

View File

@@ -0,0 +1,137 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Vector SIMD implementation for non-packed native buffers
*/
public class SampleInterleavedBufferIteratorVector64Bits extends SampleBufferIterator<InterleavedComplexSamples>
{
private static final VectorSpecies<Float> VECTOR_SPECIES = FloatVector.SPECIES_64;
/**
* Constructs an instance
*
* @param samples from the device, either packed or unpacked.
* @param residualI samples from last buffer
* @param residualQ samples from last buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param samplesPerMillisecond to calculate sub-buffer fragment timestamps
*/
public SampleInterleavedBufferIteratorVector64Bits(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, float samplesPerMillisecond)
{
super(samples, residualI, residualQ, averageDc, timestamp, samplesPerMillisecond);
}
@Override
public InterleavedComplexSamples next()
{
if(mSamplesPointer >= mSamples.length)
{
throw new IllegalStateException("End of buffer exceeded");
}
long timestamp = getFragmentTimestamp(mSamplesPointer);
int offset = mSamplesPointer;
int fragmentPointer = 0;
float[] scaledSamples = new float[VECTOR_SPECIES.length()];
while(fragmentPointer < FRAGMENT_SIZE)
{
for(int y = 0; y < VECTOR_SPECIES.length(); y++)
{
//Couldn't figure out an easy way to load as a short vector and recast to a float vector
scaledSamples[y] = mSamples[offset++];
}
//SIMD scaling operation
FloatVector.fromArray(VECTOR_SPECIES, scaledSamples, 0)
.sub(2048.0f)
.mul(SCALE_SIGNED_12_BIT_TO_FLOAT)
.sub(mAverageDc)
.intoArray(scaledSamples, 0);
for(int y = 0; y < VECTOR_SPECIES.length(); y += 2)
{
mIBuffer[fragmentPointer + I_OVERLAP] = scaledSamples[y];
mQBuffer[fragmentPointer++ + Q_OVERLAP] = scaledSamples[y + 1];
}
}
mSamplesPointer = offset;
float[] samples = new float[FRAGMENT_SIZE * 2];
FloatVector accumulator;
FloatVector f1 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 0);
FloatVector f2 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 2);
FloatVector f3 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 4);
FloatVector f4 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 6);
FloatVector f5 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 8);
FloatVector f6 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 10);
FloatVector f7 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 12);
FloatVector f8 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 14);
FloatVector f9 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 16);
FloatVector f10 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 18);
FloatVector f11 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 20);
FloatVector f12 = FloatVector.fromArray(VECTOR_SPECIES, COEFFICIENTS, 22);
for(int x = 0; x < FRAGMENT_SIZE; x++)
{
accumulator = FloatVector.zero(VECTOR_SPECIES);
accumulator = f1.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x), accumulator);
accumulator = f2.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 2), accumulator);
accumulator = f3.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 4), accumulator);
accumulator = f4.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 6), accumulator);
accumulator = f5.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 8), accumulator);
accumulator = f6.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 10), accumulator);
accumulator = f7.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 12), accumulator);
accumulator = f8.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 14), accumulator);
accumulator = f9.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 16), accumulator);
accumulator = f10.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 18), accumulator);
accumulator = f11.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 20), accumulator);
accumulator = f12.fma(FloatVector.fromArray(VECTOR_SPECIES, mQBuffer, x + 22), accumulator);
//Perform FS/2 frequency translation on final filtered values ... multiply sequence by 1, -1, etc.
if(x % 2 == 0)
{
samples[2 * x] = mIBuffer[x];
samples[2 * x + 1] = accumulator.reduceLanes(VectorOperators.ADD);
}
else
{
samples[2 * x] = -mIBuffer[x];
samples[2 * x + 1] = -accumulator.reduceLanes(VectorOperators.ADD);
}
}
//Copy residual end samples to beginning of buffers for the next iteration
System.arraycopy(mIBuffer, FRAGMENT_SIZE, mIBuffer, 0, I_OVERLAP);
System.arraycopy(mQBuffer, FRAGMENT_SIZE, mQBuffer, 0, Q_OVERLAP);
return new InterleavedComplexSamples(samples, timestamp);
}
}

View File

@@ -0,0 +1,103 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.buffer.AbstractNativeBuffer;
import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
import io.github.dsheirer.vector.calibrate.Implementation;
import java.util.Iterator;
/**
* Native buffer scalar implementation for non-packed samples.
*/
public class SampleNativeBuffer extends AbstractNativeBuffer
{
private final short[] mSamples;
private final short[] mResidualI;
private final short[] mResidualQ;
private final float mAverageDc;
private final Implementation mInterleavedImplementation;
private final Implementation mNonInterleavedImplementation;
/**
* Constructs an instance
* @param samples (non-packed) from the device
* @param residualI samples from previous buffer
* @param residualQ samples from previous buffer
* @param averageDc measured
* @param timestamp of the buffer
* @param interleavedImplementation optimal, scalar vs vector SIMD
* @param nonInterleavedImplementation optimal, scalar vs vector SIMD
* @param samplesPerMillisecond used to calculate sub-buffer fragment timestamp offsets from the start of this buffer.
*/
public SampleNativeBuffer(short[] samples, short[] residualI, short[] residualQ, float averageDc,
long timestamp, Implementation interleavedImplementation,
Implementation nonInterleavedImplementation, float samplesPerMillisecond)
{
super(timestamp, samplesPerMillisecond);
//Ensure we're an even multiple of the fragment size. Typically, this will be 64k or 128k
if(samples.length % SampleBufferIterator.FRAGMENT_SIZE != 0)
{
throw new IllegalArgumentException("Samples short[] length [" + samples.length +
"] must be an even multiple of " + SampleBufferIterator.FRAGMENT_SIZE);
}
mSamples = samples;
mResidualI = residualI;
mResidualQ = residualQ;
mAverageDc = averageDc;
mInterleavedImplementation = interleavedImplementation;
mNonInterleavedImplementation = nonInterleavedImplementation;
}
@Override
public int sampleCount()
{
return mSamples.length / 2;
}
@Override
public Iterator<ComplexSamples> iterator()
{
return switch(mNonInterleavedImplementation)
{
case VECTOR_SIMD_512 -> new SampleBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_256-> new SampleBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_128-> new SampleBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_64 ->new SampleBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
default -> new SampleBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
};
}
@Override
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
{
return switch(mInterleavedImplementation)
{
case VECTOR_SIMD_512 -> new SampleInterleavedBufferIteratorVector512Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_256-> new SampleInterleavedBufferIteratorVector256Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_128-> new SampleInterleavedBufferIteratorVector128Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
case VECTOR_SIMD_64 ->new SampleInterleavedBufferIteratorVector64Bits(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
default -> new SampleInterleavedBufferIteratorScalar(mSamples, mResidualI, mResidualQ, mAverageDc, getTimestamp(), getSamplesPerMillisecond());
};
}
}

View File

@@ -0,0 +1,135 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.buffer.AbstractNativeBufferFactory;
import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.vector.calibrate.CalibrationManager;
import io.github.dsheirer.vector.calibrate.CalibrationType;
import io.github.dsheirer.vector.calibrate.Implementation;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
* Implements a factory for creating SignedByteNativeBuffer instances
*/
public class SampleNativeBufferFactory extends AbstractNativeBufferFactory
{
private boolean mSamplePacking = false;
private short[] mResidualI = new short[SampleBufferIterator.I_OVERLAP];
private short[] mResidualQ = new short[SampleBufferIterator.Q_OVERLAP];
private ISampleConverter mConverter;
private Implementation mInterleavedIteratorImplementation;
private Implementation mNonInterleavedIteratorImplementation;
/**
* Constructs an instance
*/
public SampleNativeBufferFactory()
{
updateConverter();
mInterleavedIteratorImplementation = CalibrationManager.getInstance()
.getImplementation(CalibrationType.SAMPLE_UNPACKED_INTERLEAVED_ITERATOR);
mNonInterleavedIteratorImplementation = CalibrationManager.getInstance()
.getImplementation(CalibrationType.SAMPLE_UNPACKED_ITERATOR);
}
/**
* Sample packing places two 12-bit samples into 3 bytes when enabled or
* places two 12-bit samples into 4 bytes when disabled.
*
* @param enabled
*/
public void setSamplePacking(boolean enabled)
{
mSamplePacking = enabled;
updateConverter();
}
/**
* Creates an optimal sample converter instance.
*/
private void updateConverter()
{
if(mSamplePacking)
{
if(!(mConverter instanceof ScalarPackedSampleConverter))
{
mConverter = new ScalarPackedSampleConverter();
}
}
else
{
Implementation implementation = CalibrationManager.getInstance().getImplementation(CalibrationType.SAMPLE_PACKED_CONVERTER);
if(implementation == Implementation.VECTOR_SIMD_PREFERRED)
{
if(!(mConverter instanceof VectorUnpackedSampleConverter))
{
mConverter = new VectorUnpackedSampleConverter();
}
}
else
{
if(!(mConverter instanceof ScalarUnpackedSampleConverter))
{
mConverter = new ScalarUnpackedSampleConverter();
}
}
}
}
@Override
public INativeBuffer getBuffer(ByteBuffer buffer, long timestamp)
{
short[] samples = mConverter.convert(buffer);
INativeBuffer nativeBuffer = new SampleNativeBuffer(samples,
Arrays.copyOf(mResidualI, mResidualI.length),
Arrays.copyOf(mResidualQ, mResidualQ.length), mConverter.getAverageDc(), timestamp,
mInterleavedIteratorImplementation, mNonInterleavedIteratorImplementation, getSamplesPerMillisecond());
extractResidual(samples);
return nativeBuffer;
}
/**
* Extracts the residual overlap samples needed for continuity in the Hilbert transform filter.
* @param samples to extract residual from
*/
private void extractResidual(short[] samples)
{
int offset = samples.length - (SampleBufferIterator.I_OVERLAP * 2);
for(int i = 0; i < SampleBufferIterator.I_OVERLAP; i++)
{
mResidualI[i] = samples[offset + (2 * i)];
}
offset = samples.length - (SampleBufferIterator.Q_OVERLAP * 2) + 1;
for(int q = 0; q < SampleBufferIterator.Q_OVERLAP; q++)
{
mResidualQ[q] = samples[offset + (2 * q)];
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.buffer.DcCorrectionManager;
import java.nio.ByteBuffer;
/**
* Scalar implementation of sample converter for un-packed samples.
*/
public class ScalarPackedSampleConverter implements ISampleConverter
{
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
int offset = 0;
short sample;
short[] samples;
byte b1, b2, b3;
samples = new short[buffer.capacity() / 3 * 2];
if(shouldCalculateDc)
{
long dcAccumulator = 0;
for(int x = 0; x < samples.length; x += 2)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
b3 = buffer.get(offset++);
sample = (short)(((b1 & 0xFF) << 4) | ((b2 & 0xF0) >> 4));
samples[x] = sample;
dcAccumulator += sample;
sample = (short)(((b2 & 0xF) << 8) | (b3 & 0xFF));
samples[x] = sample;
dcAccumulator += sample;
}
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= SampleBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
mDcCalculationManager.adjust(averageDcNow);
}
else
{
for(int x = 0; x < samples.length; x += 2)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
b3 = buffer.get(offset++);
sample = (short)(((b1 & 0xFF) << 4) | ((b2 & 0xF0) >> 4));
samples[x] = sample;
sample = (short)(((b2 & 0xF) << 8) | (b3 & 0xFF));
samples[x] = sample;
}
}
return samples;
}
@Override
public float getAverageDc()
{
return mDcCalculationManager.getAverageDc();
}
public static void main(String[] args)
{
byte[] raw = new byte[262144];
ByteBuffer buffer = ByteBuffer.wrap(raw);
ScalarPackedSampleConverter scalar = new ScalarPackedSampleConverter();
VectorUnpackedSampleConverter vector = new VectorUnpackedSampleConverter();
long accumulator = 0;
int iterations = 1_000_000;
System.out.println("Starting ...");
long start = System.currentTimeMillis();
for(int count = 0; count < iterations; count++)
{
// short[] samples = scalar.convert(buffer);
short[] samples = vector.convert(buffer);
accumulator += samples[1];
}
long elapsed = System.currentTimeMillis() - start;
System.out.println("Accumulator: " + accumulator);
System.out.println("Elapsed: " + (elapsed / 1000.0f));
System.out.println("Finished");
}
}

View File

@@ -0,0 +1,83 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.buffer.DcCorrectionManager;
import java.nio.ByteBuffer;
/**
* Scalar implementation of sample converter for un-packed samples.
*/
public class ScalarUnpackedSampleConverter implements ISampleConverter
{
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
int offset = 0;
short sample;
short[] samples;
byte b1, b2;
samples = new short[buffer.capacity() / 2];
if(shouldCalculateDc)
{
long dcAccumulator = 0;
for(int x = 0; x < samples.length; x++)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[x] = sample;
dcAccumulator += sample;
}
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= SampleBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
mDcCalculationManager.adjust(averageDcNow);
}
else
{
for(int x = 0; x < samples.length; x++)
{
b1 = buffer.get(offset++);
b2 = buffer.get(offset++);
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[x] = sample;
}
}
return samples;
}
@Override
public float getAverageDc()
{
return mDcCalculationManager.getAverageDc();
}
}

View File

@@ -0,0 +1,129 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2025 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.buffer.sample;
import io.github.dsheirer.buffer.DcCorrectionManager;
import java.nio.ByteBuffer;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
/**
* Scalar implementation of sample converter for un-packed samples.
*/
public class VectorUnpackedSampleConverter implements ISampleConverter
{
private static final VectorSpecies<Short> VECTOR_SPECIES = ShortVector.SPECIES_PREFERRED;
/**
* Manages DC calculations and processing interval
*/
private DcCorrectionManager mDcCalculationManager = new DcCorrectionManager();
@Override
public short[] convert(ByteBuffer buffer)
{
boolean shouldCalculateDc = mDcCalculationManager.shouldCalculateDc();
short sample;
short[] samples;
byte b1, b2;
samples = new short[buffer.capacity() / 2];
int bytesOffset;
int rawPointer = 0;
ShortVector vector;
int samplesOffset = 0;
short[] bytes1 = new short[VECTOR_SPECIES.length()];
short[] bytes2 = new short[VECTOR_SPECIES.length()];
if(shouldCalculateDc)
{
long dcAccumulator = 0;
for(; samplesOffset < VECTOR_SPECIES.loopBound(samples.length); samplesOffset += VECTOR_SPECIES.length())
{
bytesOffset = 0;
while(bytesOffset < VECTOR_SPECIES.length())
{
bytes1[bytesOffset] = (short)(buffer.get(rawPointer++) & 0xFF);
bytes2[bytesOffset++] = (short)(buffer.get(rawPointer++) & 0x0F);
}
vector = ShortVector.fromArray(VECTOR_SPECIES, bytes1, 0)
.or(ShortVector.fromArray(VECTOR_SPECIES, bytes2, 0).lanewise(VectorOperators.LSHL, 8));
dcAccumulator += vector.reduceLanes(VectorOperators.ADD);
vector.intoArray(samples, samplesOffset);
}
for(; samplesOffset < samples.length; samplesOffset++)
{
b1 = buffer.get(rawPointer++);
b2 = buffer.get(rawPointer++);
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[samplesOffset] = sample;
dcAccumulator += sample;
}
float averageDcNow = ((float)dcAccumulator / (float)samples.length) - 2048.0f;
averageDcNow *= SampleBufferIterator.SCALE_SIGNED_12_BIT_TO_FLOAT;
mDcCalculationManager.adjust(averageDcNow);
}
else
{
for(; samplesOffset < VECTOR_SPECIES.loopBound(samples.length); samplesOffset += VECTOR_SPECIES.length())
{
bytesOffset = 0;
while(bytesOffset < VECTOR_SPECIES.length())
{
bytes1[bytesOffset] = (short)(buffer.get(rawPointer++) & 0xFF);
bytes2[bytesOffset++] = (short)(buffer.get(rawPointer++) & 0x0F);
}
vector = ShortVector.fromArray(VECTOR_SPECIES, bytes1, 0)
.or(ShortVector.fromArray(VECTOR_SPECIES, bytes2, 0).lanewise(VectorOperators.LSHL, 8));
vector.intoArray(samples, samplesOffset);
}
for(; samplesOffset < samples.length; samplesOffset++)
{
b1 = buffer.get(rawPointer++);
b2 = buffer.get(rawPointer++);
sample = (short)(((b2 & 0x0F) << 8) | (b1 & 0xFF));
samples[samplesOffset] = sample;
}
}
return samples;
}
@Override
public float getAverageDc()
{
return mDcCalculationManager.getAverageDc();
}
}

View File

@@ -1,779 +0,0 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*
* The transform kernels in this class are ported from the mixed radix complex FFT (cffti, cfftf and passf2/3/4/5)
* in JTransforms org.jtransforms.fft.FloatFFT_1D, which carries the following license:
*
* JTransforms
* Copyright (c) 2007 onward, Piotr Wendykier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.github.dsheirer.dsp.fft;
/**
* Allocation-free mixed radix complex FFT for sizes that factor into 2, 3 and 5 only.
*
* This is a port of the JTransforms FloatFFT_1D mixed radix complex transform path. JTransforms allocates a new
* 2N float scratch array on every mixed radix transform, which creates significant garbage collection pressure when
* the transform runs at block rate (e.g. the polyphase channelizer IFFT). This implementation pre-allocates the
* scratch buffer once and reuses it for each transform.
*
* Results match JTransforms FloatFFT_1D complexForward() and complexInverse(): the forward transform uses the
* exp(-j...) kernel, the inverse uses exp(+j...), and the inverse optionally scales by 1/N. Twiddle factors are
* calculated in double precision, so results can differ from JTransforms in the least significant bits.
*
* Samples are interleaved complex: a[offset + 2k] = Re[k] and a[offset + 2k + 1] = Im[k] for 0 <= k < N.
*
* Note: this class is NOT thread-safe since it reuses an internal scratch buffer. Use one instance per thread.
*/
public class MixedRadixComplexFFT
{
private static final int[] FACTORS = {4, 2, 3, 5};
private static final int FORWARD = -1;
private static final int INVERSE = 1;
private final int mSize;
private final int[] mFactors;
private final float[] mTwiddles;
private final float[] mScratch;
private final float mScale;
/**
* Constructs an instance
* @param size of the transform in complex samples. Must be a positive value with no prime factors other than
* 2, 3 and 5.
* @throws IllegalArgumentException if the size is not supported
*/
public MixedRadixComplexFFT(int size)
{
if(!isSupported(size))
{
throw new IllegalArgumentException("Unsupported FFT size [" + size +
"] - size must be positive and have no prime factors other than 2, 3 and 5");
}
mSize = size;
mFactors = factorize(size);
mTwiddles = new float[2 * size + 2];
mScratch = new float[2 * size];
mScale = 1.0f / size;
calculateTwiddles();
}
/**
* Indicates if the size can be transformed by this class.
* @param size in complex samples
* @return true if the size is positive and has no prime factors other than 2, 3 and 5.
*/
public static boolean isSupported(int size)
{
if(size < 1)
{
return false;
}
int remainder = size;
for(int factor: new int[]{2, 3, 5})
{
while(remainder % factor == 0)
{
remainder /= factor;
}
}
return remainder == 1;
}
/**
* Size of this transform
* @return size in complex samples
*/
public int getSize()
{
return mSize;
}
/**
* Computes the forward DFT of the interleaved complex samples, in place. Equivalent to JTransforms
* FloatFFT_1D.complexForward(samples, offset).
* @param samples interleaved complex, with at least 2N values from the offset
* @param offset to the first sample
*/
public void forward(float[] samples, int offset)
{
transform(samples, offset, FORWARD);
}
/**
* Computes the forward DFT of the interleaved complex samples, in place.
* @param samples interleaved complex, with at least 2N values
*/
public void forward(float[] samples)
{
forward(samples, 0);
}
/**
* Computes the inverse DFT of the interleaved complex samples, in place. Equivalent to JTransforms
* FloatFFT_1D.complexInverse(samples, offset, scale).
* @param samples interleaved complex, with at least 2N values from the offset
* @param offset to the first sample
* @param scale true to scale the results by 1/N
*/
public void inverse(float[] samples, int offset, boolean scale)
{
transform(samples, offset, INVERSE);
if(scale && mSize > 1)
{
int end = offset + 2 * mSize;
for(int x = offset; x < end; x++)
{
samples[x] *= mScale;
}
}
}
/**
* Computes the inverse DFT of the interleaved complex samples, in place.
* @param samples interleaved complex, with at least 2N values
* @param scale true to scale the results by 1/N
*/
public void inverse(float[] samples, boolean scale)
{
inverse(samples, 0, scale);
}
/**
* Factors the size into the radix sequence used by the transform, ported from JTransforms cffti(). Radix 4 is
* preferred, then 2, 3 and 5, and a radix 2 factor is moved to the front of the sequence.
*/
private static int[] factorize(int size)
{
if(size == 1)
{
return new int[0];
}
int[] factors = new int[32];
int count = 0;
int remainder = size;
for(int factor: FACTORS)
{
while(remainder % factor == 0)
{
factors[count++] = factor;
remainder /= factor;
if(factor == 2 && count != 1)
{
System.arraycopy(factors, 0, factors, 1, count - 1);
factors[0] = 2;
}
}
}
if(remainder != 1)
{
throw new IllegalArgumentException("Unsupported FFT size [" + size + "]");
}
int[] result = new int[count];
System.arraycopy(factors, 0, result, 0, count);
return result;
}
/**
* Calculates the twiddle factor table, ported from JTransforms cffti() with the table offset removed and the
* angles calculated in double precision.
*/
private void calculateTwiddles()
{
if(mSize == 1)
{
return;
}
double angleIncrement = 2.0 * Math.PI / mSize;
int i = 1;
int l1 = 1;
for(int factor: mFactors)
{
int ld = 0;
int l2 = l1 * factor;
int ido = mSize / l2;
int idot = ido + ido + 2;
for(int j = 1; j < factor; j++)
{
mTwiddles[i - 1] = 1;
mTwiddles[i] = 0;
ld += l1;
int fi = 0;
double argld = ld * angleIncrement;
for(int ii = 4; ii <= idot; ii += 2)
{
i += 2;
fi++;
double arg = fi * argld;
mTwiddles[i - 1] = (float)Math.cos(arg);
mTwiddles[i] = (float)Math.sin(arg);
}
}
l1 = l2;
}
}
/**
* Performs the transform, ported from JTransforms cfftf() using the reusable scratch buffer.
* @param a samples
* @param offa offset to first sample
* @param isign -1 for forward and +1 for inverse
*/
private void transform(float[] a, int offa, int isign)
{
if(mSize == 1)
{
return;
}
float[] ch = mScratch;
int twon = 2 * mSize;
boolean inScratch = false;
int l1 = 1;
int iw = 0;
for(int factor: mFactors)
{
int l2 = factor * l1;
int idot = 2 * (mSize / l2);
switch(factor)
{
case 4:
if(inScratch)
{
passf4(idot, l1, ch, 0, a, offa, iw, isign);
}
else
{
passf4(idot, l1, a, offa, ch, 0, iw, isign);
}
break;
case 2:
if(inScratch)
{
passf2(idot, l1, ch, 0, a, offa, iw, isign);
}
else
{
passf2(idot, l1, a, offa, ch, 0, iw, isign);
}
break;
case 3:
if(inScratch)
{
passf3(idot, l1, ch, 0, a, offa, iw, isign);
}
else
{
passf3(idot, l1, a, offa, ch, 0, iw, isign);
}
break;
case 5:
if(inScratch)
{
passf5(idot, l1, ch, 0, a, offa, iw, isign);
}
else
{
passf5(idot, l1, a, offa, ch, 0, iw, isign);
}
break;
default:
throw new IllegalStateException("Unsupported radix: " + factor);
}
inScratch = !inScratch;
l1 = l2;
iw += (factor - 1) * idot;
}
if(inScratch)
{
System.arraycopy(ch, 0, a, offa, twon);
}
}
/**
* Radix 2 butterfly, ported from JTransforms passf2().
*/
private void passf2(final int ido, final int l1, final float[] in, final int in_off, final float[] out,
final int out_off, final int offset, final int isign)
{
final float[] wtable = mTwiddles;
int iw1 = offset;
int idx = ido * l1;
if(ido <= 2)
{
for(int k = 0; k < l1; k++)
{
int idx0 = k * ido;
int iidx1 = in_off + 2 * idx0;
int iidx2 = iidx1 + ido;
float a1r = in[iidx1];
float a1i = in[iidx1 + 1];
float a2r = in[iidx2];
float a2i = in[iidx2 + 1];
int oidx1 = out_off + idx0;
int oidx2 = oidx1 + idx;
out[oidx1] = a1r + a2r;
out[oidx1 + 1] = a1i + a2i;
out[oidx2] = a1r - a2r;
out[oidx2 + 1] = a1i - a2i;
}
}
else
{
for(int k = 0; k < l1; k++)
{
for(int i = 0; i < ido - 1; i += 2)
{
int idx0 = k * ido;
int iidx1 = in_off + i + 2 * idx0;
int iidx2 = iidx1 + ido;
float i1r = in[iidx1];
float i1i = in[iidx1 + 1];
float i2r = in[iidx2];
float i2i = in[iidx2 + 1];
int widx1 = i + iw1;
float w1r = wtable[widx1];
float w1i = isign * wtable[widx1 + 1];
float t1r = i1r - i2r;
float t1i = i1i - i2i;
int oidx1 = out_off + i + idx0;
int oidx2 = oidx1 + idx;
out[oidx1] = i1r + i2r;
out[oidx1 + 1] = i1i + i2i;
out[oidx2] = w1r * t1r - w1i * t1i;
out[oidx2 + 1] = w1r * t1i + w1i * t1r;
}
}
}
}
/**
* Radix 3 butterfly, ported from JTransforms passf3().
*/
private void passf3(final int ido, final int l1, final float[] in, final int in_off, final float[] out,
final int out_off, final int offset, final int isign)
{
final float taur = -0.5f;
final float taui = 0.866025403784438707610604524234076962f;
final float[] wtable = mTwiddles;
int iw1 = offset;
int iw2 = iw1 + ido;
final int idxt = l1 * ido;
if(ido == 2)
{
for(int k = 1; k <= l1; k++)
{
int iidx1 = in_off + (3 * k - 2) * ido;
int iidx2 = iidx1 + ido;
int iidx3 = iidx1 - ido;
float i1r = in[iidx1];
float i1i = in[iidx1 + 1];
float i2r = in[iidx2];
float i2i = in[iidx2 + 1];
float i3r = in[iidx3];
float i3i = in[iidx3 + 1];
float tr2 = i1r + i2r;
float cr2 = i3r + taur * tr2;
float ti2 = i1i + i2i;
float ci2 = i3i + taur * ti2;
float cr3 = isign * taui * (i1r - i2r);
float ci3 = isign * taui * (i1i - i2i);
int oidx1 = out_off + (k - 1) * ido;
int oidx2 = oidx1 + idxt;
int oidx3 = oidx2 + idxt;
out[oidx1] = i3r + tr2;
out[oidx1 + 1] = i3i + ti2;
out[oidx2] = cr2 - ci3;
out[oidx2 + 1] = ci2 + cr3;
out[oidx3] = cr2 + ci3;
out[oidx3 + 1] = ci2 - cr3;
}
}
else
{
for(int k = 1; k <= l1; k++)
{
int idx1 = in_off + (3 * k - 2) * ido;
int idx2 = out_off + (k - 1) * ido;
for(int i = 0; i < ido - 1; i += 2)
{
int iidx1 = i + idx1;
int iidx2 = iidx1 + ido;
int iidx3 = iidx1 - ido;
float a1r = in[iidx1];
float a1i = in[iidx1 + 1];
float a2r = in[iidx2];
float a2i = in[iidx2 + 1];
float a3r = in[iidx3];
float a3i = in[iidx3 + 1];
float tr2 = a1r + a2r;
float cr2 = a3r + taur * tr2;
float ti2 = a1i + a2i;
float ci2 = a3i + taur * ti2;
float cr3 = isign * taui * (a1r - a2r);
float ci3 = isign * taui * (a1i - a2i);
float dr2 = cr2 - ci3;
float dr3 = cr2 + ci3;
float di2 = ci2 + cr3;
float di3 = ci2 - cr3;
int widx1 = i + iw1;
int widx2 = i + iw2;
float w1r = wtable[widx1];
float w1i = isign * wtable[widx1 + 1];
float w2r = wtable[widx2];
float w2i = isign * wtable[widx2 + 1];
int oidx1 = i + idx2;
int oidx2 = oidx1 + idxt;
int oidx3 = oidx2 + idxt;
out[oidx1] = a3r + tr2;
out[oidx1 + 1] = a3i + ti2;
out[oidx2] = w1r * dr2 - w1i * di2;
out[oidx2 + 1] = w1r * di2 + w1i * dr2;
out[oidx3] = w2r * dr3 - w2i * di3;
out[oidx3 + 1] = w2r * di3 + w2i * dr3;
}
}
}
}
/**
* Radix 4 butterfly, ported from JTransforms passf4().
*/
private void passf4(final int ido, final int l1, final float[] in, final int in_off, final float[] out,
final int out_off, final int offset, final int isign)
{
final float[] wtable = mTwiddles;
int iw1 = offset;
int iw2 = iw1 + ido;
int iw3 = iw2 + ido;
int idx0 = l1 * ido;
if(ido == 2)
{
for(int k = 0; k < l1; k++)
{
int idxt1 = k * ido;
int iidx1 = in_off + 4 * idxt1 + 1;
int iidx2 = iidx1 + ido;
int iidx3 = iidx2 + ido;
int iidx4 = iidx3 + ido;
float i1i = in[iidx1 - 1];
float i1r = in[iidx1];
float i2i = in[iidx2 - 1];
float i2r = in[iidx2];
float i3i = in[iidx3 - 1];
float i3r = in[iidx3];
float i4i = in[iidx4 - 1];
float i4r = in[iidx4];
float ti1 = i1r - i3r;
float ti2 = i1r + i3r;
float tr4 = i4r - i2r;
float ti3 = i2r + i4r;
float tr1 = i1i - i3i;
float tr2 = i1i + i3i;
float ti4 = i2i - i4i;
float tr3 = i2i + i4i;
int oidx1 = out_off + idxt1;
int oidx2 = oidx1 + idx0;
int oidx3 = oidx2 + idx0;
int oidx4 = oidx3 + idx0;
out[oidx1] = tr2 + tr3;
out[oidx1 + 1] = ti2 + ti3;
out[oidx2] = tr1 + isign * tr4;
out[oidx2 + 1] = ti1 + isign * ti4;
out[oidx3] = tr2 - tr3;
out[oidx3 + 1] = ti2 - ti3;
out[oidx4] = tr1 - isign * tr4;
out[oidx4 + 1] = ti1 - isign * ti4;
}
}
else
{
for(int k = 0; k < l1; k++)
{
int idx1 = k * ido;
int idx2 = in_off + 1 + 4 * idx1;
for(int i = 0; i < ido - 1; i += 2)
{
int iidx1 = i + idx2;
int iidx2 = iidx1 + ido;
int iidx3 = iidx2 + ido;
int iidx4 = iidx3 + ido;
float i1i = in[iidx1 - 1];
float i1r = in[iidx1];
float i2i = in[iidx2 - 1];
float i2r = in[iidx2];
float i3i = in[iidx3 - 1];
float i3r = in[iidx3];
float i4i = in[iidx4 - 1];
float i4r = in[iidx4];
float ti1 = i1r - i3r;
float ti2 = i1r + i3r;
float ti3 = i2r + i4r;
float tr4 = i4r - i2r;
float tr1 = i1i - i3i;
float tr2 = i1i + i3i;
float ti4 = i2i - i4i;
float tr3 = i2i + i4i;
float cr3 = tr2 - tr3;
float ci3 = ti2 - ti3;
float cr2 = tr1 + isign * tr4;
float cr4 = tr1 - isign * tr4;
float ci2 = ti1 + isign * ti4;
float ci4 = ti1 - isign * ti4;
int widx1 = i + iw1;
int widx2 = i + iw2;
int widx3 = i + iw3;
float w1r = wtable[widx1];
float w1i = isign * wtable[widx1 + 1];
float w2r = wtable[widx2];
float w2i = isign * wtable[widx2 + 1];
float w3r = wtable[widx3];
float w3i = isign * wtable[widx3 + 1];
int oidx1 = out_off + i + idx1;
int oidx2 = oidx1 + idx0;
int oidx3 = oidx2 + idx0;
int oidx4 = oidx3 + idx0;
out[oidx1] = tr2 + tr3;
out[oidx1 + 1] = ti2 + ti3;
out[oidx2] = w1r * cr2 - w1i * ci2;
out[oidx2 + 1] = w1r * ci2 + w1i * cr2;
out[oidx3] = w2r * cr3 - w2i * ci3;
out[oidx3 + 1] = w2r * ci3 + w2i * cr3;
out[oidx4] = w3r * cr4 - w3i * ci4;
out[oidx4 + 1] = w3r * ci4 + w3i * cr4;
}
}
}
}
/**
* Radix 5 butterfly, ported from JTransforms passf5().
*/
private void passf5(final int ido, final int l1, final float[] in, final int in_off, final float[] out,
final int out_off, final int offset, final int isign)
{
final float tr11 = 0.309016994374947451262869435595348477f;
final float ti11 = 0.951056516295153531181938433292089030f;
final float tr12 = -0.809016994374947340240566973079694435f;
final float ti12 = 0.587785252292473248125759255344746634f;
final float[] wtable = mTwiddles;
int iw1 = offset;
int iw2 = iw1 + ido;
int iw3 = iw2 + ido;
int iw4 = iw3 + ido;
int idx0 = l1 * ido;
if(ido == 2)
{
for(int k = 1; k <= l1; ++k)
{
int iidx1 = in_off + (5 * k - 4) * ido + 1;
int iidx2 = iidx1 + ido;
int iidx3 = iidx1 - ido;
int iidx4 = iidx2 + ido;
int iidx5 = iidx4 + ido;
float i1i = in[iidx1 - 1];
float i1r = in[iidx1];
float i2i = in[iidx2 - 1];
float i2r = in[iidx2];
float i3i = in[iidx3 - 1];
float i3r = in[iidx3];
float i4i = in[iidx4 - 1];
float i4r = in[iidx4];
float i5i = in[iidx5 - 1];
float i5r = in[iidx5];
float ti5 = i1r - i5r;
float ti2 = i1r + i5r;
float ti4 = i2r - i4r;
float ti3 = i2r + i4r;
float tr5 = i1i - i5i;
float tr2 = i1i + i5i;
float tr4 = i2i - i4i;
float tr3 = i2i + i4i;
float cr2 = i3i + tr11 * tr2 + tr12 * tr3;
float ci2 = i3r + tr11 * ti2 + tr12 * ti3;
float cr3 = i3i + tr12 * tr2 + tr11 * tr3;
float ci3 = i3r + tr12 * ti2 + tr11 * ti3;
float cr5 = isign * (ti11 * tr5 + ti12 * tr4);
float ci5 = isign * (ti11 * ti5 + ti12 * ti4);
float cr4 = isign * (ti12 * tr5 - ti11 * tr4);
float ci4 = isign * (ti12 * ti5 - ti11 * ti4);
int oidx1 = out_off + (k - 1) * ido;
int oidx2 = oidx1 + idx0;
int oidx3 = oidx2 + idx0;
int oidx4 = oidx3 + idx0;
int oidx5 = oidx4 + idx0;
out[oidx1] = i3i + tr2 + tr3;
out[oidx1 + 1] = i3r + ti2 + ti3;
out[oidx2] = cr2 - ci5;
out[oidx2 + 1] = ci2 + cr5;
out[oidx3] = cr3 - ci4;
out[oidx3 + 1] = ci3 + cr4;
out[oidx4] = cr3 + ci4;
out[oidx4 + 1] = ci3 - cr4;
out[oidx5] = cr2 + ci5;
out[oidx5 + 1] = ci2 - cr5;
}
}
else
{
for(int k = 1; k <= l1; k++)
{
int idx1 = in_off + 1 + (k * 5 - 4) * ido;
int idx2 = out_off + (k - 1) * ido;
for(int i = 0; i < ido - 1; i += 2)
{
int iidx1 = i + idx1;
int iidx2 = iidx1 + ido;
int iidx3 = iidx1 - ido;
int iidx4 = iidx2 + ido;
int iidx5 = iidx4 + ido;
float i1i = in[iidx1 - 1];
float i1r = in[iidx1];
float i2i = in[iidx2 - 1];
float i2r = in[iidx2];
float i3i = in[iidx3 - 1];
float i3r = in[iidx3];
float i4i = in[iidx4 - 1];
float i4r = in[iidx4];
float i5i = in[iidx5 - 1];
float i5r = in[iidx5];
float ti5 = i1r - i5r;
float ti2 = i1r + i5r;
float ti4 = i2r - i4r;
float ti3 = i2r + i4r;
float tr5 = i1i - i5i;
float tr2 = i1i + i5i;
float tr4 = i2i - i4i;
float tr3 = i2i + i4i;
float cr2 = i3i + tr11 * tr2 + tr12 * tr3;
float ci2 = i3r + tr11 * ti2 + tr12 * ti3;
float cr3 = i3i + tr12 * tr2 + tr11 * tr3;
float ci3 = i3r + tr12 * ti2 + tr11 * ti3;
float cr5 = isign * (ti11 * tr5 + ti12 * tr4);
float ci5 = isign * (ti11 * ti5 + ti12 * ti4);
float cr4 = isign * (ti12 * tr5 - ti11 * tr4);
float ci4 = isign * (ti12 * ti5 - ti11 * ti4);
float dr3 = cr3 - ci4;
float dr4 = cr3 + ci4;
float di3 = ci3 + cr4;
float di4 = ci3 - cr4;
float dr5 = cr2 + ci5;
float dr2 = cr2 - ci5;
float di5 = ci2 - cr5;
float di2 = ci2 + cr5;
int widx1 = i + iw1;
int widx2 = i + iw2;
int widx3 = i + iw3;
int widx4 = i + iw4;
float w1r = wtable[widx1];
float w1i = isign * wtable[widx1 + 1];
float w2r = wtable[widx2];
float w2i = isign * wtable[widx2 + 1];
float w3r = wtable[widx3];
float w3i = isign * wtable[widx3 + 1];
float w4r = wtable[widx4];
float w4i = isign * wtable[widx4 + 1];
int oidx1 = i + idx2;
int oidx2 = oidx1 + idx0;
int oidx3 = oidx2 + idx0;
int oidx4 = oidx3 + idx0;
int oidx5 = oidx4 + idx0;
out[oidx1] = i3i + tr2 + tr3;
out[oidx1 + 1] = i3r + ti2 + ti3;
out[oidx2] = w1r * dr2 - w1i * di2;
out[oidx2 + 1] = w1r * di2 + w1i * dr2;
out[oidx3] = w2r * dr3 - w2i * di3;
out[oidx3 + 1] = w2r * di3 + w2i * dr3;
out[oidx4] = w3r * dr4 - w3i * di4;
out[oidx4 + 1] = w3r * di4 + w3i * dr4;
out[oidx5] = w4r * dr5 - w4i * di5;
out[oidx5 + 1] = w4r * di5 + w4i * dr5;
}
}
}
}
}

View File

@@ -18,7 +18,6 @@
*/
package io.github.dsheirer.dsp.filter.channelizer;
import io.github.dsheirer.dsp.fft.MixedRadixComplexFFT;
import io.github.dsheirer.dsp.filter.FilterFactory;
import io.github.dsheirer.dsp.filter.design.FilterDesignException;
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
@@ -28,6 +27,7 @@ import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import org.apache.commons.math3.util.FastMath;
import org.jtransforms.fft.ReusableFloatInverseFFT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -85,8 +85,7 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
//Sized to process 40 times per second
private IFFTProcessorDispatcher mIFFTProcessorDispatcher = new IFFTProcessorDispatcher(25);
//Allocation-free IFFT. Only used by the IFFT processor dispatcher thread since it reuses a scratch buffer.
private MixedRadixComplexFFT mFFT;
private ReusableFloatInverseFFT mFFT;
private ChannelDFT mChannelDFT;
private float[] mInlineSamples;
private float[] mInlineFilter;
@@ -454,7 +453,7 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
private void init(float[] coefficients)
{
int channelCount = getChannelCount();
mFFT = new MixedRadixComplexFFT(channelCount);
mFFT = new ReusableFloatInverseFFT(channelCount);
mChannelDFT = ChannelDFTFactory.getChannelDFT(channelCount);
int bufferLength = getSubChannelCount() * mTapsPerChannel;
mSamplesPerBlock = channelCount; //Same as subChannelCount / 2
@@ -506,7 +505,7 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
for(int offset = 0; offset < samples.length; offset += blockLength)
{
//Rotate each of the channels to the correct phase using the IFFT
mFFT.inverse(samples, offset, true);
mFFT.complexInverse(samples, offset);
}
}

View File

@@ -56,6 +56,7 @@ import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.TunerEvent;
import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.sdrplay.api.SDRPlayLibraryHelper;
import io.github.dsheirer.source.tuner.ui.TunerSpectralDisplayManager;
import io.github.dsheirer.spectrum.DisableSpectrumWaterfallMenuItem;
import io.github.dsheirer.spectrum.ShowTunerMenuItem;
@@ -153,6 +154,14 @@ public class SDRTrunk implements Listener<TunerEvent>
mApplicationLog = new ApplicationLog(mUserPreferences);
mApplicationLog.start();
//Note: invoke this early in the application lifecycle, before the TunerManager causes the sdrplay classes
//to be loaded since the jextract auto-generated code attempts to load the library by name and that can fail
//when the library was not installed into a normal/default location, particularly on windows OS systems.
if(SDRPlayLibraryHelper.LOADED)
{
mLog.info("SDRPlay API native library preemptively loaded");
}
mResourceMonitor = new ResourceMonitor(mUserPreferences);
ThreadPool.logSettings();

View File

@@ -1,84 +0,0 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.gui.control;
import javafx.collections.ListChangeListener;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import org.controlsfx.control.SegmentedButton;
/**
* Screen reader (accessibility) utilities for JavaFX controls.
*/
public final class AccessibilityUtil
{
private AccessibilityUtil()
{
//Not instantiable
}
/**
* Provides an accessible name for each toggle button in a segmented button group, combining the group label with
* the button text (e.g. "Channel Bandwidth: 12.5 kHz").
*
* A segmented button is a container, so a label can't identify it via Label.setLabelFor() in a way that screen
* readers announce: each toggle button receives focus individually and would otherwise be announced by its own text
* only, without the context of the group. Buttons added to the group later are also named.
*
* @param groupLabel that visually identifies the segmented button group
* @param segmentedButton containing the toggle buttons
*/
public static void labelGroup(Label groupLabel, SegmentedButton segmentedButton)
{
String groupName = groupLabel.getText() == null ? "" : groupLabel.getText().trim();
//Remove a trailing colon so that the name doesn't announce "colon colon"
if(groupName.endsWith(":"))
{
groupName = groupName.substring(0, groupName.length() - 1).trim();
}
final String name = groupName;
for(ToggleButton button: segmentedButton.getButtons())
{
setGroupName(name, button);
}
segmentedButton.getButtons().addListener((ListChangeListener<ToggleButton>)change -> {
while(change.next())
{
for(ToggleButton added: change.getAddedSubList())
{
setGroupName(name, added);
}
}
});
}
/**
* Sets the accessible text for the button as the group name and button text.
*/
private static void setGroupName(String groupName, ToggleButton button)
{
String text = button.getText() == null ? "" : button.getText();
button.setAccessibleText(groupName.isEmpty() ? text : groupName + ": " + text);
}
}

View File

@@ -1,80 +0,0 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.gui.control;
import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import org.controlsfx.control.ToggleSwitch;
/**
* ControlsFX toggle switch that exposes its role and on/off state to screen readers.
*
* The ControlsFX toggle switch doesn't provide an accessible role or selected state, so assistive technology sees it
* as a generic node with no state. This version reports itself as a toggle button, reports the selected state, and
* supports the accessible fire (toggle) action. The accessible name comes from the switch text, or from a label that
* identifies this switch via Label.setLabelFor().
*/
public class AccessibleToggleSwitch extends ToggleSwitch
{
/**
* Constructs an instance with no text. Use Label.setLabelFor() or setAccessibleText() to provide an accessible name.
*/
public AccessibleToggleSwitch()
{
this(null);
}
/**
* Constructs an instance
* @param text to display alongside the switch, also used as the accessible name.
*/
public AccessibleToggleSwitch(String text)
{
super(text);
setAccessibleRole(AccessibleRole.TOGGLE_BUTTON);
selectedProperty().addListener((observable, oldValue, newValue) ->
notifyAccessibleAttributeChanged(AccessibleAttribute.SELECTED));
}
@Override
public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters)
{
if(attribute == AccessibleAttribute.SELECTED)
{
return isSelected();
}
return super.queryAccessibleAttribute(attribute, parameters);
}
@Override
public void executeAccessibleAction(AccessibleAction action, Object... parameters)
{
if(action == AccessibleAction.FIRE)
{
fire();
}
else
{
super.executeAccessibleAction(action, parameters);
}
}
}

View File

@@ -21,7 +21,6 @@ package io.github.dsheirer.gui.playlist.alias;
import com.google.common.collect.Ordering;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.icon.Icon;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -101,7 +100,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(separator);
Label colorLabel = new Label("Color");
colorLabel.setLabelFor(getColorPicker());
GridPane.setHalignment(colorLabel, HPos.RIGHT);
GridPane.setConstraints(colorLabel, 0, ++row);
gridPane.getChildren().add(colorLabel);
@@ -116,7 +114,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getResetColorButton());
Label iconLabel = new Label("Icon");
iconLabel.setLabelFor(getIconNodeComboBox());
GridPane.setHalignment(iconLabel, HPos.RIGHT);
GridPane.setConstraints(iconLabel, 0, ++row);
gridPane.getChildren().add(iconLabel);
@@ -128,7 +125,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getApplyIconButton());
Label listenLabel = new Label("Listen");
listenLabel.setLabelFor(getMonitorAudioToggleSwitch());
GridPane.setHalignment(listenLabel, HPos.RIGHT);
GridPane.setConstraints(listenLabel, 0, ++row);
gridPane.getChildren().add(listenLabel);
@@ -137,7 +133,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getMonitorAudioToggleSwitch());
Label priorityLabel = new Label("Priority");
priorityLabel.setLabelFor(getMonitorPriorityComboBox());
GridPane.setHalignment(priorityLabel, HPos.RIGHT);
GridPane.setConstraints(priorityLabel, 2, row);
gridPane.getChildren().add(priorityLabel);
@@ -149,7 +144,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getApplyMonitorButton());
Label recordLabel = new Label("Record");
recordLabel.setLabelFor(getRecordToggleSwitch());
GridPane.setHalignment(recordLabel, HPos.RIGHT);
GridPane.setConstraints(recordLabel, 0, ++row);
gridPane.getChildren().add(recordLabel);
@@ -241,7 +235,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyColorButton == null)
{
mApplyColorButton = new Button("Apply");
mApplyColorButton.setAccessibleText("Apply color to selected aliases");
mApplyColorButton.setOnAction(event ->
{
startChange();
@@ -265,7 +258,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mResetColorButton == null)
{
mResetColorButton = new Button("Reset Color");
mResetColorButton.setAccessibleText("Reset color for selected aliases");
mResetColorButton.setOnAction(event ->
{
startChange();
@@ -305,7 +297,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyIconButton == null)
{
mApplyIconButton = new Button("Apply");
mApplyIconButton.setAccessibleText("Apply icon to selected aliases");
mApplyIconButton.setDisable(true);
mApplyIconButton.setOnAction(new EventHandler<ActionEvent>()
{
@@ -336,7 +327,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
if(mMonitorAudioToggleSwitch == null)
{
mMonitorAudioToggleSwitch = new AccessibleToggleSwitch();
mMonitorAudioToggleSwitch = new ToggleSwitch();
mMonitorAudioToggleSwitch.setSelected(true);
mMonitorAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -349,7 +340,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
if(mRecordToggleSwitch == null)
{
mRecordToggleSwitch = new AccessibleToggleSwitch();
mRecordToggleSwitch = new ToggleSwitch();
mRecordToggleSwitch.setSelected(false);
mRecordToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -383,7 +374,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyMonitorButton == null)
{
mApplyMonitorButton = new Button("Apply");
mApplyMonitorButton.setAccessibleText("Apply listen and priority to selected aliases");
mApplyMonitorButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
@@ -424,7 +414,6 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyRecordButton == null)
{
mApplyRecordButton = new Button("Apply");
mApplyRecordButton.setAccessibleText("Apply record to selected aliases");
mApplyRecordButton.setOnAction(event -> {
startChange();
boolean record = getRecordToggleSwitch().isSelected();
@@ -467,15 +456,12 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
setText(null);
setGraphic(null);
setAccessibleText(null);
}
else
{
textLabel.setText(item.getName());
iconLabel.setGraphic(new ImageView(item.getFxImage()));
setGraphic(gridPane);
//The name is shown in a nested label, so expose it as the cell's accessible text
setAccessibleText(item.getName());
}
}
};

View File

@@ -273,9 +273,7 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
Label listLabel = new Label("Alias List");
listLabel.setLabelFor(getAliasListNameComboBox());
Label searchLabel = new Label("Search");
searchLabel.setLabelFor(getSearchField());
searchLabel.setAlignment(Pos.CENTER_RIGHT);
HBox searchBox = new HBox();
@@ -453,7 +451,6 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
if(mAliasTableView == null)
{
mAliasTableView = new TableView<>();
mAliasTableView.setAccessibleText("Aliases");
TableColumn nameColumn = new TableColumn();
nameColumn.setText("Alias");
@@ -754,18 +751,15 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
UIManager.getColor("TextField.background"));
rectangle.setFill(ColorUtil.fromInteger(readable.equals(color) ? alias.getColor() :
readable.getRGB()));
setAccessibleText(String.format("#%06X", alias.getColor() & 0xFFFFFF));
}
else
{
rectangle.setVisible(false);
setAccessibleText(null);
}
}
else
{
rectangle.setVisible(false);
setAccessibleText(null);
}
}
};
@@ -804,15 +798,13 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
{
super.updateItem(item, empty);
if(!empty && getTableRow() != null && item != null)
if(!empty && getTableRow() != null)
{
iconNode.setVisible(item);
setAccessibleText(item ? "Yes" : "No");
}
else
{
iconNode.setVisible(false);
setAccessibleText(null);
}
}
};
@@ -927,7 +919,6 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
{
super.updateItem(item, empty);
setAlignment(Pos.CENTER);
setAccessibleText(null);
if(empty)
{
@@ -946,7 +937,6 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
if(icon != null && icon.getFxImage() != null)
{
setGraphic(new ImageView(icon.getFxImage()));
setAccessibleText(icon.getName());
}
else
{

View File

@@ -57,7 +57,6 @@ import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
import io.github.dsheirer.alias.id.tone.TonesID;
import io.github.dsheirer.audio.broadcast.ConfiguredBroadcast;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerFormatter;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.gui.playlist.alias.action.ActionEditor;
@@ -575,7 +574,6 @@ public class AliasItemEditor extends Editor<Alias>
{
mActionsList = new ListView<>(FXCollections.observableArrayList(AliasAction.extractor()));
mActionsList.setPrefHeight(75);
mActionsList.setAccessibleText("Alias actions");
mActionsList.setDisable(true);
mActionsList.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> setAction(newValue));
@@ -688,7 +686,6 @@ public class AliasItemEditor extends Editor<Alias>
mIdentifiersList = new ListView<>(FXCollections.observableArrayList(AliasID.extractor()));
mIdentifiersList.setDisable(true);
mIdentifiersList.setPrefHeight(75);
mIdentifiersList.setAccessibleText("Alias identifiers");
mIdentifiersList.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> setIdentifier(newValue));
mIdentifiersList.setCellFactory(param -> new AliasIdentifierCell());
@@ -849,17 +846,13 @@ public class AliasItemEditor extends Editor<Alias>
buttonBox.setSpacing(5);
buttonBox.getChildren().addAll(new Label(" "), getAddStreamButton(), getRemoveStreamButton());
Label availableLabel = new Label("Available");
getAvailableStreamsView().setAccessibleText("Available streams");
VBox availableBox = new VBox();
VBox.setVgrow(getAvailableStreamsView(), Priority.ALWAYS);
availableBox.getChildren().addAll(availableLabel, getAvailableStreamsView());
availableBox.getChildren().addAll(new Label("Available"), getAvailableStreamsView());
Label selectedLabel = new Label("Selected");
getSelectedStreamsView().setAccessibleText("Selected streams");
VBox selectedBox = new VBox();
VBox.setVgrow(getSelectedStreamsView(), Priority.ALWAYS);
selectedBox.getChildren().addAll(selectedLabel, getSelectedStreamsView());
selectedBox.getChildren().addAll(new Label("Selected"), getSelectedStreamsView());
HBox hbox = new HBox();
hbox.setSpacing(10);
@@ -871,7 +864,6 @@ public class AliasItemEditor extends Editor<Alias>
vbox.setSpacing(10);
VBox.setVgrow(hbox, Priority.ALWAYS);
Label label = new Label("Stream this Alias as Talkgroup:");
label.setLabelFor(getStreamAsTalkgroupField());
HBox streamAsHBox = new HBox();
streamAsHBox.setAlignment(Pos.CENTER_LEFT);
streamAsHBox.setSpacing(10);
@@ -972,8 +964,6 @@ public class AliasItemEditor extends Editor<Alias>
.or(Bindings.isNull(getAvailableStreamsView().getSelectionModel().selectedItemProperty())));
mAddStreamButton.setMaxWidth(Double.MAX_VALUE);
mAddStreamButton.setGraphic(new IconNode(FontAwesome.ANGLE_RIGHT));
mAddStreamButton.setAccessibleText("Add selected stream");
mAddStreamButton.setTooltip(new Tooltip("Add selected stream"));
mAddStreamButton.setAlignment(Pos.CENTER);
mAddStreamButton.setOnAction(event -> {
String stream = getAvailableStreamsView().getSelectionModel().getSelectedItem();
@@ -1000,8 +990,6 @@ public class AliasItemEditor extends Editor<Alias>
.or(Bindings.isNull(getSelectedStreamsView().getSelectionModel().selectedItemProperty())));
mRemoveStreamButton.setMaxWidth(Double.MAX_VALUE);
mRemoveStreamButton.setGraphic(new IconNode(FontAwesome.ANGLE_LEFT));
mRemoveStreamButton.setAccessibleText("Remove selected stream");
mRemoveStreamButton.setTooltip(new Tooltip("Remove selected stream"));
mRemoveStreamButton.setAlignment(Pos.CENTER);
mRemoveStreamButton.setOnAction(event -> {
BroadcastChannel broadcastChannel = getSelectedStreamsView().getSelectionModel().getSelectedItem();
@@ -1062,7 +1050,6 @@ public class AliasItemEditor extends Editor<Alias>
int row = 0;
Label nameLabel = new Label("Alias");
nameLabel.setLabelFor(getNameField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, row);
mTextFieldPane.getChildren().add(nameLabel);
@@ -1071,7 +1058,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getNameField());
Label monitorAudioLabel = new Label("Listen");
monitorAudioLabel.setLabelFor(getMonitorAudioToggleSwitch());
GridPane.setHalignment(monitorAudioLabel, HPos.RIGHT);
GridPane.setConstraints(monitorAudioLabel, 2, row);
mTextFieldPane.getChildren().add(monitorAudioLabel);
@@ -1079,7 +1065,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getMonitorAudioToggleSwitch());
Label monitorPriorityLabel = new Label("Priority");
monitorPriorityLabel.setLabelFor(getMonitorPriorityComboBox());
GridPane.setHalignment(monitorPriorityLabel, HPos.RIGHT);
GridPane.setConstraints(monitorPriorityLabel, 4, row);
mTextFieldPane.getChildren().add(monitorPriorityLabel);
@@ -1087,7 +1072,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getMonitorPriorityComboBox());
Label colorLabel = new Label("Color");
colorLabel.setLabelFor(getColorPicker());
GridPane.setHalignment(colorLabel, HPos.RIGHT);
GridPane.setConstraints(colorLabel, 6, row);
mTextFieldPane.getChildren().add(colorLabel);
@@ -1095,7 +1079,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getColorPicker());
Label groupLabel = new Label("Group");
groupLabel.setLabelFor(getGroupField());
GridPane.setHalignment(groupLabel, HPos.RIGHT);
GridPane.setConstraints(groupLabel, 0, ++row);
mTextFieldPane.getChildren().add(groupLabel);
@@ -1104,7 +1087,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getGroupField());
Label recordAudioLabel = new Label("Record");
recordAudioLabel.setLabelFor(getRecordAudioToggleSwitch());
GridPane.setHalignment(recordAudioLabel, HPos.RIGHT);
GridPane.setConstraints(recordAudioLabel, 2, row);
mTextFieldPane.getChildren().add(recordAudioLabel);
@@ -1112,7 +1094,6 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getRecordAudioToggleSwitch());
Label iconLabel = new Label("Icon");
iconLabel.setLabelFor(getIconNodeComboBox());
GridPane.setHalignment(iconLabel, HPos.RIGHT);
GridPane.setConstraints(iconLabel, 4, row);
mTextFieldPane.getChildren().add(iconLabel);
@@ -1127,7 +1108,7 @@ public class AliasItemEditor extends Editor<Alias>
{
if(mMonitorAudioToggleSwitch == null)
{
mMonitorAudioToggleSwitch = new AccessibleToggleSwitch();
mMonitorAudioToggleSwitch = new ToggleSwitch();
mMonitorAudioToggleSwitch.setDisable(true);
mMonitorAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -1160,7 +1141,7 @@ public class AliasItemEditor extends Editor<Alias>
{
if(mRecordAudioToggleSwitch == null)
{
mRecordAudioToggleSwitch = new AccessibleToggleSwitch();
mRecordAudioToggleSwitch = new ToggleSwitch();
mRecordAudioToggleSwitch.setDisable(true);
mRecordAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -1839,15 +1820,12 @@ public class AliasItemEditor extends Editor<Alias>
{
setText(null);
setGraphic(null);
setAccessibleText(null);
}
else
{
textLabel.setText(item.getName());
iconLabel.setGraphic(new ImageView(item.getFxImage()));
setGraphic(gridPane);
//The name is shown in a nested label, so expose it as the cell's accessible text
setAccessibleText(item.getName());
}
}
};

View File

@@ -23,21 +23,11 @@ import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.alias.id.AliasID;
import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.radio.P25FullyQualifiedRadio;
import io.github.dsheirer.alias.id.radio.Radio;
import io.github.dsheirer.alias.id.radio.RadioRange;
import io.github.dsheirer.alias.id.status.UnitStatusID;
import io.github.dsheirer.alias.id.status.UserStatusID;
import io.github.dsheirer.alias.id.talkgroup.P25FullyQualifiedTalkgroup;
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.protocol.Protocol;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
@@ -49,7 +39,6 @@ import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
@@ -63,7 +52,6 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
@@ -74,7 +62,7 @@ public class AliasViewByIdentifierEditor extends VBox
private ComboBox<String> mAliasListNameComboBox;
private ComboBox<AliasIDType> mAliasIDTypeComboBox;
private TableView<AliasAndIdentifier> mAliasAndIdentifierTableView;
private TableColumn<AliasAndIdentifier,AliasID> mIdentifierColumn;
private TableColumn<AliasAndIdentifier,String> mIdentifierColumn;
private Button mViewAliasButton;
private boolean aliasListInvalidated;
@@ -97,7 +85,6 @@ public class AliasViewByIdentifierEditor extends VBox
gridPane.setHgap(10);
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListNameComboBox());
GridPane.setHalignment(aliasListLabel, HPos.RIGHT);
GridPane.setConstraints(aliasListLabel, 0, 0);
gridPane.getChildren().add(aliasListLabel);
@@ -107,7 +94,6 @@ public class AliasViewByIdentifierEditor extends VBox
gridPane.getChildren().add(getAliasListNameComboBox());
Label identifierLabel = new Label("Identifier Type");
identifierLabel.setLabelFor(getAliasIDTypeComboBox());
GridPane.setHalignment(identifierLabel, HPos.RIGHT);
GridPane.setConstraints(identifierLabel, 0, 1);
gridPane.getChildren().add(identifierLabel);
@@ -212,29 +198,9 @@ public class AliasViewByIdentifierEditor extends VBox
if(mAliasAndIdentifierTableView == null)
{
mAliasAndIdentifierTableView = new TableView<>(FXCollections.observableArrayList(AliasAndIdentifier.extractor()));
mAliasAndIdentifierTableView.setAccessibleText("Aliases by identifier");
mAliasAndIdentifierTableView.setPlaceholder(new Label("No aliases or identifiers available"));
mIdentifierColumn = new TableColumn<>("Identifier");
mIdentifierColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getAliasIdentifier()));
mIdentifierColumn.setCellFactory(column -> new TableCell<>()
{
@Override
protected void updateItem(AliasID item, boolean empty)
{
super.updateItem(item, empty);
textProperty().unbind();
if(empty || item == null)
{
setText(null);
}
else
{
textProperty().bind(item.valueProperty());
}
}
});
mIdentifierColumn.setComparator(new AliasIdentifierComparator());
mIdentifierColumn.setCellValueFactory(new PropertyValueFactory<>("identifier"));
mIdentifierColumn.setPrefWidth(350);
TableColumn<AliasAndIdentifier, String> aliasColumn = new TableColumn<>();
@@ -302,103 +268,6 @@ public class AliasViewByIdentifierEditor extends VBox
return mAliasIDTypeComboBox;
}
/**
* Compares alias identifiers by protocol and then by numeric identifier value(s) so that the identifier column
* sorts numerically rather than alphabetically by the formatted display text. Identifiers that don't have a
* numeric value fall back to comparing the display text.
*/
public static class AliasIdentifierComparator implements Comparator<AliasID>
{
private static final Comparator<Protocol> PROTOCOL_COMPARATOR = Comparator.nullsLast(Comparator.naturalOrder());
@Override
public int compare(AliasID a, AliasID b)
{
if(a == b)
{
return 0;
}
if(a == null)
{
return 1;
}
if(b == null)
{
return -1;
}
int comparison = PROTOCOL_COMPARATOR.compare(getProtocol(a), getProtocol(b));
if(comparison == 0)
{
long[] aValues = getValues(a);
long[] bValues = getValues(b);
if(aValues != null && bValues != null)
{
for(int x = 0; x < Math.min(aValues.length, bValues.length) && comparison == 0; x++)
{
comparison = Long.compare(aValues[x], bValues[x]);
}
if(comparison == 0)
{
comparison = Integer.compare(aValues.length, bValues.length);
}
}
else if(aValues != null)
{
comparison = -1;
}
else if(bValues != null)
{
comparison = 1;
}
}
if(comparison == 0)
{
comparison = String.valueOf(a).compareTo(String.valueOf(b));
}
return comparison;
}
/**
* Protocol for the identifier, or null if the identifier doesn't have a protocol.
*/
private static Protocol getProtocol(AliasID id)
{
return switch(id)
{
case Talkgroup talkgroup -> talkgroup.getProtocol();
case TalkgroupRange talkgroupRange -> talkgroupRange.getProtocol();
case Radio radio -> radio.getProtocol();
case RadioRange radioRange -> radioRange.getProtocol();
default -> null;
};
}
/**
* Numeric values for the identifier, in order of sort significance, or null if the identifier is not numeric.
*/
private static long[] getValues(AliasID id)
{
return switch(id)
{
case P25FullyQualifiedTalkgroup fqt -> new long[]{fqt.getWacn(), fqt.getSystem(), fqt.getValue()};
case P25FullyQualifiedRadio fqr -> new long[]{fqr.getWacn(), fqr.getSystem(), fqr.getValue()};
case Talkgroup talkgroup -> new long[]{talkgroup.getValue()};
case TalkgroupRange range -> new long[]{range.getMinTalkgroup(), range.getMaxTalkgroup()};
case Radio radio -> new long[]{radio.getValue()};
case RadioRange range -> new long[]{range.getMinRadio(), range.getMaxRadio()};
case UnitStatusID status -> new long[]{status.getStatus()};
case UserStatusID status -> new long[]{status.getStatus()};
default -> null;
};
}
}
public static class AliasAndIdentifier
{
private Alias mAlias;

View File

@@ -34,7 +34,6 @@ import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
@@ -158,14 +157,12 @@ public class AliasViewByRecordingEditor extends VBox
aliasListBox.setAlignment(Pos.CENTER);
aliasListBox.setSpacing(5);
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListNameComboBox());
aliasListBox.getChildren().addAll(aliasListLabel, getAliasListNameComboBox());
HBox searchBox = new HBox();
searchBox.setAlignment(Pos.CENTER);
searchBox.setSpacing(5);
Label searchLabel = new Label("Search");
searchLabel.setLabelFor(getSearchField());
searchBox.getChildren().addAll(searchLabel, getSearchField());
mTopBox.getChildren().addAll(aliasListBox, searchBox);
@@ -231,7 +228,6 @@ public class AliasViewByRecordingEditor extends VBox
if(mNoRecordAliasTableView == null)
{
mNoRecordAliasTableView = new TableView<>();
mNoRecordAliasTableView.setAccessibleText("Don't record audio aliases");
mNoRecordAliasTableView.setMaxHeight(Double.MAX_VALUE);
mNoRecordAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -270,7 +266,6 @@ public class AliasViewByRecordingEditor extends VBox
if(mRecordAliasTableView == null)
{
mRecordAliasTableView = new TableView<>();
mRecordAliasTableView.setAccessibleText("Record audio aliases");
mRecordAliasTableView.setMaxHeight(Double.MAX_VALUE);
mRecordAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -312,8 +307,6 @@ public class AliasViewByRecordingEditor extends VBox
mAddButton.setDisable(true);
mAddButton.setMaxWidth(Double.MAX_VALUE);
mAddButton.setGraphic(new IconNode(FontAwesome.ANGLE_RIGHT));
mAddButton.setAccessibleText("Record audio for selected alias");
mAddButton.setTooltip(new Tooltip("Record audio for selected alias"));
mAddButton.setAlignment(Pos.CENTER);
mAddButton.setOnAction(event -> {
Alias selectedAlias = getNoRecordAliasTableView().getSelectionModel().getSelectedItem();
@@ -337,8 +330,6 @@ public class AliasViewByRecordingEditor extends VBox
mAddAllButton.setDisable(true);
mAddAllButton.setMaxWidth(Double.MAX_VALUE);
mAddAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_RIGHT));
mAddAllButton.setAccessibleText("Record audio for all selected aliases");
mAddAllButton.setTooltip(new Tooltip("Record audio for all selected aliases"));
mAddAllButton.setAlignment(Pos.CENTER);
mAddAllButton.setOnAction(event -> {
List<Alias> selectedAliases =
@@ -367,8 +358,6 @@ public class AliasViewByRecordingEditor extends VBox
mRemoveButton.setDisable(true);
mRemoveButton.setMaxWidth(Double.MAX_VALUE);
mRemoveButton.setGraphic(new IconNode(FontAwesome.ANGLE_LEFT));
mRemoveButton.setAccessibleText("Don't record audio for selected alias");
mRemoveButton.setTooltip(new Tooltip("Don't record audio for selected alias"));
mRemoveButton.setAlignment(Pos.CENTER);
mRemoveButton.setOnAction(event -> {
Alias selectedAlias = getRecordAliasTableView().getSelectionModel().getSelectedItem();
@@ -392,8 +381,6 @@ public class AliasViewByRecordingEditor extends VBox
mRemoveAllButton.setDisable(true);
mRemoveAllButton.setMaxWidth(Double.MAX_VALUE);
mRemoveAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_LEFT));
mRemoveAllButton.setAccessibleText("Don't record audio for all selected aliases");
mRemoveAllButton.setTooltip(new Tooltip("Don't record audio for all selected aliases"));
mRemoveAllButton.setAlignment(Pos.CENTER);
mRemoveAllButton.setOnAction(event -> {
List<Alias> selectedAliases =

View File

@@ -66,7 +66,6 @@ public class BeepEditor extends ActionEditor<BeepAction>
int row = 0;
Label intervalLabel = new Label(("Beep"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, row);
gridPane.getChildren().add(intervalLabel);
@@ -81,7 +80,6 @@ public class BeepEditor extends ActionEditor<BeepAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -157,7 +155,6 @@ public class BeepEditor extends ActionEditor<BeepAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test beep");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setOnAction(event -> test());
}

View File

@@ -71,7 +71,6 @@ public class ClipEditor extends ActionEditor<ClipAction>
int row = 0;
Label fileLabel = new Label("Audio File");
fileLabel.setLabelFor(getFilePath());
GridPane.setHalignment(fileLabel, HPos.RIGHT);
GridPane.setConstraints(fileLabel, 0, row);
gridPane.getChildren().add(fileLabel);
@@ -84,7 +83,6 @@ public class ClipEditor extends ActionEditor<ClipAction>
gridPane.getChildren().add(getFileChooser());
Label intervalLabel = new Label(("Play Audio Clip"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, ++row);
gridPane.getChildren().add(intervalLabel);
@@ -99,7 +97,6 @@ public class ClipEditor extends ActionEditor<ClipAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -226,7 +223,6 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test audio clip");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setDisable(true);
mTestButton.setOnAction(event -> test());
@@ -240,7 +236,6 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mFileChooser == null)
{
mFileChooser = new Button(("Select ..."));
mFileChooser.setAccessibleText("Select audio file");
mFileChooser.setMaxWidth(Double.MAX_VALUE);
mFileChooser.setDisable(true);
mFileChooser.setOnAction(event -> {
@@ -283,8 +278,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mFilePath == null)
{
mFilePath = new TextField(PLEASE_SELECT_A_FILE);
//Read-only rather than disabled so that the selected file remains focusable for screen readers
mFilePath.setEditable(false);
mFilePath.setDisable(true);
mFilePath.setMaxWidth(Double.MAX_VALUE);
mFilePath.textProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null && !newValue.isEmpty() && !newValue.contentEquals(PLEASE_SELECT_A_FILE))

View File

@@ -71,7 +71,6 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
int row = 0;
Label fileLabel = new Label("Script File");
fileLabel.setLabelFor(getFilePath());
GridPane.setHalignment(fileLabel, HPos.RIGHT);
GridPane.setConstraints(fileLabel, 0, row);
gridPane.getChildren().add(fileLabel);
@@ -84,7 +83,6 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
gridPane.getChildren().add(getFileChooser());
Label intervalLabel = new Label(("Run Script"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, ++row);
gridPane.getChildren().add(intervalLabel);
@@ -99,7 +97,6 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -226,7 +223,6 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test script");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setDisable(true);
mTestButton.setOnAction(event -> test());
@@ -240,7 +236,6 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mFileChooser == null)
{
mFileChooser = new Button(("Select ..."));
mFileChooser.setAccessibleText("Select script file");
mFileChooser.setMaxWidth(Double.MAX_VALUE);
mFileChooser.setDisable(true);
mFileChooser.setOnAction(event -> {
@@ -283,8 +278,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mFilePath == null)
{
mFilePath = new TextField(PLEASE_SELECT_A_FILE);
//Read-only rather than disabled so that the selected file remains focusable for screen readers
mFilePath.setEditable(false);
mFilePath.setDisable(true);
mFilePath.setMaxWidth(Double.MAX_VALUE);
mFilePath.textProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null && !newValue.isEmpty() && !newValue.contentEquals(PLEASE_SELECT_A_FILE))

View File

@@ -44,7 +44,6 @@ public class DcsEditor extends IdentifierEditor<Dcs>
gridPane.setHgap(5);
Label typeLabel = new Label("DCS Code");
typeLabel.setLabelFor(getDCSCodeComboBox());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);

View File

@@ -54,7 +54,6 @@ public class EsnEditor extends IdentifierEditor<Esn>
gridPane.setHgap(5);
Label typeLabel = new Label("ESN");
typeLabel.setLabelFor(getEsnField());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);

View File

@@ -47,7 +47,6 @@ public class LojackEditor extends IdentifierEditor<LoJackFunctionAndID>
gridPane.setHgap(5);
Label typeLabel = new Label("LoJack Function");
typeLabel.setLabelFor(getFunctionComboBox());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);
@@ -58,10 +57,6 @@ public class LojackEditor extends IdentifierEditor<LoJackFunctionAndID>
gridPane.getChildren().add(getIdentifierField());
Label helpLabel = new Label("Format: 5 numbers, characters or (*)wildcard - e.g. AB*12");
//The identifier field has no label of its own, so the help label provides its accessible name and help text
helpLabel.setLabelFor(getIdentifierField());
helpLabel.setAccessibleText("LoJack ID");
getIdentifierField().setAccessibleHelp(helpLabel.getText());
GridPane.setConstraints(helpLabel, 3, 0);
gridPane.getChildren().add(helpLabel);

View File

@@ -76,13 +76,11 @@ public class NXDNTypeDEditor<T extends AliasID & INXDNTypeD> extends IdentifierE
gridPane.add(new Label("NXDN Type-D"), 0, 0);
Label homeRepeaterLabel = new Label("Home Repeater");
homeRepeaterLabel.setLabelFor(mHomeRepeaterField);
GridPane.setHalignment(homeRepeaterLabel, HPos.RIGHT);
gridPane.add(homeRepeaterLabel, 1, 0);
gridPane.add(mHomeRepeaterField, 2, 0);
Label identifierFieldLabel = new Label(identifierLabel);
identifierFieldLabel.setLabelFor(mIdentifierField);
GridPane.setHalignment(identifierFieldLabel, HPos.RIGHT);
gridPane.add(identifierFieldLabel, 3, 0);
gridPane.add(mIdentifierField, 4, 0);

View File

@@ -89,21 +89,15 @@ public class NXDNTypeDRangeEditor<T extends AliasID & INXDNTypeDRange> extends I
gridPane.add(new Label("NXDN Type-D"), 0, 0);
Label homeRepeaterLabel = new Label("Home Repeater");
homeRepeaterLabel.setLabelFor(mHomeRepeaterField);
GridPane.setHalignment(homeRepeaterLabel, HPos.RIGHT);
gridPane.add(homeRepeaterLabel, 1, 0);
gridPane.add(mHomeRepeaterField, 2, 0);
Label rangeFieldLabel = new Label(rangeLabel);
rangeFieldLabel.setLabelFor(mMinField);
rangeFieldLabel.setAccessibleText(rangeLabel + " start");
GridPane.setHalignment(rangeFieldLabel, HPos.RIGHT);
gridPane.add(rangeFieldLabel, 3, 0);
gridPane.add(mMinField, 4, 0);
Label dashLabel = new Label("-");
dashLabel.setLabelFor(mMaxField);
dashLabel.setAccessibleText(rangeLabel + " end");
gridPane.add(dashLabel, 5, 0);
gridPane.add(new Label("-"), 5, 0);
gridPane.add(mMaxField, 6, 0);
getChildren().add(gridPane);

View File

@@ -70,7 +70,6 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("WACN");
valueLabel.setLabelFor(getWacnField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -79,7 +78,6 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getWacnField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 3, 0);
gridPane.getChildren().add(systemLabel);
@@ -88,7 +86,6 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getSystemField());
Label radioLabel = new Label("Radio ID");
radioLabel.setLabelFor(getRadioField());
GridPane.setHalignment(radioLabel, HPos.RIGHT);
GridPane.setConstraints(radioLabel, 5, 0);
gridPane.getChildren().add(radioLabel);

View File

@@ -70,7 +70,6 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("WACN");
valueLabel.setLabelFor(getWacnField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -79,7 +78,6 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getWacnField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 3, 0);
gridPane.getChildren().add(systemLabel);
@@ -88,7 +86,6 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getSystemField());
Label radioLabel = new Label("Talkgroup");
radioLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(radioLabel, HPos.RIGHT);
GridPane.setConstraints(radioLabel, 5, 0);
gridPane.getChildren().add(radioLabel);

View File

@@ -71,7 +71,6 @@ public class RadioIdEditor extends IdentifierEditor<Radio>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Radio ID");
valueLabel.setLabelFor(getRadioIdField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -73,8 +73,6 @@ public class RadioIdRangeEditor extends IdentifierEditor<RadioRange>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Radio ID Range");
valueLabel.setLabelFor(getMinRadioIdField());
valueLabel.setAccessibleText("Radio ID Range start");
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -83,8 +81,6 @@ public class RadioIdRangeEditor extends IdentifierEditor<RadioRange>
gridPane.getChildren().add(getMinRadioIdField());
Label dashLabel = new Label("-");
dashLabel.setLabelFor(getMaxRadioIdField());
dashLabel.setAccessibleText("Radio ID Range end");
GridPane.setConstraints(dashLabel, 3, 0);
gridPane.getChildren().add(dashLabel);
@@ -296,10 +292,10 @@ public class RadioIdRangeEditor extends IdentifierEditor<RadioRange>
new IntegerFormatter(0,0xFFFFFF), "Format: 0 - 16777215"));
details.add(new RadioIdDetail(Protocol.APCO25, IntegerFormat.HEXADECIMAL, new HexFormatter(0,0xFFFFFF),
new HexFormatter(0,0xFFFFFF), "Format: 0 - FFFFFF"));
details.add(new RadioIdDetail(Protocol.NXDN, IntegerFormat.DECIMAL, new IntegerFormatter(1,0xFFFF),
new IntegerFormatter(1,0xFFFF),"Format: 1 - 65,535"));
details.add(new RadioIdDetail(Protocol.NXDN, IntegerFormat.HEXADECIMAL, new HexFormatter(1,0xFFFF),
new HexFormatter(1,0xFFFF),"Format: 1 - FFFF"));
details.add(new RadioIdDetail(Protocol.NXDN, IntegerFormat.DECIMAL, new IntegerFormatter(0,0xFFFF),
new IntegerFormatter(0,0xFFFF),"Format: 1 - 65,535"));
details.add(new RadioIdDetail(Protocol.NXDN, IntegerFormat.HEXADECIMAL, new HexFormatter(0,0xFFFF),
new HexFormatter(0,0xFFFF),"Format: 1 - FFFF"));
details.add(new RadioIdDetail(Protocol.PASSPORT, IntegerFormat.DECIMAL, new IntegerFormatter(0,0x7FFFFF),
new IntegerFormatter(0,0x7FFFFF), "Format: 0 - 8388607"));
details.add(new RadioIdDetail(Protocol.PASSPORT, IntegerFormat.HEXADECIMAL, new HexFormatter(0,0x7FFFFF),

View File

@@ -73,7 +73,6 @@ public class TalkgroupEditor extends IdentifierEditor<Talkgroup>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Talkgroup");
valueLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -75,8 +75,6 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Talkgroup Range");
valueLabel.setLabelFor(getMinTalkgroupField());
valueLabel.setAccessibleText("Talkgroup Range start");
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -85,8 +83,6 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
gridPane.getChildren().add(getMinTalkgroupField());
Label dashLabel = new Label("-");
dashLabel.setLabelFor(getMaxTalkgroupField());
dashLabel.setAccessibleText("Talkgroup Range end");
GridPane.setConstraints(dashLabel, 3, 0);
gridPane.getChildren().add(dashLabel);
@@ -224,7 +220,7 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
if(mMaxTalkgroupField == null)
{
mMaxTalkgroupField = new TextField();
mMaxTalkgroupField.setTextFormatter(mMaxIntegerTextFormatter);
mMaxTalkgroupField.setTextFormatter(mMinIntegerTextFormatter);
}
return mMaxTalkgroupField;
@@ -305,7 +301,7 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
details.add(new TalkgroupDetail(Protocol.DMR, IntegerFormat.DECIMAL, new IntegerFormatter(1,16777215),
new IntegerFormatter(1,16777215), "Format: 1 - 16777215"));
details.add(new TalkgroupDetail(Protocol.DMR, IntegerFormat.HEXADECIMAL, new HexFormatter(1,0XFFFFFF),
new HexFormatter(1, 0xFFFFFF), "Format: 1 - FFFFFF"));
new HexFormatter(1, 0xFFFFFF), "Format: 0 - FFFFFF"));
details.add(new TalkgroupDetail(Protocol.FLEETSYNC, IntegerFormat.FORMATTED,
new PrefixIdentFormatter(0,0xFFFFF), new PrefixIdentFormatter(0,0xFFFFF),
"Format: PPP-IIII = Prefix (0-127), Ident (0-8191)"));
@@ -322,10 +318,10 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
new IntegerFormatter(0,65535), "Format 0 - 65535"));
details.add(new TalkgroupDetail(Protocol.NBFM, IntegerFormat.HEXADECIMAL, new HexFormatter(0,65535),
new HexFormatter(0,65535), "Format 0 - FFFF"));
details.add(new TalkgroupDetail(Protocol.NXDN, IntegerFormat.DECIMAL, new IntegerFormatter(0,0xFFFF),
new IntegerFormatter(0,0xFFFF),"Format: 0 - 65,535"));
details.add(new TalkgroupDetail(Protocol.NXDN, IntegerFormat.HEXADECIMAL, new HexFormatter(0,0xFFFF),
new HexFormatter(0,0xFFFF),"Format: 0 - FFFF"));
details.add(new TalkgroupDetail(Protocol.NXDN, IntegerFormat.DECIMAL, new IntegerFormatter(1,0xFFFF),
new IntegerFormatter(1,0xFFFF),"Format: 1 - 65,535"));
details.add(new TalkgroupDetail(Protocol.NXDN, IntegerFormat.HEXADECIMAL, new HexFormatter(1,0xFFFF),
new HexFormatter(1,0xFFFF),"Format: 1 - FFFF"));
details.add(new TalkgroupDetail(Protocol.PASSPORT, IntegerFormat.DECIMAL, new IntegerFormatter(0,0xFFFF),
new IntegerFormatter(0,0xFFFF), "Format: 0 - 65535"));
details.add(new TalkgroupDetail(Protocol.PASSPORT, IntegerFormat.HEXADECIMAL, new HexFormatter(0,0xFFFF),

View File

@@ -73,7 +73,6 @@ public class TonesEditor extends IdentifierEditor<TonesID>
editorsPane.setVgap(10);
Label toneLabel = new Label("Tone");
toneLabel.setLabelFor(getAmbeToneComboBox());
GridPane.setConstraints(toneLabel, 0, 0);
GridPane.setHalignment(toneLabel, HPos.RIGHT);
editorsPane.getChildren().add(toneLabel);
@@ -82,7 +81,6 @@ public class TonesEditor extends IdentifierEditor<TonesID>
editorsPane.getChildren().add(getAmbeToneComboBox());
Label durationLabel = new Label("Duration 1-50");
durationLabel.setLabelFor(getDurationTextField());
GridPane.setConstraints(durationLabel, 0, 1);
GridPane.setHalignment(durationLabel, HPos.RIGHT);
editorsPane.getChildren().add(durationLabel);
@@ -224,7 +222,6 @@ public class TonesEditor extends IdentifierEditor<TonesID>
iconNode.setIconSize(12);
iconNode.setFill(getMoveUpButton().getTextFill());
mMoveUpButton.setGraphic(iconNode);
mMoveUpButton.setAccessibleText("Move tone up");
mMoveUpButton.setMaxWidth(Double.MAX_VALUE);
mMoveUpButton.setDisable(true);
mMoveUpButton.setOnAction(event -> {
@@ -252,7 +249,6 @@ public class TonesEditor extends IdentifierEditor<TonesID>
iconNode.setIconSize(12);
iconNode.setFill(getMoveDownButton().getTextFill());
mMoveDownButton.setGraphic(iconNode);
mMoveDownButton.setAccessibleText("Move tone down");
mMoveDownButton.setMaxWidth(Double.MAX_VALUE);
mMoveDownButton.setDisable(true);
mMoveDownButton.setOnAction(event -> {
@@ -278,7 +274,6 @@ public class TonesEditor extends IdentifierEditor<TonesID>
mToneListView = new ListView<>();
mToneListView.setDisable(true);
mToneListView.setPrefHeight(75);
mToneListView.setAccessibleText("Tone sequence");
mToneListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
setTone(newValue);
});

View File

@@ -58,7 +58,6 @@ public class UnitStatusEditor extends IdentifierEditor<UnitStatusID>
gridPane.setVgap(3);
Label valueLabel = new Label("Unit Status");
valueLabel.setLabelFor(getUnitStatusField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 0, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -51,7 +51,6 @@ public class UserStatusEditor extends IdentifierEditor<UserStatusID>
gridPane.setVgap(3);
Label valueLabel = new Label("User Status");
valueLabel.setLabelFor(getUserStatusField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 0, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -19,8 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.DbPowerMeter;
import io.github.dsheirer.gui.control.HexFormatter;
import io.github.dsheirer.gui.control.IntegerFormatter;
@@ -136,7 +134,6 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label bandwidthLabel = new Label("Channel Bandwidth");
AccessibilityUtil.labelGroup(bandwidthLabel, getBandwidthButton());
GridPane.setHalignment(bandwidthLabel, HPos.RIGHT);
GridPane.setConstraints(bandwidthLabel, 0, row);
gridPane.getChildren().add(bandwidthLabel);
@@ -145,7 +142,6 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBandwidthButton());
Label squelchLabel = new Label("Squelch Threshold");
squelchLabel.setLabelFor(getSquelchThresholdField());
GridPane.setHalignment(squelchLabel, HPos.RIGHT);
GridPane.setConstraints(squelchLabel, 0, row);
gridPane.getChildren().add(squelchLabel);
@@ -154,7 +150,6 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSquelchThresholdField());
Label autoTrackLabel = new Label("Squelch Auto-Track");
autoTrackLabel.setLabelFor(getSquelchAutoTrackSwitch());
GridPane.setHalignment(autoTrackLabel, HPos.RIGHT);
GridPane.setConstraints(autoTrackLabel, 2, row);
gridPane.getChildren().add(autoTrackLabel);
@@ -164,7 +159,6 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSquelchAutoTrackSwitch());
Label talkgroupLabel = new Label("Talkgroup To Assign");
talkgroupLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(talkgroupLabel, HPos.RIGHT);
GridPane.setConstraints(talkgroupLabel, 4, row);
gridPane.getChildren().add(talkgroupLabel);
@@ -216,7 +210,6 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBasebandRecordSwitch());
Label recordBasebandLabel = new Label("Channel (Baseband I&Q)");
recordBasebandLabel.setLabelFor(getBasebandRecordSwitch());
GridPane.setHalignment(recordBasebandLabel, HPos.LEFT);
GridPane.setConstraints(recordBasebandLabel, 1, 1);
gridPane.getChildren().add(recordBasebandLabel);
@@ -261,7 +254,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{
if(mBasebandRecordSwitch == null)
{
mBasebandRecordSwitch = new AccessibleToggleSwitch();
mBasebandRecordSwitch = new ToggleSwitch();
mBasebandRecordSwitch.setDisable(true);
mBasebandRecordSwitch.setTextAlignment(TextAlignment.RIGHT);
mBasebandRecordSwitch.selectedProperty()
@@ -355,7 +348,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{
if(mSquelchAutoTrackSwitch == null)
{
mSquelchAutoTrackSwitch = new AccessibleToggleSwitch();
mSquelchAutoTrackSwitch = new ToggleSwitch();
mSquelchAutoTrackSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -23,7 +23,6 @@ import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelException;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.MaxLengthUnaryOperator;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.gui.preference.PreferenceEditorType;
@@ -465,7 +464,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
{
if(mAutoStartSwitch == null)
{
mAutoStartSwitch = new AccessibleToggleSwitch();
mAutoStartSwitch = new ToggleSwitch();
mAutoStartSwitch.setDisable(true);
mAutoStartSwitch.setDisable(true);
mAutoStartSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -534,7 +533,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
int row = 0;
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, row);
mTextFieldPane.getChildren().add(systemLabel);
@@ -544,7 +542,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getSystemField());
Label autoStartLabel = new Label("Auto-Start");
autoStartLabel.setLabelFor(getAutoStartSwitch());
GridPane.setHalignment(autoStartLabel, HPos.RIGHT);
GridPane.setConstraints(autoStartLabel, 2, row);
mTextFieldPane.getChildren().add(autoStartLabel);
@@ -557,7 +554,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getPlayButton());
Label siteLabel = new Label("Site");
siteLabel.setLabelFor(getSiteField());
GridPane.setHalignment(siteLabel, HPos.RIGHT);
GridPane.setConstraints(siteLabel, 0, ++row);
mTextFieldPane.getChildren().add(siteLabel);
@@ -567,7 +563,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getSiteField());
Label autoStartOrderLabel = new Label("Start Order");
autoStartOrderLabel.setLabelFor(getAutoStartOrderSpinner());
GridPane.setHalignment(autoStartOrderLabel, HPos.RIGHT);
GridPane.setConstraints(autoStartOrderLabel, 2, row);
mTextFieldPane.getChildren().add(autoStartOrderLabel);
@@ -577,7 +572,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getAutoStartOrderSpinner());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, ++row);
mTextFieldPane.getChildren().add(nameLabel);
@@ -587,7 +581,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getNameField());
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListComboBox());
GridPane.setHalignment(aliasListLabel, HPos.RIGHT);
GridPane.setConstraints(aliasListLabel, 2, row);
mTextFieldPane.getChildren().add(aliasListLabel);
@@ -715,25 +708,20 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
audioPane.add(new Label(title), 0, 0);
Label noiseGainLabel = new Label("Comfort Noise Volume:");
noiseGainLabel.setLabelFor(noiseGainSlider);
GridPane.setHalignment(noiseGainLabel, HPos.RIGHT);
audioPane.add(noiseGainLabel, 1, 0);
audioPane.add(createSliderWithReset(noiseGainSlider, DecodeConfigJMBE.DEFAULT_COMFORT_NOISE_GAIN,
"Reset comfort noise volume"), 2, 0);
audioPane.add(createSliderWithReset(noiseGainSlider, DecodeConfigJMBE.DEFAULT_COMFORT_NOISE_GAIN), 2, 0);
Label agcLabel = new Label("AGC:");
agcLabel.setLabelFor(agcSwitch);
agcLabel.setTooltip(agcSwitch.getTooltip());
GridPane.setHalignment(agcLabel, HPos.RIGHT);
audioPane.add(agcLabel, 3, 0);
audioPane.add(agcSwitch, 4, 0);
Label toneGainLabel = new Label("Tone Volume:");
toneGainLabel.setLabelFor(toneGainSlider);
GridPane.setHalignment(toneGainLabel, HPos.RIGHT);
audioPane.add(toneGainLabel, 1, 1);
audioPane.add(createSliderWithReset(toneGainSlider, DecodeConfigJMBE.DEFAULT_TONE_GAIN, "Reset tone volume"), 2, 1);
audioPane.add(createSliderWithReset(toneGainSlider, DecodeConfigJMBE.DEFAULT_TONE_GAIN), 2, 1);
Label legacyToneLevelsLabel = new Label("Use Legacy Tone Levels:");
legacyToneLevelsLabel.setLabelFor(legacyToneLevelsSwitch);
legacyToneLevelsLabel.setTooltip(legacyToneLevelsSwitch.getTooltip());
GridPane.setHalignment(legacyToneLevelsLabel, HPos.RIGHT);
audioPane.add(legacyToneLevelsLabel, 3, 1);
@@ -751,10 +739,9 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
* current slider value and a small reset button. The label and button track the disabled state of the slider.
* @param slider to wrap
* @param defaultValue to apply to the slider when the reset button is clicked
* @param resetName accessible name for the reset button, announced by screen readers
* @return box containing the slider, the value label and the reset button
*/
private HBox createSliderWithReset(Slider slider, double defaultValue, String resetName)
private HBox createSliderWithReset(Slider slider, double defaultValue)
{
IconNode resetIcon = new IconNode(FontAwesome.UNDO);
resetIcon.setIconSize(10);
@@ -763,7 +750,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
resetIcon.fillProperty().bind(resetButton.textFillProperty());
resetButton.setGraphic(resetIcon);
resetButton.setTooltip(new Tooltip("Reset to default value"));
resetButton.setAccessibleText(resetName);
resetButton.disableProperty().bind(slider.disableProperty());
resetButton.setOnAction(event -> slider.setValue(defaultValue));

View File

@@ -21,7 +21,6 @@ package io.github.dsheirer.gui.playlist.channel;
import com.google.common.base.Joiner;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.IAliasListRefreshListener;
import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.DecoderType;
@@ -337,7 +336,6 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
searchBox.setSpacing(5);
searchBox.setAlignment(Pos.CENTER);
Label searchLabel = new Label("Search:");
searchLabel.setLabelFor(getSearchField());
searchLabel.setAlignment(Pos.CENTER_RIGHT);
searchBox.getChildren().addAll(searchLabel, getSearchField());
@@ -345,7 +343,6 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
viewBox.setSpacing(5);
viewBox.setAlignment(Pos.CENTER);
Label viewLabel = new Label("View Channels:");
AccessibilityUtil.labelGroup(viewLabel, getViewSegmentedButton());
viewBox.getChildren().addAll(viewLabel, getViewSegmentedButton());
mSearchAndViewBox.getChildren().addAll(searchBox, viewBox);
@@ -412,7 +409,6 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(mChannelTableView == null)
{
mChannelTableView = new TableView<>();
mChannelTableView.setAccessibleText("Channels");
TableColumn<Channel,Boolean> playingColumn = new TableColumn("Playing");
playingColumn.setPrefWidth(75);
@@ -429,14 +425,12 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(empty || item == null || !item)
{
setGraphic(null);
setAccessibleText(empty ? null : "No");
}
else
{
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Yes");
}
}
};
@@ -459,14 +453,12 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(empty || item == null || !item)
{
setGraphic(null);
setAccessibleText(empty ? null : "No");
}
else
{
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Yes");
}
}
};

View File

@@ -19,7 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -143,7 +142,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -155,7 +153,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label ignoreDataLabel = new Label("Ignore Data Calls");
ignoreDataLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(ignoreDataLabel, HPos.LEFT);
GridPane.setConstraints(ignoreDataLabel, 3, row);
gridPane.getChildren().add(ignoreDataLabel);
@@ -164,7 +161,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreCRCChecksumsButton());
Label ignoreCRCLabel = new Label("Ignore CRC Checksums (RAS)");
ignoreCRCLabel.setLabelFor(getIgnoreCRCChecksumsButton());
GridPane.setHalignment(ignoreCRCLabel, HPos.LEFT);
GridPane.setConstraints(ignoreCRCLabel, 5, row);
gridPane.getChildren().add(ignoreCRCLabel);
@@ -173,7 +169,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getUseCompressedTalkgroupsToggle());
Label useCompressedTalkgroupsLabel = new Label("Use Compressed Talkgroups");
useCompressedTalkgroupsLabel.setLabelFor(getUseCompressedTalkgroupsToggle());
GridPane.setHalignment(useCompressedTalkgroupsLabel, HPos.LEFT);
GridPane.setConstraints(useCompressedTalkgroupsLabel, 7, row);
gridPane.getChildren().add(useCompressedTalkgroupsLabel);
@@ -201,11 +196,9 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
editorBox.setSpacing(5);
Label lcnLabel = new Label("LCN");
lcnLabel.setLabelFor(getLogicalChannelNumberField());
editorBox.getChildren().addAll(lcnLabel, getLogicalChannelNumberField());
Label downlinkLabel = new Label("Frequency (MHz)");
downlinkLabel.setLabelFor(getDownlinkFrequencyField());
downlinkLabel.setPadding(new Insets(0,0,0,5));
editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField());
@@ -293,7 +286,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mTimeslotFrequencyTable == null)
{
mTimeslotFrequencyTable = new TableView<>(FXCollections.observableArrayList(TimeslotFrequency.extractor()));
mTimeslotFrequencyTable.setAccessibleText("Logical channel number (LCN) to frequency map");
mTimeslotFrequencyTable.setPrefHeight(100.0);
TableColumn<TimeslotFrequency,Number> numberColumn = new TableColumn("LCN");
@@ -354,7 +346,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mAddTimeslotFrequencyButton == null)
{
mAddTimeslotFrequencyButton = new Button("Add");
mAddTimeslotFrequencyButton.setAccessibleText("Add LCN frequency");
mAddTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mAddTimeslotFrequencyButton.setOnAction(event -> addTimeslot());
}
@@ -403,7 +394,6 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mDeleteTimeslotFrequencyButton == null)
{
mDeleteTimeslotFrequencyButton = new Button("Delete");
mDeleteTimeslotFrequencyButton.setAccessibleText("Delete LCN frequency");
mDeleteTimeslotFrequencyButton.setDisable(true);
mDeleteTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mDeleteTimeslotFrequencyButton.setOnAction(new EventHandler<ActionEvent>()
@@ -511,7 +501,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -524,7 +514,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreCRCChecksumsButton == null)
{
mIgnoreCRCChecksumsButton = new AccessibleToggleSwitch();
mIgnoreCRCChecksumsButton = new ToggleSwitch();
mIgnoreCRCChecksumsButton.setDisable(true);
mIgnoreCRCChecksumsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -542,7 +532,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mUseCompressedTalkgroupsToggle == null)
{
mUseCompressedTalkgroupsToggle = new AccessibleToggleSwitch();
mUseCompressedTalkgroupsToggle = new ToggleSwitch();
mUseCompressedTalkgroupsToggle.setTooltip(new Tooltip("Use Compressed Talkgroups. This is only for Hytera Tier-III Trunked Systems"));
mUseCompressedTalkgroupsToggle.setDisable(true);
mUseCompressedTalkgroupsToggle.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -573,7 +563,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -586,7 +576,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));

View File

@@ -19,7 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -147,7 +146,6 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
gridPane.setHgap(10);
Label directionLabel = new Label("Direction");
AccessibilityUtil.labelGroup(directionLabel, getDirectionButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 0, 0);
gridPane.getChildren().add(directionLabel);

View File

@@ -19,7 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -147,7 +146,6 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
gridPane.setHgap(10);
Label directionLabel = new Label("Direction");
AccessibilityUtil.labelGroup(directionLabel, getDirectionButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 0, 0);
gridPane.getChildren().add(directionLabel);

View File

@@ -126,7 +126,6 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.setVgap(10);
Label channelMapLabel = new Label("Channel Map");
channelMapLabel.setLabelFor(getChannelMapComboBox());
GridPane.setHalignment(channelMapLabel, HPos.RIGHT);
GridPane.setConstraints(channelMapLabel, 0, 0);
gridPane.getChildren().add(channelMapLabel);
@@ -139,7 +138,6 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getChannelMapEditButton());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, 1);
gridPane.getChildren().add(poolSizeLabel);
@@ -148,7 +146,6 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getTrafficChannelPoolSizeSpinner());
Label callTimeoutLabel = new Label("Call Timeout Seconds");
callTimeoutLabel.setLabelFor(getCallTimeoutSpinner());
GridPane.setHalignment(callTimeoutLabel, HPos.RIGHT);
GridPane.setConstraints(callTimeoutLabel, 2, 1);
gridPane.getChildren().add(callTimeoutLabel);

View File

@@ -19,8 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.HexFormatter;
import io.github.dsheirer.gui.control.IntegerFormatter;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
@@ -137,7 +135,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// channel bandwidth
Label bandwidthLabel = new Label("Channel Bandwidth");
AccessibilityUtil.labelGroup(bandwidthLabel, getBandwidthButton());
GridPane.setHalignment(bandwidthLabel, HPos.RIGHT);
GridPane.setConstraints(bandwidthLabel, 0, 0);
gridPane.getChildren().add(bandwidthLabel);
@@ -147,7 +144,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
//De-emphasis
Label deemphasisLabel = new Label("De-emphasis");
deemphasisLabel.setLabelFor(getDeemphasisCombo());
GridPane.setHalignment(deemphasisLabel, HPos.RIGHT);
GridPane.setConstraints(deemphasisLabel, 0, 1);
gridPane.getChildren().add(deemphasisLabel);
@@ -158,7 +154,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// Note: normally the label and its toggle switch are one cell. They were split to make the next row
// look better. The label is manually created and placed here. Might want to create a new grid pane instead.
Label HPFLabel = new Label("High-pass Audio Filter (300 Hz)");
HPFLabel.setLabelFor(getAudioFilterEnable());
GridPane.setHalignment(HPFLabel, HPos.RIGHT);
GridPane.setConstraints(HPFLabel, 2, 1);
gridPane.getChildren().add(HPFLabel);
@@ -177,7 +172,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
*/
// talkgroup
Label talkgroupLabel = new Label("Talkgroup To Assign");
talkgroupLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(talkgroupLabel, HPos.RIGHT);
GridPane.setConstraints(talkgroupLabel, 0, 2);
gridPane.getChildren().add(talkgroupLabel);
@@ -204,7 +198,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
modifiedProperty().set(true);
});
GridPane.setConstraints(mSquelchTypeCombo, 3, 2);
typeLabel.setLabelFor(mSquelchTypeCombo);
gridPane.getChildren().add(mSquelchTypeCombo);
// CTCSS code selector
@@ -325,7 +318,6 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBasebandRecordSwitch());
Label recordBasebandLabel = new Label("Channel (Baseband I&Q)");
recordBasebandLabel.setLabelFor(getBasebandRecordSwitch());
GridPane.setHalignment(recordBasebandLabel, HPos.LEFT);
GridPane.setConstraints(recordBasebandLabel, 1, 0);
gridPane.getChildren().add(recordBasebandLabel);
@@ -389,7 +381,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// removed label from toggle switch so that the label and the switch can be in different columns
// to make things look better on the next line. Perhaps make a new grid pane instead.
//mAudioFilterEnable = new ToggleSwitch("High-Pass Audio Filter (300 Hz)");
mAudioFilterEnable = new AccessibleToggleSwitch("");
mAudioFilterEnable = new ToggleSwitch("");
mAudioFilterEnable.setTooltip(new Tooltip("High-pass filter to remove DC offset and sub-audible signalling"));
mAudioFilterEnable.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
@@ -404,7 +396,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{
if(mALCEnable == null)
{
mALCEnable = new AccessibleToggleSwitch("Automatic Level Control");
mALCEnable = new ToggleSwitch("Automatic Level Control");
mALCEnable.setTooltip(new Tooltip("Automatic Level Control (ALC). Tries to make the volume of each received transmission the same."));
mALCEnable.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
@@ -526,7 +518,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{
if(mBasebandRecordSwitch == null)
{
mBasebandRecordSwitch = new AccessibleToggleSwitch();
mBasebandRecordSwitch = new ToggleSwitch();
mBasebandRecordSwitch.setDisable(true);
mBasebandRecordSwitch.setTextAlignment(TextAlignment.RIGHT);
mBasebandRecordSwitch.selectedProperty()

View File

@@ -19,8 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -150,7 +148,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label mode = new Label("Mode:");
AccessibilityUtil.labelGroup(mode, getTransmissionModeButton());
GridPane.setHalignment(mode, HPos.RIGHT);
GridPane.setConstraints(mode, 0, row);
gridPane.getChildren().add(mode);
@@ -159,7 +156,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getTransmissionModeButton());
Label encoding = new Label("Talker Alias Encoding:");
encoding.setLabelFor(getEncodingComboBox());
GridPane.setHalignment(encoding, HPos.RIGHT);
GridPane.setConstraints(encoding, 2, row);
gridPane.getChildren().add(encoding);
@@ -168,7 +164,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getEncodingComboBox());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 4, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -210,11 +205,9 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
editorBox.setSpacing(5);
Label lcnLabel = new Label("Channel Number");
lcnLabel.setLabelFor(getChannelField());
editorBox.getChildren().addAll(lcnLabel, getChannelField());
Label downlinkLabel = new Label("Downlink Frequency (MHz)");
downlinkLabel.setLabelFor(getDownlinkFrequencyField());
downlinkLabel.setPadding(new Insets(0,0,0,5));
editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField());
@@ -319,7 +312,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mChannelMapTable == null)
{
mChannelMapTable = new TableView<>(FXCollections.observableArrayList(ObservableChannelFrequency.extractor()));
mChannelMapTable.setAccessibleText("Channel number (LCN) to frequency map");
mChannelMapTable.setPrefHeight(100.0);
TableColumn<ObservableChannelFrequency,Number> channelColumn = new TableColumn<>("Channel");
@@ -409,7 +401,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mAddTimeslotFrequencyButton == null)
{
mAddTimeslotFrequencyButton = new Button("Add");
mAddTimeslotFrequencyButton.setAccessibleText("Add channel frequency");
mAddTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mAddTimeslotFrequencyButton.setOnAction(event -> addChannelFrequency());
}
@@ -434,7 +425,6 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mDeleteButton == null)
{
mDeleteButton = new Button("Delete");
mDeleteButton.setAccessibleText("Delete channel frequency");
mDeleteButton.setDisable(true);
mDeleteButton.setMaxWidth(Double.MAX_VALUE);
mDeleteButton.setOnAction(event -> {
@@ -529,8 +519,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsToggle == null)
{
mIgnoreDataCallsToggle = new AccessibleToggleSwitch("Data Calls");
mIgnoreDataCallsToggle.setAccessibleText("Ignore data calls");
mIgnoreDataCallsToggle = new ToggleSwitch("Data Calls");
mIgnoreDataCallsToggle.setDisable(true);
mIgnoreDataCallsToggle.selectedProperty().addListener((o, ov, nv) -> modifiedProperty().set(true));
}
@@ -545,8 +534,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreEncryptedCallsToggle == null)
{
mIgnoreEncryptedCallsToggle = new AccessibleToggleSwitch("Encrypted Calls");
mIgnoreEncryptedCallsToggle.setAccessibleText("Ignore encrypted calls");
mIgnoreEncryptedCallsToggle = new ToggleSwitch("Encrypted Calls");
mIgnoreEncryptedCallsToggle.setDisable(true);
mIgnoreEncryptedCallsToggle.selectedProperty().addListener((o, ov, nv) -> modifiedProperty().set(true));
}
@@ -558,7 +546,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -571,7 +559,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeLegacyToneLevelsButton == null)
{
mJmbeLegacyToneLevelsButton = new AccessibleToggleSwitch();
mJmbeLegacyToneLevelsButton = new ToggleSwitch();
mJmbeLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));

View File

@@ -19,8 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
import io.github.dsheirer.gui.playlist.source.FrequencyEditor;
@@ -131,7 +129,6 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label modulationLabel = new Label("Modulation");
AccessibilityUtil.labelGroup(modulationLabel, getModulationSegmentedButton());
GridPane.setHalignment(modulationLabel, HPos.RIGHT);
GridPane.setConstraints(modulationLabel, 0, row);
gridPane.getChildren().add(modulationLabel);
@@ -140,7 +137,6 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().addAll(getModulationSegmentedButton());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 2, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -152,7 +148,6 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label directionLabel = new Label("Ignore Data Calls");
directionLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 5, row);
gridPane.getChildren().add(directionLabel);
@@ -273,7 +268,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -286,7 +281,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));
@@ -347,7 +342,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -19,7 +19,6 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -125,7 +124,6 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -137,13 +135,11 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label directionLabel = new Label("Ignore Data Calls");
directionLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 3, row);
gridPane.getChildren().add(directionLabel);
Label wacnLabel = new Label("WACN");
wacnLabel.setLabelFor(getWacnTextField());
GridPane.setHalignment(wacnLabel, HPos.RIGHT);
GridPane.setConstraints(wacnLabel, 0, ++row);
gridPane.getChildren().add(wacnLabel);
@@ -152,7 +148,6 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getWacnTextField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 2, row);
gridPane.getChildren().add(systemLabel);
@@ -161,7 +156,6 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSystemTextField());
Label nacLabel = new Label("NAC");
nacLabel.setLabelFor(getNacTextField());
GridPane.setHalignment(nacLabel, HPos.RIGHT);
GridPane.setConstraints(nacLabel, 4, row);
gridPane.getChildren().add(nacLabel);
@@ -189,7 +183,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -202,7 +196,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));
@@ -304,7 +298,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -276,7 +276,6 @@ public class ChannelMapEditor extends SplitPane
if(mChannelMapListView == null)
{
mChannelMapListView = new ListView<>();
mChannelMapListView.setAccessibleText("Channel maps");
mChannelMapListView.setItems(mChannelMapModel.getChannelMaps());
mChannelMapListView.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> {
@@ -391,7 +390,6 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.setHgap(5);
Label firstLabel = new Label("First Channel");
firstLabel.setLabelFor(getFirstField());
GridPane.setHalignment(firstLabel, HPos.RIGHT);
GridPane.setConstraints(firstLabel, 0, 0);
mChannelRangePane.getChildren().add(firstLabel);
@@ -401,7 +399,6 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getFirstField());
Label lastLabel = new Label("Last Channel");
lastLabel.setLabelFor(getLastField());
GridPane.setHalignment(lastLabel, HPos.RIGHT);
GridPane.setConstraints(lastLabel, 0, 1);
mChannelRangePane.getChildren().add(lastLabel);
@@ -411,7 +408,6 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getLastField());
Label baseLabel = new Label("Base Frequency (Hz)");
baseLabel.setLabelFor(getBaseFrequencyField());
GridPane.setHalignment(baseLabel, HPos.RIGHT);
GridPane.setConstraints(baseLabel, 0, 2);
mChannelRangePane.getChildren().add(baseLabel);
@@ -421,7 +417,6 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getBaseFrequencyField());
Label stepSizeLabel = new Label("Step Size (Hz)");
stepSizeLabel.setLabelFor(getStepSizeField());
GridPane.setHalignment(stepSizeLabel, HPos.RIGHT);
GridPane.setConstraints(stepSizeLabel, 0, 3);
mChannelRangePane.getChildren().add(stepSizeLabel);
@@ -450,9 +445,7 @@ public class ChannelMapEditor extends SplitPane
nameBox.setSpacing(10);
nameBox.setAlignment(Pos.CENTER);
HBox.setHgrow(getNameField(), Priority.ALWAYS);
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameField());
nameBox.getChildren().addAll(nameLabel, getNameField());
nameBox.getChildren().addAll(new Label("Name"), getNameField());
VBox contentsBox = new VBox();
VBox.setVgrow(nameBox, Priority.NEVER);
@@ -606,7 +599,6 @@ public class ChannelMapEditor extends SplitPane
if(mChannelRangeTableView == null)
{
mChannelRangeTableView = new TableView<>();
mChannelRangeTableView.setAccessibleText("Channel ranges");
TableColumn<ChannelRange,Integer> firstColumn = new TableColumn("First");
firstColumn.setCellValueFactory(new PropertyValueFactory<ChannelRange,Integer>("firstChannel"));
@@ -798,8 +790,6 @@ public class ChannelMapEditor extends SplitPane
item == null || empty);
this.setStyle(invalidRange ? BACKGROUND_COLOR_RED : BACKGROND_COLOR_NONE);
//Invalid ranges are only shown in red, so also report them to screen readers
setAccessibleText(invalidRange && item != null && !empty ? item + ", invalid or overlapping range" : null);
}
@Override

View File

@@ -22,7 +22,6 @@
package io.github.dsheirer.gui.playlist.decoder;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
@@ -122,7 +121,6 @@ public class AuxDecoderConfigurationEditor extends Editor<AuxDecodeConfiguration
getChildren().add(getToggleSwitch());
Label label = new Label(mDecoderType.getDisplayString());
label.setLabelFor(getToggleSwitch());
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setConstraints(label, 1, 0);
getChildren().add(label);
@@ -132,7 +130,7 @@ public class AuxDecoderConfigurationEditor extends Editor<AuxDecodeConfiguration
{
if(mToggleSwitch == null)
{
mToggleSwitch = new AccessibleToggleSwitch();
mToggleSwitch = new ToggleSwitch();
mToggleSwitch.setDisable(true);
mToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -22,7 +22,6 @@
package io.github.dsheirer.gui.playlist.eventlog;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.module.log.EventLogType;
import io.github.dsheirer.module.log.config.EventLogConfiguration;
@@ -118,7 +117,6 @@ public class EventLogConfigurationEditor extends Editor<EventLogConfiguration>
getChildren().add(getToggleSwitch());
Label label = new Label(mEventLogType.getDisplayString());
label.setLabelFor(getToggleSwitch());
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setConstraints(label, 1, 0);
getChildren().add(label);
@@ -128,7 +126,7 @@ public class EventLogConfigurationEditor extends Editor<EventLogConfiguration>
{
if(mToggleSwitch == null)
{
mToggleSwitch = new AccessibleToggleSwitch();
mToggleSwitch = new ToggleSwitch();
mToggleSwitch.setDisable(true);
mToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -127,7 +127,6 @@ public class PlaylistManagerEditor extends HBox
if(mPlaylistTableView == null)
{
mPlaylistTableView = new TableView<>();
mPlaylistTableView.setAccessibleText("Playlists");
TableColumn<Path,String> iconColumn = new TableColumn("Selected");
iconColumn.setPrefWidth(100);
iconColumn.setCellFactory(new Callback<TableColumn<Path,String>,TableCell<Path,String>>()
@@ -145,7 +144,6 @@ public class PlaylistManagerEditor extends HBox
if(empty || getTableRow() == null || getTableRow().getItem() == null)
{
setGraphic(null);
setAccessibleText(null);
}
else
{
@@ -156,19 +154,16 @@ public class PlaylistManagerEditor extends HBox
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Selected");
}
else if(!path.toFile().exists())
{
IconNode iconNode = new IconNode(FontAwesome.TIMES);
iconNode.setFill(Color.RED);
setGraphic(iconNode);
setAccessibleText("File not found");
}
else
{
setGraphic(null);
setAccessibleText("Not selected");
}
}
}

View File

@@ -138,7 +138,6 @@ public class AgencyEditor extends VBox
if(mAgencyListView == null)
{
mAgencyListView = new ListView<>();
mAgencyListView.setAccessibleText("Agencies");
mAgencyListView.setPrefHeight(200);
mAgencyListView.setCellFactory(param -> new AgencyListCell());
mAgencyListView.getSelectionModel().selectedItemProperty()

View File

@@ -94,7 +94,6 @@ public class AgencyFrequencyEditor extends GridPane
getColumnConstraints().addAll(column1, column2, column3);
Label categoryLabel = new Label("Category");
categoryLabel.setLabelFor(getCategoryComboBox());
GridPane.setConstraints(categoryLabel, 0, row);
GridPane.setHalignment(categoryLabel, HPos.RIGHT);
getChildren().add(categoryLabel);
@@ -104,7 +103,6 @@ public class AgencyFrequencyEditor extends GridPane
getChildren().add(getCategoryComboBox());
Label subCategoryLabel = new Label("Sub-Category");
subCategoryLabel.setLabelFor(getSubCategoryComboBox());
GridPane.setConstraints(subCategoryLabel, 0, ++row);
GridPane.setHalignment(subCategoryLabel, HPos.RIGHT);
getChildren().add(subCategoryLabel);
@@ -209,7 +207,6 @@ public class AgencyFrequencyEditor extends GridPane
if(mFrequencyTableView == null)
{
mFrequencyTableView = new TableView<>();
mFrequencyTableView.setAccessibleText("Agency frequencies");
mFrequencyTableView.setMaxHeight(Double.MAX_VALUE);
mFrequencyTableView.setPlaceholder(getPlaceholderLabel());

View File

@@ -97,7 +97,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(detailsLabel);
Label alphaLabel = new Label("Alpha Tag");
alphaLabel.setLabelFor(getAlphaTagTextField());
GridPane.setHalignment(alphaLabel, HPos.RIGHT);
GridPane.setConstraints(alphaLabel, 0, ++row);
gridPane.getChildren().add(alphaLabel);
@@ -107,7 +106,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getAlphaTagTextField());
Label toneLabel = new Label("Tone");
toneLabel.setLabelFor(getToneTextField());
GridPane.setHalignment(toneLabel, HPos.RIGHT);
GridPane.setConstraints(toneLabel, 0, ++row);
gridPane.getChildren().add(toneLabel);
@@ -117,7 +115,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getToneTextField());
Label modeLabel = new Label("Mode");
modeLabel.setLabelFor(getModeTextField());
GridPane.setHalignment(modeLabel, HPos.RIGHT);
GridPane.setConstraints(modeLabel, 0, ++row);
gridPane.getChildren().add(modeLabel);
@@ -127,7 +124,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getModeTextField());
Label frequencyLabel = new Label("Frequency");
frequencyLabel.setLabelFor(getFrequencyTextField());
GridPane.setHalignment(frequencyLabel, HPos.RIGHT);
GridPane.setConstraints(frequencyLabel, 0, ++row);
gridPane.getChildren().add(frequencyLabel);
@@ -145,7 +141,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(createLabel);
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, ++row);
gridPane.getChildren().add(systemLabel);
@@ -155,7 +150,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getSystemTextField());
Label siteLabel = new Label("Site");
siteLabel.setLabelFor(getSiteTextField());
GridPane.setHalignment(siteLabel, HPos.RIGHT);
GridPane.setConstraints(siteLabel, 0, ++row);
gridPane.getChildren().add(siteLabel);
@@ -165,7 +159,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getSiteTextField());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, ++row);
gridPane.getChildren().add(nameLabel);
@@ -175,7 +168,6 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getNameTextField());
Label decoderLabel = new Label("Decoder");
decoderLabel.setLabelFor(getDecoderTextField());
GridPane.setHalignment(decoderLabel, HPos.RIGHT);
GridPane.setConstraints(decoderLabel, 0, ++row);
gridPane.getChildren().add(decoderLabel);

Some files were not shown because too many files have changed in this diff Show More